diff options
Diffstat (limited to 'src/strife/p_inter.c')
-rw-r--r-- | src/strife/p_inter.c | 1404 |
1 files changed, 1404 insertions, 0 deletions
diff --git a/src/strife/p_inter.c b/src/strife/p_inter.c new file mode 100644 index 00000000..4a7a173d --- /dev/null +++ b/src/strife/p_inter.c @@ -0,0 +1,1404 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005 Simon Howard +// +// 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). +// +//----------------------------------------------------------------------------- + +// Data. +#include "doomdef.h" +#include "dstrings.h" +#include "sounds.h" +#include "deh_main.h" +#include "deh_misc.h" +#include "doomstat.h" +#include "m_random.h" +#include "i_system.h" +#include "am_map.h" +#include "p_local.h" +#include "p_dialog.h" // villsa [STRIFE] +#include "s_sound.h" +#include "p_inter.h" + +#include "hu_stuff.h" // villsa [STRIFE] +#include "z_zone.h" // villsa [STRIFE] + +// haleyjd [STRIFE] +#include "w_wad.h" +#include "p_pspr.h" +#include "p_dialog.h" +#include "f_finale.h" + + +#define BONUSADD 6 + + +// a weapon is found with two clip loads, +// a big item has five clip loads +// villsa [STRIFE] updated arrays +int maxammo[NUMAMMO] = { 250, 50, 25, 400, 100, 30, 16 }; +int clipammo[NUMAMMO] = { 10, 4, 2, 20, 4, 6, 4 }; + + +// +// 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 +// +// [STRIFE] Modified for Strife ammo types +// +boolean P_GiveAmmo(player_t* player, ammotype_t ammo, int num) +{ + int oldammo; + + if(ammo == am_noammo) + return false; + + if(ammo > NUMAMMO) + I_Error ("P_GiveAmmo: bad type %i", ammo); + + if(player->ammo[ammo] == player->maxammo[ammo]) + return false; + + if(num) + num *= clipammo[ammo]; + else + num = clipammo[ammo]/2; + + if(gameskill == sk_baby + || gameskill == sk_nightmare) + { + // give double ammo in trainer mode, + // you'll need in 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. + + // villsa [STRIFE] ammo update + // where's the check for grenades? - haleyjd: verified no switch to grenades + // haleyjd 10/03/10: don't change to electric bow when picking up poison + // arrows. + if(!player->readyweapon) + { + switch(ammo) + { + case am_bullets: + if(player->weaponowned[wp_rifle]) + player->pendingweapon = wp_rifle; + break; + + case am_elecbolts: + if(player->weaponowned[wp_elecbow]) + player->pendingweapon = wp_elecbow; + break; + + case am_cell: + if(player->weaponowned[wp_mauler]) + player->pendingweapon = wp_mauler; + break; + + case am_missiles: + if(player->weaponowned[wp_missile]) + player->pendingweapon = wp_missile; + break; + + default: + break; + } + } + + return true; +} + + +// +// P_GiveWeapon +// The weapon name may have a MF_DROPPED flag ored in. +// +// villsa [STRIFE] some stuff has been changed/moved around +// +boolean P_GiveWeapon(player_t* player, weapontype_t weapon, boolean dropped) +{ + boolean gaveammo; + boolean gaveweapon; + + // villsa [STRIFE] new code for giving alternate version + // of the weapon to player + if(player->weaponowned[weapon]) + gaveweapon = false; + else + { + gaveweapon = true; + player->weaponowned[weapon] = true; + + // Alternate "sister" weapons that you also get as a bonus: + switch(weapon) + { + case wp_elecbow: + player->weaponowned[wp_poisonbow] = true; + break; + + case wp_hegrenade: + player->weaponowned[wp_wpgrenade] = true; + break; + + case wp_mauler: + player->weaponowned[wp_torpedo] = true; + break; + + default: + break; + } + + // check for the standard weapons only + if(weapon > player->readyweapon && weapon <= wp_sigil) + player->pendingweapon = weapon; + + } + + if(netgame && (deathmatch != 2) && !dropped) + { + // leave placed weapons forever on net games + if(!gaveweapon) + return false; + + player->bonuscount += BONUSADD; + player->weaponowned[weapon] = true; + + if(deathmatch) + P_GiveAmmo(player, weaponinfo[weapon].ammo, 5); + else + P_GiveAmmo(player, weaponinfo[weapon].ammo, 2); + + if(player == &players[consoleplayer]) + S_StartSound (NULL, sfx_wpnup); + return false; + } + + if(weaponinfo[weapon].ammo != am_noammo) + { + // give one clip with a dropped weapon, + // two clips with a found weapon + if(dropped) + gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 1); + else + gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 2); + } + else + gaveammo = false; + + return(gaveweapon || gaveammo); +} + + + +// +// P_GiveBody +// Returns false if the body isn't needed at all +// +// villsa [STRIFE] a lot of changes have been added for stamina +// +boolean P_GiveBody(player_t* player, int num) +{ + int maxhealth; + int healing; + + maxhealth = MAXHEALTH + player->stamina; + + if(num >= 0) // haleyjd 20100923: fixed to give proper amount of health + { + mobj_t *mo; // haleyjd 20110225: needed below... + + // any healing to do? + if(player->health >= maxhealth) + return false; + + // give, and cap to maxhealth + player->health += num; + if(player->health >= maxhealth) + player->health = maxhealth; + + // Set mo->health for consistency. + // haleyjd 20110225: Seems Strife can call this on a NULL player->mo + // when giving items to players that are not in the game... + // STRIFE-FIXME: needs major verification! + mo = P_SubstNullMobj(player->mo); + mo->health = player->health; + } + else + { + // [STRIFE] handle healing from the Front's medic + // The amount the player's health will be set to scales up with stamina + // increases. + // Ex 1: On the wimpiest skill level, -100 is sent in. This restores + // full health no matter what your stamina. + // (100*100)/100 = 100 + // (200*100)/100 = 200 + // Ex 2: On the most stringent skill levels, -50 is sent in. This will + // restore at most half of your health. + // (100*50)/100 = 50 + // (200*50)/100 = 100 + healing = (-num * maxhealth) / MAXHEALTH; + + // This is also the "threshold" of healing. You need less health than + // the amount that will be restored in order to get any benefit. + // So on the easiest skill you will always be fully healed. + // On the hardest skill you must have less than 50 health, and will + // only recover to 50 (assuming base stamina stat) + if(player->health >= healing) + return false; + + // Set health. Oddly, mo->health is NOT set here... + player->health = healing; + } + + return true; +} + + + +// +// P_GiveArmor +// Returns false if the armor is worse +// than the current armor. +// +// [STRIFE] Modified for Strife armor items +// +boolean P_GiveArmor(player_t* player, int armortype) +{ + int hits; + + // villsa [STRIFE] + if(armortype < 0) + { + if(player->armorpoints) + return false; + + armortype = -armortype; + } + + hits = armortype * 100; + if(player->armorpoints >= hits) + return false; // don't pick up + + player->armortype = armortype; + player->armorpoints = hits; + + return true; +} + + + +// +// P_GiveCard +// +// [STRIFE] Modified to use larger bonuscount +// +boolean P_GiveCard(player_t* player, card_t card) +{ + if (player->cards[card]) + return false; + + // villsa [STRIFE] multiply by 2 + player->bonuscount = BONUSADD * 2; + player->cards[card] = true; + + return true; +} + + +// +// P_GivePower +// +// [STRIFE] Modifications for new powerups +// +boolean P_GivePower(player_t* player, powertype_t power) +{ + // haleyjd 09/14/10: [STRIFE] moved to top, exception for Shadow Armor + if(player->powers[power] && power != pw_invisibility) + return false; // already got it + + // if giving pw_invisibility and player already has MVIS, no can do. + if(power == pw_invisibility && (player->mo->flags & MF_MVIS)) + return false; + + // villsa [STRIFE] + if(power == pw_targeter) + { + player->powers[power] = TARGTICS; + P_SetPsprite(player, ps_targcenter, S_TRGT_00); // 10 + P_SetPsprite(player, ps_targleft, S_TRGT_01); // 11 + P_SetPsprite(player, ps_targright, S_TRGT_02); // 12 + + player->psprites[ps_targcenter].sx = (160*FRACUNIT); + player->psprites[ps_targleft ].sy = (100*FRACUNIT); + player->psprites[ps_targcenter].sy = (100*FRACUNIT); + player->psprites[ps_targright ].sy = (100*FRACUNIT); + return true; + } + + if(power == pw_invisibility) + { + // if player already had this power... + if(player->powers[power]) + { + // remove SHADOW, give MVIS. + player->mo->flags &= ~MF_SHADOW; + player->mo->flags |= MF_MVIS; + } + else // give SHADOW + player->mo->flags |= MF_SHADOW; + + // set tics if giving shadow, or renew them if MVIS. + player->powers[power] = INVISTICS; + + return true; + } + + if(power == pw_ironfeet) + { + player->powers[power] = IRONTICS; + return true; + } + + if(power == pw_strength) + { + P_GiveBody(player, 100); + player->powers[power] = 1; + return true; + } + + // villsa [STRIFE] + if(power == pw_allmap) + { + // remember in mapstate + if(gamemap < 40) + player->mapstate[gamemap] = true; + + player->powers[power] = 1; + return true; + } + + // villsa [STRIFE] + if(power == pw_communicator) + { + player->powers[power] = 1; + return true; + } + + // default behavior: + player->powers[power] = 1; + return true; +} + + +// villsa [STRIFE] +static char pickupmsg[80]; + +// +// P_TouchSpecialThing +// +// [STRIFE] Rewritten for Strife collectables. +// +void P_TouchSpecialThing(mobj_t* special, mobj_t* toucher) +{ + player_t* player; + int i; + fixed_t delta; + int sound; + + 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; + + // villsa [STRIFE] damage toucher if special is spectral + // haleyjd 09/21/10: corrected to test for SPECTRE thingtypes specifically + switch(special->type) + { + case MT_SPECTRE_A: + case MT_SPECTRE_B: + case MT_SPECTRE_C: + case MT_SPECTRE_D: + case MT_SPECTRE_E: + case MT_ENTITY: + case MT_SUBENTITY: + P_DamageMobj(toucher, NULL, NULL, 5); + return; + default: + break; + } + + // villsa [STRIFE] + pickupmsg[0] = 0; + + // Identify by sprite. + // villsa [STRIFE] new items + switch(special->sprite) + { + // bullets + case SPR_BLIT: // haleyjd: fixed missing MF_DROPPED check + if(!P_GiveAmmo(player, am_bullets, !(special->flags & MF_DROPPED))) + return; + break; + + // box of bullets + case SPR_BBOX: + if(!P_GiveAmmo(player, am_bullets, 5)) + return; + break; + + // missile + case SPR_ROKT: + if(!P_GiveAmmo(player, am_missiles, 1)) + return; + break; + + // box of missiles + case SPR_MSSL: + if(!P_GiveAmmo(player, am_missiles, 5)) + return; + break; + + // battery + case SPR_BRY1: + if(!P_GiveAmmo(player, am_cell, 1)) + return; + break; + + // cell pack + case SPR_CPAC: + if(!P_GiveAmmo(player, am_cell, 5)) + return; + break; + + // poison bolts + case SPR_PQRL: + if(!P_GiveAmmo(player, am_poisonbolts, 5)) + return; + break; + + // electric bolts + case SPR_XQRL: + if(!P_GiveAmmo(player, am_elecbolts, 5)) + return; + break; + + // he grenades + case SPR_GRN1: + if(!P_GiveAmmo(player, am_hegrenades, 1)) + return; + break; + + // wp grenades + case SPR_GRN2: + if(!P_GiveAmmo(player, am_wpgrenades, 1)) + return; + break; + + // rifle + case SPR_RIFL: + if(!P_GiveWeapon(player, wp_rifle, special->flags & MF_DROPPED)) + return; + sound = sfx_wpnup; // haleyjd: SHK-CHK! + break; + + // flame thrower + case SPR_FLAM: + if(!P_GiveWeapon(player, wp_flame, false)) + return; + // haleyjd: gives extra ammo. + P_GiveAmmo(player, am_cell, 3); + sound = sfx_wpnup; // haleyjd: SHK-CHK! + break; + + // missile launcher + case SPR_MMSL: + if(!P_GiveWeapon(player, wp_missile, false)) + return; + sound = sfx_wpnup; // haleyjd: SHK-CHK! + break; + + // grenade launcher + case SPR_GRND: + if(!P_GiveWeapon(player, wp_hegrenade, special->flags & MF_DROPPED)) + return; + sound = sfx_wpnup; // haleyjd: SHK-CHK! + break; + + // mauler + case SPR_TRPD: + if(!P_GiveWeapon(player, wp_mauler, false)) + return; + sound = sfx_wpnup; // haleyjd: SHK-CHK! + break; + + // electric bolt crossbow + case SPR_CBOW: + if(!P_GiveWeapon(player, wp_elecbow, special->flags & MF_DROPPED)) + return; + sound = sfx_wpnup; // haleyjd: SHK-CHK! + break; + + // haleyjd 09/21/10: missed case: THE SIGIL! + case SPR_SIGL: + if(!P_GiveWeapon(player, wp_sigil, special->flags & MF_DROPPED)) + { + player->sigiltype = special->frame; + return; + } + + if(netgame) + player->sigiltype = 4; + + player->pendingweapon = wp_sigil; + player->st_update = true; + if(deathmatch) + return; + sound = sfx_wpnup; + break; + + // backpack + case SPR_BKPK: + 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); + break; + + // 1 Gold + case SPR_COIN: + P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1); + break; + + // 10 Gold + case SPR_CRED: + for(i = 0; i < 10; i++) + P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1); + break; + + // 25 Gold + case SPR_SACK: + // haleyjd 09/21/10: missed code: if a SPR_SACK object has negative + // health, it will give that much gold - STRIFE-TODO: verify + if(special->health < 0) + { + for(i = special->health; i != 0; i++) + P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1); + } + else + { + for(i = 0; i < 25; i++) + P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1); + } + break; + + // 50 Gold + case SPR_CHST: + for(i = 0; i < 50; i++) + P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1); + break; + + // Leather Armor + case SPR_ARM1: + if(!P_GiveArmor(player, -2)) + if(!P_GiveInventoryItem(player, special->sprite, special->type)) + pickupmsg[0] = '!'; + break; + + // Metal Armor + case SPR_ARM2: + if(!P_GiveArmor(player, -1)) + if(!P_GiveInventoryItem(player, special->sprite, special->type)) + pickupmsg[0] = '!'; + break; + + // All-map powerup + case SPR_PMAP: + if(!P_GivePower(player, pw_allmap)) + return; + sound = sfx_yeah; + break; + + // The Comm Unit - because you need Blackbird whining in your ear the + // whole time and telling you how lost she is :P + case SPR_COMM: + if(!P_GivePower(player, pw_communicator)) + return; + sound = sfx_yeah; + break; + + // haleyjd 09/21/10: missed case - Shadow Armor; though, I do not know why + // this has a case distinct from generic inventory items... Maybe it started + // out as an auto-use-if-possible item much like regular armor... + case SPR_SHD1: + if(!P_GiveInventoryItem(player, SPR_SHD1, special->type)) + pickupmsg[0] = '!'; + break; + + // villsa [STRIFE] check default items + case SPR_TOKN: + default: + if(special->type >= MT_KEY_BASE && special->type <= MT_NEWKEY5) + { + // haleyjd 09/21/10: Strife player still picks up keys that + // he has already found. (break, not return) + if(!P_GiveCard(player, special->type - MT_KEY_BASE)) + break; + } + else + { + if(!P_GiveInventoryItem(player, special->sprite, special->type)) + pickupmsg[0] = '!'; + } + break; + } + + // villsa [STRIFE] set message + if(!pickupmsg[0]) + { + if(special->info->name) + { + DEH_snprintf(pickupmsg, sizeof(pickupmsg), + "You picked up the %s.", DEH_String(special->info->name)); + } + else + DEH_snprintf(pickupmsg, sizeof(pickupmsg), "You picked up the item."); + } + // use the first character to indicate that the player is full on items + else if(pickupmsg[0] == '!') + { + DEH_snprintf(pickupmsg, sizeof(pickupmsg), "You cannot hold any more."); + player->message = pickupmsg; + return; + } + + if(special->flags & MF_GIVEQUEST) + { + // [STRIFE] TODO - verify this. Seems that questflag isn't + // applied if the special's speed is equal to 8 or if + // the player has received a specific quest token + if(special->info->speed != 8 || !(player->questflags & QF_QUEST6)) + player->questflags |= 1 << (special->info->speed - 1); + } + + + // haleyjd 08/30/10: [STRIFE] No itemcount + //if (special->flags & MF_COUNTITEM) + // player->itemcount++; + + P_RemoveMobj(special); + player->message = pickupmsg; + player->bonuscount += BONUSADD; + + if(player == &players[consoleplayer]) + S_StartSound(NULL, sound); +} + +// villsa [STRIFE] +static char plrkilledmsg[80]; + +// +// KillMobj +// +// [STRIFE] Major modifications for drop types, no tic randomization, etc. +// +void P_KillMobj(mobj_t* source, mobj_t* target) +{ + mobjtype_t item; + mobj_t* mo; + line_t junk; + int i; + + // villsa [STRIFE] corpse and dropoff are removed, but why when these two flags + // are set a few lines later? watcom nonsense perhaps? + target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_BOUNCE|MF_CORPSE|MF_DROPOFF); + + // villsa [STRIFE] unused + /* + if (target->type != MT_SKULL) + target->flags &= ~MF_NOGRAVITY; + */ + + target->flags |= MF_CORPSE|MF_DROPOFF; + target->height = FRACUNIT; // villsa [STRIFE] set to fracunit instead of >>= 2 + + if(source && source->player) + { + // count for intermission + if(target->flags & MF_COUNTKILL) + source->player->killcount++; + + if(target->player) + { + source->player->frags[target->player-players]++; + + // villsa [STRIFE] new messages when fragging players + DEH_snprintf(plrkilledmsg, sizeof(plrkilledmsg), + "%s killed %s", + pnameprefixes[source->player->mo->miscdata], + pnameprefixes[target->player->mo->miscdata]); + + if(netgame) + players[consoleplayer].message = plrkilledmsg; + } + } + else if(!netgame && (target->flags & MF_COUNTKILL)) + { + // count all monster deaths, + // even those caused by other monsters + players[0].killcount++; + } + + if(target->player) + { + // count environment kills against you + if(!source) + target->player->frags[target->player-players]++; + + if(gamemap == 29 && !netgame) + { + // haleyjd 09/13/10: [STRIFE] Give player the bad ending. + F_StartFinale(); + return; + } + + // villsa [STRIFE] spit out inventory items when killed + if(netgame) + { + int amount = 0; + mobj_t* loot; + int r = 0; + + while(1) + { + if(target->player->inventory[0].amount <= 0) + break; + + item = target->player->inventory[0].type; + if(item == MT_MONY_1) + { + loot = P_SpawnMobj(target->x, target->y, + target->z + (24*FRACUNIT), MT_MONY_25); + + // [STRIFE] TODO - what the hell is it doing here? + loot->health = target->player->inventory[0].amount; + loot->health = -target->player->inventory[0].amount; + + amount = target->player->inventory[0].amount; + } + else + { + loot = P_SpawnMobj(target->x, target->y, + target->z + (24*FRACUNIT), item); + amount = 1; + } + + P_RemoveInventoryItem(target->player, 0, amount); + r = P_Random(); + loot->momx += ((r & 7) - (P_Random() & 7)) << FRACBITS; + loot->momy += ((P_Random() & 7) + 1) << FRACBITS; + loot->flags |= MF_DROPPED; + } + } + + target->flags &= ~MF_SOLID; + target->player->playerstate = PST_DEAD; + target->player->mo->momz = 5*FRACUNIT; // [STRIFE]: small hop! + P_DropWeapon(target->player); + + if(target->player == &players[consoleplayer] + && automapactive) + { + // don't die in auto map, + // switch view prior to dying + AM_Stop (); + } + + } + + // villsa [STRIFE] some modifications to setting states + if(target->state != &states[S_BURN_23]) + { + if(target->health == -6666) + P_SetMobjState(target, S_DISR_00); // 373 + else + { + if(target->health < -target->info->spawnhealth + && target->info->xdeathstate) + P_SetMobjState(target, target->info->xdeathstate); + else + P_SetMobjState(target, target->info->deathstate); + } + } + + // villsa [STRIFE] no death tics randomization + + // Drop stuff. + // villsa [STRIFE] get item from dialog target + item = P_DialogFind(target->type, target->miscdata)->dropitem; + + if(!item) + { + // villsa [STRIFE] drop default items + switch(target->type) + { + case MT_ORACLE: + item = MT_MEAT; + break; + + case MT_PROGRAMMER: + item = MT_SIGIL_A; + break; + + case MT_PRIEST: + item = MT_JUNK; + break; + + case MT_BISHOP: + item = MT_AMINIBOX; + break; + + case MT_PGUARD: + case MT_CRUSADER: + item = MT_ACELL; + break; + + case MT_RLEADER: + item = MT_AAMMOBOX; + break; + + case MT_GUARD1: + case MT_REBEL1: + case MT_SHADOWGUARD: + item = MT_ACLIP; + break; + + case MT_SPECTRE_B: + item = MT_SIGIL_B; + break; + + case MT_SPECTRE_C: + item = MT_SIGIL_C; + break; + + case MT_SPECTRE_D: + item = MT_SIGIL_D; + break; + + case MT_SPECTRE_E: + item = MT_SIGIL_E; + break; + + case MT_COUPLING: + junk.tag = 225; + EV_DoDoor(&junk, close); + + junk.tag = 44; + EV_DoFloor(&junk, lowerFloor); + + GiveVoiceObjective("VOC13", "LOG13", 0); + + item = MT_COUPLING_BROKEN; + players[0].questflags |= (1 << (mobjinfo[MT_COUPLING].speed - 1)); + break; + + default: + return; + } + } + + // handle special case for scripted target's dropped item + switch(item) + { + case MT_TOKEN_SHOPCLOSE: + junk.tag = 222; + EV_DoDoor(&junk, close); + P_NoiseAlert(players[0].mo, players[0].mo); + + sprintf(plrkilledmsg, "%s", DEH_String("You're dead! You set off the alarm.")); + if(!deathmatch) + players[consoleplayer].message = plrkilledmsg; + + return; + + case MT_TOKEN_PRISON_PASS: + junk.tag = 223; + EV_DoDoor(&junk, open); + return; + + case MT_TOKEN_DOOR3: + junk.tag = 224; + EV_DoDoor(&junk, open); + return; + + case MT_SIGIL_A: + case MT_SIGIL_B: + case MT_SIGIL_C: + case MT_SIGIL_D: + case MT_SIGIL_E: + for(i = 0; i < MAXPLAYERS; i++) + { + if(!P_GiveWeapon(&players[i], wp_sigil, false)) + { + if(players[i].sigiltype++ > 4) + players[i].sigiltype = 4; + } + + // haleyjd 20110225: fixed these two assignments which Watcom munged + // up in the assembly by pre-incrementing the pointer into players[] + players[i].st_update = true; + players[i].pendingweapon = wp_sigil; + } + return; + + case MT_TOKEN_ALARM: + P_NoiseAlert(players[0].mo, players[0].mo); + + sprintf(plrkilledmsg, "%s", DEH_String("You Fool! You've set off the alarm")); + if(!deathmatch) + players[consoleplayer].message = plrkilledmsg; + return; + + default: + break; + } + + // villsa [STRIFE] toss out item + if(!deathmatch || !(mobjinfo[item].flags & MF_NOTDMATCH)) + { + int r; + + mo = P_SpawnMobj(target->x, target->y, target->z + (24*FRACUNIT), item); + r = P_Random(); + mo->momx += ((r & 7) - (P_Random() & 7)) << FRACBITS; + r = P_Random(); + mo->momy += ((r & 7) - (P_Random() & 7)) << FRACBITS; + mo->flags |= (MF_SPECIAL|MF_DROPPED); // special versions of items + } +} + +// +// P_IsMobjBoss +// +// villsa [STRIFE] new function +// +static boolean P_IsMobjBoss(mobjtype_t type) +{ + switch(type) + { + case MT_PROGRAMMER: + case MT_BISHOP: + case MT_RLEADER: + case MT_ORACLE: + case MT_PRIEST: + return true; + + default: + return false; + } +} + + +// +// 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. +// +// [STRIFE] Extensive changes for spectrals, fire damage, disintegration, and +// a plethora of mobjtype-specific hacks. +// +void P_DamageMobj(mobj_t* target, mobj_t* inflictor, mobj_t* source, int damage) +{ + angle_t ang; + int saved; + player_t* player; + fixed_t thrust; + int temp; + + if(!(target->flags & MF_SHOOTABLE) ) + return; // shouldn't happen... + + if(target->health <= 0) + return; + + player = target->player; + + // villsa [STRIFE] unused - skullfly check (removed) + + // villsa [STRIFE] handle spectral stuff + // notes on projectile health: + // -2 == enemy spectral projectile + // -1 == player spectral projectile + + // haleyjd 20110203: refactored completely + if(inflictor && (inflictor->flags & MF_SPECTRAL)) + { + // players aren't damaged by their own (or others???) sigils + // STRIFE-TODO: verify in deathmatch + if(target->type == MT_PLAYER && inflictor->health == -1) + return; + // enemies aren't damaged by enemy sigil attacks + if((target->flags & MF_SPECTRAL) && inflictor->health == -2) + return; + // Macil2, Oracle, and Spectre C cannot be damaged by Sigil A + switch(target->type) + { + case MT_RLEADER2: + case MT_ORACLE: + case MT_SPECTRE_C: + // haleyjd: added source->player validity check for safety... + if(source->player && source->player->sigiltype < 1) + return; + default: + break; + } + } + + // villsa [STRIFE] new checks for various actors + if(inflictor) + { + // Fire damage inflictors + if(inflictor->type == MT_SFIREBALL || + inflictor->type == MT_C_FLAME || + inflictor->type == MT_PFLAME) + { + temp = damage / 2; + + if(P_IsMobjBoss(target->type)) + damage /= 2; + else if(inflictor->type == MT_PFLAME) + { + damage /= 2; + // robots take very little damage + if(target->flags & MF_NOBLOOD) + damage = temp / 2; + } + } + else + { + switch(inflictor->type) + { + case MT_HOOKSHOT: + // haleyjd 20110203: should use source, not inflictor + ang = R_PointToAngle2( + target->x, + target->y, + source->x, + source->y) >> ANGLETOFINESHIFT; + + target->momx += FixedMul(finecosine[ang], (12750*FRACUNIT) / target->info->mass); + target->momy += FixedMul(finesine[ang], (12750*FRACUNIT) / target->info->mass); + target->reactiontime += 10; + + temp = P_AproxDistance(target->x - source->x, target->y - source->y); + temp /= target->info->mass; + + if(temp < 1) + temp = 1; + + target->momz = (source->z - target->z) / temp; + break; + + case MT_POISARROW: + // don't affect robots + if(target->flags & MF_NOBLOOD) + return; + + // instant kill + damage = target->health + 10; + break; + + default: + // Spectral retaliation, though this may in fact be unreachable + // since non-spectral inflictors are mostly filtered out. + if(target->flags & MF_SPECTRAL + && !(inflictor->flags & MF_SPECTRAL)) + { + P_SetMobjState(target, target->info->missilestate); + return; // take no damage + } + break; + } + } + } + + // villsa [STRIFE] special cases for shopkeepers and macil + if((target->type >= MT_SHOPKEEPER_W && target->type <= MT_SHOPKEEPER_M) + || target->type == MT_RLEADER) + { + if(source) + target->target = source; + + P_SetMobjState(target, target->info->painstate); + return; + } + + // villsa [STRIFE] handle fieldguard damage + if(target->type == MT_FIELDGUARD) + { + // degnin ores are only allowed to damage the fieldguard + if(!inflictor || inflictor->type != MT_DEGNINORE) + return; + + damage = target->health; + } + + 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_flame)) + { + ang = R_PointToAngle2(inflictor->x, + inflictor->y, + target->x, + target->y); + + 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() & 1)) + { + ang += ANG180; + thrust *= 4; + } + + ang >>= ANGLETOFINESHIFT; + target->momx += FixedMul (thrust, finecosine[ang]); + target->momy += FixedMul (thrust, finesine[ang]); + } + + // 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. + // villsa [STRIFE] removed pw_invulnerability check + if(damage < 1000 && (player->cheats & CF_GODMODE)) + return; + + // villsa [STRIFE] flame attacks don't damage player if wearing envirosuit + if(player->powers[pw_ironfeet] && inflictor) + { + if(inflictor->type == MT_SFIREBALL || + inflictor->type == MT_C_FLAME || + inflictor->type == MT_PFLAME) + { + damage = 0; + } + } + + if(player->armortype) + { + if (player->armortype == 1) + saved = damage/3; + else + saved = damage/2; + + if(player->armorpoints <= saved) + { + // armor is used up + saved = player->armorpoints; + player->armortype = 0; + + // villsa [STRIFE] + P_UseInventoryItem(player, SPR_ARM1); + P_UseInventoryItem(player, SPR_ARM2); + } + 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 + + // haleyjd 20110203 [STRIFE]: target->target set here + if(target != source) + target->target = source; + + if(player->damagecount > 100) + player->damagecount = 100; // teleport stomp does 10k points... + + temp = damage < 100 ? damage : 100; + + if(player == &players[consoleplayer]) + I_Tactile (40,10,40+temp*2); + } + + // do the damage + target->health -= damage; + + // villsa [STRIFE] auto use medkits + if(player && player->health < 50) + { + if(deathmatch || player->cheats & CF_AUTOHEALTH) + { + while(player->health < 50 && P_UseInventoryItem(player, SPR_MDKT)); + while(player->health < 50 && P_UseInventoryItem(player, SPR_STMP)); + } + } + + + if(target->health <= 0) + { + // villsa [STRIFE] grenades hurt... OUCH + if(inflictor && inflictor->type == MT_HEGRENADE) + target->health = -target->info->spawnhealth; + else if(!(target->flags & MF_NOBLOOD)) + { + // villsa [STRIFE] disintegration death + if(inflictor && + (inflictor->type == MT_STRIFEPUFF3 || + inflictor->type == MT_L_LASER || + inflictor->type == MT_TORPEDO || + inflictor->type == MT_TORPEDOSPREAD)) + { + S_StartSound(target, sfx_dsrptr); + target->health = -6666; + } + } + + // villsa [STRIFE] flame death stuff + if(!(target->flags & MF_NOBLOOD) + && inflictor + && (inflictor->type == MT_SFIREBALL || + inflictor->type == MT_C_FLAME || + inflictor->type == MT_PFLAME)) + { + target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SHADOW|MF_MVIS); + if(target->player) + { + target->player->cheats |= CF_ONFIRE; + target->player->powers[pw_communicator] = false; + target->player->readyweapon = 0; + P_SetPsprite(target->player, ps_weapon, S_WAVE_00); // 02 + P_SetPsprite(target->player, ps_flash, S_NULL); + } + + P_SetMobjState(target, S_BURN_00); // 349 + S_StartSound(target, sfx_burnme); + + return; + } + + P_KillMobj(source, target); + return; + } + + // villsa [STRIFE] set crash state + if(target->health <= 6 && target->info->crashstate) + { + P_SetMobjState(target, target->info->crashstate); + return; + } + + if(damage) + { + // villsa [STRIFE] removed unused skullfly flag + if(P_Random() < target->info->painchance) + { + target->flags |= MF_JUSTHIT; // fight back! + P_SetMobjState (target, target->info->painstate); + } + } + + target->reactiontime = 0; // we're awake now... + + // villsa [STRIFE] new checks for thing types + if (target->type != MT_PROGRAMMER + && (!target->threshold || target->type == MT_ENTITY) + && source && source != target + && source->type != MT_ENTITY + && ((source->flags & MF_ALLY) != (target->flags & MF_ALLY))) + { + // if not intent on another player, + // chase after this one + target->target = source; + target->threshold = BASETHRESHOLD; + + if(target->state == &states[target->info->spawnstate] + && target->info->seestate != S_NULL) + P_SetMobjState (target, target->info->seestate); + } +} + |