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