123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920 |
- /* Emacs style mode select -*- C++ -*-
- *-----------------------------------------------------------------------------
- *
- *
- * PrBoom: a Doom port merged with LxDoom and LSDLDoom
- * based on BOOM, a modified and improved DOOM engine
- * Copyright (C) 1999 by
- * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
- * Copyright (C) 1999-2000 by
- * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
- * Copyright 2005, 2006 by
- * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * DESCRIPTION:
- * Handling interactions (i.e., collisions).
- *
- *-----------------------------------------------------------------------------*/
- #include "doomstat.h"
- #include "dstrings.h"
- #include "m_random.h"
- #include "am_map.h"
- #include "r_main.h"
- #include "s_sound.h"
- #include "sounds.h"
- #include "d_deh.h" // Ty 03/22/98 - externalized strings
- #include "p_tick.h"
- #include "lprintf.h"
- #include "p_inter.h"
- #include "p_enemy.h"
- #ifdef __GNUG__
- #pragma implementation "p_inter.h"
- #endif
- #include "p_inter.h"
- #include "doomiphone.h"
- #define BONUSADD 6
- // Ty 03/07/98 - add deh externals
- // Maximums and such were hardcoded values. Need to externalize those for
- // dehacked support (and future flexibility). Most var names came from the key
- // strings used in dehacked.
- int initial_health = 100;
- int initial_bullets = 50;
- int maxhealth = 100; // was MAXHEALTH as a #define, used only in this module
- int max_armor = 200;
- int green_armor_class = 1; // these are involved with armortype below
- int blue_armor_class = 2;
- int max_soul = 200;
- int soul_health = 100;
- int mega_health = 200;
- int god_health = 100; // these are used in cheats (see st_stuff.c)
- int idfa_armor = 200;
- int idfa_armor_class = 2;
- // not actually used due to pairing of cheat_k and cheat_fa
- int idkfa_armor = 200;
- int idkfa_armor_class = 2;
- int bfgcells = 40; // used in p_pspr.c
- int monsters_infight = 0; // e6y: Dehacked support - monsters infight
- // Ty 03/07/98 - end deh externals
- // a weapon is found with two clip loads,
- // a big item has five clip loads
- int maxammo[NUMAMMO] = {200, 50, 300, 50};
- int clipammo[NUMAMMO] = { 10, 4, 20, 1};
- //
- // GET STUFF
- //
- //
- // P_GiveAmmo
- // Num is the number of clip loads,
- // not the individual count (0= 1/2 clip).
- // Returns false if the ammo can't be picked up at all
- //
- static boolean P_GiveAmmo(player_t *player, ammotype_t ammo, int num)
- {
- int oldammo;
- if (ammo == am_noammo)
- return false;
- #ifdef RANGECHECK
- if (ammo > NUMAMMO)
- I_Error ("P_GiveAmmo: bad type %i", ammo);
- #endif
- if ( player->ammo[ammo] == player->maxammo[ammo] )
- return false;
- if (num)
- num *= clipammo[ammo];
- else
- num = clipammo[ammo]/2;
- // give double ammo in trainer mode, you'll need in nightmare
- if (gameskill == sk_baby || gameskill == sk_nightmare)
- num <<= 1;
- oldammo = player->ammo[ammo];
- player->ammo[ammo] += num;
- if (player->ammo[ammo] > player->maxammo[ammo])
- player->ammo[ammo] = player->maxammo[ammo];
- // If non zero ammo, don't change up weapons, player was lower on purpose.
- if (oldammo)
- return true;
- // We were down to zero, so select a new weapon.
- // Preferences are not user selectable.
- switch (ammo)
- {
- case am_clip:
- if (player->readyweapon == wp_fist) {
- if (player->weaponowned[wp_chaingun])
- player->pendingweapon = wp_chaingun;
- else
- player->pendingweapon = wp_pistol;
- }
- break;
- case am_shell:
- if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol)
- if (player->weaponowned[wp_shotgun])
- player->pendingweapon = wp_shotgun;
- break;
- case am_cell:
- if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol)
- if (player->weaponowned[wp_plasma])
- player->pendingweapon = wp_plasma;
- break;
- case am_misl:
- if (player->readyweapon == wp_fist)
- if (player->weaponowned[wp_missile])
- player->pendingweapon = wp_missile;
- default:
- break;
- }
- return true;
- }
- //
- // P_GiveWeapon
- // The weapon name may have a MF_DROPPED flag ored in.
- //
- static boolean P_GiveWeapon(player_t *player, weapontype_t weapon, boolean dropped)
- {
- boolean gaveammo;
- boolean gaveweapon;
- if (netgame && deathmatch!=2 && !dropped)
- {
- // leave placed weapons forever on net games
- if (player->weaponowned[weapon])
- return false;
- player->bonuscount += BONUSADD;
- player->weaponowned[weapon] = true;
- P_GiveAmmo(player, weaponinfo[weapon].ammo, deathmatch ? 5 : 2);
- player->pendingweapon = weapon;
- /* cph 20028/10 - for old-school DM addicts, allow old behavior
- * where only consoleplayer's pickup sounds are heard */
- // displayplayer, not consoleplayer, for viewing multiplayer demos
- if (!comp[comp_sound] || player == &players[displayplayer])
- S_StartSound (player->mo, sfx_wpnup|PICKUP_SOUND); // killough 4/25/98
- return false;
- }
- if (weaponinfo[weapon].ammo != am_noammo)
- {
- // give one clip with a dropped weapon,
- // two clips with a found weapon
- gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, dropped ? 1 : 2);
- }
- else
- gaveammo = false;
- if (player->weaponowned[weapon])
- gaveweapon = false;
- else
- {
- gaveweapon = true;
- player->weaponowned[weapon] = true;
- player->pendingweapon = weapon;
- }
- return gaveweapon || gaveammo;
- }
- //
- // P_GiveBody
- // Returns false if the body isn't needed at all
- //
- static boolean P_GiveBody(player_t *player, int num)
- {
- if (player->health >= maxhealth)
- return false; // Ty 03/09/98 externalized MAXHEALTH to maxhealth
- player->health += num;
- if (player->health > maxhealth)
- player->health = maxhealth;
- player->mo->health = player->health;
- return true;
- }
- //
- // P_GiveArmor
- // Returns false if the armor is worse
- // than the current armor.
- //
- static boolean P_GiveArmor(player_t *player, int armortype)
- {
- int hits = armortype*100;
- if (player->armorpoints >= hits)
- return false; // don't pick up
- player->armortype = armortype;
- player->armorpoints = hits;
- return true;
- }
- //
- // P_GiveCard
- //
- static void P_GiveCard(player_t *player, card_t card)
- {
- if (player->cards[card])
- return;
- player->bonuscount = BONUSADD;
- player->cards[card] = 1;
- }
- //
- // P_GivePower
- //
- // Rewritten by Lee Killough
- //
- boolean P_GivePower(player_t *player, int power)
- {
- static const int tics[NUMPOWERS] = {
- INVULNTICS, 1 /* strength */, INVISTICS,
- IRONTICS, 1 /* allmap */, INFRATICS,
- };
- switch (power)
- {
- case pw_invisibility:
- player->mo->flags |= MF_SHADOW;
- break;
- case pw_allmap:
- if (player->powers[pw_allmap])
- return false;
- break;
- case pw_strength:
- P_GiveBody(player,100);
- break;
- }
- // Unless player has infinite duration cheat, set duration (killough)
- if (player->powers[power] >= 0)
- player->powers[power] = tics[power];
- return true;
- }
- //
- // P_TouchSpecialThing
- //
- void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher)
- {
- player_t *player;
- int i;
- int sound;
- fixed_t delta = special->z - toucher->z;
- if (delta > toucher->height || delta < -8*FRACUNIT)
- return; // out of reach
- sound = sfx_itemup;
- player = toucher->player;
- // Dead thing touching.
- // Can happen with a sliding player corpse.
- if (toucher->health <= 0)
- return;
- // Identify by sprite.
- switch (special->sprite)
- {
- // armor
- case SPR_ARM1:
- if (!P_GiveArmor (player, green_armor_class))
- return;
- player->message = s_GOTARMOR; // Ty 03/22/98 - externalized
- break;
- case SPR_ARM2:
- if (!P_GiveArmor (player, blue_armor_class))
- return;
- player->message = s_GOTMEGA; // Ty 03/22/98 - externalized
- break;
- // bonus items
- case SPR_BON1:
- player->health++; // can go over 100%
- if (player->health > (maxhealth * 2))
- player->health = (maxhealth * 2);
- player->mo->health = player->health;
- player->message = s_GOTHTHBONUS; // Ty 03/22/98 - externalized
- break;
- case SPR_BON2:
- player->armorpoints++; // can go over 100%
- if (player->armorpoints > max_armor)
- player->armorpoints = max_armor;
- if (!player->armortype)
- player->armortype = green_armor_class;
- player->message = s_GOTARMBONUS; // Ty 03/22/98 - externalized
- break;
- case SPR_SOUL:
- player->health += soul_health;
- if (player->health > max_soul)
- player->health = max_soul;
- player->mo->health = player->health;
- player->message = s_GOTSUPER; // Ty 03/22/98 - externalized
- sound = sfx_getpow;
- break;
- case SPR_MEGA:
- if (gamemode != commercial)
- return;
- player->health = mega_health;
- player->mo->health = player->health;
- P_GiveArmor (player,blue_armor_class);
- player->message = s_GOTMSPHERE; // Ty 03/22/98 - externalized
- sound = sfx_getpow;
- break;
- // cards
- // leave cards for everyone
- case SPR_BKEY:
- if (!player->cards[it_bluecard])
- player->message = s_GOTBLUECARD; // Ty 03/22/98 - externalized
- P_GiveCard (player, it_bluecard);
- if (!netgame)
- break;
- return;
- case SPR_YKEY:
- if (!player->cards[it_yellowcard])
- player->message = s_GOTYELWCARD; // Ty 03/22/98 - externalized
- P_GiveCard (player, it_yellowcard);
- if (!netgame)
- break;
- return;
- case SPR_RKEY:
- if (!player->cards[it_redcard])
- player->message = s_GOTREDCARD; // Ty 03/22/98 - externalized
- P_GiveCard (player, it_redcard);
- if (!netgame)
- break;
- return;
- case SPR_BSKU:
- if (!player->cards[it_blueskull])
- player->message = s_GOTBLUESKUL; // Ty 03/22/98 - externalized
- P_GiveCard (player, it_blueskull);
- if (!netgame)
- break;
- return;
- case SPR_YSKU:
- if (!player->cards[it_yellowskull])
- player->message = s_GOTYELWSKUL; // Ty 03/22/98 - externalized
- P_GiveCard (player, it_yellowskull);
- if (!netgame)
- break;
- return;
- case SPR_RSKU:
- if (!player->cards[it_redskull])
- player->message = s_GOTREDSKULL; // Ty 03/22/98 - externalized
- P_GiveCard (player, it_redskull);
- if (!netgame)
- break;
- return;
- // medikits, heals
- case SPR_STIM:
- if (!P_GiveBody (player, 10))
- return;
- player->message = s_GOTSTIM; // Ty 03/22/98 - externalized
- break;
- case SPR_MEDI:
- if (!P_GiveBody (player, 25))
- return;
- if (player->health < 50) // cph - 25 + the 25 just added, thanks to Quasar for reporting this bug
- player->message = s_GOTMEDINEED; // Ty 03/22/98 - externalized
- else
- player->message = s_GOTMEDIKIT; // Ty 03/22/98 - externalized
- break;
- // power ups
- case SPR_PINV:
- if (!P_GivePower (player, pw_invulnerability))
- return;
- player->message = s_GOTINVUL; // Ty 03/22/98 - externalized
- sound = sfx_getpow;
- break;
- case SPR_PSTR:
- if (!P_GivePower (player, pw_strength))
- return;
- player->message = s_GOTBERSERK; // Ty 03/22/98 - externalized
- if (player->readyweapon != wp_fist)
- player->pendingweapon = wp_fist;
- sound = sfx_getpow;
- break;
- case SPR_PINS:
- if (!P_GivePower (player, pw_invisibility))
- return;
- player->message = s_GOTINVIS; // Ty 03/22/98 - externalized
- sound = sfx_getpow;
- break;
- case SPR_SUIT:
- if (!P_GivePower (player, pw_ironfeet))
- return;
- player->message = s_GOTSUIT; // Ty 03/22/98 - externalized
- sound = sfx_getpow;
- break;
- case SPR_PMAP:
- if (!P_GivePower (player, pw_allmap))
- return;
- player->message = s_GOTMAP; // Ty 03/22/98 - externalized
- sound = sfx_getpow;
- break;
- case SPR_PVIS:
- if (!P_GivePower (player, pw_infrared))
- return;
- player->message = s_GOTVISOR; // Ty 03/22/98 - externalized
- sound = sfx_getpow;
- break;
- // ammo
- case SPR_CLIP:
- if (special->flags & MF_DROPPED)
- {
- if (!P_GiveAmmo (player,am_clip,0))
- return;
- }
- else
- {
- if (!P_GiveAmmo (player,am_clip,1))
- return;
- }
- player->message = s_GOTCLIP; // Ty 03/22/98 - externalized
- break;
- case SPR_AMMO:
- if (!P_GiveAmmo (player, am_clip,5))
- return;
- player->message = s_GOTCLIPBOX; // Ty 03/22/98 - externalized
- break;
- case SPR_ROCK:
- if (!P_GiveAmmo (player, am_misl,1))
- return;
- player->message = s_GOTROCKET; // Ty 03/22/98 - externalized
- break;
- case SPR_BROK:
- if (!P_GiveAmmo (player, am_misl,5))
- return;
- player->message = s_GOTROCKBOX; // Ty 03/22/98 - externalized
- break;
- case SPR_CELL:
- if (!P_GiveAmmo (player, am_cell,1))
- return;
- player->message = s_GOTCELL; // Ty 03/22/98 - externalized
- break;
- case SPR_CELP:
- if (!P_GiveAmmo (player, am_cell,5))
- return;
- player->message = s_GOTCELLBOX; // Ty 03/22/98 - externalized
- break;
- case SPR_SHEL:
- if (!P_GiveAmmo (player, am_shell,1))
- return;
- player->message = s_GOTSHELLS; // Ty 03/22/98 - externalized
- break;
- case SPR_SBOX:
- if (!P_GiveAmmo (player, am_shell,5))
- return;
- player->message = s_GOTSHELLBOX; // Ty 03/22/98 - externalized
- break;
- case SPR_BPAK:
- if (!player->backpack)
- {
- for (i=0 ; i<NUMAMMO ; i++)
- player->maxammo[i] *= 2;
- player->backpack = true;
- }
- for (i=0 ; i<NUMAMMO ; i++)
- P_GiveAmmo (player, i, 1);
- player->message = s_GOTBACKPACK; // Ty 03/22/98 - externalized
- break;
- // weapons
- case SPR_BFUG:
- if (!P_GiveWeapon (player, wp_bfg, false) )
- return;
- player->message = s_GOTBFG9000; // Ty 03/22/98 - externalized
- sound = sfx_wpnup;
- break;
- case SPR_MGUN:
- if (!P_GiveWeapon (player, wp_chaingun, (special->flags&MF_DROPPED)!=0) )
- return;
- player->message = s_GOTCHAINGUN; // Ty 03/22/98 - externalized
- sound = sfx_wpnup;
- break;
- case SPR_CSAW:
- if (!P_GiveWeapon (player, wp_chainsaw, false) )
- return;
- player->message = s_GOTCHAINSAW; // Ty 03/22/98 - externalized
- sound = sfx_wpnup;
- break;
- case SPR_LAUN:
- if (!P_GiveWeapon (player, wp_missile, false) )
- return;
- player->message = s_GOTLAUNCHER; // Ty 03/22/98 - externalized
- sound = sfx_wpnup;
- break;
- case SPR_PLAS:
- if (!P_GiveWeapon (player, wp_plasma, false) )
- return;
- player->message = s_GOTPLASMA; // Ty 03/22/98 - externalized
- sound = sfx_wpnup;
- break;
- case SPR_SHOT:
- if (!P_GiveWeapon (player, wp_shotgun, (special->flags&MF_DROPPED)!=0 ) )
- return;
- player->message = s_GOTSHOTGUN; // Ty 03/22/98 - externalized
- sound = sfx_wpnup;
- break;
- case SPR_SGN2:
- if (!P_GiveWeapon(player, wp_supershotgun, (special->flags&MF_DROPPED)!=0))
- return;
- player->message = s_GOTSHOTGUN2; // Ty 03/22/98 - externalized
- sound = sfx_wpnup;
- break;
- default:
- I_Error ("P_SpecialThing: Unknown gettable thing");
- }
- if (special->flags & MF_COUNTITEM)
- player->itemcount++;
- P_RemoveMobj (special);
- player->bonuscount += BONUSADD;
- /* cph 20028/10 - for old-school DM addicts, allow old behavior
- * where only consoleplayer's pickup sounds are heard */
- // displayplayer, not consoleplayer, for viewing multiplayer demos
- if (!comp[comp_sound] || player == &players[displayplayer])
- S_StartSound (player->mo, sound | PICKUP_SOUND); // killough 4/25/98
- }
- //
- // KillMobj
- //
- // killough 11/98: make static
- static void P_KillMobj(mobj_t *source, mobj_t *target)
- {
- mobjtype_t item;
- mobj_t *mo;
- target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY);
- if (target->type != MT_SKULL)
- target->flags &= ~MF_NOGRAVITY;
- target->flags |= MF_CORPSE|MF_DROPOFF;
- target->height >>= 2;
- if (!((target->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL)))
- totallive--;
- if (source && source->player)
- {
- // count for intermission
- if (target->flags & MF_COUNTKILL)
- source->player->killcount++;
- if (target->player)
- source->player->frags[target->player-players]++;
- }
- else
- if (target->flags & MF_COUNTKILL) { /* Add to kills tally */
- if ((compatibility_level < lxdoom_1_compatibility) || !netgame) {
- if (!netgame)
- // count all monster deaths,
- // even those caused by other monsters
- players[0].killcount++;
- } else
- if (!deathmatch) {
- // try and find a player to give the kill to, otherwise give the
- // kill to a random player. this fixes the missing monsters bug
- // in coop - rain
- // CPhipps - not a bug as such, but certainly an inconsistency.
- if (target->lastenemy && target->lastenemy->health > 0
- && target->lastenemy->player) // Fighting a player
- target->lastenemy->player->killcount++;
- else {
- // cph - randomely choose a player in the game to be credited
- // and do it uniformly between the active players
- unsigned int activeplayers = 0, player, i;
- for (player = 0; player<MAXPLAYERS; player++)
- if (playeringame[player])
- activeplayers++;
- if (activeplayers) {
- player = P_Random(pr_friends) % activeplayers;
- for (i=0; i<MAXPLAYERS; i++)
- if (playeringame[i])
- if (!player--)
- players[i].killcount++;
- }
- }
- }
- }
- if (target->player)
- {
- // count environment kills against you
- if (!source)
- target->player->frags[target->player-players]++;
- target->flags &= ~MF_SOLID;
- target->player->playerstate = PST_DEAD;
- P_DropWeapon (target->player);
- if (target->player == &players[consoleplayer] && (automapmode & am_active))
- AM_Stop(); // don't die in auto map; switch view prior to dying
- }
- if (target->health < -target->info->spawnhealth && target->info->xdeathstate)
- P_SetMobjState (target, target->info->xdeathstate);
- else
- P_SetMobjState (target, target->info->deathstate);
- target->tics -= P_Random(pr_killtics)&3;
- if (target->tics < 1)
- target->tics = 1;
- // Drop stuff.
- // This determines the kind of object spawned
- // during the death frame of a thing.
- switch (target->type)
- {
- case MT_WOLFSS:
- case MT_POSSESSED:
- item = MT_CLIP;
- break;
- case MT_SHOTGUY:
- item = MT_SHOTGUN;
- break;
- case MT_CHAINGUY:
- item = MT_CHAINGUN;
- break;
- default:
- return;
- }
- mo = P_SpawnMobj (target->x,target->y,ONFLOORZ, item);
- mo->flags |= MF_DROPPED; // special versions of items
- }
- //
- // P_DamageMobj
- // Damages both enemies and players
- // "inflictor" is the thing that caused the damage
- // creature or missile, can be NULL (slime, etc)
- // "source" is the thing to target after taking damage
- // creature or NULL
- // Source and inflictor are the same for melee attacks.
- // Source can be NULL for slime, barrel explosions
- // and other environmental stuff.
- //
- void P_DamageMobj(mobj_t *target,mobj_t *inflictor, mobj_t *source, int damage)
- {
- player_t *player;
- boolean justhit = false; /* killough 11/98 */
- /* killough 8/31/98: allow bouncers to take damage */
- if (!(target->flags & (MF_SHOOTABLE | MF_BOUNCES)))
- return; // shouldn't happen...
- if (target->health <= 0)
- return;
- if (target->flags & MF_SKULLFLY)
- target->momx = target->momy = target->momz = 0;
- player = target->player;
- if (player && gameskill == sk_baby)
- damage >>= 1; // take half damage in trainer mode
- // Some close combat weapons should not
- // inflict thrust and push the victim out of reach,
- // thus kick away unless using the chainsaw.
- if (inflictor && !(target->flags & MF_NOCLIP) &&
- (!source || !source->player ||
- source->player->readyweapon != wp_chainsaw))
- {
- unsigned ang = R_PointToAngle2 (inflictor->x, inflictor->y,
- target->x, target->y);
- fixed_t thrust = damage*(FRACUNIT>>3)*100/target->info->mass;
- // make fall forwards sometimes
- if ( damage < 40 && damage > target->health
- && target->z - inflictor->z > 64*FRACUNIT
- && P_Random(pr_damagemobj) & 1)
- {
- ang += ANG180;
- thrust *= 4;
- }
- ang >>= ANGLETOFINESHIFT;
- target->momx += FixedMul (thrust, finecosine[ang]);
- target->momy += FixedMul (thrust, finesine[ang]);
- /* killough 11/98: thrust objects hanging off ledges */
- if (target->intflags & MIF_FALLING && target->gear >= MAXGEAR)
- target->gear = 0;
- }
- // player specific
- if (player)
- {
- // end of game hell hack
- if (target->subsector->sector->special == 11 && damage >= target->health)
- damage = target->health - 1;
- // Below certain threshold,
- // ignore damage in GOD mode, or with INVUL power.
- // killough 3/26/98: make god mode 100% god mode in non-compat mode
- if ((damage < 1000 || (!comp[comp_god] && (player->cheats&CF_GODMODE))) &&
- (player->cheats&CF_GODMODE || player->powers[pw_invulnerability]))
- return;
- if (player->armortype)
- {
- int saved = player->armortype == 1 ? damage/3 : damage/2;
- if (player->armorpoints <= saved)
- {
- // armor is used up
- saved = player->armorpoints;
- player->armortype = 0;
- }
- player->armorpoints -= saved;
- damage -= saved;
- }
- player->health -= damage; // mirror mobj health here for Dave
- if (player->health < 0)
- player->health = 0;
- player->attacker = source;
- player->damagecount += damage; // add damage after armor / invuln
- #ifdef IPHONE
- if ( player == &players[consoleplayer] && !demoplayback ) { // vibe during demos is annoying
- SysIPhoneVibrate();
- }
- #endif
- if (player->damagecount > 100)
- player->damagecount = 100; // teleport stomp does 10k points...
- }
- // do the damage
- target->health -= damage;
- if (target->health <= 0)
- {
- P_KillMobj (source, target);
- return;
- }
- // killough 9/7/98: keep track of targets so that friends can help friends
- if (mbf_features)
- {
- /* If target is a player, set player's target to source,
- * so that a friend can tell who's hurting a player
- */
- if (player)
- P_SetTarget(&target->target, source);
- /* killough 9/8/98:
- * If target's health is less than 50%, move it to the front of its list.
- * This will slightly increase the chances that enemies will choose to
- * "finish it off", but its main purpose is to alert friends of danger.
- */
- if (target->health*2 < target->info->spawnhealth)
- {
- thinker_t *cap = &thinkerclasscap[target->flags & MF_FRIEND ?
- th_friends : th_enemies];
- (target->thinker.cprev->cnext = target->thinker.cnext)->cprev =
- target->thinker.cprev;
- (target->thinker.cnext = cap->cnext)->cprev = &target->thinker;
- (target->thinker.cprev = cap)->cnext = &target->thinker;
- }
- }
- if (P_Random (pr_painchance) < target->info->painchance &&
- !(target->flags & MF_SKULLFLY)) { //killough 11/98: see below
- if (mbf_features)
- justhit = true;
- else
- target->flags |= MF_JUSTHIT; // fight back!
- P_SetMobjState(target, target->info->painstate);
- }
- target->reactiontime = 0; // we're awake now...
- /* killough 9/9/98: cleaned up, made more consistent: */
- if (source && source != target && source->type != MT_VILE &&
- (!target->threshold || target->type == MT_VILE) &&
- ((source->flags ^ target->flags) & MF_FRIEND ||
- monster_infighting ||
- !mbf_features))
- {
- /* if not intent on another player, chase after this one
- *
- * killough 2/15/98: remember last enemy, to prevent
- * sleeping early; 2/21/98: Place priority on players
- * killough 9/9/98: cleaned up, made more consistent:
- */
- if (!target->lastenemy || target->lastenemy->health <= 0 ||
- (!mbf_features ?
- !target->lastenemy->player :
- !((target->flags ^ target->lastenemy->flags) & MF_FRIEND) &&
- target->target != source)) // remember last enemy - killough
- P_SetTarget(&target->lastenemy, target->target);
- P_SetTarget(&target->target, source); // killough 11/98
- target->threshold = BASETHRESHOLD;
- if (target->state == &states[target->info->spawnstate]
- && target->info->seestate != S_NULL)
- P_SetMobjState (target, target->info->seestate);
- }
- /* killough 11/98: Don't attack a friend, unless hit by that friend.
- * cph 2006/04/01 - implicitly this is only if mbf_features */
- if (justhit && (target->target == source || !target->target ||
- !(target->flags & target->target->flags & MF_FRIEND)))
- target->flags |= MF_JUSTHIT; // fight back!
- }
|