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