1 /* Emacs style mode select   -*- C++ -*-
2  *-----------------------------------------------------------------------------
3  *
4  *
5  *  PrBoom: a Doom port merged with LxDoom and LSDLDoom
6  *  based on BOOM, a modified and improved DOOM engine
7  *  Copyright (C) 1999 by
8  *  id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9  *  Copyright (C) 1999-2000 by
10  *  Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11  *  Copyright 2005, 2006 by
12  *  Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13  *
14  *  This program is free software; you can redistribute it and/or
15  *  modify it under the terms of the GNU General Public License
16  *  as published by the Free Software Foundation; either version 2
17  *  of the License, or (at your option) any later version.
18  *
19  *  This program is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU General Public License for more details.
23  *
24  *  You should have received a copy of the GNU General Public License
25  *  along with this program; if not, write to the Free Software
26  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27  *  02111-1307, USA.
28  *
29  * DESCRIPTION:
30  *      Handling interactions (i.e., collisions).
31  *
32  *-----------------------------------------------------------------------------*/
33 
34 #include "doomstat.h"
35 #include "dstrings.h"
36 #include "m_random.h"
37 #include "am_map.h"
38 #include "r_main.h"
39 #include "s_sound.h"
40 #include "sounds.h"
41 #include "d_deh.h"  // Ty 03/22/98 - externalized strings
42 #include "p_tick.h"
43 #include "lprintf.h"
44 
45 #include "p_inter.h"
46 #include "p_enemy.h"
47 
48 #include "p_inter.h"
49 
50 #define BONUSADD        6
51 
52 // Ty 03/07/98 - add deh externals
53 // Maximums and such were hardcoded values.  Need to externalize those for
54 // dehacked support (and future flexibility).  Most var names came from the key
55 // strings used in dehacked.
56 
57 int initial_health = 100;
58 int initial_bullets = 50;
59 int maxhealth = 100; // was MAXHEALTH as a #define, used only in this module
60 int max_armor = 200;
61 int green_armor_class = 1;  // these are involved with armortype below
62 int blue_armor_class = 2;
63 int max_soul = 200;
64 int soul_health = 100;
65 int mega_health = 200;
66 int god_health = 100;   // these are used in cheats (see st_stuff.c)
67 int idfa_armor = 200;
68 int idfa_armor_class = 2;
69 // not actually used due to pairing of cheat_k and cheat_fa
70 int idkfa_armor = 200;
71 int idkfa_armor_class = 2;
72 
73 int bfgcells = 40;      // used in p_pspr.c
74 int monsters_infight = 0; // e6y: Dehacked support - monsters infight
75 // Ty 03/07/98 - end deh externals
76 
77 // a weapon is found with two clip loads,
78 // a big item has five clip loads
79 int maxammo[NUMAMMO]  = {200, 50, 300, 50};
80 int clipammo[NUMAMMO] = { 10,  4,  20,  1};
81 
82 //
83 // GET STUFF
84 //
85 
86 //
87 // P_GiveAmmo
88 // Num is the number of clip loads,
89 // not the individual count (0= 1/2 clip).
90 // Returns FALSE if the ammo can't be picked up at all
91 //
92 
P_GiveAmmo(player_t * player,ammotype_t ammo,int num)93 static dbool   P_GiveAmmo(player_t *player, ammotype_t ammo, int num)
94 {
95    int oldammo;
96 
97    if (ammo == AM_NOAMMO)
98       return FALSE;
99 
100    if ( player->ammo[ammo] == player->maxammo[ammo]  )
101       return FALSE;
102 
103    if (num)
104       num *= clipammo[ammo];
105    else
106       num = clipammo[ammo]/2;
107 
108    // give double ammo in trainer mode, you'll need in nightmare
109    if (gameskill == sk_baby || gameskill == sk_nightmare)
110       num <<= 1;
111 
112    oldammo = player->ammo[ammo];
113    player->ammo[ammo] += num;
114 
115    if (player->ammo[ammo] > player->maxammo[ammo])
116       player->ammo[ammo] = player->maxammo[ammo];
117 
118    // If non zero ammo, don't change up weapons, player was lower on purpose.
119    if (oldammo)
120       return TRUE;
121 
122    // We were down to zero, so select a new weapon.
123    // Preferences are not user selectable.
124 
125    switch (ammo)
126    {
127       case AM_CLIP:
128          if (player->readyweapon == WP_FIST)
129          {
130             if (player->weaponowned[WP_CHAINGUN])
131                player->pendingweapon = WP_CHAINGUN;
132             else
133                player->pendingweapon = WP_PISTOL;
134          }
135          break;
136 
137       case AM_SHELL:
138          if (player->readyweapon == WP_FIST || player->readyweapon == WP_PISTOL)
139             if (player->weaponowned[WP_SHOTGUN])
140                player->pendingweapon = WP_SHOTGUN;
141          break;
142 
143       case AM_CELL:
144          if (player->readyweapon == WP_FIST || player->readyweapon == WP_PISTOL)
145             if (player->weaponowned[WP_PLASMA])
146                player->pendingweapon = WP_PLASMA;
147          break;
148 
149       case AM_MISL:
150          if (player->readyweapon == WP_FIST)
151             if (player->weaponowned[WP_MISSILE])
152                player->pendingweapon = WP_MISSILE;
153       default:
154          break;
155    }
156    return TRUE;
157 }
158 
159 //
160 // P_GiveWeapon
161 // The weapon name may have a MF_DROPPED flag ored in.
162 //
163 
P_GiveWeapon(player_t * player,weapontype_t weapon,dbool dropped)164 static dbool   P_GiveWeapon(player_t *player, weapontype_t weapon, dbool   dropped)
165 {
166   dbool   gaveammo;
167   dbool   gaveweapon;
168 
169   if (netgame && deathmatch!=2 && !dropped)
170     {
171       // leave placed weapons forever on net games
172       if (player->weaponowned[weapon])
173         return FALSE;
174 
175       player->bonuscount += BONUSADD;
176       player->weaponowned[weapon] = TRUE;
177 
178       P_GiveAmmo(player, weaponinfo[weapon].ammo, deathmatch ? 5 : 2);
179 
180       player->pendingweapon = weapon;
181       /* cph 20028/10 - for old-school DM addicts, allow old behavior
182        * where only consoleplayer's pickup sounds are heard */
183       // displayplayer, not consoleplayer, for viewing multiplayer demos
184       if (!comp[comp_sound] || player == &players[displayplayer])
185         S_StartSound (player->mo, sfx_wpnup|PICKUP_SOUND); // killough 4/25/98
186       return FALSE;
187     }
188 
189   if (weaponinfo[weapon].ammo != AM_NOAMMO)
190     {
191       // give one clip with a dropped weapon,
192       // two clips with a found weapon
193       gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, dropped ? 1 : 2);
194     }
195   else
196     gaveammo = FALSE;
197 
198   if (player->weaponowned[weapon])
199     gaveweapon = FALSE;
200   else
201     {
202       gaveweapon = TRUE;
203       player->weaponowned[weapon] = TRUE;
204       player->pendingweapon = weapon;
205     }
206   return gaveweapon || gaveammo;
207 }
208 
209 //
210 // P_GiveBody
211 // Returns FALSE if the body isn't needed at all
212 //
213 
P_GiveBody(player_t * player,int num)214 static dbool   P_GiveBody(player_t *player, int num)
215 {
216   if (player->health >= maxhealth)
217     return FALSE; // Ty 03/09/98 externalized MAXHEALTH to maxhealth
218   player->health += num;
219   if (player->health > maxhealth)
220     player->health = maxhealth;
221   player->mo->health = player->health;
222   return TRUE;
223 }
224 
225 //
226 // P_GiveArmor
227 // Returns FALSE if the armor is worse
228 // than the current armor.
229 //
230 
P_GiveArmor(player_t * player,int armortype)231 static dbool   P_GiveArmor(player_t *player, int armortype)
232 {
233   int hits = armortype*100;
234   if (player->armorpoints >= hits)
235     return FALSE;   // don't pick up
236   player->armortype = armortype;
237   player->armorpoints = hits;
238   return TRUE;
239 }
240 
241 //
242 // P_GiveCard
243 //
244 
P_GiveCard(player_t * player,card_t card)245 static void P_GiveCard(player_t *player, card_t card)
246 {
247   if (player->cards[card])
248     return;
249   player->bonuscount = BONUSADD;
250   player->cards[card] = 1;
251 }
252 
253 //
254 // P_GivePower
255 //
256 // Rewritten by Lee Killough
257 //
258 
P_GivePower(player_t * player,int power)259 dbool   P_GivePower(player_t *player, int power)
260 {
261   static const int tics[NUMPOWERS] = {
262     INVULNTICS, 1 /* strength */, INVISTICS,
263     IRONTICS, 1 /* allmap */, INFRATICS,
264    };
265 
266   switch (power)
267     {
268       case pw_invisibility:
269         player->mo->flags |= MF_SHADOW;
270         break;
271       case pw_allmap:
272         if (player->powers[pw_allmap])
273           return FALSE;
274         break;
275       case pw_strength:
276         P_GiveBody(player,100);
277         break;
278     }
279 
280   // Unless player has infinite duration cheat, set duration (killough)
281 
282   if (player->powers[power] >= 0)
283     player->powers[power] = tics[power];
284   return TRUE;
285 }
286 
287 //
288 // P_TouchSpecialThing
289 //
290 
291 extern void retro_set_rumble_touch(unsigned intensity, float duration);
292 
P_TouchSpecialThing(mobj_t * special,mobj_t * toucher)293 void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher)
294 {
295   player_t *player;
296   int      i;
297   int      sound;
298   fixed_t  delta = special->z - toucher->z;
299 
300   if (delta > toucher->height || delta < -8*FRACUNIT)
301     return;        // out of reach
302 
303   sound = sfx_itemup;
304   player = toucher->player;
305 
306   // Dead thing touching.
307   // Can happen with a sliding player corpse.
308   if (toucher->health <= 0)
309     return;
310 
311     // Identify by sprite.
312   switch (special->sprite)
313     {
314       // armor
315     case SPR_ARM1:
316       if (!P_GiveArmor (player, green_armor_class))
317         return;
318       player->message = s_GOTARMOR; // Ty 03/22/98 - externalized
319       retro_set_rumble_touch(12, 160.0f);
320       break;
321 
322     case SPR_ARM2:
323       if (!P_GiveArmor (player, blue_armor_class))
324         return;
325       player->message = s_GOTMEGA; // Ty 03/22/98 - externalized
326       retro_set_rumble_touch(14, 160.0f);
327       break;
328 
329         // bonus items
330     case SPR_BON1:
331       player->health++;               // can go over 100%
332       if (player->health > (maxhealth * 2))
333         player->health = (maxhealth * 2);
334       player->mo->health = player->health;
335       player->message = s_GOTHTHBONUS; // Ty 03/22/98 - externalized
336       retro_set_rumble_touch(5, 160.0f);
337       break;
338 
339     case SPR_BON2:
340       player->armorpoints++;          // can go over 100%
341       if (player->armorpoints > max_armor)
342         player->armorpoints = max_armor;
343       if (!player->armortype)
344         player->armortype = green_armor_class;
345       player->message = s_GOTARMBONUS; // Ty 03/22/98 - externalized
346       retro_set_rumble_touch(5, 160.0f);
347       break;
348 
349     case SPR_SOUL:
350       player->health += soul_health;
351       if (player->health > max_soul)
352         player->health = max_soul;
353       player->mo->health = player->health;
354       player->message = s_GOTSUPER; // Ty 03/22/98 - externalized
355       sound = sfx_getpow;
356       retro_set_rumble_touch(14, 160.0f);
357       break;
358 
359     case SPR_MEGA:
360       if (gamemode != commercial)
361         return;
362       player->health = mega_health;
363       player->mo->health = player->health;
364       P_GiveArmor (player,blue_armor_class);
365       player->message = s_GOTMSPHERE; // Ty 03/22/98 - externalized
366       sound = sfx_getpow;
367       retro_set_rumble_touch(16, 160.0f);
368       break;
369 
370         // cards
371         // leave cards for everyone
372     case SPR_BKEY:
373       if (!player->cards[it_bluecard])
374         player->message = s_GOTBLUECARD; // Ty 03/22/98 - externalized
375       P_GiveCard (player, it_bluecard);
376       retro_set_rumble_touch(7, 150.0f);
377       if (!netgame)
378         break;
379       return;
380 
381     case SPR_YKEY:
382       if (!player->cards[it_yellowcard])
383         player->message = s_GOTYELWCARD; // Ty 03/22/98 - externalized
384       P_GiveCard (player, it_yellowcard);
385       retro_set_rumble_touch(7, 150.0f);
386       if (!netgame)
387         break;
388       return;
389 
390     case SPR_RKEY:
391       if (!player->cards[it_redcard])
392         player->message = s_GOTREDCARD; // Ty 03/22/98 - externalized
393       P_GiveCard (player, it_redcard);
394       retro_set_rumble_touch(7, 150.0f);
395       if (!netgame)
396         break;
397       return;
398 
399     case SPR_BSKU:
400       if (!player->cards[it_blueskull])
401         player->message = s_GOTBLUESKUL; // Ty 03/22/98 - externalized
402       P_GiveCard (player, it_blueskull);
403       retro_set_rumble_touch(8, 150.0f);
404       if (!netgame)
405         break;
406       return;
407 
408     case SPR_YSKU:
409       if (!player->cards[it_yellowskull])
410         player->message = s_GOTYELWSKUL; // Ty 03/22/98 - externalized
411       P_GiveCard (player, it_yellowskull);
412       retro_set_rumble_touch(8, 150.0f);
413       if (!netgame)
414         break;
415       return;
416 
417     case SPR_RSKU:
418       if (!player->cards[it_redskull])
419         player->message = s_GOTREDSKULL; // Ty 03/22/98 - externalized
420       P_GiveCard (player, it_redskull);
421       retro_set_rumble_touch(8, 150.0f);
422       if (!netgame)
423         break;
424       return;
425 
426       // medikits, heals
427     case SPR_STIM:
428       if (!P_GiveBody (player, 10))
429         return;
430       player->message = s_GOTSTIM; // Ty 03/22/98 - externalized
431       retro_set_rumble_touch(6, 160.0f);
432       break;
433 
434     case SPR_MEDI:
435       if (!P_GiveBody (player, 25))
436         return;
437 
438       if (player->health < 50) // cph - 25 + the 25 just added, thanks to Quasar for reporting this bug
439         player->message = s_GOTMEDINEED; // Ty 03/22/98 - externalized
440       else
441         player->message = s_GOTMEDIKIT; // Ty 03/22/98 - externalized
442 
443       retro_set_rumble_touch(8, 160.0f);
444       break;
445 
446 
447       // power ups
448     case SPR_PINV:
449       if (!P_GivePower (player, pw_invulnerability))
450         return;
451       player->message = s_GOTINVUL; // Ty 03/22/98 - externalized
452       sound = sfx_getpow;
453       retro_set_rumble_touch(18, 160.0f);
454       break;
455 
456     case SPR_PSTR:
457       if (!P_GivePower (player, pw_strength))
458         return;
459       player->message = s_GOTBERSERK; // Ty 03/22/98 - externalized
460       if (player->readyweapon != WP_FIST)
461         player->pendingweapon = WP_FIST;
462       sound = sfx_getpow;
463       retro_set_rumble_touch(20, 180.0f);
464       break;
465 
466     case SPR_PINS:
467       if (!P_GivePower (player, pw_invisibility))
468         return;
469       player->message = s_GOTINVIS; // Ty 03/22/98 - externalized
470       sound = sfx_getpow;
471       retro_set_rumble_touch(18, 160.0f);
472       break;
473 
474     case SPR_SUIT:
475       if (!P_GivePower (player, pw_ironfeet))
476         return;
477       player->message = s_GOTSUIT; // Ty 03/22/98 - externalized
478       sound = sfx_getpow;
479       retro_set_rumble_touch(18, 160.0f);
480       break;
481 
482     case SPR_PMAP:
483       if (!P_GivePower (player, pw_allmap))
484         return;
485       player->message = s_GOTMAP; // Ty 03/22/98 - externalized
486       sound = sfx_getpow;
487       retro_set_rumble_touch(18, 160.0f);
488       break;
489 
490     case SPR_PVIS:
491       if (!P_GivePower (player, pw_infrared))
492         return;
493       player->message = s_GOTVISOR; // Ty 03/22/98 - externalized
494       sound = sfx_getpow;
495       retro_set_rumble_touch(18, 160.0f);
496       break;
497 
498       // ammo
499     case SPR_CLIP:
500       if (special->flags & MF_DROPPED)
501         {
502           if (!P_GiveAmmo (player,AM_CLIP,0))
503             return;
504         }
505       else
506         {
507           if (!P_GiveAmmo (player,AM_CLIP,1))
508             return;
509         }
510       player->message = s_GOTCLIP; // Ty 03/22/98 - externalized
511 
512       retro_set_rumble_touch(6, 140.0f);
513       break;
514 
515     case SPR_AMMO:
516       if (!P_GiveAmmo (player, AM_CLIP,5))
517         return;
518       player->message = s_GOTCLIPBOX; // Ty 03/22/98 - externalized
519       retro_set_rumble_touch(8, 140.0f);
520       break;
521 
522     case SPR_ROCK:
523       if (!P_GiveAmmo (player, AM_MISL,1))
524         return;
525       player->message = s_GOTROCKET; // Ty 03/22/98 - externalized
526       retro_set_rumble_touch(6, 140.0f);
527       break;
528 
529     case SPR_BROK:
530       if (!P_GiveAmmo (player, AM_MISL,5))
531         return;
532       player->message = s_GOTROCKBOX; // Ty 03/22/98 - externalized
533       retro_set_rumble_touch(8, 140.0f);
534       break;
535 
536     case SPR_CELL:
537       if (!P_GiveAmmo (player, AM_CELL,1))
538         return;
539       player->message = s_GOTCELL; // Ty 03/22/98 - externalized
540       retro_set_rumble_touch(6, 140.0f);
541       break;
542 
543     case SPR_CELP:
544       if (!P_GiveAmmo (player, AM_CELL,5))
545         return;
546       player->message = s_GOTCELLBOX; // Ty 03/22/98 - externalized
547       retro_set_rumble_touch(8, 140.0f);
548       break;
549 
550     case SPR_SHEL:
551       if (!P_GiveAmmo (player, AM_SHELL,1))
552         return;
553       player->message = s_GOTSHELLS; // Ty 03/22/98 - externalized
554       retro_set_rumble_touch(6, 140.0f);
555       break;
556 
557     case SPR_SBOX:
558       if (!P_GiveAmmo (player, AM_SHELL,5))
559         return;
560       player->message = s_GOTSHELLBOX; // Ty 03/22/98 - externalized
561       retro_set_rumble_touch(8, 140.0f);
562       break;
563 
564     case SPR_BPAK:
565       if (!player->backpack)
566         {
567           for (i=0 ; i<NUMAMMO ; i++)
568             player->maxammo[i] *= 2;
569           player->backpack = TRUE;
570         }
571       for (i=0 ; i<NUMAMMO ; i++)
572         P_GiveAmmo (player, i, 1);
573       player->message = s_GOTBACKPACK; // Ty 03/22/98 - externalized
574       retro_set_rumble_touch(12, 160.0f);
575       break;
576 
577         // weapons
578     case SPR_BFUG:
579       if (!P_GiveWeapon (player, WP_BFG, FALSE) )
580         return;
581       player->message = s_GOTBFG9000; // Ty 03/22/98 - externalized
582       sound = sfx_wpnup;
583       retro_set_rumble_touch(20, 180.0f);
584       break;
585 
586     case SPR_MGUN:
587       if (!P_GiveWeapon (player, WP_CHAINGUN, (special->flags&MF_DROPPED)!=0) )
588         return;
589       player->message = s_GOTCHAINGUN; // Ty 03/22/98 - externalized
590       sound = sfx_wpnup;
591       retro_set_rumble_touch(15, 180.0f);
592       break;
593 
594     case SPR_CSAW:
595       if (!P_GiveWeapon (player, WP_CHAINSAW, FALSE) )
596         return;
597       player->message = s_GOTCHAINSAW; // Ty 03/22/98 - externalized
598       sound = sfx_wpnup;
599       retro_set_rumble_touch(15, 180.0f);
600       break;
601 
602     case SPR_LAUN:
603       if (!P_GiveWeapon (player, WP_MISSILE, FALSE) )
604         return;
605       player->message = s_GOTLAUNCHER; // Ty 03/22/98 - externalized
606       sound = sfx_wpnup;
607       retro_set_rumble_touch(18, 180.0f);
608       break;
609 
610     case SPR_PLAS:
611       if (!P_GiveWeapon (player, WP_PLASMA, FALSE) )
612         return;
613       player->message = s_GOTPLASMA; // Ty 03/22/98 - externalized
614       sound = sfx_wpnup;
615       retro_set_rumble_touch(17, 180.0f);
616       break;
617 
618     case SPR_SHOT:
619       if (!P_GiveWeapon (player, WP_SHOTGUN, (special->flags&MF_DROPPED)!=0 ) )
620         return;
621       player->message = s_GOTSHOTGUN; // Ty 03/22/98 - externalized
622       sound = sfx_wpnup;
623       retro_set_rumble_touch(14, 180.0f);
624       break;
625 
626     case SPR_SGN2:
627       if (!P_GiveWeapon(player, WP_SUPERSHOTGUN, (special->flags&MF_DROPPED)!=0))
628         return;
629       player->message = s_GOTSHOTGUN2; // Ty 03/22/98 - externalized
630       sound = sfx_wpnup;
631       retro_set_rumble_touch(16, 180.0f);
632       break;
633 
634     default:
635       I_Error ("P_SpecialThing: Unknown gettable thing");
636     }
637 
638   if (special->flags & MF_COUNTITEM)
639     player->itemcount++;
640   P_RemoveMobj (special);
641   player->bonuscount += BONUSADD;
642 
643   /* cph 20028/10 - for old-school DM addicts, allow old behavior
644    * where only consoleplayer's pickup sounds are heard */
645   // displayplayer, not consoleplayer, for viewing multiplayer demos
646   if (!comp[comp_sound] || player == &players[displayplayer])
647     S_StartSound (player->mo, sound | PICKUP_SOUND);   // killough 4/25/98
648 }
649 
650 //
651 // KillMobj
652 //
653 // killough 11/98: make static
P_KillMobj(mobj_t * source,mobj_t * target)654 static void P_KillMobj(mobj_t *source, mobj_t *target)
655 {
656   target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY);
657 
658   if (!(target->flags & MF_DONTFALL))
659     target->flags &= ~MF_NOGRAVITY;
660 
661   target->flags |= MF_CORPSE|MF_DROPOFF;
662   target->height >>= 2;
663 
664   if (!((target->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL)))
665     totallive--;
666 
667   if (source && source->player)
668     {
669       // count for intermission
670       if (target->flags & MF_COUNTKILL)
671         source->player->killcount++;
672       if (target->player)
673         source->player->frags[target->player-players]++;
674     }
675     else
676       if (target->flags & MF_COUNTKILL) { /* Add to kills tally */
677   if ((compatibility_level < lxdoom_1_compatibility) || !netgame) {
678     if (!netgame)
679       // count all monster deaths,
680       // even those caused by other monsters
681       players[0].killcount++;
682   } else
683     if (!deathmatch) {
684       // try and find a player to give the kill to, otherwise give the
685       // kill to a random player.  this fixes the missing monsters bug
686       // in coop - rain
687       // CPhipps - not a bug as such, but certainly an inconsistency.
688       if (target->lastenemy && target->lastenemy->health > 0
689     && target->lastenemy->player) // Fighting a player
690           target->lastenemy->player->killcount++;
691         else {
692         // cph - randomely choose a player in the game to be credited
693         //  and do it uniformly between the active players
694         unsigned int activeplayers = 0, player, i;
695 
696         for (player = 0; player<MAXPLAYERS; player++)
697     if (playeringame[player])
698       activeplayers++;
699 
700         if (activeplayers) {
701     player = P_Random(pr_friends) % activeplayers;
702 
703     for (i=0; i<MAXPLAYERS; i++)
704       if (playeringame[i])
705         if (!player--)
706           players[i].killcount++;
707         }
708       }
709     }
710       }
711 
712   if (target->player)
713     {
714       // count environment kills against you
715       if (!source)
716         target->player->frags[target->player-players]++;
717 
718       target->flags &= ~MF_SOLID;
719       target->player->playerstate = PST_DEAD;
720       P_DropWeapon (target->player);
721 
722       if (target->player == &players[consoleplayer] && (automapmode & am_active))
723         AM_Stop();    // don't die in auto map; switch view prior to dying
724     }
725 
726   if (target->health < -target->info->spawnhealth && target->info->xdeathstate)
727     P_SetMobjState (target, target->info->xdeathstate);
728   else
729     P_SetMobjState (target, target->info->deathstate);
730 
731   target->tics -= P_Random(pr_killtics)&3;
732 
733   if (target->tics < 1)
734     target->tics = 1;
735 
736   // Drop stuff.
737   // This determines the kind of object spawned
738   // during the death frame of a thing.
739   if (target->info->droppeditem != MT_NULL)
740   {
741     mobj_t     *mo;
742     mo = P_SpawnMobj (target->x,target->y,ONFLOORZ, target->info->droppeditem);
743     mo->flags |= MF_DROPPED;    // special versions of items
744   }
745 }
746 
747 //
748 // P_DamageMobj
749 // Damages both enemies and players
750 // "inflictor" is the thing that caused the damage
751 //  creature or missile, can be NULL (slime, etc)
752 // "source" is the thing to target after taking damage
753 //  creature or NULL
754 // Source and inflictor are the same for melee attacks.
755 // Source can be NULL for slime, barrel explosions
756 // and other environmental stuff.
757 //
758 
P_DamageMobj(mobj_t * target,mobj_t * inflictor,mobj_t * source,int damage)759 void P_DamageMobj(mobj_t *target,mobj_t *inflictor, mobj_t *source, int damage)
760 {
761   player_t *player;
762   dbool   justhit = FALSE;          /* killough 11/98 */
763 
764   /* killough 8/31/98: allow bouncers to take damage */
765   if (!(target->flags & (MF_SHOOTABLE | MF_BOUNCES)))
766     return; // shouldn't happen...
767 
768   if (target->health <= 0)
769     return;
770 
771   if (target->flags & MF_SKULLFLY)
772     target->momx = target->momy = target->momz = 0;
773 
774   player = target->player;
775   if (player && gameskill == sk_baby)
776     damage >>= 1;   // take half damage in trainer mode
777 
778   // Some close combat weapons should not
779   // inflict thrust and push the victim out of reach,
780   // thus kick away unless using the chainsaw.
781 
782   if (inflictor && !(target->flags & MF_NOCLIP) &&
783       (!source || !source->player ||
784        source->player->readyweapon != WP_CHAINSAW))
785     {
786       unsigned ang = R_PointToAngle2 (inflictor->x, inflictor->y,
787                                       target->x,    target->y);
788 
789       fixed_t thrust = damage*(FRACUNIT>>3)*100/target->info->mass;
790 
791       // make fall forwards sometimes
792       if ( damage < 40 && damage > target->health
793            && target->z - inflictor->z > 64*FRACUNIT
794            && P_Random(pr_damagemobj) & 1)
795         {
796           ang += ANG180;
797           thrust *= 4;
798         }
799 
800       ang >>= ANGLETOFINESHIFT;
801       target->momx += FixedMul (thrust, finecosine[ang]);
802       target->momy += FixedMul (thrust, finesine[ang]);
803 
804       /* killough 11/98: thrust objects hanging off ledges */
805       if (target->intflags & MIF_FALLING && target->gear >= MAXGEAR)
806         target->gear = 0;
807     }
808 
809   // player specific
810   if (player)
811     {
812       // end of game hell hack
813       if (target->subsector->sector->special == 11 && damage >= target->health)
814         damage = target->health - 1;
815 
816       // Below certain threshold,
817       // ignore damage in GOD mode, or with INVUL power.
818       // killough 3/26/98: make god mode 100% god mode in non-compat mode
819 
820       if ((damage < 1000 || (!comp[comp_god] && (player->cheats&CF_GODMODE))) &&
821           (player->cheats&CF_GODMODE || player->powers[pw_invulnerability]))
822         return;
823 
824       if (player->armortype)
825         {
826           int saved = player->armortype == 1 ? damage/3 : damage/2;
827           if (player->armorpoints <= saved)
828             {
829               // armor is used up
830               saved = player->armorpoints;
831               player->armortype = 0;
832             }
833           player->armorpoints -= saved;
834           damage -= saved;
835         }
836 
837       player->health -= damage;       // mirror mobj health here for Dave
838       if (player->health < 0)
839         player->health = 0;
840 
841       player->attacker = source;
842       player->damagecount += damage;  // add damage after armor / invuln
843 
844       if (player->damagecount > 100)
845         player->damagecount = 100;  // teleport stomp does 10k points...
846     }
847 
848   // do the damage
849   target->health -= damage;
850   if (target->health <= 0)
851     {
852       P_KillMobj (source, target);
853       return;
854     }
855 
856   // killough 9/7/98: keep track of targets so that friends can help friends
857   if (mbf_features)
858     {
859       /* If target is a player, set player's target to source,
860        * so that a friend can tell who's hurting a player
861        */
862       if (player)
863   P_SetTarget(&target->target, source);
864 
865       /* killough 9/8/98:
866        * If target's health is less than 50%, move it to the front of its list.
867        * This will slightly increase the chances that enemies will choose to
868        * "finish it off", but its main purpose is to alert friends of danger.
869        */
870       if (target->health*2 < target->info->spawnhealth)
871   {
872     thinker_t *cap = &thinkerclasscap[target->flags & MF_FRIEND ?
873              th_friends : th_enemies];
874     (target->thinker.cprev->cnext = target->thinker.cnext)->cprev =
875       target->thinker.cprev;
876     (target->thinker.cnext = cap->cnext)->cprev = &target->thinker;
877     (target->thinker.cprev = cap)->cnext = &target->thinker;
878   }
879     }
880 
881   if (P_Random (pr_painchance) < target->info->painchance &&
882       !(target->flags & MF_SKULLFLY)) { //killough 11/98: see below
883     if (mbf_features)
884       justhit = TRUE;
885     else
886       target->flags |= MF_JUSTHIT;    // fight back!
887 
888     P_SetMobjState(target, target->info->painstate);
889   }
890 
891   target->reactiontime = 0;           // we're awake now...
892 
893   /* killough 9/9/98: cleaned up, made more consistent: */
894 
895   if (source && source != target && !(source->flags & MF_NOTARGET) &&
896       (!target->threshold || (target->flags & MF_QUICKTORETALIATE)) &&
897       ((source->flags ^ target->flags) & MF_FRIEND ||
898        monster_infighting ||
899        !mbf_features))
900     {
901       /* if not intent on another player, chase after this one
902        *
903        * killough 2/15/98: remember last enemy, to prevent
904        * sleeping early; 2/21/98: Place priority on players
905        * killough 9/9/98: cleaned up, made more consistent:
906        */
907 
908       if (!target->lastenemy || target->lastenemy->health <= 0 ||
909     (!mbf_features ?
910      !target->lastenemy->player :
911      !((target->flags ^ target->lastenemy->flags) & MF_FRIEND) &&
912      target->target != source)) // remember last enemy - killough
913   P_SetTarget(&target->lastenemy, target->target);
914 
915       P_SetTarget(&target->target, source);       // killough 11/98
916       target->threshold = BASETHRESHOLD;
917       if (target->state == &states[target->info->spawnstate]
918           && target->info->seestate != S_NULL)
919         P_SetMobjState (target, target->info->seestate);
920     }
921 
922   /* killough 11/98: Don't attack a friend, unless hit by that friend.
923    * cph 2006/04/01 - implicitly this is only if mbf_features */
924   if (justhit && (target->target == source || !target->target ||
925       !(target->flags & target->target->flags & MF_FRIEND)))
926     target->flags |= MF_JUSTHIT;    // fight back!
927 }
928