home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #2 / amigaacscoverdisc1998-021998.iso / games / doom / source / linuxdoom-1.10 / p_inter.c < prev    next >
C/C++ Source or Header  |  1997-12-22  |  18KB  |  919 lines

  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. //    Handling interactions (i.e., collisions).
  21. //
  22. //-----------------------------------------------------------------------------
  23.  
  24.  
  25. static const char
  26. rcsid[] = "$Id: p_inter.c,v 1.4 1997/02/03 22:45:11 b1 Exp $";
  27.  
  28.  
  29. // Data.
  30. #include "doomdef.h"
  31. #include "dstrings.h"
  32. #include "sounds.h"
  33.  
  34. #include "doomstat.h"
  35.  
  36. #include "m_random.h"
  37. #include "i_system.h"
  38.  
  39. #include "am_map.h"
  40.  
  41. #include "p_local.h"
  42.  
  43. #include "s_sound.h"
  44.  
  45. #ifdef __GNUG__
  46. #pragma implementation "p_inter.h"
  47. #endif
  48. #include "p_inter.h"
  49.  
  50.  
  51. #define BONUSADD    6
  52.  
  53.  
  54.  
  55.  
  56. // a weapon is found with two clip loads,
  57. // a big item has five clip loads
  58. int    maxammo[NUMAMMO] = {200, 50, 300, 50};
  59. int    clipammo[NUMAMMO] = {10, 4, 20, 1};
  60.  
  61.  
  62. //
  63. // GET STUFF
  64. //
  65.  
  66. //
  67. // P_GiveAmmo
  68. // Num is the number of clip loads,
  69. // not the individual count (0= 1/2 clip).
  70. // Returns false if the ammo can't be picked up at all
  71. //
  72.  
  73. boolean
  74. P_GiveAmmo
  75. ( player_t*    player,
  76.   ammotype_t    ammo,
  77.   int        num )
  78. {
  79.     int        oldammo;
  80.     
  81.     if (ammo == am_noammo)
  82.     return false;
  83.         
  84.     if (ammo < 0 || ammo > NUMAMMO)
  85.     I_Error ("P_GiveAmmo: bad type %i", ammo);
  86.         
  87.     if ( player->ammo[ammo] == player->maxammo[ammo]  )
  88.     return false;
  89.         
  90.     if (num)
  91.     num *= clipammo[ammo];
  92.     else
  93.     num = clipammo[ammo]/2;
  94.     
  95.     if (gameskill == sk_baby
  96.     || gameskill == sk_nightmare)
  97.     {
  98.     // give double ammo in trainer mode,
  99.     // you'll need in nightmare
  100.     num <<= 1;
  101.     }
  102.     
  103.         
  104.     oldammo = player->ammo[ammo];
  105.     player->ammo[ammo] += num;
  106.  
  107.     if (player->ammo[ammo] > player->maxammo[ammo])
  108.     player->ammo[ammo] = player->maxammo[ammo];
  109.  
  110.     // If non zero ammo, 
  111.     // don't change up weapons,
  112.     // player was lower on purpose.
  113.     if (oldammo)
  114.     return true;    
  115.  
  116.     // We were down to zero,
  117.     // so select a new weapon.
  118.     // Preferences are not user selectable.
  119.     switch (ammo)
  120.     {
  121.       case am_clip:
  122.     if (player->readyweapon == wp_fist)
  123.     {
  124.         if (player->weaponowned[wp_chaingun])
  125.         player->pendingweapon = wp_chaingun;
  126.         else
  127.         player->pendingweapon = wp_pistol;
  128.     }
  129.     break;
  130.     
  131.       case am_shell:
  132.     if (player->readyweapon == wp_fist
  133.         || player->readyweapon == wp_pistol)
  134.     {
  135.         if (player->weaponowned[wp_shotgun])
  136.         player->pendingweapon = wp_shotgun;
  137.     }
  138.     break;
  139.     
  140.       case am_cell:
  141.     if (player->readyweapon == wp_fist
  142.         || player->readyweapon == wp_pistol)
  143.     {
  144.         if (player->weaponowned[wp_plasma])
  145.         player->pendingweapon = wp_plasma;
  146.     }
  147.     break;
  148.     
  149.       case am_misl:
  150.     if (player->readyweapon == wp_fist)
  151.     {
  152.         if (player->weaponowned[wp_missile])
  153.         player->pendingweapon = wp_missile;
  154.     }
  155.       default:
  156.     break;
  157.     }
  158.     
  159.     return true;
  160. }
  161.  
  162.  
  163. //
  164. // P_GiveWeapon
  165. // The weapon name may have a MF_DROPPED flag ored in.
  166. //
  167. boolean
  168. P_GiveWeapon
  169. ( player_t*    player,
  170.   weapontype_t    weapon,
  171.   boolean    dropped )
  172. {
  173.     boolean    gaveammo;
  174.     boolean    gaveweapon;
  175.     
  176.     if (netgame
  177.     && (deathmatch!=2)
  178.      && !dropped )
  179.     {
  180.     // leave placed weapons forever on net games
  181.     if (player->weaponowned[weapon])
  182.         return false;
  183.  
  184.     player->bonuscount += BONUSADD;
  185.     player->weaponowned[weapon] = true;
  186.  
  187.     if (deathmatch)
  188.         P_GiveAmmo (player, weaponinfo[weapon].ammo, 5);
  189.     else
  190.         P_GiveAmmo (player, weaponinfo[weapon].ammo, 2);
  191.     player->pendingweapon = weapon;
  192.  
  193.     if (player == &players[consoleplayer])
  194.         S_StartSound (NULL, sfx_wpnup);
  195.     return false;
  196.     }
  197.     
  198.     if (weaponinfo[weapon].ammo != am_noammo)
  199.     {
  200.     // give one clip with a dropped weapon,
  201.     // two clips with a found weapon
  202.     if (dropped)
  203.         gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 1);
  204.     else
  205.         gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 2);
  206.     }
  207.     else
  208.     gaveammo = false;
  209.     
  210.     if (player->weaponowned[weapon])
  211.     gaveweapon = false;
  212.     else
  213.     {
  214.     gaveweapon = true;
  215.     player->weaponowned[weapon] = true;
  216.     player->pendingweapon = weapon;
  217.     }
  218.     
  219.     return (gaveweapon || gaveammo);
  220. }
  221.  
  222.  
  223.  
  224. //
  225. // P_GiveBody
  226. // Returns false if the body isn't needed at all
  227. //
  228. boolean
  229. P_GiveBody
  230. ( player_t*    player,
  231.   int        num )
  232. {
  233.     if (player->health >= MAXHEALTH)
  234.     return false;
  235.         
  236.     player->health += num;
  237.     if (player->health > MAXHEALTH)
  238.     player->health = MAXHEALTH;
  239.     player->mo->health = player->health;
  240.     
  241.     return true;
  242. }
  243.  
  244.  
  245.  
  246. //
  247. // P_GiveArmor
  248. // Returns false if the armor is worse
  249. // than the current armor.
  250. //
  251. boolean
  252. P_GiveArmor
  253. ( player_t*    player,
  254.   int        armortype )
  255. {
  256.     int        hits;
  257.     
  258.     hits = armortype*100;
  259.     if (player->armorpoints >= hits)
  260.     return false;    // don't pick up
  261.         
  262.     player->armortype = armortype;
  263.     player->armorpoints = hits;
  264.     
  265.     return true;
  266. }
  267.  
  268.  
  269.  
  270. //
  271. // P_GiveCard
  272. //
  273. void
  274. P_GiveCard
  275. ( player_t*    player,
  276.   card_t    card )
  277. {
  278.     if (player->cards[card])
  279.     return;
  280.     
  281.     player->bonuscount = BONUSADD;
  282.     player->cards[card] = 1;
  283. }
  284.  
  285.  
  286. //
  287. // P_GivePower
  288. //
  289. boolean
  290. P_GivePower
  291. ( player_t*    player,
  292.   int /*powertype_t*/    power )
  293. {
  294.     if (power == pw_invulnerability)
  295.     {
  296.     player->powers[power] = INVULNTICS;
  297.     return true;
  298.     }
  299.     
  300.     if (power == pw_invisibility)
  301.     {
  302.     player->powers[power] = INVISTICS;
  303.     player->mo->flags |= MF_SHADOW;
  304.     return true;
  305.     }
  306.     
  307.     if (power == pw_infrared)
  308.     {
  309.     player->powers[power] = INFRATICS;
  310.     return true;
  311.     }
  312.     
  313.     if (power == pw_ironfeet)
  314.     {
  315.     player->powers[power] = IRONTICS;
  316.     return true;
  317.     }
  318.     
  319.     if (power == pw_strength)
  320.     {
  321.     P_GiveBody (player, 100);
  322.     player->powers[power] = 1;
  323.     return true;
  324.     }
  325.     
  326.     if (player->powers[power])
  327.     return false;    // already got it
  328.         
  329.     player->powers[power] = 1;
  330.     return true;
  331. }
  332.  
  333.  
  334.  
  335. //
  336. // P_TouchSpecialThing
  337. //
  338. void
  339. P_TouchSpecialThing
  340. ( mobj_t*    special,
  341.   mobj_t*    toucher )
  342. {
  343.     player_t*    player;
  344.     int        i;
  345.     fixed_t    delta;
  346.     int        sound;
  347.         
  348.     delta = special->z - toucher->z;
  349.  
  350.     if (delta > toucher->height
  351.     || delta < -8*FRACUNIT)
  352.     {
  353.     // out of reach
  354.     return;
  355.     }
  356.     
  357.     
  358.     sound = sfx_itemup;    
  359.     player = toucher->player;
  360.  
  361.     // Dead thing touching.
  362.     // Can happen with a sliding player corpse.
  363.     if (toucher->health <= 0)
  364.     return;
  365.  
  366.     // Identify by sprite.
  367.     switch (special->sprite)
  368.     {
  369.     // armor
  370.       case SPR_ARM1:
  371.     if (!P_GiveArmor (player, 1))
  372.         return;
  373.     player->message = GOTARMOR;
  374.     break;
  375.         
  376.       case SPR_ARM2:
  377.     if (!P_GiveArmor (player, 2))
  378.         return;
  379.     player->message = GOTMEGA;
  380.     break;
  381.     
  382.     // bonus items
  383.       case SPR_BON1:
  384.     player->health++;        // can go over 100%
  385.     if (player->health > 200)
  386.         player->health = 200;
  387.     player->mo->health = player->health;
  388.     player->message = GOTHTHBONUS;
  389.     break;
  390.     
  391.       case SPR_BON2:
  392.     player->armorpoints++;        // can go over 100%
  393.     if (player->armorpoints > 200)
  394.         player->armorpoints = 200;
  395.     if (!player->armortype)
  396.         player->armortype = 1;
  397.     player->message = GOTARMBONUS;
  398.     break;
  399.     
  400.       case SPR_SOUL:
  401.     player->health += 100;
  402.     if (player->health > 200)
  403.         player->health = 200;
  404.     player->mo->health = player->health;
  405.     player->message = GOTSUPER;
  406.     sound = sfx_getpow;
  407.     break;
  408.     
  409.       case SPR_MEGA:
  410.     if (gamemode != commercial)
  411.         return;
  412.     player->health = 200;
  413.     player->mo->health = player->health;
  414.     P_GiveArmor (player,2);
  415.     player->message = GOTMSPHERE;
  416.     sound = sfx_getpow;
  417.     break;
  418.     
  419.     // cards
  420.     // leave cards for everyone
  421.       case SPR_BKEY:
  422.     if (!player->cards[it_bluecard])
  423.         player->message = GOTBLUECARD;
  424.     P_GiveCard (player, it_bluecard);
  425.     if (!netgame)
  426.         break;
  427.     return;
  428.     
  429.       case SPR_YKEY:
  430.     if (!player->cards[it_yellowcard])
  431.         player->message = GOTYELWCARD;
  432.     P_GiveCard (player, it_yellowcard);
  433.     if (!netgame)
  434.         break;
  435.     return;
  436.     
  437.       case SPR_RKEY:
  438.     if (!player->cards[it_redcard])
  439.         player->message = GOTREDCARD;
  440.     P_GiveCard (player, it_redcard);
  441.     if (!netgame)
  442.         break;
  443.     return;
  444.     
  445.       case SPR_BSKU:
  446.     if (!player->cards[it_blueskull])
  447.         player->message = GOTBLUESKUL;
  448.     P_GiveCard (player, it_blueskull);
  449.     if (!netgame)
  450.         break;
  451.     return;
  452.     
  453.       case SPR_YSKU:
  454.     if (!player->cards[it_yellowskull])
  455.         player->message = GOTYELWSKUL;
  456.     P_GiveCard (player, it_yellowskull);
  457.     if (!netgame)
  458.         break;
  459.     return;
  460.     
  461.       case SPR_RSKU:
  462.     if (!player->cards[it_redskull])
  463.         player->message = GOTREDSKULL;
  464.     P_GiveCard (player, it_redskull);
  465.     if (!netgame)
  466.         break;
  467.     return;
  468.     
  469.     // medikits, heals
  470.       case SPR_STIM:
  471.     if (!P_GiveBody (player, 10))
  472.         return;
  473.     player->message = GOTSTIM;
  474.     break;
  475.     
  476.       case SPR_MEDI:
  477.     if (!P_GiveBody (player, 25))
  478.         return;
  479.  
  480.     if (player->health < 25)
  481.         player->message = GOTMEDINEED;
  482.     else
  483.         player->message = GOTMEDIKIT;
  484.     break;
  485.  
  486.     
  487.     // power ups
  488.       case SPR_PINV:
  489.     if (!P_GivePower (player, pw_invulnerability))
  490.         return;
  491.     player->message = GOTINVUL;
  492.     sound = sfx_getpow;
  493.     break;
  494.     
  495.       case SPR_PSTR:
  496.     if (!P_GivePower (player, pw_strength))
  497.         return;
  498.     player->message = GOTBERSERK;
  499.     if (player->readyweapon != wp_fist)
  500.         player->pendingweapon = wp_fist;
  501.     sound = sfx_getpow;
  502.     break;
  503.     
  504.       case SPR_PINS:
  505.     if (!P_GivePower (player, pw_invisibility))
  506.         return;
  507.     player->message = GOTINVIS;
  508.     sound = sfx_getpow;
  509.     break;
  510.     
  511.       case SPR_SUIT:
  512.     if (!P_GivePower (player, pw_ironfeet))
  513.         return;
  514.     player->message = GOTSUIT;
  515.     sound = sfx_getpow;
  516.     break;
  517.     
  518.       case SPR_PMAP:
  519.     if (!P_GivePower (player, pw_allmap))
  520.         return;
  521.     player->message = GOTMAP;
  522.     sound = sfx_getpow;
  523.     break;
  524.     
  525.       case SPR_PVIS:
  526.     if (!P_GivePower (player, pw_infrared))
  527.         return;
  528.     player->message = GOTVISOR;
  529.     sound = sfx_getpow;
  530.     break;
  531.     
  532.     // ammo
  533.       case SPR_CLIP:
  534.     if (special->flags & MF_DROPPED)
  535.     {
  536.         if (!P_GiveAmmo (player,am_clip,0))
  537.         return;
  538.     }
  539.     else
  540.     {
  541.         if (!P_GiveAmmo (player,am_clip,1))
  542.         return;
  543.     }
  544.     player->message = GOTCLIP;
  545.     break;
  546.     
  547.       case SPR_AMMO:
  548.     if (!P_GiveAmmo (player, am_clip,5))
  549.         return;
  550.     player->message = GOTCLIPBOX;
  551.     break;
  552.     
  553.       case SPR_ROCK:
  554.     if (!P_GiveAmmo (player, am_misl,1))
  555.         return;
  556.     player->message = GOTROCKET;
  557.     break;
  558.     
  559.       case SPR_BROK:
  560.     if (!P_GiveAmmo (player, am_misl,5))
  561.         return;
  562.     player->message = GOTROCKBOX;
  563.     break;
  564.     
  565.       case SPR_CELL:
  566.     if (!P_GiveAmmo (player, am_cell,1))
  567.         return;
  568.     player->message = GOTCELL;
  569.     break;
  570.     
  571.       case SPR_CELP:
  572.     if (!P_GiveAmmo (player, am_cell,5))
  573.         return;
  574.     player->message = GOTCELLBOX;
  575.     break;
  576.     
  577.       case SPR_SHEL:
  578.     if (!P_GiveAmmo (player, am_shell,1))
  579.         return;
  580.     player->message = GOTSHELLS;
  581.     break;
  582.     
  583.       case SPR_SBOX:
  584.     if (!P_GiveAmmo (player, am_shell,5))
  585.         return;
  586.     player->message = GOTSHELLBOX;
  587.     break;
  588.     
  589.       case SPR_BPAK:
  590.     if (!player->backpack)
  591.     {
  592.         for (i=0 ; i<NUMAMMO ; i++)
  593.         player->maxammo[i] *= 2;
  594.         player->backpack = true;
  595.     }
  596.     for (i=0 ; i<NUMAMMO ; i++)
  597.         P_GiveAmmo (player, i, 1);
  598.     player->message = GOTBACKPACK;
  599.     break;
  600.     
  601.     // weapons
  602.       case SPR_BFUG:
  603.     if (!P_GiveWeapon (player, wp_bfg, false) )
  604.         return;
  605.     player->message = GOTBFG9000;
  606.     sound = sfx_wpnup;    
  607.     break;
  608.     
  609.       case SPR_MGUN:
  610.     if (!P_GiveWeapon (player, wp_chaingun, special->flags&MF_DROPPED) )
  611.         return;
  612.     player->message = GOTCHAINGUN;
  613.     sound = sfx_wpnup;    
  614.     break;
  615.     
  616.       case SPR_CSAW:
  617.     if (!P_GiveWeapon (player, wp_chainsaw, false) )
  618.         return;
  619.     player->message = GOTCHAINSAW;
  620.     sound = sfx_wpnup;    
  621.     break;
  622.     
  623.       case SPR_LAUN:
  624.     if (!P_GiveWeapon (player, wp_missile, false) )
  625.         return;
  626.     player->message = GOTLAUNCHER;
  627.     sound = sfx_wpnup;    
  628.     break;
  629.     
  630.       case SPR_PLAS:
  631.     if (!P_GiveWeapon (player, wp_plasma, false) )
  632.         return;
  633.     player->message = GOTPLASMA;
  634.     sound = sfx_wpnup;    
  635.     break;
  636.     
  637.       case SPR_SHOT:
  638.     if (!P_GiveWeapon (player, wp_shotgun, special->flags&MF_DROPPED ) )
  639.         return;
  640.     player->message = GOTSHOTGUN;
  641.     sound = sfx_wpnup;    
  642.     break;
  643.         
  644.       case SPR_SGN2:
  645.     if (!P_GiveWeapon (player, wp_supershotgun, special->flags&MF_DROPPED ) )
  646.         return;
  647.     player->message = GOTSHOTGUN2;
  648.     sound = sfx_wpnup;    
  649.     break;
  650.         
  651.       default:
  652.     I_Error ("P_SpecialThing: Unknown gettable thing");
  653.     }
  654.     
  655.     if (special->flags & MF_COUNTITEM)
  656.     player->itemcount++;
  657.     P_RemoveMobj (special);
  658.     player->bonuscount += BONUSADD;
  659.     if (player == &players[consoleplayer])
  660.     S_StartSound (NULL, sound);
  661. }
  662.  
  663.  
  664. //
  665. // KillMobj
  666. //
  667. void
  668. P_KillMobj
  669. ( mobj_t*    source,
  670.   mobj_t*    target )
  671. {
  672.     mobjtype_t    item;
  673.     mobj_t*    mo;
  674.     
  675.     target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY);
  676.  
  677.     if (target->type != MT_SKULL)
  678.     target->flags &= ~MF_NOGRAVITY;
  679.  
  680.     target->flags |= MF_CORPSE|MF_DROPOFF;
  681.     target->height >>= 2;
  682.  
  683.     if (source && source->player)
  684.     {
  685.     // count for intermission
  686.     if (target->flags & MF_COUNTKILL)
  687.         source->player->killcount++;    
  688.  
  689.     if (target->player)
  690.         source->player->frags[target->player-players]++;
  691.     }
  692.     else if (!netgame && (target->flags & MF_COUNTKILL) )
  693.     {
  694.     // count all monster deaths,
  695.     // even those caused by other monsters
  696.     players[0].killcount++;
  697.     }
  698.     
  699.     if (target->player)
  700.     {
  701.     // count environment kills against you
  702.     if (!source)    
  703.         target->player->frags[target->player-players]++;
  704.             
  705.     target->flags &= ~MF_SOLID;
  706.     target->player->playerstate = PST_DEAD;
  707.     P_DropWeapon (target->player);
  708.  
  709.     if (target->player == &players[consoleplayer]
  710.         && automapactive)
  711.     {
  712.         // don't die in auto map,
  713.         // switch view prior to dying
  714.         AM_Stop ();
  715.     }
  716.     
  717.     }
  718.  
  719.     if (target->health < -target->info->spawnhealth 
  720.     && target->info->xdeathstate)
  721.     {
  722.     P_SetMobjState (target, target->info->xdeathstate);
  723.     }
  724.     else
  725.     P_SetMobjState (target, target->info->deathstate);
  726.     target->tics -= P_Random()&3;
  727.  
  728.     if (target->tics < 1)
  729.     target->tics = 1;
  730.         
  731.     //    I_StartSound (&actor->r, actor->info->deathsound);
  732.  
  733.  
  734.     // Drop stuff.
  735.     // This determines the kind of object spawned
  736.     // during the death frame of a thing.
  737.     switch (target->type)
  738.     {
  739.       case MT_WOLFSS:
  740.       case MT_POSSESSED:
  741.     item = MT_CLIP;
  742.     break;
  743.     
  744.       case MT_SHOTGUY:
  745.     item = MT_SHOTGUN;
  746.     break;
  747.     
  748.       case MT_CHAINGUY:
  749.     item = MT_CHAINGUN;
  750.     break;
  751.     
  752.       default:
  753.     return;
  754.     }
  755.  
  756.     mo = P_SpawnMobj (target->x,target->y,ONFLOORZ, item);
  757.     mo->flags |= MF_DROPPED;    // special versions of items
  758. }
  759.  
  760.  
  761.  
  762.  
  763. //
  764. // P_DamageMobj
  765. // Damages both enemies and players
  766. // "inflictor" is the thing that caused the damage
  767. //  creature or missile, can be NULL (slime, etc)
  768. // "source" is the thing to target after taking damage
  769. //  creature or NULL
  770. // Source and inflictor are the same for melee attacks.
  771. // Source can be NULL for slime, barrel explosions
  772. // and other environmental stuff.
  773. //
  774. void
  775. P_DamageMobj
  776. ( mobj_t*    target,
  777.   mobj_t*    inflictor,
  778.   mobj_t*    source,
  779.   int         damage )
  780. {
  781.     unsigned    ang;
  782.     int        saved;
  783.     player_t*    player;
  784.     fixed_t    thrust;
  785.     int        temp;
  786.     
  787.     if ( !(target->flags & MF_SHOOTABLE) )
  788.     return;    // shouldn't happen...
  789.         
  790.     if (target->health <= 0)
  791.     return;
  792.  
  793.     if ( target->flags & MF_SKULLFLY )
  794.     {
  795.     target->momx = target->momy = target->momz = 0;
  796.     }
  797.     
  798.     player = target->player;
  799.     if (player && gameskill == sk_baby)
  800.     damage >>= 1;     // take half damage in trainer mode
  801.         
  802.  
  803.     // Some close combat weapons should not
  804.     // inflict thrust and push the victim out of reach,
  805.     // thus kick away unless using the chainsaw.
  806.     if (inflictor
  807.     && !(target->flags & MF_NOCLIP)
  808.     && (!source
  809.         || !source->player
  810.         || source->player->readyweapon != wp_chainsaw))
  811.     {
  812.     ang = R_PointToAngle2 ( inflictor->x,
  813.                 inflictor->y,
  814.                 target->x,
  815.                 target->y);
  816.         
  817.     thrust = damage*(FRACUNIT>>3)*100/target->info->mass;
  818.  
  819.     // make fall forwards sometimes
  820.     if ( damage < 40
  821.          && damage > target->health
  822.          && target->z - inflictor->z > 64*FRACUNIT
  823.          && (P_Random ()&1) )
  824.     {
  825.         ang += ANG180;
  826.         thrust *= 4;
  827.     }
  828.         
  829.     ang >>= ANGLETOFINESHIFT;
  830.     target->momx += FixedMul (thrust, finecosine[ang]);
  831.     target->momy += FixedMul (thrust, finesine[ang]);
  832.     }
  833.     
  834.     // player specific
  835.     if (player)
  836.     {
  837.     // end of game hell hack
  838.     if (target->subsector->sector->special == 11
  839.         && damage >= target->health)
  840.     {
  841.         damage = target->health - 1;
  842.     }
  843.     
  844.  
  845.     // Below certain threshold,
  846.     // ignore damage in GOD mode, or with INVUL power.
  847.     if ( damage < 1000
  848.          && ( (player->cheats&CF_GODMODE)
  849.           || player->powers[pw_invulnerability] ) )
  850.     {
  851.         return;
  852.     }
  853.     
  854.     if (player->armortype)
  855.     {
  856.         if (player->armortype == 1)
  857.         saved = damage/3;
  858.         else
  859.         saved = damage/2;
  860.         
  861.         if (player->armorpoints <= saved)
  862.         {
  863.         // armor is used up
  864.         saved = player->armorpoints;
  865.         player->armortype = 0;
  866.         }
  867.         player->armorpoints -= saved;
  868.         damage -= saved;
  869.     }
  870.     player->health -= damage;     // mirror mobj health here for Dave
  871.     if (player->health < 0)
  872.         player->health = 0;
  873.     
  874.     player->attacker = source;
  875.     player->damagecount += damage;    // add damage after armor / invuln
  876.  
  877.     if (player->damagecount > 100)
  878.         player->damagecount = 100;    // teleport stomp does 10k points...
  879.     
  880.     temp = damage < 100 ? damage : 100;
  881.  
  882.     if (player == &players[consoleplayer])
  883.         I_Tactile (40,10,40+temp*2);
  884.     }
  885.     
  886.     // do the damage    
  887.     target->health -= damage;    
  888.     if (target->health <= 0)
  889.     {
  890.     P_KillMobj (source, target);
  891.     return;
  892.     }
  893.  
  894.     if ( (P_Random () < target->info->painchance)
  895.      && !(target->flags&MF_SKULLFLY) )
  896.     {
  897.     target->flags |= MF_JUSTHIT;    // fight back!
  898.     
  899.     P_SetMobjState (target, target->info->painstate);
  900.     }
  901.             
  902.     target->reactiontime = 0;        // we're awake now...    
  903.  
  904.     if ( (!target->threshold || target->type == MT_VILE)
  905.      && source && source != target
  906.      && source->type != MT_VILE)
  907.     {
  908.     // if not intent on another player,
  909.     // chase after this one
  910.     target->target = source;
  911.     target->threshold = BASETHRESHOLD;
  912.     if (target->state == &states[target->info->spawnstate]
  913.         && target->info->seestate != S_NULL)
  914.         P_SetMobjState (target, target->info->seestate);
  915.     }
  916.             
  917. }
  918.  
  919.