1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
6 // Copyright (C) 1993-1996 by id Software, Inc.
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.
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
20 // Handling interactions (i.e., collisions).
22 //-----------------------------------------------------------------------------
26 rcsid[] = "$Id: p_inter.c,v 1.4 1997/02/03 22:45:11 b1 Exp $";
46 #pragma implementation "p_inter.h"
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};
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
81 if (ammo == am_noammo)
84 if (ammo < 0 || ammo > NUMAMMO)
85 I_Error ("P_GiveAmmo: bad type %i", ammo);
87 if ( player->ammo[ammo] == player->maxammo[ammo] )
91 num *= clipammo[ammo];
93 num = clipammo[ammo]/2;
95 if (gameskill == sk_baby
96 || gameskill == sk_nightmare)
98 // give double ammo in trainer mode,
99 // you'll need in nightmare
104 oldammo = player->ammo[ammo];
105 player->ammo[ammo] += num;
107 if (player->ammo[ammo] > player->maxammo[ammo])
108 player->ammo[ammo] = player->maxammo[ammo];
111 // don't change up weapons,
112 // player was lower on purpose.
116 // We were down to zero,
117 // so select a new weapon.
118 // Preferences are not user selectable.
122 if (player->readyweapon == wp_fist)
124 if (player->weaponowned[wp_chaingun])
125 player->pendingweapon = wp_chaingun;
127 player->pendingweapon = wp_pistol;
132 if (player->readyweapon == wp_fist
133 || player->readyweapon == wp_pistol)
135 if (player->weaponowned[wp_shotgun])
136 player->pendingweapon = wp_shotgun;
141 if (player->readyweapon == wp_fist
142 || player->readyweapon == wp_pistol)
144 if (player->weaponowned[wp_plasma])
145 player->pendingweapon = wp_plasma;
150 if (player->readyweapon == wp_fist)
152 if (player->weaponowned[wp_missile])
153 player->pendingweapon = wp_missile;
165 // The weapon name may have a MF_DROPPED flag ored in.
180 // leave placed weapons forever on net games
181 if (player->weaponowned[weapon])
184 player->bonuscount += BONUSADD;
185 player->weaponowned[weapon] = true;
188 P_GiveAmmo (player, weaponinfo[weapon].ammo, 5);
190 P_GiveAmmo (player, weaponinfo[weapon].ammo, 2);
191 player->pendingweapon = weapon;
193 if (player == &players[consoleplayer])
194 S_StartSound (NULL, sfx_wpnup);
198 if (weaponinfo[weapon].ammo != am_noammo)
200 // give one clip with a dropped weapon,
201 // two clips with a found weapon
203 gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 1);
205 gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 2);
210 if (player->weaponowned[weapon])
215 player->weaponowned[weapon] = true;
216 player->pendingweapon = weapon;
219 return (gaveweapon || gaveammo);
226 // Returns false if the body isn't needed at all
233 if (player->health >= MAXHEALTH)
236 player->health += num;
237 if (player->health > MAXHEALTH)
238 player->health = MAXHEALTH;
239 player->mo->health = player->health;
248 // Returns false if the armor is worse
249 // than the current armor.
258 hits = armortype*100;
259 if (player->armorpoints >= hits)
260 return false; // don't pick up
262 player->armortype = armortype;
263 player->armorpoints = hits;
278 if (player->cards[card])
281 player->bonuscount = BONUSADD;
282 player->cards[card] = 1;
292 int /*powertype_t*/ power )
294 if (power == pw_invulnerability)
296 player->powers[power] = INVULNTICS;
300 if (power == pw_invisibility)
302 player->powers[power] = INVISTICS;
303 player->mo->flags |= MF_SHADOW;
307 if (power == pw_infrared)
309 player->powers[power] = INFRATICS;
313 if (power == pw_ironfeet)
315 player->powers[power] = IRONTICS;
319 if (power == pw_strength)
321 P_GiveBody (player, 100);
322 player->powers[power] = 1;
326 if (player->powers[power])
327 return false; // already got it
329 player->powers[power] = 1;
336 // P_TouchSpecialThing
348 delta = special->z - toucher->z;
350 if (delta > toucher->height
351 || delta < -8*FRACUNIT)
359 player = toucher->player;
361 // Dead thing touching.
362 // Can happen with a sliding player corpse.
363 if (toucher->health <= 0)
366 // Identify by sprite.
367 switch (special->sprite)
371 if (!P_GiveArmor (player, 1))
373 player->message = GOTARMOR;
377 if (!P_GiveArmor (player, 2))
379 player->message = GOTMEGA;
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;
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;
401 player->health += 100;
402 if (player->health > 200)
403 player->health = 200;
404 player->mo->health = player->health;
405 player->message = GOTSUPER;
410 if (gamemode != commercial)
412 player->health = 200;
413 player->mo->health = player->health;
414 P_GiveArmor (player,2);
415 player->message = GOTMSPHERE;
420 // leave cards for everyone
422 if (!player->cards[it_bluecard])
423 player->message = GOTBLUECARD;
424 P_GiveCard (player, it_bluecard);
430 if (!player->cards[it_yellowcard])
431 player->message = GOTYELWCARD;
432 P_GiveCard (player, it_yellowcard);
438 if (!player->cards[it_redcard])
439 player->message = GOTREDCARD;
440 P_GiveCard (player, it_redcard);
446 if (!player->cards[it_blueskull])
447 player->message = GOTBLUESKUL;
448 P_GiveCard (player, it_blueskull);
454 if (!player->cards[it_yellowskull])
455 player->message = GOTYELWSKUL;
456 P_GiveCard (player, it_yellowskull);
462 if (!player->cards[it_redskull])
463 player->message = GOTREDSKULL;
464 P_GiveCard (player, it_redskull);
471 if (!P_GiveBody (player, 10))
473 player->message = GOTSTIM;
477 if (!P_GiveBody (player, 25))
480 if (player->health < 25)
481 player->message = GOTMEDINEED;
483 player->message = GOTMEDIKIT;
489 if (!P_GivePower (player, pw_invulnerability))
491 player->message = GOTINVUL;
496 if (!P_GivePower (player, pw_strength))
498 player->message = GOTBERSERK;
499 if (player->readyweapon != wp_fist)
500 player->pendingweapon = wp_fist;
505 if (!P_GivePower (player, pw_invisibility))
507 player->message = GOTINVIS;
512 if (!P_GivePower (player, pw_ironfeet))
514 player->message = GOTSUIT;
519 if (!P_GivePower (player, pw_allmap))
521 player->message = GOTMAP;
526 if (!P_GivePower (player, pw_infrared))
528 player->message = GOTVISOR;
534 if (special->flags & MF_DROPPED)
536 if (!P_GiveAmmo (player,am_clip,0))
541 if (!P_GiveAmmo (player,am_clip,1))
544 player->message = GOTCLIP;
548 if (!P_GiveAmmo (player, am_clip,5))
550 player->message = GOTCLIPBOX;
554 if (!P_GiveAmmo (player, am_misl,1))
556 player->message = GOTROCKET;
560 if (!P_GiveAmmo (player, am_misl,5))
562 player->message = GOTROCKBOX;
566 if (!P_GiveAmmo (player, am_cell,1))
568 player->message = GOTCELL;
572 if (!P_GiveAmmo (player, am_cell,5))
574 player->message = GOTCELLBOX;
578 if (!P_GiveAmmo (player, am_shell,1))
580 player->message = GOTSHELLS;
584 if (!P_GiveAmmo (player, am_shell,5))
586 player->message = GOTSHELLBOX;
590 if (!player->backpack)
592 for (i=0 ; i<NUMAMMO ; i++)
593 player->maxammo[i] *= 2;
594 player->backpack = true;
596 for (i=0 ; i<NUMAMMO ; i++)
597 P_GiveAmmo (player, i, 1);
598 player->message = GOTBACKPACK;
603 if (!P_GiveWeapon (player, wp_bfg, false) )
605 player->message = GOTBFG9000;
610 if (!P_GiveWeapon (player, wp_chaingun, special->flags&MF_DROPPED) )
612 player->message = GOTCHAINGUN;
617 if (!P_GiveWeapon (player, wp_chainsaw, false) )
619 player->message = GOTCHAINSAW;
624 if (!P_GiveWeapon (player, wp_missile, false) )
626 player->message = GOTLAUNCHER;
631 if (!P_GiveWeapon (player, wp_plasma, false) )
633 player->message = GOTPLASMA;
638 if (!P_GiveWeapon (player, wp_shotgun, special->flags&MF_DROPPED ) )
640 player->message = GOTSHOTGUN;
645 if (!P_GiveWeapon (player, wp_supershotgun, special->flags&MF_DROPPED ) )
647 player->message = GOTSHOTGUN2;
652 I_Error ("P_SpecialThing: Unknown gettable thing");
655 if (special->flags & MF_COUNTITEM)
657 P_RemoveMobj (special);
658 player->bonuscount += BONUSADD;
659 if (player == &players[consoleplayer])
660 S_StartSound (NULL, sound);
675 target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY);
677 if (target->type != MT_SKULL)
678 target->flags &= ~MF_NOGRAVITY;
680 target->flags |= MF_CORPSE|MF_DROPOFF;
681 target->height >>= 2;
683 if (source && source->player)
685 // count for intermission
686 if (target->flags & MF_COUNTKILL)
687 source->player->killcount++;
690 source->player->frags[target->player-players]++;
692 else if (!netgame && (target->flags & MF_COUNTKILL) )
694 // count all monster deaths,
695 // even those caused by other monsters
696 players[0].killcount++;
701 // count environment kills against you
703 target->player->frags[target->player-players]++;
705 target->flags &= ~MF_SOLID;
706 target->player->playerstate = PST_DEAD;
707 P_DropWeapon (target->player);
709 if (target->player == &players[consoleplayer]
712 // don't die in auto map,
713 // switch view prior to dying
719 if (target->health < -target->info->spawnhealth
720 && target->info->xdeathstate)
722 P_SetMobjState (target, target->info->xdeathstate);
725 P_SetMobjState (target, target->info->deathstate);
726 target->tics -= P_Random()&3;
728 if (target->tics < 1)
731 // I_StartSound (&actor->r, actor->info->deathsound);
735 // This determines the kind of object spawned
736 // during the death frame of a thing.
737 switch (target->type)
756 mo = P_SpawnMobj (target->x,target->y,ONFLOORZ, item);
757 mo->flags |= MF_DROPPED; // special versions of items
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
770 // Source and inflictor are the same for melee attacks.
771 // Source can be NULL for slime, barrel explosions
772 // and other environmental stuff.
787 if ( !(target->flags & MF_SHOOTABLE) )
788 return; // shouldn't happen...
790 if (target->health <= 0)
793 if ( target->flags & MF_SKULLFLY )
795 target->momx = target->momy = target->momz = 0;
798 player = target->player;
799 if (player && gameskill == sk_baby)
800 damage >>= 1; // take half damage in trainer mode
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.
807 && !(target->flags & MF_NOCLIP)
810 || source->player->readyweapon != wp_chainsaw))
812 ang = R_PointToAngle2 ( inflictor->x,
817 thrust = damage*(FRACUNIT>>3)*100/target->info->mass;
819 // make fall forwards sometimes
821 && damage > target->health
822 && target->z - inflictor->z > 64*FRACUNIT
829 ang >>= ANGLETOFINESHIFT;
830 target->momx += FixedMul (thrust, finecosine[ang]);
831 target->momy += FixedMul (thrust, finesine[ang]);
837 // end of game hell hack
838 if (target->subsector->sector->special == 11
839 && damage >= target->health)
841 damage = target->health - 1;
845 // Below certain threshold,
846 // ignore damage in GOD mode, or with INVUL power.
848 && ( (player->cheats&CF_GODMODE)
849 || player->powers[pw_invulnerability] ) )
854 if (player->armortype)
856 if (player->armortype == 1)
861 if (player->armorpoints <= saved)
864 saved = player->armorpoints;
865 player->armortype = 0;
867 player->armorpoints -= saved;
870 player->health -= damage; // mirror mobj health here for Dave
871 if (player->health < 0)
874 player->attacker = source;
875 player->damagecount += damage; // add damage after armor / invuln
877 if (player->damagecount > 100)
878 player->damagecount = 100; // teleport stomp does 10k points...
880 temp = damage < 100 ? damage : 100;
882 if (player == &players[consoleplayer])
883 I_Tactile (40,10,40+temp*2);
887 target->health -= damage;
888 if (target->health <= 0)
890 P_KillMobj (source, target);
894 if ( (P_Random () < target->info->painchance)
895 && !(target->flags&MF_SKULLFLY) )
897 target->flags |= MF_JUSTHIT; // fight back!
899 P_SetMobjState (target, target->info->painstate);
902 target->reactiontime = 0; // we're awake now...
904 if ( (!target->threshold || target->type == MT_VILE)
905 && source && source != target
906 && source->type != MT_VILE)
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);