* Onda VX747: add browse screen, pitchscreen, context menu, quickscreen, rewind...
[kugel-rb.git] / apps / plugins / doom / p_inter.c
blob9a34af1358ae65e172936ac3d699f07783fc0e61
1 /* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
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
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25 * 02111-1307, USA.
27 * DESCRIPTION:
28 * Handling interactions (i.e., collisions).
30 *-----------------------------------------------------------------------------*/
32 #include "doomstat.h"
33 #include "dstrings.h"
34 #include "m_random.h"
35 #include "am_map.h"
36 #include "r_main.h"
37 #include "s_sound.h"
38 #include "sounds.h"
39 #include "d_deh.h" // Ty 03/22/98 - externalized strings
40 #include "p_tick.h"
41 #include "i_system.h"
43 #include "p_inter.h"
44 #include "p_enemy.h"
46 #ifdef __GNUG__
47 #pragma implementation "p_inter.h"
48 #endif
49 #include "p_inter.h"
51 #define BONUSADD 6
53 // Ty 03/07/98 - add deh externals
54 // Maximums and such were hardcoded values. Need to externalize those for
55 // dehacked support (and future flexibility). Most var names came from the key
56 // strings used in dehacked.
58 int initial_health = 100;
59 int initial_bullets = 50;
60 int maxhealth = 100; // was MAXHEALTH as a #define, used only in this module
61 int max_armor = 200;
62 int green_armor_class = 1; // these are involved with armortype below
63 int blue_armor_class = 2;
64 int max_soul = 200;
65 int soul_health = 100;
66 int mega_health = 200;
67 int god_health = 100; // these are used in cheats (see st_stuff.c)
68 int idfa_armor = 200;
69 int idfa_armor_class = 2;
70 // not actually used due to pairing of cheat_k and cheat_fa
71 int idkfa_armor = 200;
72 int idkfa_armor_class = 2;
74 int bfgcells = 40; // used in p_pspr.c
75 // Ty 03/07/98 - end deh externals
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};
83 // GET STUFF
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
93 boolean P_GiveAmmo(player_t *player, ammotype_t ammo, int num)
95 int oldammo;
97 if (ammo == am_noammo)
98 return false;
100 #ifdef RANGECHECK
101 if (ammo < 0 || ammo > NUMAMMO)
102 I_Error ("P_GiveAmmo: bad type %i", ammo);
103 #endif
105 if ( player->ammo[ammo] == player->maxammo[ammo] )
106 return false;
108 if (num)
109 num *= clipammo[ammo];
110 else
111 num = clipammo[ammo]/2;
113 // give double ammo in trainer mode, you'll need in nightmare
114 if (gameskill == sk_baby || gameskill == sk_nightmare)
115 num <<= 1;
117 oldammo = player->ammo[ammo];
118 player->ammo[ammo] += num;
120 if (player->ammo[ammo] > player->maxammo[ammo])
121 player->ammo[ammo] = player->maxammo[ammo];
123 // If non zero ammo, don't change up weapons, player was lower on purpose.
124 if (oldammo)
125 return true;
127 // We were down to zero, so select a new weapon.
128 // Preferences are not user selectable.
130 switch (ammo)
132 case am_clip:
133 if (player->readyweapon == wp_fist) {
134 if (player->weaponowned[wp_chaingun])
135 player->pendingweapon = wp_chaingun;
136 else
137 player->pendingweapon = wp_pistol;
139 break;
141 case am_shell:
142 if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol)
143 if (player->weaponowned[wp_shotgun])
144 player->pendingweapon = wp_shotgun;
145 break;
147 case am_cell:
148 if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol)
149 if (player->weaponowned[wp_plasma])
150 player->pendingweapon = wp_plasma;
151 break;
153 case am_misl:
154 if (player->readyweapon == wp_fist)
155 if (player->weaponowned[wp_missile])
156 player->pendingweapon = wp_missile;
157 default:
158 break;
160 return true;
164 // P_GiveWeapon
165 // The weapon name may have a MF_DROPPED flag ored in.
168 boolean P_GiveWeapon(player_t *player, weapontype_t weapon, boolean dropped)
170 boolean gaveammo;
171 boolean gaveweapon;
173 if (netgame && deathmatch!=2 && !dropped)
175 // leave placed weapons forever on net games
176 if (player->weaponowned[weapon])
177 return false;
179 player->bonuscount += BONUSADD;
180 player->weaponowned[weapon] = true;
182 P_GiveAmmo(player, weaponinfo[weapon].ammo, deathmatch ? 5 : 2);
184 player->pendingweapon = weapon;
185 /* cph 20028/10 - for old-school DM addicts, allow old behavior
186 * where only consoleplayer's pickup sounds are heard */
187 if (!comp[comp_sound] || player == &players[consoleplayer])
188 S_StartSound (player->mo, sfx_wpnup|PICKUP_SOUND); // killough 4/25/98
189 return false;
192 if (weaponinfo[weapon].ammo != am_noammo)
194 // give one clip with a dropped weapon,
195 // two clips with a found weapon
196 gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, dropped ? 1 : 2);
198 else
199 gaveammo = false;
201 if (player->weaponowned[weapon])
202 gaveweapon = false;
203 else
205 gaveweapon = true;
206 player->weaponowned[weapon] = true;
207 player->pendingweapon = weapon;
209 return gaveweapon || gaveammo;
213 // P_GiveBody
214 // Returns false if the body isn't needed at all
217 boolean P_GiveBody(player_t *player, int num)
219 if (player->health >= maxhealth)
220 return false; // Ty 03/09/98 externalized MAXHEALTH to maxhealth
221 player->health += num;
222 if (player->health > maxhealth)
223 player->health = maxhealth;
224 player->mo->health = player->health;
225 return true;
229 // P_GiveArmor
230 // Returns false if the armor is worse
231 // than the current armor.
234 boolean P_GiveArmor(player_t *player, int armortype)
236 int hits = armortype*100;
237 if (player->armorpoints >= hits)
238 return false; // don't pick up
239 player->armortype = armortype;
240 player->armorpoints = hits;
241 return true;
245 // P_GiveCard
248 void P_GiveCard(player_t *player, card_t card)
250 if (player->cards[card])
251 return;
252 player->bonuscount = BONUSADD;
253 player->cards[card] = 1;
257 // P_GivePower
259 // Rewritten by Lee Killough
262 boolean P_GivePower(player_t *player, int power)
264 static const int tics[NUMPOWERS] = {
265 INVULNTICS, 1 /* strength */, INVISTICS,
266 IRONTICS, 1 /* allmap */, INFRATICS,
269 switch (power)
271 case pw_invisibility:
272 player->mo->flags |= MF_SHADOW;
273 break;
274 case pw_allmap:
275 if (player->powers[pw_allmap])
276 return false;
277 break;
278 case pw_strength:
279 P_GiveBody(player,100);
280 break;
283 // Unless player has infinite duration cheat, set duration (killough)
285 if (player->powers[power] >= 0)
286 player->powers[power] = tics[power];
287 return true;
291 // P_TouchSpecialThing
294 void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher)
296 player_t *player;
297 int i;
298 int sound;
299 fixed_t delta = special->z - toucher->z;
301 if (delta > toucher->height || delta < -8*FRACUNIT)
302 return; // out of reach
304 sound = sfx_itemup;
305 player = toucher->player;
307 // Dead thing touching.
308 // Can happen with a sliding player corpse.
309 if (toucher->health <= 0)
310 return;
312 // Identify by sprite.
313 switch (special->sprite)
315 // armor
316 case SPR_ARM1:
317 if (!P_GiveArmor (player, green_armor_class))
318 return;
319 player->message = s_GOTARMOR; // Ty 03/22/98 - externalized
320 break;
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 break;
328 // bonus items
329 case SPR_BON1:
330 player->health++; // can go over 100%
331 if (player->health > (maxhealth * 2))
332 player->health = (maxhealth * 2);
333 player->mo->health = player->health;
334 player->message = s_GOTHTHBONUS; // Ty 03/22/98 - externalized
335 break;
337 case SPR_BON2:
338 player->armorpoints++; // can go over 100%
339 if (player->armorpoints > max_armor)
340 player->armorpoints = max_armor;
341 if (!player->armortype)
342 player->armortype = green_armor_class;
343 player->message = s_GOTARMBONUS; // Ty 03/22/98 - externalized
344 break;
346 case SPR_SOUL:
347 player->health += soul_health;
348 if (player->health > max_soul)
349 player->health = max_soul;
350 player->mo->health = player->health;
351 player->message = s_GOTSUPER; // Ty 03/22/98 - externalized
352 sound = sfx_getpow;
353 break;
355 case SPR_MEGA:
356 if (gamemode != commercial)
357 return;
358 player->health = mega_health;
359 player->mo->health = player->health;
360 P_GiveArmor (player,blue_armor_class);
361 player->message = s_GOTMSPHERE; // Ty 03/22/98 - externalized
362 sound = sfx_getpow;
363 break;
365 // cards
366 // leave cards for everyone
367 case SPR_BKEY:
368 if (!player->cards[it_bluecard])
369 player->message = s_GOTBLUECARD; // Ty 03/22/98 - externalized
370 P_GiveCard (player, it_bluecard);
371 if (!netgame)
372 break;
373 return;
375 case SPR_YKEY:
376 if (!player->cards[it_yellowcard])
377 player->message = s_GOTYELWCARD; // Ty 03/22/98 - externalized
378 P_GiveCard (player, it_yellowcard);
379 if (!netgame)
380 break;
381 return;
383 case SPR_RKEY:
384 if (!player->cards[it_redcard])
385 player->message = s_GOTREDCARD; // Ty 03/22/98 - externalized
386 P_GiveCard (player, it_redcard);
387 if (!netgame)
388 break;
389 return;
391 case SPR_BSKU:
392 if (!player->cards[it_blueskull])
393 player->message = s_GOTBLUESKUL; // Ty 03/22/98 - externalized
394 P_GiveCard (player, it_blueskull);
395 if (!netgame)
396 break;
397 return;
399 case SPR_YSKU:
400 if (!player->cards[it_yellowskull])
401 player->message = s_GOTYELWSKUL; // Ty 03/22/98 - externalized
402 P_GiveCard (player, it_yellowskull);
403 if (!netgame)
404 break;
405 return;
407 case SPR_RSKU:
408 if (!player->cards[it_redskull])
409 player->message = s_GOTREDSKULL; // Ty 03/22/98 - externalized
410 P_GiveCard (player, it_redskull);
411 if (!netgame)
412 break;
413 return;
415 // medikits, heals
416 case SPR_STIM:
417 if (!P_GiveBody (player, 10))
418 return;
419 player->message = s_GOTSTIM; // Ty 03/22/98 - externalized
420 break;
422 case SPR_MEDI:
423 if (!P_GiveBody (player, 25))
424 return;
426 if (player->health < 50) // cph - 25 + the 25 just added, thanks to Quasar for reporting this bug
427 player->message = s_GOTMEDINEED; // Ty 03/22/98 - externalized
428 else
429 player->message = s_GOTMEDIKIT; // Ty 03/22/98 - externalized
430 break;
433 // power ups
434 case SPR_PINV:
435 if (!P_GivePower (player, pw_invulnerability))
436 return;
437 player->message = s_GOTINVUL; // Ty 03/22/98 - externalized
438 sound = sfx_getpow;
439 break;
441 case SPR_PSTR:
442 if (!P_GivePower (player, pw_strength))
443 return;
444 player->message = s_GOTBERSERK; // Ty 03/22/98 - externalized
445 if (player->readyweapon != wp_fist)
446 player->pendingweapon = wp_fist;
447 sound = sfx_getpow;
448 break;
450 case SPR_PINS:
451 if (!P_GivePower (player, pw_invisibility))
452 return;
453 player->message = s_GOTINVIS; // Ty 03/22/98 - externalized
454 sound = sfx_getpow;
455 break;
457 case SPR_SUIT:
458 if (!P_GivePower (player, pw_ironfeet))
459 return;
460 player->message = s_GOTSUIT; // Ty 03/22/98 - externalized
461 sound = sfx_getpow;
462 break;
464 case SPR_PMAP:
465 if (!P_GivePower (player, pw_allmap))
466 return;
467 player->message = s_GOTMAP; // Ty 03/22/98 - externalized
468 sound = sfx_getpow;
469 break;
471 case SPR_PVIS:
472 if (!P_GivePower (player, pw_infrared))
473 return;
474 player->message = s_GOTVISOR; // Ty 03/22/98 - externalized
475 sound = sfx_getpow;
476 break;
478 // ammo
479 case SPR_CLIP:
480 if (special->flags & MF_DROPPED)
482 if (!P_GiveAmmo (player,am_clip,0))
483 return;
485 else
487 if (!P_GiveAmmo (player,am_clip,1))
488 return;
490 player->message = s_GOTCLIP; // Ty 03/22/98 - externalized
491 break;
493 case SPR_AMMO:
494 if (!P_GiveAmmo (player, am_clip,5))
495 return;
496 player->message = s_GOTCLIPBOX; // Ty 03/22/98 - externalized
497 break;
499 case SPR_ROCK:
500 if (!P_GiveAmmo (player, am_misl,1))
501 return;
502 player->message = s_GOTROCKET; // Ty 03/22/98 - externalized
503 break;
505 case SPR_BROK:
506 if (!P_GiveAmmo (player, am_misl,5))
507 return;
508 player->message = s_GOTROCKBOX; // Ty 03/22/98 - externalized
509 break;
511 case SPR_CELL:
512 if (!P_GiveAmmo (player, am_cell,1))
513 return;
514 player->message = s_GOTCELL; // Ty 03/22/98 - externalized
515 break;
517 case SPR_CELP:
518 if (!P_GiveAmmo (player, am_cell,5))
519 return;
520 player->message = s_GOTCELLBOX; // Ty 03/22/98 - externalized
521 break;
523 case SPR_SHEL:
524 if (!P_GiveAmmo (player, am_shell,1))
525 return;
526 player->message = s_GOTSHELLS; // Ty 03/22/98 - externalized
527 break;
529 case SPR_SBOX:
530 if (!P_GiveAmmo (player, am_shell,5))
531 return;
532 player->message = s_GOTSHELLBOX; // Ty 03/22/98 - externalized
533 break;
535 case SPR_BPAK:
536 if (!player->backpack)
538 for (i=0 ; i<NUMAMMO ; i++)
539 player->maxammo[i] *= 2;
540 player->backpack = true;
542 for (i=0 ; i<NUMAMMO ; i++)
543 P_GiveAmmo (player, i, 1);
544 player->message = s_GOTBACKPACK; // Ty 03/22/98 - externalized
545 break;
547 // weapons
548 case SPR_BFUG:
549 if (!P_GiveWeapon (player, wp_bfg, false) )
550 return;
551 player->message = s_GOTBFG9000; // Ty 03/22/98 - externalized
552 sound = sfx_wpnup;
553 break;
555 case SPR_MGUN:
556 if (!P_GiveWeapon (player, wp_chaingun, (special->flags&MF_DROPPED)!=0) )
557 return;
558 player->message = s_GOTCHAINGUN; // Ty 03/22/98 - externalized
559 sound = sfx_wpnup;
560 break;
562 case SPR_CSAW:
563 if (!P_GiveWeapon (player, wp_chainsaw, false) )
564 return;
565 player->message = s_GOTCHAINSAW; // Ty 03/22/98 - externalized
566 sound = sfx_wpnup;
567 break;
569 case SPR_LAUN:
570 if (!P_GiveWeapon (player, wp_missile, false) )
571 return;
572 player->message = s_GOTLAUNCHER; // Ty 03/22/98 - externalized
573 sound = sfx_wpnup;
574 break;
576 case SPR_PLAS:
577 if (!P_GiveWeapon (player, wp_plasma, false) )
578 return;
579 player->message = s_GOTPLASMA; // Ty 03/22/98 - externalized
580 sound = sfx_wpnup;
581 break;
583 case SPR_SHOT:
584 if (!P_GiveWeapon (player, wp_shotgun, (special->flags&MF_DROPPED)!=0 ) )
585 return;
586 player->message = s_GOTSHOTGUN; // Ty 03/22/98 - externalized
587 sound = sfx_wpnup;
588 break;
590 case SPR_SGN2:
591 if (!P_GiveWeapon(player, wp_supershotgun, (special->flags&MF_DROPPED)!=0))
592 return;
593 player->message = s_GOTSHOTGUN2; // Ty 03/22/98 - externalized
594 sound = sfx_wpnup;
595 break;
597 default:
598 I_Error ("P_SpecialThing: Unknown gettable thing");
601 if (special->flags & MF_COUNTITEM)
602 player->itemcount++;
603 P_RemoveMobj (special);
604 player->bonuscount += BONUSADD;
606 /* cph 20028/10 - for old-school DM addicts, allow old behavior
607 * where only consoleplayer's pickup sounds are heard */
608 if (!comp[comp_sound] || player == &players[consoleplayer])
609 S_StartSound (player->mo, sound | PICKUP_SOUND); // killough 4/25/98
613 // KillMobj
615 // killough 11/98: make static
616 static void P_KillMobj(mobj_t *source, mobj_t *target)
618 mobjtype_t item;
619 mobj_t *mo;
621 target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY);
623 if (target->type != MT_SKULL)
624 target->flags &= ~MF_NOGRAVITY;
626 target->flags |= MF_CORPSE|MF_DROPOFF;
627 target->height >>= 2;
629 if (!((target->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL)))
630 totallive--;
632 if (source && source->player)
634 // count for intermission
635 if (target->flags & MF_COUNTKILL)
636 source->player->killcount++;
637 if (target->player)
638 source->player->frags[target->player-players]++;
640 else
641 if (target->flags & MF_COUNTKILL) { /* Add to kills tally */
642 if ((compatibility_level < lxdoom_1_compatibility) || !netgame) {
643 if (!netgame)
644 // count all monster deaths,
645 // even those caused by other monsters
646 players[0].killcount++;
647 } else
648 if (!deathmatch) {
649 // try and find a player to give the kill to, otherwise give the
650 // kill to a random player. this fixes the missing monsters bug
651 // in coop - rain
652 // CPhipps - not a bug as such, but certainly an inconsistency.
653 if (target->lastenemy && target->lastenemy->health > 0
654 && target->lastenemy->player) // Fighting a player
655 target->lastenemy->player->killcount++;
656 else {
657 // cph - randomely choose a player in the game to be credited
658 // and do it uniformly between the active players
659 unsigned int activeplayers = 0, player, i;
661 for (player = 0; player<MAXPLAYERS; player++)
662 if (playeringame[player])
663 activeplayers++;
665 if (activeplayers) {
666 player = P_Random(pr_friends) % activeplayers;
668 for (i=0; i<MAXPLAYERS; i++)
669 if (playeringame[i])
670 if (!player--)
671 players[i].killcount++;
677 if (target->player)
679 // count environment kills against you
680 if (!source)
681 target->player->frags[target->player-players]++;
683 target->flags &= ~MF_SOLID;
684 target->player->playerstate = PST_DEAD;
685 P_DropWeapon (target->player);
687 if (target->player == &players[consoleplayer] && (automapmode & am_active))
688 AM_Stop(); // don't die in auto map; switch view prior to dying
691 if (target->health < -target->info->spawnhealth && target->info->xdeathstate)
692 P_SetMobjState (target, target->info->xdeathstate);
693 else
694 P_SetMobjState (target, target->info->deathstate);
696 target->tics -= P_Random(pr_killtics)&3;
698 if (target->tics < 1)
699 target->tics = 1;
701 // Drop stuff.
702 // This determines the kind of object spawned
703 // during the death frame of a thing.
705 switch (target->type)
707 case MT_WOLFSS:
708 case MT_POSSESSED:
709 item = MT_CLIP;
710 break;
712 case MT_SHOTGUY:
713 item = MT_SHOTGUN;
714 break;
716 case MT_CHAINGUY:
717 item = MT_CHAINGUN;
718 break;
720 default:
721 return;
724 mo = P_SpawnMobj (target->x,target->y,ONFLOORZ, item);
725 mo->flags |= MF_DROPPED; // special versions of items
729 // P_DamageMobj
730 // Damages both enemies and players
731 // "inflictor" is the thing that caused the damage
732 // creature or missile, can be NULL (slime, etc)
733 // "source" is the thing to target after taking damage
734 // creature or NULL
735 // Source and inflictor are the same for melee attacks.
736 // Source can be NULL for slime, barrel explosions
737 // and other environmental stuff.
740 void P_DamageMobj(mobj_t *target,mobj_t *inflictor, mobj_t *source, int damage)
742 player_t *player;
743 boolean justhit; /* killough 11/98 */
745 /* killough 8/31/98: allow bouncers to take damage */
746 if (!(target->flags & (MF_SHOOTABLE | MF_BOUNCES)))
747 return; // shouldn't happen...
749 if (target->health <= 0)
750 return;
752 /* proff 11/22/98: Andy Baker's Stealth monsters */
753 if (target->flags & MF_STEALTH)
754 P_BecomeVisible(target);
756 if (target->flags & MF_SKULLFLY)
757 target->momx = target->momy = target->momz = 0;
759 player = target->player;
760 if (player && gameskill == sk_baby)
761 damage >>= 1; // take half damage in trainer mode
763 // Some close combat weapons should not
764 // inflict thrust and push the victim out of reach,
765 // thus kick away unless using the chainsaw.
767 if (inflictor && !(target->flags & MF_NOCLIP) &&
768 (!source || !source->player ||
769 source->player->readyweapon != wp_chainsaw))
771 unsigned ang = R_PointToAngle2 (inflictor->x, inflictor->y,
772 target->x, target->y);
774 fixed_t thrust = damage*(FRACUNIT>>3)*100/target->info->mass;
776 // make fall forwards sometimes
777 if ( damage < 40 && damage > target->health
778 && target->z - inflictor->z > 64*FRACUNIT
779 && P_Random(pr_damagemobj) & 1)
781 ang += ANG180;
782 thrust *= 4;
785 ang >>= ANGLETOFINESHIFT;
786 target->momx += FixedMul (thrust, finecosine[ang]);
787 target->momy += FixedMul (thrust, finesine[ang]);
789 /* killough 11/98: thrust objects hanging off ledges */
790 if (target->intflags & MIF_FALLING && target->gear >= MAXGEAR)
791 target->gear = 0;
794 // player specific
795 if (player)
797 // end of game hell hack
798 if (target->subsector->sector->special == 11 && damage >= target->health)
799 damage = target->health - 1;
801 // Below certain threshold,
802 // ignore damage in GOD mode, or with INVUL power.
803 // killough 3/26/98: make god mode 100% god mode in non-compat mode
805 if ((damage < 1000 || (!comp[comp_god] && (player->cheats&CF_GODMODE))) &&
806 (player->cheats&CF_GODMODE || player->powers[pw_invulnerability]))
807 return;
809 if (player->armortype)
811 int saved = player->armortype == 1 ? damage/3 : damage/2;
812 if (player->armorpoints <= saved)
814 // armor is used up
815 saved = player->armorpoints;
816 player->armortype = 0;
818 player->armorpoints -= saved;
819 damage -= saved;
822 player->health -= damage; // mirror mobj health here for Dave
823 if (player->health < 0)
824 player->health = 0;
826 player->attacker = source;
827 player->damagecount += damage; // add damage after armor / invuln
829 if (player->damagecount > 100)
830 player->damagecount = 100; // teleport stomp does 10k points...
833 // do the damage
834 target->health -= damage;
835 if (target->health <= 0)
837 P_KillMobj (source, target);
838 return;
841 // killough 9/7/98: keep track of targets so that friends can help friends
842 if (mbf_features)
844 /* If target is a player, set player's target to source,
845 * so that a friend can tell who's hurting a player
847 if (player)
848 P_SetTarget(&target->target, source);
850 /* killough 9/8/98:
851 * If target's health is less than 50%, move it to the front of its list.
852 * This will slightly increase the chances that enemies will choose to
853 * "finish it off", but its main purpose is to alert friends of danger.
855 if (target->health*2 < target->info->spawnhealth)
857 thinker_t *cap = &thinkerclasscap[target->flags & MF_FRIEND ?
858 th_friends : th_enemies];
859 (target->thinker.cprev->cnext = target->thinker.cnext)->cprev =
860 target->thinker.cprev;
861 (target->thinker.cnext = cap->cnext)->cprev = &target->thinker;
862 (target->thinker.cprev = cap)->cnext = &target->thinker;
866 if ((justhit = (P_Random (pr_painchance) < target->info->painchance &&
867 !(target->flags & MF_SKULLFLY)))) //killough 11/98: see below
868 P_SetMobjState(target, target->info->painstate);
870 target->reactiontime = 0; // we're awake now...
872 /* killough 9/9/98: cleaned up, made more consistent: */
874 if (source && source != target && source->type != MT_VILE &&
875 (!target->threshold || target->type == MT_VILE) &&
876 ((source->flags ^ target->flags) & MF_FRIEND ||
877 monster_infighting ||
878 !mbf_features))
880 /* if not intent on another player, chase after this one
882 * killough 2/15/98: remember last enemy, to prevent
883 * sleeping early; 2/21/98: Place priority on players
884 * killough 9/9/98: cleaned up, made more consistent:
887 if (!target->lastenemy || target->lastenemy->health <= 0 ||
888 (!mbf_features ?
889 !target->lastenemy->player :
890 !((target->flags ^ target->lastenemy->flags) & MF_FRIEND) &&
891 target->target != source)) // remember last enemy - killough
892 P_SetTarget(&target->lastenemy, target->target);
894 P_SetTarget(&target->target, source); // killough 11/98
895 target->threshold = BASETHRESHOLD;
896 if (target->state == &states[target->info->spawnstate]
897 && target->info->seestate != S_NULL)
898 P_SetMobjState (target, target->info->seestate);
901 /* killough 11/98: Don't attack a friend, unless hit by that friend. */
902 if (justhit && (target->target == source || !target->target ||
903 !(target->flags & target->target->flags & MF_FRIEND)))
904 target->flags |= MF_JUSTHIT; // fight back!