1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 2005-2014 Simon Howard
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // DESCRIPTION:
16 // Enemy thinking, AI.
17 // Action Pointer Functions
18 // that are associated with states/frames.
19 //
20
21 #include <stdio.h>
22 #include <stdlib.h>
23
24 #include "m_random.h"
25 #include "i_system.h"
26
27 #include "doomdef.h"
28 #include "p_local.h"
29
30 #include "s_sound.h"
31
32 #include "g_game.h"
33
34 // State.
35 #include "doomstat.h"
36 #include "r_state.h"
37
38 // Data.
39 #include "sounds.h"
40
41
42
43
44 typedef enum
45 {
46 DI_EAST,
47 DI_NORTHEAST,
48 DI_NORTH,
49 DI_NORTHWEST,
50 DI_WEST,
51 DI_SOUTHWEST,
52 DI_SOUTH,
53 DI_SOUTHEAST,
54 DI_NODIR,
55 NUMDIRS
56
57 } dirtype_t;
58
59
60 //
61 // P_NewChaseDir related LUT.
62 //
63 dirtype_t opposite[] =
64 {
65 DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST,
66 DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_NODIR
67 };
68
69 dirtype_t diags[] =
70 {
71 DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST
72 };
73
74
75
76
77
78 void A_Fall (mobj_t *actor);
79
80
81 //
82 // ENEMY THINKING
83 // Enemies are allways spawned
84 // with targetplayer = -1, threshold = 0
85 // Most monsters are spawned unaware of all players,
86 // but some can be made preaware
87 //
88
89
90 //
91 // Called by P_NoiseAlert.
92 // Recursively traverse adjacent sectors,
93 // sound blocking lines cut off traversal.
94 //
95
96 mobj_t* soundtarget;
97
98 void
P_RecursiveSound(sector_t * sec,int soundblocks)99 P_RecursiveSound
100 ( sector_t* sec,
101 int soundblocks )
102 {
103 int i;
104 line_t* check;
105 sector_t* other;
106
107 // wake up all monsters in this sector
108 if (sec->validcount == validcount
109 && sec->soundtraversed <= soundblocks+1)
110 {
111 return; // already flooded
112 }
113
114 sec->validcount = validcount;
115 sec->soundtraversed = soundblocks+1;
116 sec->soundtarget = soundtarget;
117
118 for (i=0 ;i<sec->linecount ; i++)
119 {
120 check = sec->lines[i];
121 if (! (check->flags & ML_TWOSIDED) )
122 continue;
123
124 P_LineOpening (check);
125
126 if (openrange <= 0)
127 continue; // closed door
128
129 if ( sides[ check->sidenum[0] ].sector == sec)
130 other = sides[ check->sidenum[1] ] .sector;
131 else
132 other = sides[ check->sidenum[0] ].sector;
133
134 if (check->flags & ML_SOUNDBLOCK)
135 {
136 if (!soundblocks)
137 P_RecursiveSound (other, 1);
138 }
139 else
140 P_RecursiveSound (other, soundblocks);
141 }
142 }
143
144
145
146 //
147 // P_NoiseAlert
148 // If a monster yells at a player,
149 // it will alert other monsters to the player.
150 //
151 void
P_NoiseAlert(mobj_t * target,mobj_t * emmiter)152 P_NoiseAlert
153 ( mobj_t* target,
154 mobj_t* emmiter )
155 {
156 soundtarget = target;
157 validcount++;
158 P_RecursiveSound (emmiter->subsector->sector, 0);
159 }
160
161
162
163
164 //
165 // P_CheckMeleeRange
166 //
P_CheckMeleeRange(mobj_t * actor)167 boolean P_CheckMeleeRange (mobj_t* actor)
168 {
169 mobj_t* pl;
170 fixed_t dist;
171
172 if (!actor->target)
173 return false;
174
175 pl = actor->target;
176 dist = P_AproxDistance (pl->x-actor->x, pl->y-actor->y);
177
178 if (dist >= MELEERANGE-20*FRACUNIT+pl->info->radius)
179 return false;
180
181 if (! P_CheckSight (actor, actor->target) )
182 return false;
183
184 return true;
185 }
186
187 //
188 // P_CheckMissileRange
189 //
P_CheckMissileRange(mobj_t * actor)190 boolean P_CheckMissileRange (mobj_t* actor)
191 {
192 fixed_t dist;
193
194 if (! P_CheckSight (actor, actor->target) )
195 return false;
196
197 if ( actor->flags & MF_JUSTHIT )
198 {
199 // the target just hit the enemy,
200 // so fight back!
201 actor->flags &= ~MF_JUSTHIT;
202 return true;
203 }
204
205 if (actor->reactiontime)
206 return false; // do not attack yet
207
208 // OPTIMIZE: get this from a global checksight
209 dist = P_AproxDistance ( actor->x-actor->target->x,
210 actor->y-actor->target->y) - 64*FRACUNIT;
211
212 if (!actor->info->meleestate)
213 dist -= 128*FRACUNIT; // no melee attack, so fire more
214
215 dist >>= FRACBITS;
216
217 if (actor->type == MT_VILE)
218 {
219 if (dist > 14*64)
220 return false; // too far away
221 }
222
223
224 if (actor->type == MT_UNDEAD)
225 {
226 if (dist < 196)
227 return false; // close for fist attack
228 dist >>= 1;
229 }
230
231
232 if (actor->type == MT_CYBORG
233 || actor->type == MT_SPIDER
234 || actor->type == MT_SKULL)
235 {
236 dist >>= 1;
237 }
238
239 if (dist > 200)
240 dist = 200;
241
242 if (actor->type == MT_CYBORG && dist > 160)
243 dist = 160;
244
245 if (P_Random () < dist)
246 return false;
247
248 return true;
249 }
250
251
252 //
253 // P_Move
254 // Move in the current direction,
255 // returns false if the move is blocked.
256 //
257 fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};
258 fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};
259
P_Move(mobj_t * actor)260 boolean P_Move (mobj_t* actor)
261 {
262 fixed_t tryx;
263 fixed_t tryy;
264
265 line_t* ld;
266
267 // warning: 'catch', 'throw', and 'try'
268 // are all C++ reserved words
269 boolean try_ok;
270 boolean good;
271
272 if (actor->movedir == DI_NODIR)
273 return false;
274
275 if ((unsigned)actor->movedir >= 8)
276 I_Error ("Weird actor->movedir!");
277
278 tryx = actor->x + actor->info->speed*xspeed[actor->movedir];
279 tryy = actor->y + actor->info->speed*yspeed[actor->movedir];
280
281 try_ok = P_TryMove (actor, tryx, tryy);
282
283 if (!try_ok)
284 {
285 // open any specials
286 if (actor->flags & MF_FLOAT && floatok)
287 {
288 // must adjust height
289 if (actor->z < tmfloorz)
290 actor->z += FLOATSPEED;
291 else
292 actor->z -= FLOATSPEED;
293
294 actor->flags |= MF_INFLOAT;
295 return true;
296 }
297
298 if (!numspechit)
299 return false;
300
301 actor->movedir = DI_NODIR;
302 good = false;
303 while (numspechit--)
304 {
305 ld = spechit[numspechit];
306 // if the special is not a door
307 // that can be opened,
308 // return false
309 if (P_UseSpecialLine (actor, ld,0))
310 good = true;
311 }
312 return good;
313 }
314 else
315 {
316 actor->flags &= ~MF_INFLOAT;
317 }
318
319
320 if (! (actor->flags & MF_FLOAT) )
321 actor->z = actor->floorz;
322 return true;
323 }
324
325
326 //
327 // TryWalk
328 // Attempts to move actor on
329 // in its current (ob->moveangle) direction.
330 // If blocked by either a wall or an actor
331 // returns FALSE
332 // If move is either clear or blocked only by a door,
333 // returns TRUE and sets...
334 // If a door is in the way,
335 // an OpenDoor call is made to start it opening.
336 //
P_TryWalk(mobj_t * actor)337 boolean P_TryWalk (mobj_t* actor)
338 {
339 if (!P_Move (actor))
340 {
341 return false;
342 }
343
344 actor->movecount = P_Random()&15;
345 return true;
346 }
347
348
349
350
P_NewChaseDir(mobj_t * actor)351 void P_NewChaseDir (mobj_t* actor)
352 {
353 fixed_t deltax;
354 fixed_t deltay;
355
356 dirtype_t d[3];
357
358 int tdir;
359 dirtype_t olddir;
360
361 dirtype_t turnaround;
362
363 if (!actor->target)
364 I_Error ("P_NewChaseDir: called with no target");
365
366 olddir = actor->movedir;
367 turnaround=opposite[olddir];
368
369 deltax = actor->target->x - actor->x;
370 deltay = actor->target->y - actor->y;
371
372 if (deltax>10*FRACUNIT)
373 d[1]= DI_EAST;
374 else if (deltax<-10*FRACUNIT)
375 d[1]= DI_WEST;
376 else
377 d[1]=DI_NODIR;
378
379 if (deltay<-10*FRACUNIT)
380 d[2]= DI_SOUTH;
381 else if (deltay>10*FRACUNIT)
382 d[2]= DI_NORTH;
383 else
384 d[2]=DI_NODIR;
385
386 // try direct route
387 if (d[1] != DI_NODIR
388 && d[2] != DI_NODIR)
389 {
390 actor->movedir = diags[((deltay<0)<<1)+(deltax>0)];
391 if (actor->movedir != (int) turnaround && P_TryWalk(actor))
392 return;
393 }
394
395 // try other directions
396 if (P_Random() > 200
397 || abs(deltay)>abs(deltax))
398 {
399 tdir=d[1];
400 d[1]=d[2];
401 d[2]=tdir;
402 }
403
404 if (d[1]==turnaround)
405 d[1]=DI_NODIR;
406 if (d[2]==turnaround)
407 d[2]=DI_NODIR;
408
409 if (d[1]!=DI_NODIR)
410 {
411 actor->movedir = d[1];
412 if (P_TryWalk(actor))
413 {
414 // either moved forward or attacked
415 return;
416 }
417 }
418
419 if (d[2]!=DI_NODIR)
420 {
421 actor->movedir =d[2];
422
423 if (P_TryWalk(actor))
424 return;
425 }
426
427 // there is no direct path to the player,
428 // so pick another direction.
429 if (olddir!=DI_NODIR)
430 {
431 actor->movedir =olddir;
432
433 if (P_TryWalk(actor))
434 return;
435 }
436
437 // randomly determine direction of search
438 if (P_Random()&1)
439 {
440 for ( tdir=DI_EAST;
441 tdir<=DI_SOUTHEAST;
442 tdir++ )
443 {
444 if (tdir != (int) turnaround)
445 {
446 actor->movedir =tdir;
447
448 if ( P_TryWalk(actor) )
449 return;
450 }
451 }
452 }
453 else
454 {
455 for ( tdir=DI_SOUTHEAST;
456 tdir != (DI_EAST-1);
457 tdir-- )
458 {
459 if (tdir != (int) turnaround)
460 {
461 actor->movedir = tdir;
462
463 if ( P_TryWalk(actor) )
464 return;
465 }
466 }
467 }
468
469 if (turnaround != DI_NODIR)
470 {
471 actor->movedir =turnaround;
472 if ( P_TryWalk(actor) )
473 return;
474 }
475
476 actor->movedir = DI_NODIR; // can not move
477 }
478
479
480
481 //
482 // P_LookForPlayers
483 // If allaround is false, only look 180 degrees in front.
484 // Returns true if a player is targeted.
485 //
486 boolean
P_LookForPlayers(mobj_t * actor,boolean allaround)487 P_LookForPlayers
488 ( mobj_t* actor,
489 boolean allaround )
490 {
491 int c;
492 int stop;
493 player_t* player;
494 angle_t an;
495 fixed_t dist;
496
497 c = 0;
498 stop = (actor->lastlook-1)&3;
499
500 for ( ; ; actor->lastlook = (actor->lastlook+1)&3 )
501 {
502 if (!playeringame[actor->lastlook])
503 continue;
504
505 if (c++ == 2
506 || actor->lastlook == stop)
507 {
508 // done looking
509 return false;
510 }
511
512 player = &players[actor->lastlook];
513
514 if (player->health <= 0)
515 continue; // dead
516
517 if (!P_CheckSight (actor, player->mo))
518 continue; // out of sight
519
520 if (!allaround)
521 {
522 an = R_PointToAngle2 (actor->x,
523 actor->y,
524 player->mo->x,
525 player->mo->y)
526 - actor->angle;
527
528 if (an > ANG90 && an < ANG270)
529 {
530 dist = P_AproxDistance (player->mo->x - actor->x,
531 player->mo->y - actor->y);
532 // if real close, react anyway
533 if (dist > MELEERANGE)
534 continue; // behind back
535 }
536 }
537
538 actor->target = player->mo;
539 return true;
540 }
541
542 return false;
543 }
544
545
546 //
547 // A_KeenDie
548 // DOOM II special, map 32.
549 // Uses special tag 666.
550 //
A_KeenDie(mobj_t * mo)551 void A_KeenDie (mobj_t* mo)
552 {
553 thinker_t* th;
554 mobj_t* mo2;
555 line_t junk;
556
557 A_Fall (mo);
558
559 // scan the remaining thinkers
560 // to see if all Keens are dead
561 for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
562 {
563 if (th->function.acp1 != (actionf_p1)P_MobjThinker)
564 continue;
565
566 mo2 = (mobj_t *)th;
567 if (mo2 != mo
568 && mo2->type == mo->type
569 && mo2->health > 0)
570 {
571 // other Keen not dead
572 return;
573 }
574 }
575
576 junk.tag = 666;
577 EV_DoDoor(&junk, vld_open);
578 }
579
580
581 //
582 // ACTION ROUTINES
583 //
584
585 //
586 // A_Look
587 // Stay in state until a player is sighted.
588 //
A_Look(mobj_t * actor)589 void A_Look (mobj_t* actor)
590 {
591 mobj_t* targ;
592
593 actor->threshold = 0; // any shot will wake up
594 targ = actor->subsector->sector->soundtarget;
595
596 if (targ
597 && (targ->flags & MF_SHOOTABLE) )
598 {
599 actor->target = targ;
600
601 if ( actor->flags & MF_AMBUSH )
602 {
603 if (P_CheckSight (actor, actor->target))
604 goto seeyou;
605 }
606 else
607 goto seeyou;
608 }
609
610
611 if (!P_LookForPlayers (actor, false) )
612 return;
613
614 // go into chase state
615 seeyou:
616 if (actor->info->seesound)
617 {
618 int sound;
619
620 switch (actor->info->seesound)
621 {
622 case sfx_posit1:
623 case sfx_posit2:
624 case sfx_posit3:
625 sound = sfx_posit1+P_Random()%3;
626 break;
627
628 case sfx_bgsit1:
629 case sfx_bgsit2:
630 sound = sfx_bgsit1+P_Random()%2;
631 break;
632
633 default:
634 sound = actor->info->seesound;
635 break;
636 }
637
638 if (actor->type==MT_SPIDER
639 || actor->type == MT_CYBORG)
640 {
641 // full volume
642 S_StartSound (NULL, sound);
643 }
644 else
645 S_StartSound (actor, sound);
646 }
647
648 P_SetMobjState (actor, actor->info->seestate);
649 }
650
651
652 //
653 // A_Chase
654 // Actor has a melee attack,
655 // so it tries to close as fast as possible
656 //
A_Chase(mobj_t * actor)657 void A_Chase (mobj_t* actor)
658 {
659 int delta;
660
661 if (actor->reactiontime)
662 actor->reactiontime--;
663
664
665 // modify target threshold
666 if (actor->threshold)
667 {
668 if (!actor->target
669 || actor->target->health <= 0)
670 {
671 actor->threshold = 0;
672 }
673 else
674 actor->threshold--;
675 }
676
677 // turn towards movement direction if not there yet
678 if (actor->movedir < 8)
679 {
680 actor->angle &= (7<<29);
681 delta = actor->angle - (actor->movedir << 29);
682
683 if (delta > 0)
684 actor->angle -= ANG90/2;
685 else if (delta < 0)
686 actor->angle += ANG90/2;
687 }
688
689 if (!actor->target
690 || !(actor->target->flags&MF_SHOOTABLE))
691 {
692 // look for a new target
693 if (P_LookForPlayers(actor,true))
694 return; // got a new target
695
696 P_SetMobjState (actor, actor->info->spawnstate);
697 return;
698 }
699
700 // do not attack twice in a row
701 if (actor->flags & MF_JUSTATTACKED)
702 {
703 actor->flags &= ~MF_JUSTATTACKED;
704 if (gameskill != sk_nightmare && !fastparm)
705 P_NewChaseDir (actor);
706 return;
707 }
708
709 // check for melee attack
710 if (actor->info->meleestate
711 && P_CheckMeleeRange (actor))
712 {
713 if (actor->info->attacksound)
714 S_StartSound (actor, actor->info->attacksound);
715
716 P_SetMobjState (actor, actor->info->meleestate);
717 return;
718 }
719
720 // check for missile attack
721 if (actor->info->missilestate)
722 {
723 if (gameskill < sk_nightmare
724 && !fastparm && actor->movecount)
725 {
726 goto nomissile;
727 }
728
729 if (!P_CheckMissileRange (actor))
730 goto nomissile;
731
732 P_SetMobjState (actor, actor->info->missilestate);
733 actor->flags |= MF_JUSTATTACKED;
734 return;
735 }
736
737 // ?
738 nomissile:
739 // possibly choose another target
740 if (netgame
741 && !actor->threshold
742 && !P_CheckSight (actor, actor->target) )
743 {
744 if (P_LookForPlayers(actor,true))
745 return; // got a new target
746 }
747
748 // chase towards player
749 if (--actor->movecount<0
750 || !P_Move (actor))
751 {
752 P_NewChaseDir (actor);
753 }
754
755 // make active sound
756 if (actor->info->activesound
757 && P_Random () < 3)
758 {
759 S_StartSound (actor, actor->info->activesound);
760 }
761 }
762
763
764 //
765 // A_FaceTarget
766 //
A_FaceTarget(mobj_t * actor)767 void A_FaceTarget (mobj_t* actor)
768 {
769 if (!actor->target)
770 return;
771
772 actor->flags &= ~MF_AMBUSH;
773
774 actor->angle = R_PointToAngle2 (actor->x,
775 actor->y,
776 actor->target->x,
777 actor->target->y);
778
779 if (actor->target->flags & MF_SHADOW)
780 actor->angle += P_SubRandom() << 21;
781 }
782
783
784 //
785 // A_PosAttack
786 //
A_PosAttack(mobj_t * actor)787 void A_PosAttack (mobj_t* actor)
788 {
789 int angle;
790 int damage;
791 int slope;
792
793 if (!actor->target)
794 return;
795
796 A_FaceTarget (actor);
797 angle = actor->angle;
798 slope = P_AimLineAttack (actor, angle, MISSILERANGE);
799
800 S_StartSound (actor, sfx_pistol);
801 angle += P_SubRandom() << 20;
802 damage = ((P_Random()%5)+1)*3;
803 P_LineAttack (actor, angle, MISSILERANGE, slope, damage);
804 }
805
A_SPosAttack(mobj_t * actor)806 void A_SPosAttack (mobj_t* actor)
807 {
808 int i;
809 int angle;
810 int bangle;
811 int damage;
812 int slope;
813
814 if (!actor->target)
815 return;
816
817 S_StartSound (actor, sfx_shotgn);
818 A_FaceTarget (actor);
819 bangle = actor->angle;
820 slope = P_AimLineAttack (actor, bangle, MISSILERANGE);
821
822 for (i=0 ; i<3 ; i++)
823 {
824 angle = bangle + (P_SubRandom() << 20);
825 damage = ((P_Random()%5)+1)*3;
826 P_LineAttack (actor, angle, MISSILERANGE, slope, damage);
827 }
828 }
829
A_CPosAttack(mobj_t * actor)830 void A_CPosAttack (mobj_t* actor)
831 {
832 int angle;
833 int bangle;
834 int damage;
835 int slope;
836
837 if (!actor->target)
838 return;
839
840 S_StartSound (actor, sfx_shotgn);
841 A_FaceTarget (actor);
842 bangle = actor->angle;
843 slope = P_AimLineAttack (actor, bangle, MISSILERANGE);
844
845 angle = bangle + (P_SubRandom() << 20);
846 damage = ((P_Random()%5)+1)*3;
847 P_LineAttack (actor, angle, MISSILERANGE, slope, damage);
848 }
849
A_CPosRefire(mobj_t * actor)850 void A_CPosRefire (mobj_t* actor)
851 {
852 // keep firing unless target got out of sight
853 A_FaceTarget (actor);
854
855 if (P_Random () < 40)
856 return;
857
858 if (!actor->target
859 || actor->target->health <= 0
860 || !P_CheckSight (actor, actor->target) )
861 {
862 P_SetMobjState (actor, actor->info->seestate);
863 }
864 }
865
866
A_SpidRefire(mobj_t * actor)867 void A_SpidRefire (mobj_t* actor)
868 {
869 // keep firing unless target got out of sight
870 A_FaceTarget (actor);
871
872 if (P_Random () < 10)
873 return;
874
875 if (!actor->target
876 || actor->target->health <= 0
877 || !P_CheckSight (actor, actor->target) )
878 {
879 P_SetMobjState (actor, actor->info->seestate);
880 }
881 }
882
A_BspiAttack(mobj_t * actor)883 void A_BspiAttack (mobj_t *actor)
884 {
885 if (!actor->target)
886 return;
887
888 A_FaceTarget (actor);
889
890 // launch a missile
891 P_SpawnMissile (actor, actor->target, MT_ARACHPLAZ);
892 }
893
894
895 //
896 // A_TroopAttack
897 //
A_TroopAttack(mobj_t * actor)898 void A_TroopAttack (mobj_t* actor)
899 {
900 int damage;
901
902 if (!actor->target)
903 return;
904
905 A_FaceTarget (actor);
906 if (P_CheckMeleeRange (actor))
907 {
908 S_StartSound (actor, sfx_claw);
909 damage = (P_Random()%8+1)*3;
910 P_DamageMobj (actor->target, actor, actor, damage);
911 return;
912 }
913
914
915 // launch a missile
916 P_SpawnMissile (actor, actor->target, MT_TROOPSHOT);
917 }
918
919
A_SargAttack(mobj_t * actor)920 void A_SargAttack (mobj_t* actor)
921 {
922 int damage;
923
924 if (!actor->target)
925 return;
926
927 A_FaceTarget (actor);
928 if (P_CheckMeleeRange (actor))
929 {
930 damage = ((P_Random()%10)+1)*4;
931 P_DamageMobj (actor->target, actor, actor, damage);
932 }
933 }
934
A_HeadAttack(mobj_t * actor)935 void A_HeadAttack (mobj_t* actor)
936 {
937 int damage;
938
939 if (!actor->target)
940 return;
941
942 A_FaceTarget (actor);
943 if (P_CheckMeleeRange (actor))
944 {
945 damage = (P_Random()%6+1)*10;
946 P_DamageMobj (actor->target, actor, actor, damage);
947 return;
948 }
949
950 // launch a missile
951 P_SpawnMissile (actor, actor->target, MT_HEADSHOT);
952 }
953
A_CyberAttack(mobj_t * actor)954 void A_CyberAttack (mobj_t* actor)
955 {
956 if (!actor->target)
957 return;
958
959 A_FaceTarget (actor);
960 P_SpawnMissile (actor, actor->target, MT_ROCKET);
961 }
962
963
A_BruisAttack(mobj_t * actor)964 void A_BruisAttack (mobj_t* actor)
965 {
966 int damage;
967
968 if (!actor->target)
969 return;
970
971 if (P_CheckMeleeRange (actor))
972 {
973 S_StartSound (actor, sfx_claw);
974 damage = (P_Random()%8+1)*10;
975 P_DamageMobj (actor->target, actor, actor, damage);
976 return;
977 }
978
979 // launch a missile
980 P_SpawnMissile (actor, actor->target, MT_BRUISERSHOT);
981 }
982
983
984 //
985 // A_SkelMissile
986 //
A_SkelMissile(mobj_t * actor)987 void A_SkelMissile (mobj_t* actor)
988 {
989 mobj_t* mo;
990
991 if (!actor->target)
992 return;
993
994 A_FaceTarget (actor);
995 actor->z += 16*FRACUNIT; // so missile spawns higher
996 mo = P_SpawnMissile (actor, actor->target, MT_TRACER);
997 actor->z -= 16*FRACUNIT; // back to normal
998
999 mo->x += mo->momx;
1000 mo->y += mo->momy;
1001 mo->tracer = actor->target;
1002 }
1003
1004 int TRACEANGLE = 0xc000000;
1005
A_Tracer(mobj_t * actor)1006 void A_Tracer (mobj_t* actor)
1007 {
1008 angle_t exact;
1009 fixed_t dist;
1010 fixed_t slope;
1011 mobj_t* dest;
1012 mobj_t* th;
1013
1014 if (gametic & 3)
1015 return;
1016
1017 // spawn a puff of smoke behind the rocket
1018 P_SpawnPuff (actor->x, actor->y, actor->z);
1019
1020 th = P_SpawnMobj (actor->x-actor->momx,
1021 actor->y-actor->momy,
1022 actor->z, MT_SMOKE);
1023
1024 th->momz = FRACUNIT;
1025 th->tics -= P_Random()&3;
1026 if (th->tics < 1)
1027 th->tics = 1;
1028
1029 // adjust direction
1030 dest = actor->tracer;
1031
1032 if (!dest || dest->health <= 0)
1033 return;
1034
1035 // change angle
1036 exact = R_PointToAngle2 (actor->x,
1037 actor->y,
1038 dest->x,
1039 dest->y);
1040
1041 if (exact != actor->angle)
1042 {
1043 if (exact - actor->angle > 0x80000000)
1044 {
1045 actor->angle -= TRACEANGLE;
1046 if (exact - actor->angle < 0x80000000)
1047 actor->angle = exact;
1048 }
1049 else
1050 {
1051 actor->angle += TRACEANGLE;
1052 if (exact - actor->angle > 0x80000000)
1053 actor->angle = exact;
1054 }
1055 }
1056
1057 exact = actor->angle>>ANGLETOFINESHIFT;
1058 actor->momx = FixedMul (actor->info->speed, finecosine[exact]);
1059 actor->momy = FixedMul (actor->info->speed, finesine[exact]);
1060
1061 // change slope
1062 dist = P_AproxDistance (dest->x - actor->x,
1063 dest->y - actor->y);
1064
1065 dist = dist / actor->info->speed;
1066
1067 if (dist < 1)
1068 dist = 1;
1069 slope = (dest->z+40*FRACUNIT - actor->z) / dist;
1070
1071 if (slope < actor->momz)
1072 actor->momz -= FRACUNIT/8;
1073 else
1074 actor->momz += FRACUNIT/8;
1075 }
1076
1077
A_SkelWhoosh(mobj_t * actor)1078 void A_SkelWhoosh (mobj_t* actor)
1079 {
1080 if (!actor->target)
1081 return;
1082 A_FaceTarget (actor);
1083 S_StartSound (actor,sfx_skeswg);
1084 }
1085
A_SkelFist(mobj_t * actor)1086 void A_SkelFist (mobj_t* actor)
1087 {
1088 int damage;
1089
1090 if (!actor->target)
1091 return;
1092
1093 A_FaceTarget (actor);
1094
1095 if (P_CheckMeleeRange (actor))
1096 {
1097 damage = ((P_Random()%10)+1)*6;
1098 S_StartSound (actor, sfx_skepch);
1099 P_DamageMobj (actor->target, actor, actor, damage);
1100 }
1101 }
1102
1103
1104
1105 //
1106 // PIT_VileCheck
1107 // Detect a corpse that could be raised.
1108 //
1109 mobj_t* corpsehit;
1110 mobj_t* vileobj;
1111 fixed_t viletryx;
1112 fixed_t viletryy;
1113
PIT_VileCheck(mobj_t * thing)1114 boolean PIT_VileCheck (mobj_t* thing)
1115 {
1116 int maxdist;
1117 boolean check;
1118
1119 if (!(thing->flags & MF_CORPSE) )
1120 return true; // not a monster
1121
1122 if (thing->tics != -1)
1123 return true; // not lying still yet
1124
1125 if (thing->info->raisestate == S_NULL)
1126 return true; // monster doesn't have a raise state
1127
1128 maxdist = thing->info->radius + mobjinfo[MT_VILE].radius;
1129
1130 if ( abs(thing->x - viletryx) > maxdist
1131 || abs(thing->y - viletryy) > maxdist )
1132 return true; // not actually touching
1133
1134 corpsehit = thing;
1135 corpsehit->momx = corpsehit->momy = 0;
1136 corpsehit->height <<= 2;
1137 check = P_CheckPosition (corpsehit, corpsehit->x, corpsehit->y);
1138 corpsehit->height >>= 2;
1139
1140 if (!check)
1141 return true; // doesn't fit here
1142
1143 return false; // got one, so stop checking
1144 }
1145
1146
1147
1148 //
1149 // A_VileChase
1150 // Check for ressurecting a body
1151 //
A_VileChase(mobj_t * actor)1152 void A_VileChase (mobj_t* actor)
1153 {
1154 int xl;
1155 int xh;
1156 int yl;
1157 int yh;
1158
1159 int bx;
1160 int by;
1161
1162 mobjinfo_t* info;
1163 mobj_t* temp;
1164
1165 if (actor->movedir != DI_NODIR)
1166 {
1167 // check for corpses to raise
1168 viletryx =
1169 actor->x + actor->info->speed*xspeed[actor->movedir];
1170 viletryy =
1171 actor->y + actor->info->speed*yspeed[actor->movedir];
1172
1173 xl = (viletryx - bmaporgx - MAXRADIUS*2)>>MAPBLOCKSHIFT;
1174 xh = (viletryx - bmaporgx + MAXRADIUS*2)>>MAPBLOCKSHIFT;
1175 yl = (viletryy - bmaporgy - MAXRADIUS*2)>>MAPBLOCKSHIFT;
1176 yh = (viletryy - bmaporgy + MAXRADIUS*2)>>MAPBLOCKSHIFT;
1177
1178 vileobj = actor;
1179 for (bx=xl ; bx<=xh ; bx++)
1180 {
1181 for (by=yl ; by<=yh ; by++)
1182 {
1183 // Call PIT_VileCheck to check
1184 // whether object is a corpse
1185 // that canbe raised.
1186 if (!P_BlockThingsIterator(bx,by,PIT_VileCheck))
1187 {
1188 // got one!
1189 temp = actor->target;
1190 actor->target = corpsehit;
1191 A_FaceTarget (actor);
1192 actor->target = temp;
1193
1194 P_SetMobjState (actor, S_VILE_HEAL1);
1195 S_StartSound (corpsehit, sfx_slop);
1196 info = corpsehit->info;
1197
1198 P_SetMobjState (corpsehit,info->raisestate);
1199 corpsehit->height <<= 2;
1200 corpsehit->flags = info->flags;
1201 corpsehit->health = info->spawnhealth;
1202 corpsehit->target = NULL;
1203
1204 return;
1205 }
1206 }
1207 }
1208 }
1209
1210 // Return to normal attack.
1211 A_Chase (actor);
1212 }
1213
1214
1215 //
1216 // A_VileStart
1217 //
A_VileStart(mobj_t * actor)1218 void A_VileStart (mobj_t* actor)
1219 {
1220 S_StartSound (actor, sfx_vilatk);
1221 }
1222
1223
1224 //
1225 // A_Fire
1226 // Keep fire in front of player unless out of sight
1227 //
1228 void A_Fire (mobj_t* actor);
1229
A_StartFire(mobj_t * actor)1230 void A_StartFire (mobj_t* actor)
1231 {
1232 S_StartSound(actor,sfx_flamst);
1233 A_Fire(actor);
1234 }
1235
A_FireCrackle(mobj_t * actor)1236 void A_FireCrackle (mobj_t* actor)
1237 {
1238 S_StartSound(actor,sfx_flame);
1239 A_Fire(actor);
1240 }
1241
A_Fire(mobj_t * actor)1242 void A_Fire (mobj_t* actor)
1243 {
1244 mobj_t* dest;
1245 mobj_t* target;
1246 unsigned an;
1247
1248 dest = actor->tracer;
1249 if (!dest)
1250 return;
1251
1252 target = P_SubstNullMobj(actor->target);
1253
1254 // don't move it if the vile lost sight
1255 if (!P_CheckSight (target, dest) )
1256 return;
1257
1258 an = dest->angle >> ANGLETOFINESHIFT;
1259
1260 P_UnsetThingPosition (actor);
1261 actor->x = dest->x + FixedMul (24*FRACUNIT, finecosine[an]);
1262 actor->y = dest->y + FixedMul (24*FRACUNIT, finesine[an]);
1263 actor->z = dest->z;
1264 P_SetThingPosition (actor);
1265 }
1266
1267
1268
1269 //
1270 // A_VileTarget
1271 // Spawn the hellfire
1272 //
A_VileTarget(mobj_t * actor)1273 void A_VileTarget (mobj_t* actor)
1274 {
1275 mobj_t* fog;
1276
1277 if (!actor->target)
1278 return;
1279
1280 A_FaceTarget (actor);
1281
1282 fog = P_SpawnMobj (actor->target->x,
1283 actor->target->x,
1284 actor->target->z, MT_FIRE);
1285
1286 actor->tracer = fog;
1287 fog->target = actor;
1288 fog->tracer = actor->target;
1289 A_Fire (fog);
1290 }
1291
1292
1293
1294
1295 //
1296 // A_VileAttack
1297 //
A_VileAttack(mobj_t * actor)1298 void A_VileAttack (mobj_t* actor)
1299 {
1300 mobj_t* fire;
1301 int an;
1302
1303 if (!actor->target)
1304 return;
1305
1306 A_FaceTarget (actor);
1307
1308 if (!P_CheckSight (actor, actor->target) )
1309 return;
1310
1311 S_StartSound (actor, sfx_barexp);
1312 P_DamageMobj (actor->target, actor, actor, 20);
1313 actor->target->momz = 1000*FRACUNIT/actor->target->info->mass;
1314
1315 an = actor->angle >> ANGLETOFINESHIFT;
1316
1317 fire = actor->tracer;
1318
1319 if (!fire)
1320 return;
1321
1322 // move the fire between the vile and the player
1323 fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]);
1324 fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]);
1325 P_RadiusAttack (fire, actor, 70 );
1326 }
1327
1328
1329
1330
1331 //
1332 // Mancubus attack,
1333 // firing three missiles (bruisers)
1334 // in three different directions?
1335 // Doesn't look like it.
1336 //
1337 #define FATSPREAD (ANG90/8)
1338
A_FatRaise(mobj_t * actor)1339 void A_FatRaise (mobj_t *actor)
1340 {
1341 A_FaceTarget (actor);
1342 S_StartSound (actor, sfx_manatk);
1343 }
1344
1345
A_FatAttack1(mobj_t * actor)1346 void A_FatAttack1 (mobj_t* actor)
1347 {
1348 mobj_t* mo;
1349 mobj_t* target;
1350 int an;
1351
1352 A_FaceTarget (actor);
1353
1354 // Change direction to ...
1355 actor->angle += FATSPREAD;
1356 target = P_SubstNullMobj(actor->target);
1357 P_SpawnMissile (actor, target, MT_FATSHOT);
1358
1359 mo = P_SpawnMissile (actor, target, MT_FATSHOT);
1360 mo->angle += FATSPREAD;
1361 an = mo->angle >> ANGLETOFINESHIFT;
1362 mo->momx = FixedMul (mo->info->speed, finecosine[an]);
1363 mo->momy = FixedMul (mo->info->speed, finesine[an]);
1364 }
1365
A_FatAttack2(mobj_t * actor)1366 void A_FatAttack2 (mobj_t* actor)
1367 {
1368 mobj_t* mo;
1369 mobj_t* target;
1370 int an;
1371
1372 A_FaceTarget (actor);
1373 // Now here choose opposite deviation.
1374 actor->angle -= FATSPREAD;
1375 target = P_SubstNullMobj(actor->target);
1376 P_SpawnMissile (actor, target, MT_FATSHOT);
1377
1378 mo = P_SpawnMissile (actor, target, MT_FATSHOT);
1379 mo->angle -= FATSPREAD*2;
1380 an = mo->angle >> ANGLETOFINESHIFT;
1381 mo->momx = FixedMul (mo->info->speed, finecosine[an]);
1382 mo->momy = FixedMul (mo->info->speed, finesine[an]);
1383 }
1384
A_FatAttack3(mobj_t * actor)1385 void A_FatAttack3 (mobj_t* actor)
1386 {
1387 mobj_t* mo;
1388 mobj_t* target;
1389 int an;
1390
1391 A_FaceTarget (actor);
1392
1393 target = P_SubstNullMobj(actor->target);
1394
1395 mo = P_SpawnMissile (actor, target, MT_FATSHOT);
1396 mo->angle -= FATSPREAD/2;
1397 an = mo->angle >> ANGLETOFINESHIFT;
1398 mo->momx = FixedMul (mo->info->speed, finecosine[an]);
1399 mo->momy = FixedMul (mo->info->speed, finesine[an]);
1400
1401 mo = P_SpawnMissile (actor, target, MT_FATSHOT);
1402 mo->angle += FATSPREAD/2;
1403 an = mo->angle >> ANGLETOFINESHIFT;
1404 mo->momx = FixedMul (mo->info->speed, finecosine[an]);
1405 mo->momy = FixedMul (mo->info->speed, finesine[an]);
1406 }
1407
1408
1409 //
1410 // SkullAttack
1411 // Fly at the player like a missile.
1412 //
1413 #define SKULLSPEED (20*FRACUNIT)
1414
A_SkullAttack(mobj_t * actor)1415 void A_SkullAttack (mobj_t* actor)
1416 {
1417 mobj_t* dest;
1418 angle_t an;
1419 int dist;
1420
1421 if (!actor->target)
1422 return;
1423
1424 dest = actor->target;
1425 actor->flags |= MF_SKULLFLY;
1426
1427 S_StartSound (actor, actor->info->attacksound);
1428 A_FaceTarget (actor);
1429 an = actor->angle >> ANGLETOFINESHIFT;
1430 actor->momx = FixedMul (SKULLSPEED, finecosine[an]);
1431 actor->momy = FixedMul (SKULLSPEED, finesine[an]);
1432 dist = P_AproxDistance (dest->x - actor->x, dest->y - actor->y);
1433 dist = dist / SKULLSPEED;
1434
1435 if (dist < 1)
1436 dist = 1;
1437 actor->momz = (dest->z+(dest->height>>1) - actor->z) / dist;
1438 }
1439
1440
1441 //
1442 // A_PainShootSkull
1443 // Spawn a lost soul and launch it at the target
1444 //
1445 void
A_PainShootSkull(mobj_t * actor,angle_t angle)1446 A_PainShootSkull
1447 ( mobj_t* actor,
1448 angle_t angle )
1449 {
1450 fixed_t x;
1451 fixed_t y;
1452 fixed_t z;
1453
1454 mobj_t* newmobj;
1455 angle_t an;
1456 int prestep;
1457 int count;
1458 thinker_t* currentthinker;
1459
1460 // count total number of skull currently on the level
1461 count = 0;
1462
1463 currentthinker = thinkercap.next;
1464 while (currentthinker != &thinkercap)
1465 {
1466 if ( (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker)
1467 && ((mobj_t *)currentthinker)->type == MT_SKULL)
1468 count++;
1469 currentthinker = currentthinker->next;
1470 }
1471
1472 // if there are allready 20 skulls on the level,
1473 // don't spit another one
1474 if (count > 20)
1475 return;
1476
1477
1478 // okay, there's playe for another one
1479 an = angle >> ANGLETOFINESHIFT;
1480
1481 prestep =
1482 4*FRACUNIT
1483 + 3*(actor->info->radius + mobjinfo[MT_SKULL].radius)/2;
1484
1485 x = actor->x + FixedMul (prestep, finecosine[an]);
1486 y = actor->y + FixedMul (prestep, finesine[an]);
1487 z = actor->z + 8*FRACUNIT;
1488
1489 newmobj = P_SpawnMobj (x , y, z, MT_SKULL);
1490
1491 // Check for movements.
1492 if (!P_TryMove (newmobj, newmobj->x, newmobj->y))
1493 {
1494 // kill it immediately
1495 P_DamageMobj (newmobj,actor,actor,10000);
1496 return;
1497 }
1498
1499 newmobj->target = actor->target;
1500 A_SkullAttack (newmobj);
1501 }
1502
1503
1504 //
1505 // A_PainAttack
1506 // Spawn a lost soul and launch it at the target
1507 //
A_PainAttack(mobj_t * actor)1508 void A_PainAttack (mobj_t* actor)
1509 {
1510 if (!actor->target)
1511 return;
1512
1513 A_FaceTarget (actor);
1514 A_PainShootSkull (actor, actor->angle);
1515 }
1516
1517
A_PainDie(mobj_t * actor)1518 void A_PainDie (mobj_t* actor)
1519 {
1520 A_Fall (actor);
1521 A_PainShootSkull (actor, actor->angle+ANG90);
1522 A_PainShootSkull (actor, actor->angle+ANG180);
1523 A_PainShootSkull (actor, actor->angle+ANG270);
1524 }
1525
1526
1527
1528
1529
1530
A_Scream(mobj_t * actor)1531 void A_Scream (mobj_t* actor)
1532 {
1533 int sound;
1534
1535 switch (actor->info->deathsound)
1536 {
1537 case 0:
1538 return;
1539
1540 case sfx_podth1:
1541 case sfx_podth2:
1542 case sfx_podth3:
1543 sound = sfx_podth1 + P_Random ()%3;
1544 break;
1545
1546 case sfx_bgdth1:
1547 case sfx_bgdth2:
1548 sound = sfx_bgdth1 + P_Random ()%2;
1549 break;
1550
1551 default:
1552 sound = actor->info->deathsound;
1553 break;
1554 }
1555
1556 // Check for bosses.
1557 if (actor->type==MT_SPIDER
1558 || actor->type == MT_CYBORG)
1559 {
1560 // full volume
1561 S_StartSound (NULL, sound);
1562 }
1563 else
1564 S_StartSound (actor, sound);
1565 }
1566
1567
A_XScream(mobj_t * actor)1568 void A_XScream (mobj_t* actor)
1569 {
1570 S_StartSound (actor, sfx_slop);
1571 }
1572
A_Pain(mobj_t * actor)1573 void A_Pain (mobj_t* actor)
1574 {
1575 if (actor->info->painsound)
1576 S_StartSound (actor, actor->info->painsound);
1577 }
1578
1579
1580
A_Fall(mobj_t * actor)1581 void A_Fall (mobj_t *actor)
1582 {
1583 // actor is on ground, it can be walked over
1584 actor->flags &= ~MF_SOLID;
1585
1586 // So change this if corpse objects
1587 // are meant to be obstacles.
1588 }
1589
1590
1591 //
1592 // A_Explode
1593 //
A_Explode(mobj_t * thingy)1594 void A_Explode (mobj_t* thingy)
1595 {
1596 P_RadiusAttack(thingy, thingy->target, 128);
1597 }
1598
1599 // Check whether the death of the specified monster type is allowed
1600 // to trigger the end of episode special action.
1601 //
1602 // This behavior changed in v1.9, the most notable effect of which
1603 // was to break uac_dead.wad
1604
CheckBossEnd(mobjtype_t motype)1605 static boolean CheckBossEnd(mobjtype_t motype)
1606 {
1607 if (gameversion < exe_ultimate)
1608 {
1609 if (gamemap != 8)
1610 {
1611 return false;
1612 }
1613
1614 // Baron death on later episodes is nothing special.
1615
1616 if (motype == MT_BRUISER && gameepisode != 1)
1617 {
1618 return false;
1619 }
1620
1621 return true;
1622 }
1623 else
1624 {
1625 // New logic that appeared in Ultimate Doom.
1626 // Looks like the logic was overhauled while adding in the
1627 // episode 4 support. Now bosses only trigger on their
1628 // specific episode.
1629
1630 switch(gameepisode)
1631 {
1632 case 1:
1633 return gamemap == 8 && motype == MT_BRUISER;
1634
1635 case 2:
1636 return gamemap == 8 && motype == MT_CYBORG;
1637
1638 case 3:
1639 return gamemap == 8 && motype == MT_SPIDER;
1640
1641 case 4:
1642 return (gamemap == 6 && motype == MT_CYBORG)
1643 || (gamemap == 8 && motype == MT_SPIDER);
1644
1645 default:
1646 return gamemap == 8;
1647 }
1648 }
1649 }
1650
1651 //
1652 // A_BossDeath
1653 // Possibly trigger special effects
1654 // if on first boss level
1655 //
A_BossDeath(mobj_t * mo)1656 void A_BossDeath (mobj_t* mo)
1657 {
1658 thinker_t* th;
1659 mobj_t* mo2;
1660 line_t junk;
1661 int i;
1662
1663 if ( gamemode == commercial)
1664 {
1665 if (gamemap != 7)
1666 return;
1667
1668 if ((mo->type != MT_FATSO)
1669 && (mo->type != MT_BABY))
1670 return;
1671 }
1672 else
1673 {
1674 if (!CheckBossEnd(mo->type))
1675 {
1676 return;
1677 }
1678 }
1679
1680 // make sure there is a player alive for victory
1681 for (i=0 ; i<MAXPLAYERS ; i++)
1682 if (playeringame[i] && players[i].health > 0)
1683 break;
1684
1685 if (i==MAXPLAYERS)
1686 return; // no one left alive, so do not end game
1687
1688 // scan the remaining thinkers to see
1689 // if all bosses are dead
1690 for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
1691 {
1692 if (th->function.acp1 != (actionf_p1)P_MobjThinker)
1693 continue;
1694
1695 mo2 = (mobj_t *)th;
1696 if (mo2 != mo
1697 && mo2->type == mo->type
1698 && mo2->health > 0)
1699 {
1700 // other boss not dead
1701 return;
1702 }
1703 }
1704
1705 // victory!
1706 if ( gamemode == commercial)
1707 {
1708 if (gamemap == 7)
1709 {
1710 if (mo->type == MT_FATSO)
1711 {
1712 junk.tag = 666;
1713 EV_DoFloor(&junk,lowerFloorToLowest);
1714 return;
1715 }
1716
1717 if (mo->type == MT_BABY)
1718 {
1719 junk.tag = 667;
1720 EV_DoFloor(&junk,raiseToTexture);
1721 return;
1722 }
1723 }
1724 }
1725 else
1726 {
1727 switch(gameepisode)
1728 {
1729 case 1:
1730 junk.tag = 666;
1731 EV_DoFloor (&junk, lowerFloorToLowest);
1732 return;
1733 break;
1734
1735 case 4:
1736 switch(gamemap)
1737 {
1738 case 6:
1739 junk.tag = 666;
1740 EV_DoDoor (&junk, vld_blazeOpen);
1741 return;
1742 break;
1743
1744 case 8:
1745 junk.tag = 666;
1746 EV_DoFloor (&junk, lowerFloorToLowest);
1747 return;
1748 break;
1749 }
1750 }
1751 }
1752
1753 G_ExitLevel ();
1754 }
1755
1756
A_Hoof(mobj_t * mo)1757 void A_Hoof (mobj_t* mo)
1758 {
1759 S_StartSound (mo, sfx_hoof);
1760 A_Chase (mo);
1761 }
1762
A_Metal(mobj_t * mo)1763 void A_Metal (mobj_t* mo)
1764 {
1765 S_StartSound (mo, sfx_metal);
1766 A_Chase (mo);
1767 }
1768
A_BabyMetal(mobj_t * mo)1769 void A_BabyMetal (mobj_t* mo)
1770 {
1771 S_StartSound (mo, sfx_bspwlk);
1772 A_Chase (mo);
1773 }
1774
1775 void
A_OpenShotgun2(player_t * player,pspdef_t * psp)1776 A_OpenShotgun2
1777 ( player_t* player,
1778 pspdef_t* psp )
1779 {
1780 S_StartSound (player->mo, sfx_dbopn);
1781 }
1782
1783 void
A_LoadShotgun2(player_t * player,pspdef_t * psp)1784 A_LoadShotgun2
1785 ( player_t* player,
1786 pspdef_t* psp )
1787 {
1788 S_StartSound (player->mo, sfx_dbload);
1789 }
1790
1791 void
1792 A_ReFire
1793 ( player_t* player,
1794 pspdef_t* psp );
1795
1796 void
A_CloseShotgun2(player_t * player,pspdef_t * psp)1797 A_CloseShotgun2
1798 ( player_t* player,
1799 pspdef_t* psp )
1800 {
1801 S_StartSound (player->mo, sfx_dbcls);
1802 A_ReFire(player,psp);
1803 }
1804
1805
1806
1807 mobj_t* braintargets[32];
1808 int numbraintargets;
1809 int braintargeton = 0;
1810
A_BrainAwake(mobj_t * mo)1811 void A_BrainAwake (mobj_t* mo)
1812 {
1813 thinker_t* thinker;
1814 mobj_t* m;
1815
1816 // find all the target spots
1817 numbraintargets = 0;
1818 braintargeton = 0;
1819
1820 thinker = thinkercap.next;
1821 for (thinker = thinkercap.next ;
1822 thinker != &thinkercap ;
1823 thinker = thinker->next)
1824 {
1825 if (thinker->function.acp1 != (actionf_p1)P_MobjThinker)
1826 continue; // not a mobj
1827
1828 m = (mobj_t *)thinker;
1829
1830 if (m->type == MT_BOSSTARGET )
1831 {
1832 braintargets[numbraintargets] = m;
1833 numbraintargets++;
1834 }
1835 }
1836
1837 S_StartSound (NULL,sfx_bossit);
1838 }
1839
1840
A_BrainPain(mobj_t * mo)1841 void A_BrainPain (mobj_t* mo)
1842 {
1843 S_StartSound (NULL,sfx_bospn);
1844 }
1845
1846
A_BrainScream(mobj_t * mo)1847 void A_BrainScream (mobj_t* mo)
1848 {
1849 int x;
1850 int y;
1851 int z;
1852 mobj_t* th;
1853
1854 for (x=mo->x - 196*FRACUNIT ; x< mo->x + 320*FRACUNIT ; x+= FRACUNIT*8)
1855 {
1856 y = mo->y - 320*FRACUNIT;
1857 z = 128 + P_Random()*2*FRACUNIT;
1858 th = P_SpawnMobj (x,y,z, MT_ROCKET);
1859 th->momz = P_Random()*512;
1860
1861 P_SetMobjState (th, S_BRAINEXPLODE1);
1862
1863 th->tics -= P_Random()&7;
1864 if (th->tics < 1)
1865 th->tics = 1;
1866 }
1867
1868 S_StartSound (NULL,sfx_bosdth);
1869 }
1870
1871
1872
A_BrainExplode(mobj_t * mo)1873 void A_BrainExplode (mobj_t* mo)
1874 {
1875 int x;
1876 int y;
1877 int z;
1878 mobj_t* th;
1879
1880 x = mo->x + P_SubRandom() * 2048;
1881 y = mo->y;
1882 z = 128 + P_Random()*2*FRACUNIT;
1883 th = P_SpawnMobj (x,y,z, MT_ROCKET);
1884 th->momz = P_Random()*512;
1885
1886 P_SetMobjState (th, S_BRAINEXPLODE1);
1887
1888 th->tics -= P_Random()&7;
1889 if (th->tics < 1)
1890 th->tics = 1;
1891 }
1892
1893
A_BrainDie(mobj_t * mo)1894 void A_BrainDie (mobj_t* mo)
1895 {
1896 G_ExitLevel ();
1897 }
1898
A_BrainSpit(mobj_t * mo)1899 void A_BrainSpit (mobj_t* mo)
1900 {
1901 mobj_t* targ;
1902 mobj_t* newmobj;
1903
1904 static int easy = 0;
1905
1906 easy ^= 1;
1907 if (gameskill <= sk_easy && (!easy))
1908 return;
1909
1910 // shoot a cube at current target
1911 targ = braintargets[braintargeton];
1912 braintargeton = (braintargeton+1)%numbraintargets;
1913
1914 // spawn brain missile
1915 newmobj = P_SpawnMissile (mo, targ, MT_SPAWNSHOT);
1916 newmobj->target = targ;
1917 newmobj->reactiontime =
1918 ((targ->y - mo->y)/newmobj->momy) / newmobj->state->tics;
1919
1920 S_StartSound(NULL, sfx_bospit);
1921 }
1922
1923
1924
1925 void A_SpawnFly (mobj_t* mo);
1926
1927 // travelling cube sound
A_SpawnSound(mobj_t * mo)1928 void A_SpawnSound (mobj_t* mo)
1929 {
1930 S_StartSound (mo,sfx_boscub);
1931 A_SpawnFly(mo);
1932 }
1933
A_SpawnFly(mobj_t * mo)1934 void A_SpawnFly (mobj_t* mo)
1935 {
1936 mobj_t* newmobj;
1937 mobj_t* fog;
1938 mobj_t* targ;
1939 int r;
1940 mobjtype_t type;
1941
1942 if (--mo->reactiontime)
1943 return; // still flying
1944
1945 targ = P_SubstNullMobj(mo->target);
1946
1947 // First spawn teleport fog.
1948 fog = P_SpawnMobj (targ->x, targ->y, targ->z, MT_SPAWNFIRE);
1949 S_StartSound (fog, sfx_telept);
1950
1951 // Randomly select monster to spawn.
1952 r = P_Random ();
1953
1954 // Probability distribution (kind of :),
1955 // decreasing likelihood.
1956 if ( r<50 )
1957 type = MT_TROOP;
1958 else if (r<90)
1959 type = MT_SERGEANT;
1960 else if (r<120)
1961 type = MT_SHADOWS;
1962 else if (r<130)
1963 type = MT_PAIN;
1964 else if (r<160)
1965 type = MT_HEAD;
1966 else if (r<162)
1967 type = MT_VILE;
1968 else if (r<172)
1969 type = MT_UNDEAD;
1970 else if (r<192)
1971 type = MT_BABY;
1972 else if (r<222)
1973 type = MT_FATSO;
1974 else if (r<246)
1975 type = MT_KNIGHT;
1976 else
1977 type = MT_BRUISER;
1978
1979 newmobj = P_SpawnMobj (targ->x, targ->y, targ->z, type);
1980 if (P_LookForPlayers (newmobj, true) )
1981 P_SetMobjState (newmobj, newmobj->info->seestate);
1982
1983 // telefrag anything in this spot
1984 P_TeleportMove (newmobj, newmobj->x, newmobj->y);
1985
1986 // remove self (i.e., cube).
1987 P_RemoveMobj (mo);
1988 }
1989
1990
1991
A_PlayerScream(mobj_t * mo)1992 void A_PlayerScream (mobj_t* mo)
1993 {
1994 // Default death sound.
1995 int sound = sfx_pldeth;
1996
1997 if ( (gamemode == commercial)
1998 && (mo->health < -50))
1999 {
2000 // IF THE PLAYER DIES
2001 // LESS THAN -50% WITHOUT GIBBING
2002 sound = sfx_pdiehi;
2003 }
2004
2005 S_StartSound (mo, sound);
2006 }
2007