set the include directory
[AROS-Contrib.git] / Games / Doom / p_enemy.c
blob97e437511b6771fde5499412d6348bdb79ac26e0
1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id$
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 //
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15 // for more details.
17 // $Log$
18 // Revision 1.3 2004/04/28 10:17:39 hkiel
19 // For consistency use __AMIGAOS__ instead of AMIGAOS and enable Xaos again
21 // Revision 1.2 2004/04/27 16:42:56 hkiel
22 // Fixed #ifdef AMIGA to #ifdef AMIGAOS
24 // Revision 1.1 2000/02/29 18:21:04 stegerg
25 // Doom port based on ADoomPPC. Read README.AROS!
28 // DESCRIPTION:
29 // Enemy thinking, AI.
30 // Action Pointer Functions
31 // that are associated with states/frames.
33 //-----------------------------------------------------------------------------
35 static const char
36 rcsid[] = "$Id$";
38 #ifdef AROS
39 #define iabs abs
40 #endif
42 #include <stdlib.h>
43 #ifdef __AMIGAOS__
44 #include <dos.h>
45 #endif
47 #include "m_random.h"
48 #include "i_system.h"
50 #include "doomdef.h"
51 #include "p_local.h"
53 #include "s_sound.h"
55 #include "g_game.h"
57 // State.
58 #include "doomstat.h"
59 #include "r_state.h"
61 // Data.
62 #include "sounds.h"
67 typedef enum
69 DI_EAST,
70 DI_NORTHEAST,
71 DI_NORTH,
72 DI_NORTHWEST,
73 DI_WEST,
74 DI_SOUTHWEST,
75 DI_SOUTH,
76 DI_SOUTHEAST,
77 DI_NODIR,
78 NUMDIRS
80 } dirtype_t;
84 // P_NewChaseDir related LUT.
86 dirtype_t opposite[] =
88 DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST,
89 DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_NODIR
92 dirtype_t diags[] =
94 DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST
101 void A_Fall (mobj_t *actor);
105 // ENEMY THINKING
106 // Enemies are allways spawned
107 // with targetplayer = -1, threshold = 0
108 // Most monsters are spawned unaware of all players,
109 // but some can be made preaware
114 // Called by P_NoiseAlert.
115 // Recursively traverse adjacent sectors,
116 // sound blocking lines cut off traversal.
119 mobj_t* soundtarget;
121 void
122 P_RecursiveSound
123 ( sector_t* sec,
124 int soundblocks )
126 int i;
127 line_t* check;
128 sector_t* other;
130 // wake up all monsters in this sector
131 if (sec->validcount == validcount
132 && sec->soundtraversed <= soundblocks+1)
134 return; // already flooded
137 sec->validcount = validcount;
138 sec->soundtraversed = soundblocks+1;
139 sec->soundtarget = soundtarget;
141 for (i=0 ;i<sec->linecount ; i++)
143 check = sec->lines[i];
144 if (! (check->flags & ML_TWOSIDED) )
145 continue;
147 P_LineOpening (check);
149 if (openrange <= 0)
150 continue; // closed door
152 if ( sides[ check->sidenum[0] ].sector == sec)
153 other = sides[ check->sidenum[1] ] .sector;
154 else
155 other = sides[ check->sidenum[0] ].sector;
157 if (check->flags & ML_SOUNDBLOCK)
159 if (!soundblocks)
160 P_RecursiveSound (other, 1);
162 else
163 P_RecursiveSound (other, soundblocks);
170 // P_NoiseAlert
171 // If a monster yells at a player,
172 // it will alert other monsters to the player.
174 void
175 P_NoiseAlert
176 ( mobj_t* target,
177 mobj_t* emmiter )
179 soundtarget = target;
180 validcount++;
181 P_RecursiveSound (emmiter->subsector->sector, 0);
188 // P_CheckMeleeRange
190 boolean P_CheckMeleeRange (mobj_t* actor)
192 mobj_t* pl;
193 fixed_t dist;
195 if (!actor->target)
196 return false;
198 pl = actor->target;
199 dist = P_AproxDistance (pl->x-actor->x, pl->y-actor->y);
201 if (dist >= MELEERANGE-20*FRACUNIT+pl->info->radius)
202 return false;
204 if (! P_CheckSight (actor, actor->target) )
205 return false;
207 return true;
211 // P_CheckMissileRange
213 boolean P_CheckMissileRange (mobj_t* actor)
215 fixed_t dist;
217 if (! P_CheckSight (actor, actor->target) )
218 return false;
220 if ( actor->flags & MF_JUSTHIT )
222 // the target just hit the enemy,
223 // so fight back!
224 actor->flags &= ~MF_JUSTHIT;
225 return true;
228 if (actor->reactiontime)
229 return false; // do not attack yet
231 // OPTIMIZE: get this from a global checksight
232 dist = P_AproxDistance ( actor->x-actor->target->x,
233 actor->y-actor->target->y) - 64*FRACUNIT;
235 if (!actor->info->meleestate)
236 dist -= 128*FRACUNIT; // no melee attack, so fire more
238 dist >>= 16;
240 if (actor->type == MT_VILE)
242 if (dist > 14*64)
243 return false; // too far away
247 if (actor->type == MT_UNDEAD)
249 if (dist < 196)
250 return false; // close for fist attack
251 dist >>= 1;
255 if (actor->type == MT_CYBORG
256 || actor->type == MT_SPIDER
257 || actor->type == MT_SKULL)
259 dist >>= 1;
262 if (dist > 200)
263 dist = 200;
265 if (actor->type == MT_CYBORG && dist > 160)
266 dist = 160;
268 if (P_Random () < dist)
269 return false;
271 return true;
276 // P_Move
277 // Move in the current direction,
278 // returns false if the move is blocked.
280 fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};
281 fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};
283 #define MAXSPECIALCROSS 20 /* was 8 */
285 extern line_t* spechit[MAXSPECIALCROSS];
286 extern int numspechit;
288 boolean P_Move (mobj_t* actor)
290 fixed_t tryx;
291 fixed_t tryy;
293 line_t* ld;
295 // warning: 'catch', 'throw', and 'try'
296 // are all C++ reserved words
297 boolean try_ok;
298 boolean good;
300 if (actor->movedir == DI_NODIR)
301 return false;
303 if ((unsigned)actor->movedir >= 8)
304 I_Error ("Weird actor->movedir!");
306 tryx = actor->x + actor->info->speed*xspeed[actor->movedir];
307 tryy = actor->y + actor->info->speed*yspeed[actor->movedir];
309 try_ok = P_TryMove (actor, tryx, tryy);
311 if (!try_ok)
313 // open any specials
314 if (actor->flags & MF_FLOAT && floatok)
316 // must adjust height
317 if (actor->z < tmfloorz)
318 actor->z += FLOATSPEED;
319 else
320 actor->z -= FLOATSPEED;
322 actor->flags |= MF_INFLOAT;
323 return true;
326 if (!numspechit)
327 return false;
329 actor->movedir = DI_NODIR;
330 good = false;
331 while (numspechit--)
333 ld = spechit[numspechit];
334 // if the special is not a door
335 // that can be opened,
336 // return false
337 if (P_UseSpecialLine (actor, ld,0))
338 good = true;
340 return good;
342 else
344 actor->flags &= ~MF_INFLOAT;
348 if (! (actor->flags & MF_FLOAT) )
349 actor->z = actor->floorz;
350 return true;
355 // TryWalk
356 // Attempts to move actor on
357 // in its current (ob->moveangle) direction.
358 // If blocked by either a wall or an actor
359 // returns FALSE
360 // If move is either clear or blocked only by a door,
361 // returns TRUE and sets...
362 // If a door is in the way,
363 // an OpenDoor call is made to start it opening.
365 boolean P_TryWalk (mobj_t* actor)
367 if (!P_Move (actor))
369 return false;
372 actor->movecount = P_Random()&15;
373 return true;
379 void P_NewChaseDir (mobj_t* actor)
381 fixed_t deltax;
382 fixed_t deltay;
384 dirtype_t d[3];
386 int tdir;
387 dirtype_t olddir;
389 dirtype_t turnaround;
391 if (!actor->target)
392 I_Error ("P_NewChaseDir: called with no target");
394 olddir = actor->movedir;
395 turnaround=opposite[olddir];
397 deltax = actor->target->x - actor->x;
398 deltay = actor->target->y - actor->y;
400 if (deltax>10*FRACUNIT)
401 d[1]= DI_EAST;
402 else if (deltax<-10*FRACUNIT)
403 d[1]= DI_WEST;
404 else
405 d[1]=DI_NODIR;
407 if (deltay<-10*FRACUNIT)
408 d[2]= DI_SOUTH;
409 else if (deltay>10*FRACUNIT)
410 d[2]= DI_NORTH;
411 else
412 d[2]=DI_NODIR;
414 // try direct route
415 if (d[1] != DI_NODIR
416 && d[2] != DI_NODIR)
418 actor->movedir = diags[((deltay<0)<<1)+(deltax>0)];
419 if (actor->movedir != turnaround && P_TryWalk(actor))
420 return;
423 // try other directions
424 if (P_Random() > 200
425 || iabs(deltay)>iabs(deltax))
427 tdir=d[1];
428 d[1]=d[2];
429 d[2]=tdir;
432 if (d[1]==turnaround)
433 d[1]=DI_NODIR;
434 if (d[2]==turnaround)
435 d[2]=DI_NODIR;
437 if (d[1]!=DI_NODIR)
439 actor->movedir = d[1];
440 if (P_TryWalk(actor))
442 // either moved forward or attacked
443 return;
447 if (d[2]!=DI_NODIR)
449 actor->movedir =d[2];
451 if (P_TryWalk(actor))
452 return;
455 // there is no direct path to the player,
456 // so pick another direction.
457 if (olddir!=DI_NODIR)
459 actor->movedir =olddir;
461 if (P_TryWalk(actor))
462 return;
465 // randomly determine direction of search
466 if (P_Random()&1)
468 for ( tdir=DI_EAST;
469 tdir<=DI_SOUTHEAST;
470 tdir++ )
472 if (tdir!=turnaround)
474 actor->movedir =tdir;
476 if ( P_TryWalk(actor) )
477 return;
481 else
483 for ( tdir=DI_SOUTHEAST;
484 tdir != (DI_EAST-1);
485 tdir-- )
487 if (tdir!=turnaround)
489 actor->movedir =tdir;
491 if ( P_TryWalk(actor) )
492 return;
497 if (turnaround != DI_NODIR)
499 actor->movedir =turnaround;
500 if ( P_TryWalk(actor) )
501 return;
504 actor->movedir = DI_NODIR; // can not move
510 // P_LookForPlayers
511 // If allaround is false, only look 180 degrees in front.
512 // Returns true if a player is targeted.
514 boolean
515 P_LookForPlayers
516 ( mobj_t* actor,
517 boolean allaround )
519 int c;
520 int stop;
521 player_t* player;
522 sector_t* sector;
523 angle_t an;
524 fixed_t dist;
526 sector = actor->subsector->sector;
528 c = 0;
529 stop = (actor->lastlook-1)&3;
531 for ( ; ; actor->lastlook = (actor->lastlook+1)&3 )
533 if (!playeringame[actor->lastlook]) {
534 #ifdef __AMIGAOS__
535 chkabort ();
536 #endif
537 continue;
540 if (c++ == 2
541 || actor->lastlook == stop)
543 // done looking
544 return false;
547 player = &players[actor->lastlook];
549 if (player->health <= 0)
550 continue; // dead
552 if (!P_CheckSight (actor, player->mo))
553 continue; // out of sight
555 if (!allaround)
557 an = R_PointToAngle2 (actor->x,
558 actor->y,
559 player->mo->x,
560 player->mo->y)
561 - actor->angle;
563 if (an > ANG90 && an < ANG270)
565 dist = P_AproxDistance (player->mo->x - actor->x,
566 player->mo->y - actor->y);
567 // if real close, react anyway
568 if (dist > MELEERANGE)
569 continue; // behind back
573 actor->target = player->mo;
574 return true;
577 return false;
582 // A_KeenDie
583 // DOOM II special, map 32.
584 // Uses special tag 666.
586 void A_KeenDie (mobj_t* mo)
588 thinker_t* th;
589 mobj_t* mo2;
590 line_t junk;
592 A_Fall (mo);
594 // scan the remaining thinkers
595 // to see if all Keens are dead
596 for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
598 if (th->function.acp1 != (actionf_p1)P_MobjThinker)
599 continue;
601 mo2 = (mobj_t *)th;
602 if (mo2 != mo
603 && mo2->type == mo->type
604 && mo2->health > 0)
606 // other Keen not dead
607 return;
611 junk.tag = 666;
612 EV_DoDoor(&junk,open);
617 // ACTION ROUTINES
621 // A_Look
622 // Stay in state until a player is sighted.
624 void A_Look (mobj_t* actor)
626 mobj_t* targ;
628 actor->threshold = 0; // any shot will wake up
629 targ = actor->subsector->sector->soundtarget;
631 if (targ
632 && (targ->flags & MF_SHOOTABLE) )
634 actor->target = targ;
636 if ( actor->flags & MF_AMBUSH )
638 if (P_CheckSight (actor, actor->target))
639 goto seeyou;
641 else
642 goto seeyou;
646 if (!P_LookForPlayers (actor, false) )
647 return;
649 // go into chase state
650 seeyou:
651 if (actor->info->seesound)
653 int sound;
655 switch (actor->info->seesound)
657 case sfx_posit1:
658 case sfx_posit2:
659 case sfx_posit3:
660 sound = sfx_posit1+P_Random()%3;
661 break;
663 case sfx_bgsit1:
664 case sfx_bgsit2:
665 sound = sfx_bgsit1+P_Random()%2;
666 break;
668 default:
669 sound = actor->info->seesound;
670 break;
673 if (actor->type==MT_SPIDER
674 || actor->type == MT_CYBORG)
676 // full volume
677 S_StartSound (NULL, sound);
679 else
680 S_StartSound (actor, sound);
683 P_SetMobjState (actor, actor->info->seestate);
688 // A_Chase
689 // Actor has a melee attack,
690 // so it tries to close as fast as possible
692 void A_Chase (mobj_t* actor)
694 int delta;
696 if (actor->reactiontime)
697 actor->reactiontime--;
700 // modify target threshold
701 if (actor->threshold)
703 if (!actor->target
704 || actor->target->health <= 0)
706 actor->threshold = 0;
708 else
709 actor->threshold--;
712 // turn towards movement direction if not there yet
713 if (actor->movedir < 8)
715 actor->angle &= (7<<29);
716 delta = actor->angle - (actor->movedir << 29);
718 if (delta > 0)
719 actor->angle -= ANG90/2;
720 else if (delta < 0)
721 actor->angle += ANG90/2;
724 if (!actor->target
725 || !(actor->target->flags&MF_SHOOTABLE))
727 // look for a new target
728 if (P_LookForPlayers(actor,true))
729 return; // got a new target
731 P_SetMobjState (actor, actor->info->spawnstate);
732 return;
735 // do not attack twice in a row
736 if (actor->flags & MF_JUSTATTACKED)
738 actor->flags &= ~MF_JUSTATTACKED;
739 if (gameskill != sk_nightmare && !fastparm)
740 P_NewChaseDir (actor);
741 return;
744 // check for melee attack
745 if (actor->info->meleestate
746 && P_CheckMeleeRange (actor))
748 if (actor->info->attacksound)
749 S_StartSound (actor, actor->info->attacksound);
751 P_SetMobjState (actor, actor->info->meleestate);
752 return;
755 // check for missile attack
756 if (actor->info->missilestate)
758 if (gameskill < sk_nightmare
759 && !fastparm && actor->movecount)
761 goto nomissile;
764 if (!P_CheckMissileRange (actor))
765 goto nomissile;
767 P_SetMobjState (actor, actor->info->missilestate);
768 actor->flags |= MF_JUSTATTACKED;
769 return;
772 // ?
773 nomissile:
774 // possibly choose another target
775 if (netgame
776 && !actor->threshold
777 && !P_CheckSight (actor, actor->target) )
779 if (P_LookForPlayers(actor,true))
780 return; // got a new target
783 // chase towards player
784 if (--actor->movecount<0
785 || !P_Move (actor))
787 P_NewChaseDir (actor);
790 // make active sound
791 if (actor->info->activesound
792 && P_Random () < 3)
794 S_StartSound (actor, actor->info->activesound);
800 // A_FaceTarget
802 void A_FaceTarget (mobj_t* actor)
804 if (!actor->target)
805 return;
807 actor->flags &= ~MF_AMBUSH;
809 actor->angle = R_PointToAngle2 (actor->x,
810 actor->y,
811 actor->target->x,
812 actor->target->y);
814 if (actor->target->flags & MF_SHADOW)
815 actor->angle += (P_Random()-P_Random())<<21;
820 // A_PosAttack
822 void A_PosAttack (mobj_t* actor)
824 int angle;
825 int damage;
826 int slope;
828 if (!actor->target)
829 return;
831 A_FaceTarget (actor);
832 angle = actor->angle;
833 slope = P_AimLineAttack (actor, angle, MISSILERANGE);
835 S_StartSound (actor, sfx_pistol);
836 angle += (P_Random()-P_Random())<<20;
837 damage = ((P_Random()%5)+1)*3;
838 P_LineAttack (actor, angle, MISSILERANGE, slope, damage);
841 void A_SPosAttack (mobj_t* actor)
843 int i;
844 int angle;
845 int bangle;
846 int damage;
847 int slope;
849 if (!actor->target)
850 return;
852 S_StartSound (actor, sfx_shotgn);
853 A_FaceTarget (actor);
854 bangle = actor->angle;
855 slope = P_AimLineAttack (actor, bangle, MISSILERANGE);
857 for (i=0 ; i<3 ; i++)
859 angle = bangle + ((P_Random()-P_Random())<<20);
860 damage = ((P_Random()%5)+1)*3;
861 P_LineAttack (actor, angle, MISSILERANGE, slope, damage);
865 void A_CPosAttack (mobj_t* actor)
867 int angle;
868 int bangle;
869 int damage;
870 int slope;
872 if (!actor->target)
873 return;
875 S_StartSound (actor, sfx_shotgn);
876 A_FaceTarget (actor);
877 bangle = actor->angle;
878 slope = P_AimLineAttack (actor, bangle, MISSILERANGE);
880 angle = bangle + ((P_Random()-P_Random())<<20);
881 damage = ((P_Random()%5)+1)*3;
882 P_LineAttack (actor, angle, MISSILERANGE, slope, damage);
885 void A_CPosRefire (mobj_t* actor)
887 // keep firing unless target got out of sight
888 A_FaceTarget (actor);
890 if (P_Random () < 40)
891 return;
893 if (!actor->target
894 || actor->target->health <= 0
895 || !P_CheckSight (actor, actor->target) )
897 P_SetMobjState (actor, actor->info->seestate);
902 void A_SpidRefire (mobj_t* actor)
904 // keep firing unless target got out of sight
905 A_FaceTarget (actor);
907 if (P_Random () < 10)
908 return;
910 if (!actor->target
911 || actor->target->health <= 0
912 || !P_CheckSight (actor, actor->target) )
914 P_SetMobjState (actor, actor->info->seestate);
918 void A_BspiAttack (mobj_t *actor)
920 if (!actor->target)
921 return;
923 A_FaceTarget (actor);
925 // launch a missile
926 P_SpawnMissile (actor, actor->target, MT_ARACHPLAZ);
931 // A_TroopAttack
933 void A_TroopAttack (mobj_t* actor)
935 int damage;
937 if (!actor->target)
938 return;
940 A_FaceTarget (actor);
941 if (P_CheckMeleeRange (actor))
943 S_StartSound (actor, sfx_claw);
944 damage = (P_Random()%8+1)*3;
945 P_DamageMobj (actor->target, actor, actor, damage);
946 return;
950 // launch a missile
951 P_SpawnMissile (actor, actor->target, MT_TROOPSHOT);
955 void A_SargAttack (mobj_t* actor)
957 int damage;
959 if (!actor->target)
960 return;
962 A_FaceTarget (actor);
963 if (P_CheckMeleeRange (actor))
965 damage = ((P_Random()%10)+1)*4;
966 P_DamageMobj (actor->target, actor, actor, damage);
970 void A_HeadAttack (mobj_t* actor)
972 int damage;
974 if (!actor->target)
975 return;
977 A_FaceTarget (actor);
978 if (P_CheckMeleeRange (actor))
980 damage = (P_Random()%6+1)*10;
981 P_DamageMobj (actor->target, actor, actor, damage);
982 return;
985 // launch a missile
986 P_SpawnMissile (actor, actor->target, MT_HEADSHOT);
989 void A_CyberAttack (mobj_t* actor)
991 if (!actor->target)
992 return;
994 A_FaceTarget (actor);
995 P_SpawnMissile (actor, actor->target, MT_ROCKET);
999 void A_BruisAttack (mobj_t* actor)
1001 int damage;
1003 if (!actor->target)
1004 return;
1006 if (P_CheckMeleeRange (actor))
1008 S_StartSound (actor, sfx_claw);
1009 damage = (P_Random()%8+1)*10;
1010 P_DamageMobj (actor->target, actor, actor, damage);
1011 return;
1014 // launch a missile
1015 P_SpawnMissile (actor, actor->target, MT_BRUISERSHOT);
1020 // A_SkelMissile
1022 void A_SkelMissile (mobj_t* actor)
1024 mobj_t* mo;
1026 if (!actor->target)
1027 return;
1029 A_FaceTarget (actor);
1030 actor->z += 16*FRACUNIT; // so missile spawns higher
1031 mo = P_SpawnMissile (actor, actor->target, MT_TRACER);
1032 actor->z -= 16*FRACUNIT; // back to normal
1034 mo->x += mo->momx;
1035 mo->y += mo->momy;
1036 mo->tracer = actor->target;
1039 int TRACEANGLE = 0xc000000;
1041 void A_Tracer (mobj_t* actor)
1043 angle_t exact;
1044 fixed_t dist;
1045 fixed_t slope;
1046 mobj_t* dest;
1047 mobj_t* th;
1049 if (gametic & 3)
1050 return;
1052 // spawn a puff of smoke behind the rocket
1053 P_SpawnPuff (actor->x, actor->y, actor->z);
1055 th = P_SpawnMobj (actor->x-actor->momx,
1056 actor->y-actor->momy,
1057 actor->z, MT_SMOKE);
1059 th->momz = FRACUNIT;
1060 th->tics -= P_Random()&3;
1061 if (th->tics < 1)
1062 th->tics = 1;
1064 // adjust direction
1065 dest = actor->tracer;
1067 if (!dest || dest->health <= 0)
1068 return;
1070 // change angle
1071 exact = R_PointToAngle2 (actor->x,
1072 actor->y,
1073 dest->x,
1074 dest->y);
1076 if (exact != actor->angle)
1078 if (exact - actor->angle > 0x80000000)
1080 actor->angle -= TRACEANGLE;
1081 if (exact - actor->angle < 0x80000000)
1082 actor->angle = exact;
1084 else
1086 actor->angle += TRACEANGLE;
1087 if (exact - actor->angle > 0x80000000)
1088 actor->angle = exact;
1092 exact = actor->angle>>ANGLETOFINESHIFT;
1093 actor->momx = FixedMul (actor->info->speed, finecosine[exact]);
1094 actor->momy = FixedMul (actor->info->speed, finesine[exact]);
1096 // change slope
1097 dist = P_AproxDistance (dest->x - actor->x,
1098 dest->y - actor->y);
1100 dist = dist / actor->info->speed;
1102 if (dist < 1)
1103 dist = 1;
1104 slope = (dest->z+40*FRACUNIT - actor->z) / dist;
1106 if (slope < actor->momz)
1107 actor->momz -= FRACUNIT/8;
1108 else
1109 actor->momz += FRACUNIT/8;
1113 void A_SkelWhoosh (mobj_t* actor)
1115 if (!actor->target)
1116 return;
1117 A_FaceTarget (actor);
1118 S_StartSound (actor,sfx_skeswg);
1121 void A_SkelFist (mobj_t* actor)
1123 int damage;
1125 if (!actor->target)
1126 return;
1128 A_FaceTarget (actor);
1130 if (P_CheckMeleeRange (actor))
1132 damage = ((P_Random()%10)+1)*6;
1133 S_StartSound (actor, sfx_skepch);
1134 P_DamageMobj (actor->target, actor, actor, damage);
1141 // PIT_VileCheck
1142 // Detect a corpse that could be raised.
1144 mobj_t* corpsehit;
1145 mobj_t* vileobj;
1146 fixed_t viletryx;
1147 fixed_t viletryy;
1149 boolean PIT_VileCheck (mobj_t* thing)
1151 int maxdist;
1152 boolean check;
1154 if (!(thing->flags & MF_CORPSE) )
1155 return true; // not a monster
1157 if (thing->tics != -1)
1158 return true; // not lying still yet
1160 if (thing->info->raisestate == S_NULL)
1161 return true; // monster doesn't have a raise state
1163 maxdist = thing->info->radius + mobjinfo[MT_VILE].radius;
1165 if ( iabs(thing->x - viletryx) > maxdist
1166 || iabs(thing->y - viletryy) > maxdist )
1167 return true; // not actually touching
1169 corpsehit = thing;
1170 corpsehit->momx = corpsehit->momy = 0;
1171 corpsehit->height <<= 2;
1172 check = P_CheckPosition (corpsehit, corpsehit->x, corpsehit->y);
1173 corpsehit->height >>= 2;
1175 if (!check)
1176 return true; // doesn't fit here
1178 return false; // got one, so stop checking
1184 // A_VileChase
1185 // Check for ressurecting a body
1187 void A_VileChase (mobj_t* actor)
1189 int xl;
1190 int xh;
1191 int yl;
1192 int yh;
1194 int bx;
1195 int by;
1197 mobjinfo_t* info;
1198 mobj_t* temp;
1200 if (actor->movedir != DI_NODIR)
1202 // check for corpses to raise
1203 viletryx =
1204 actor->x + actor->info->speed*xspeed[actor->movedir];
1205 viletryy =
1206 actor->y + actor->info->speed*yspeed[actor->movedir];
1208 xl = (viletryx - bmaporgx - MAXRADIUS*2)>>MAPBLOCKSHIFT;
1209 xh = (viletryx - bmaporgx + MAXRADIUS*2)>>MAPBLOCKSHIFT;
1210 yl = (viletryy - bmaporgy - MAXRADIUS*2)>>MAPBLOCKSHIFT;
1211 yh = (viletryy - bmaporgy + MAXRADIUS*2)>>MAPBLOCKSHIFT;
1213 vileobj = actor;
1214 for (bx=xl ; bx<=xh ; bx++)
1216 for (by=yl ; by<=yh ; by++)
1218 // Call PIT_VileCheck to check
1219 // whether object is a corpse
1220 // that canbe raised.
1221 if (!P_BlockThingsIterator(bx,by,PIT_VileCheck))
1223 // got one!
1224 temp = actor->target;
1225 actor->target = corpsehit;
1226 A_FaceTarget (actor);
1227 actor->target = temp;
1229 P_SetMobjState (actor, S_VILE_HEAL1);
1230 S_StartSound (corpsehit, sfx_slop);
1231 info = corpsehit->info;
1233 P_SetMobjState (corpsehit,info->raisestate);
1234 corpsehit->height <<= 2;
1235 corpsehit->flags = info->flags;
1236 corpsehit->health = info->spawnhealth;
1237 corpsehit->target = NULL;
1239 return;
1245 // Return to normal attack.
1246 A_Chase (actor);
1251 // A_VileStart
1253 void A_VileStart (mobj_t* actor)
1255 S_StartSound (actor, sfx_vilatk);
1260 // A_Fire
1261 // Keep fire in front of player unless out of sight
1263 void A_Fire (mobj_t* actor);
1265 void A_StartFire (mobj_t* actor)
1267 S_StartSound(actor,sfx_flamst);
1268 A_Fire(actor);
1271 void A_FireCrackle (mobj_t* actor)
1273 S_StartSound(actor,sfx_flame);
1274 A_Fire(actor);
1277 void A_Fire (mobj_t* actor)
1279 mobj_t* dest;
1280 unsigned an;
1282 dest = actor->tracer;
1283 if (!dest)
1284 return;
1286 // don't move it if the vile lost sight
1287 if (!P_CheckSight (actor->target, dest) )
1288 return;
1290 an = dest->angle >> ANGLETOFINESHIFT;
1292 P_UnsetThingPosition (actor);
1293 actor->x = dest->x + FixedMul (24*FRACUNIT, finecosine[an]);
1294 actor->y = dest->y + FixedMul (24*FRACUNIT, finesine[an]);
1295 actor->z = dest->z;
1296 P_SetThingPosition (actor);
1302 // A_VileTarget
1303 // Spawn the hellfire
1305 void A_VileTarget (mobj_t* actor)
1307 mobj_t* fog;
1309 if (!actor->target)
1310 return;
1312 A_FaceTarget (actor);
1314 fog = P_SpawnMobj (actor->target->x,
1315 actor->target->x,
1316 actor->target->z, MT_FIRE);
1318 actor->tracer = fog;
1319 fog->target = actor;
1320 fog->tracer = actor->target;
1321 A_Fire (fog);
1328 // A_VileAttack
1330 void A_VileAttack (mobj_t* actor)
1332 mobj_t* fire;
1333 int an;
1335 if (!actor->target)
1336 return;
1338 A_FaceTarget (actor);
1340 if (!P_CheckSight (actor, actor->target) )
1341 return;
1343 S_StartSound (actor, sfx_barexp);
1344 P_DamageMobj (actor->target, actor, actor, 20);
1345 actor->target->momz = 1000*FRACUNIT/actor->target->info->mass;
1347 an = actor->angle >> ANGLETOFINESHIFT;
1349 fire = actor->tracer;
1351 if (!fire)
1352 return;
1354 // move the fire between the vile and the player
1355 fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]);
1356 fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]);
1357 P_RadiusAttack (fire, actor, 70 );
1364 // Mancubus attack,
1365 // firing three missiles (bruisers)
1366 // in three different directions?
1367 // Doesn't look like it.
1369 #define FATSPREAD (ANG90/8)
1371 void A_FatRaise (mobj_t *actor)
1373 A_FaceTarget (actor);
1374 S_StartSound (actor, sfx_manatk);
1378 void A_FatAttack1 (mobj_t* actor)
1380 mobj_t* mo;
1381 int an;
1383 A_FaceTarget (actor);
1384 // Change direction to ...
1385 actor->angle += FATSPREAD;
1386 P_SpawnMissile (actor, actor->target, MT_FATSHOT);
1388 mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
1389 mo->angle += FATSPREAD;
1390 an = mo->angle >> ANGLETOFINESHIFT;
1391 mo->momx = FixedMul (mo->info->speed, finecosine[an]);
1392 mo->momy = FixedMul (mo->info->speed, finesine[an]);
1395 void A_FatAttack2 (mobj_t* actor)
1397 mobj_t* mo;
1398 int an;
1400 A_FaceTarget (actor);
1401 // Now here choose opposite deviation.
1402 actor->angle -= FATSPREAD;
1403 P_SpawnMissile (actor, actor->target, MT_FATSHOT);
1405 mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
1406 mo->angle -= FATSPREAD*2;
1407 an = mo->angle >> ANGLETOFINESHIFT;
1408 mo->momx = FixedMul (mo->info->speed, finecosine[an]);
1409 mo->momy = FixedMul (mo->info->speed, finesine[an]);
1412 void A_FatAttack3 (mobj_t* actor)
1414 mobj_t* mo;
1415 int an;
1417 A_FaceTarget (actor);
1419 mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
1420 mo->angle -= FATSPREAD/2;
1421 an = mo->angle >> ANGLETOFINESHIFT;
1422 mo->momx = FixedMul (mo->info->speed, finecosine[an]);
1423 mo->momy = FixedMul (mo->info->speed, finesine[an]);
1425 mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
1426 mo->angle += FATSPREAD/2;
1427 an = mo->angle >> ANGLETOFINESHIFT;
1428 mo->momx = FixedMul (mo->info->speed, finecosine[an]);
1429 mo->momy = FixedMul (mo->info->speed, finesine[an]);
1434 // SkullAttack
1435 // Fly at the player like a missile.
1437 #define SKULLSPEED (20*FRACUNIT)
1439 void A_SkullAttack (mobj_t* actor)
1441 mobj_t* dest;
1442 angle_t an;
1443 int dist;
1445 if (!actor->target)
1446 return;
1448 dest = actor->target;
1449 actor->flags |= MF_SKULLFLY;
1451 S_StartSound (actor, actor->info->attacksound);
1452 A_FaceTarget (actor);
1453 an = actor->angle >> ANGLETOFINESHIFT;
1454 actor->momx = FixedMul (SKULLSPEED, finecosine[an]);
1455 actor->momy = FixedMul (SKULLSPEED, finesine[an]);
1456 dist = P_AproxDistance (dest->x - actor->x, dest->y - actor->y);
1457 dist = dist / SKULLSPEED;
1459 if (dist < 1)
1460 dist = 1;
1461 actor->momz = (dest->z+(dest->height>>1) - actor->z) / dist;
1466 // A_PainShootSkull
1467 // Spawn a lost soul and launch it at the target
1469 void
1470 A_PainShootSkull
1471 ( mobj_t* actor,
1472 angle_t angle )
1474 fixed_t x;
1475 fixed_t y;
1476 fixed_t z;
1478 mobj_t* newmobj;
1479 angle_t an;
1480 int prestep;
1481 int count;
1482 thinker_t* currentthinker;
1484 // count total number of skull currently on the level
1485 count = 0;
1487 currentthinker = thinkercap.next;
1488 while (currentthinker != &thinkercap)
1490 if ( (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker)
1491 && ((mobj_t *)currentthinker)->type == MT_SKULL)
1492 count++;
1493 currentthinker = currentthinker->next;
1496 // if there are allready 20 skulls on the level,
1497 // don't spit another one
1498 if (count > 20)
1499 return;
1502 // okay, there's playe for another one
1503 an = angle >> ANGLETOFINESHIFT;
1505 prestep =
1506 4*FRACUNIT
1507 + 3*(actor->info->radius + mobjinfo[MT_SKULL].radius)/2;
1509 x = actor->x + FixedMul (prestep, finecosine[an]);
1510 y = actor->y + FixedMul (prestep, finesine[an]);
1511 z = actor->z + 8*FRACUNIT;
1513 newmobj = P_SpawnMobj (x , y, z, MT_SKULL);
1515 // Check for movements.
1516 if (!P_TryMove (newmobj, newmobj->x, newmobj->y))
1518 // kill it immediately
1519 P_DamageMobj (newmobj,actor,actor,10000);
1520 return;
1523 newmobj->target = actor->target;
1524 A_SkullAttack (newmobj);
1529 // A_PainAttack
1530 // Spawn a lost soul and launch it at the target
1532 void A_PainAttack (mobj_t* actor)
1534 if (!actor->target)
1535 return;
1537 A_FaceTarget (actor);
1538 A_PainShootSkull (actor, actor->angle);
1542 void A_PainDie (mobj_t* actor)
1544 A_Fall (actor);
1545 A_PainShootSkull (actor, actor->angle+ANG90);
1546 A_PainShootSkull (actor, actor->angle+ANG180);
1547 A_PainShootSkull (actor, actor->angle+ANG270);
1555 void A_Scream (mobj_t* actor)
1557 int sound;
1559 switch (actor->info->deathsound)
1561 case 0:
1562 return;
1564 case sfx_podth1:
1565 case sfx_podth2:
1566 case sfx_podth3:
1567 sound = sfx_podth1 + P_Random ()%3;
1568 break;
1570 case sfx_bgdth1:
1571 case sfx_bgdth2:
1572 sound = sfx_bgdth1 + P_Random ()%2;
1573 break;
1575 default:
1576 sound = actor->info->deathsound;
1577 break;
1580 // Check for bosses.
1581 if (actor->type==MT_SPIDER
1582 || actor->type == MT_CYBORG)
1584 // full volume
1585 S_StartSound (NULL, sound);
1587 else
1588 S_StartSound (actor, sound);
1592 void A_XScream (mobj_t* actor)
1594 S_StartSound (actor, sfx_slop);
1597 void A_Pain (mobj_t* actor)
1599 if (actor->info->painsound)
1600 S_StartSound (actor, actor->info->painsound);
1605 void A_Fall (mobj_t *actor)
1607 // actor is on ground, it can be walked over
1608 actor->flags &= ~MF_SOLID;
1610 // So change this if corpse objects
1611 // are meant to be obstacles.
1616 // A_Explode
1618 void A_Explode (mobj_t* thingy)
1620 P_RadiusAttack ( thingy, thingy->target, 128 );
1625 // A_BossDeath
1626 // Possibly trigger special effects
1627 // if on first boss level
1629 void A_BossDeath (mobj_t* mo)
1631 thinker_t* th;
1632 mobj_t* mo2;
1633 line_t junk;
1634 int i;
1636 if ( gamemode == commercial)
1638 if (gamemap != 7)
1639 return;
1641 if ((mo->type != MT_FATSO)
1642 && (mo->type != MT_BABY))
1643 return;
1645 else
1647 switch(gameepisode)
1649 case 1:
1650 if (gamemap != 8)
1651 return;
1653 if (mo->type != MT_BRUISER)
1654 return;
1655 break;
1657 case 2:
1658 if (gamemap != 8)
1659 return;
1661 if (mo->type != MT_CYBORG)
1662 return;
1663 break;
1665 case 3:
1666 if (gamemap != 8)
1667 return;
1669 if (mo->type != MT_SPIDER)
1670 return;
1672 break;
1674 case 4:
1675 switch(gamemap)
1677 case 6:
1678 if (mo->type != MT_CYBORG)
1679 return;
1680 break;
1682 case 8:
1683 if (mo->type != MT_SPIDER)
1684 return;
1685 break;
1687 default:
1688 return;
1689 break;
1691 break;
1693 default:
1694 if (gamemap != 8)
1695 return;
1696 break;
1702 // make sure there is a player alive for victory
1703 for (i=0 ; i<MAXPLAYERS ; i++)
1704 if (playeringame[i] && players[i].health > 0)
1705 break;
1707 if (i==MAXPLAYERS)
1708 return; // no one left alive, so do not end game
1710 // scan the remaining thinkers to see
1711 // if all bosses are dead
1712 for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
1714 if (th->function.acp1 != (actionf_p1)P_MobjThinker)
1715 continue;
1717 mo2 = (mobj_t *)th;
1718 if (mo2 != mo
1719 && mo2->type == mo->type
1720 && mo2->health > 0)
1722 // other boss not dead
1723 return;
1727 // victory!
1728 if ( gamemode == commercial)
1730 if (gamemap == 7)
1732 if (mo->type == MT_FATSO)
1734 junk.tag = 666;
1735 EV_DoFloor(&junk,lowerFloorToLowest);
1736 return;
1739 if (mo->type == MT_BABY)
1741 junk.tag = 667;
1742 EV_DoFloor(&junk,raiseToTexture);
1743 return;
1747 else
1749 switch(gameepisode)
1751 case 1:
1752 junk.tag = 666;
1753 EV_DoFloor (&junk, lowerFloorToLowest);
1754 return;
1755 break;
1757 case 4:
1758 switch(gamemap)
1760 case 6:
1761 junk.tag = 666;
1762 EV_DoDoor (&junk, blazeOpen);
1763 return;
1764 break;
1766 case 8:
1767 junk.tag = 666;
1768 EV_DoFloor (&junk, lowerFloorToLowest);
1769 return;
1770 break;
1775 G_ExitLevel ();
1779 void A_Hoof (mobj_t* mo)
1781 S_StartSound (mo, sfx_hoof);
1782 A_Chase (mo);
1785 void A_Metal (mobj_t* mo)
1787 S_StartSound (mo, sfx_metal);
1788 A_Chase (mo);
1791 void A_BabyMetal (mobj_t* mo)
1793 S_StartSound (mo, sfx_bspwlk);
1794 A_Chase (mo);
1797 void
1798 A_OpenShotgun2
1799 ( player_t* player,
1800 pspdef_t* psp )
1802 S_StartSound (player->mo, sfx_dbopn);
1805 void
1806 A_LoadShotgun2
1807 ( player_t* player,
1808 pspdef_t* psp )
1810 S_StartSound (player->mo, sfx_dbload);
1813 void
1814 A_ReFire
1815 ( player_t* player,
1816 pspdef_t* psp );
1818 void
1819 A_CloseShotgun2
1820 ( player_t* player,
1821 pspdef_t* psp )
1823 S_StartSound (player->mo, sfx_dbcls);
1824 A_ReFire(player,psp);
1829 mobj_t* braintargets[32];
1830 int numbraintargets;
1831 int braintargeton;
1833 void A_BrainAwake (mobj_t* mo)
1835 thinker_t* thinker;
1836 mobj_t* m;
1838 // find all the target spots
1839 numbraintargets = 0;
1840 braintargeton = 0;
1842 thinker = thinkercap.next;
1843 for (thinker = thinkercap.next ;
1844 thinker != &thinkercap ;
1845 thinker = thinker->next)
1847 if (thinker->function.acp1 != (actionf_p1)P_MobjThinker)
1848 continue; // not a mobj
1850 m = (mobj_t *)thinker;
1852 if (m->type == MT_BOSSTARGET )
1854 braintargets[numbraintargets] = m;
1855 numbraintargets++;
1859 S_StartSound (NULL,sfx_bossit);
1863 void A_BrainPain (mobj_t* mo)
1865 S_StartSound (NULL,sfx_bospn);
1869 void A_BrainScream (mobj_t* mo)
1871 int x;
1872 int y;
1873 int z;
1874 mobj_t* th;
1876 for (x=mo->x - 196*FRACUNIT ; x< mo->x + 320*FRACUNIT ; x+= FRACUNIT*8)
1878 y = mo->y - 320*FRACUNIT;
1879 z = 128 + P_Random()*2*FRACUNIT;
1880 th = P_SpawnMobj (x,y,z, MT_ROCKET);
1881 th->momz = P_Random()*512;
1883 P_SetMobjState (th, S_BRAINEXPLODE1);
1885 th->tics -= P_Random()&7;
1886 if (th->tics < 1)
1887 th->tics = 1;
1890 S_StartSound (NULL,sfx_bosdth);
1895 void A_BrainExplode (mobj_t* mo)
1897 int x;
1898 int y;
1899 int z;
1900 mobj_t* th;
1902 x = mo->x + (P_Random () - P_Random ())*2048;
1903 y = mo->y;
1904 z = 128 + P_Random()*2*FRACUNIT;
1905 th = P_SpawnMobj (x,y,z, MT_ROCKET);
1906 th->momz = P_Random()*512;
1908 P_SetMobjState (th, S_BRAINEXPLODE1);
1910 th->tics -= P_Random()&7;
1911 if (th->tics < 1)
1912 th->tics = 1;
1916 void A_BrainDie (mobj_t* mo)
1918 G_ExitLevel ();
1921 void A_BrainSpit (mobj_t* mo)
1923 mobj_t* targ;
1924 mobj_t* newmobj;
1926 static int easy = 0;
1928 easy ^= 1;
1929 if (gameskill <= sk_easy && (!easy))
1930 return;
1932 // shoot a cube at current target
1933 targ = braintargets[braintargeton];
1934 braintargeton = (braintargeton+1)%numbraintargets;
1936 // spawn brain missile
1937 newmobj = P_SpawnMissile (mo, targ, MT_SPAWNSHOT);
1938 newmobj->target = targ;
1939 newmobj->reactiontime =
1940 ((targ->y - mo->y)/newmobj->momy) / newmobj->state->tics;
1942 S_StartSound(NULL, sfx_bospit);
1947 void A_SpawnFly (mobj_t* mo);
1949 // travelling cube sound
1950 void A_SpawnSound (mobj_t* mo)
1952 S_StartSound (mo,sfx_boscub);
1953 A_SpawnFly(mo);
1956 void A_SpawnFly (mobj_t* mo)
1958 mobj_t* newmobj;
1959 mobj_t* fog;
1960 mobj_t* targ;
1961 int r;
1962 mobjtype_t type;
1964 if (--mo->reactiontime)
1965 return; // still flying
1967 targ = mo->target;
1969 // First spawn teleport fog.
1970 fog = P_SpawnMobj (targ->x, targ->y, targ->z, MT_SPAWNFIRE);
1971 S_StartSound (fog, sfx_telept);
1973 // Randomly select monster to spawn.
1974 r = P_Random ();
1976 // Probability distribution (kind of :),
1977 // decreasing likelihood.
1978 if ( r<50 )
1979 type = MT_TROOP;
1980 else if (r<90)
1981 type = MT_SERGEANT;
1982 else if (r<120)
1983 type = MT_SHADOWS;
1984 else if (r<130)
1985 type = MT_PAIN;
1986 else if (r<160)
1987 type = MT_HEAD;
1988 else if (r<162)
1989 type = MT_VILE;
1990 else if (r<172)
1991 type = MT_UNDEAD;
1992 else if (r<192)
1993 type = MT_BABY;
1994 else if (r<222)
1995 type = MT_FATSO;
1996 else if (r<246)
1997 type = MT_KNIGHT;
1998 else
1999 type = MT_BRUISER;
2001 newmobj = P_SpawnMobj (targ->x, targ->y, targ->z, type);
2002 if (P_LookForPlayers (newmobj, true) )
2003 P_SetMobjState (newmobj, newmobj->info->seestate);
2005 // telefrag anything in this spot
2006 P_TeleportMove (newmobj, newmobj->x, newmobj->y);
2008 // remove self (i.e., cube).
2009 P_RemoveMobj (mo);
2014 void A_PlayerScream (mobj_t* mo)
2016 // Default death sound.
2017 int sound = sfx_pldeth;
2019 if ( (gamemode == commercial)
2020 && (mo->health < -50))
2022 // IF THE PLAYER DIES
2023 // LESS THAN -50% WITHOUT GIBBING
2024 sound = sfx_pdiehi;
2027 S_StartSound (mo, sound);