Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

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