doom3-bfg/doomclassic/doom/p_inter.cpp

1278 lines
24 KiB
C++
Raw Normal View History

2012-11-26 18:58:24 +00:00
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
2022-09-05 20:25:33 +00:00
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
2012-11-26 18:58:24 +00:00
Doom 3 BFG Edition Source Code 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 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "Precompiled.h"
#include "globaldata.h"
// Data.
#include "doomdef.h"
#include "dstrings.h"
#include "sounds.h"
#include "doomstat.h"
#include "m_random.h"
#include "i_system.h"
#include "am_map.h"
#include "p_local.h"
#include "s_sound.h"
#ifdef __GNUG__
2022-09-05 20:25:33 +00:00
#pragma implementation "p_inter.h"
2012-11-26 18:58:24 +00:00
#endif
#include "p_inter.h"
#include "Main.h"
#include "sys/sys_signin.h"
#include "../../neo/d3xp/Game_local.h"
2012-11-26 18:58:24 +00:00
// a weapon is found with two clip loads,
// a big item has five clip loads
const int maxammo[NUMAMMO] = {200, 50, 300, 50};
const 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
//
qboolean
P_GiveAmmo
( player_t* player,
2022-09-05 20:25:33 +00:00
ammotype_t ammo,
int num )
2012-11-26 18:58:24 +00:00
{
int oldammo;
2022-09-05 20:25:33 +00:00
if( ammo == am_noammo )
{
2012-11-26 18:58:24 +00:00
return false;
2022-09-05 20:25:33 +00:00
}
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
if( ammo < 0 || ammo > NUMAMMO )
{
I_Error( "P_GiveAmmo: bad type %i", ammo );
}
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
if( player->ammo[ammo] == player->maxammo[ammo] )
{
2012-11-26 18:58:24 +00:00
return false;
2022-09-05 20:25:33 +00:00
}
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
if( num )
{
2012-11-26 18:58:24 +00:00
num *= clipammo[ammo];
2022-09-05 20:25:33 +00:00
}
2012-11-26 18:58:24 +00:00
else
2022-09-05 20:25:33 +00:00
{
num = clipammo[ammo] / 2;
}
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
if( ::g->gameskill == sk_baby
|| ::g->gameskill == sk_nightmare )
2012-11-26 18:58:24 +00:00
{
// give double ammo in trainer mode,
// you'll need in nightmare
num <<= 1;
}
oldammo = player->ammo[ammo];
player->ammo[ammo] += num;
2022-09-05 20:25:33 +00:00
if( player->ammo[ammo] > player->maxammo[ammo] )
{
2012-11-26 18:58:24 +00:00
player->ammo[ammo] = player->maxammo[ammo];
2022-09-05 20:25:33 +00:00
}
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
// If non zero ammo,
2012-11-26 18:58:24 +00:00
// don't change up weapons,
// player was lower on purpose.
2022-09-05 20:25:33 +00:00
if( oldammo )
{
return true;
}
2012-11-26 18:58:24 +00:00
// We were down to zero,
// so select a new weapon.
// Preferences are not user selectable.
2022-09-05 20:25:33 +00:00
switch( ammo )
2012-11-26 18:58:24 +00:00
{
2022-09-05 20:25:33 +00:00
case am_clip:
if( player->readyweapon == wp_fist )
{
if( player->weaponowned[wp_chaingun] )
{
player->pendingweapon = wp_chaingun;
}
else
{
player->pendingweapon = wp_pistol;
}
}
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case am_shell:
if( player->readyweapon == wp_fist
|| player->readyweapon == wp_pistol )
{
if( player->weaponowned[wp_shotgun] )
{
player->pendingweapon = wp_shotgun;
}
}
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case am_cell:
if( player->readyweapon == wp_fist
|| player->readyweapon == wp_pistol )
{
if( player->weaponowned[wp_plasma] )
{
player->pendingweapon = wp_plasma;
}
}
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case am_misl:
if( player->readyweapon == wp_fist )
{
if( player->weaponowned[wp_missile] )
{
player->pendingweapon = wp_missile;
}
}
default:
break;
2012-11-26 18:58:24 +00:00
}
return true;
}
//
// P_GiveWeapon
// The weapon name may have a MF_DROPPED flag ored in.
//
qboolean
P_GiveWeapon
( player_t* player,
2022-09-05 20:25:33 +00:00
weapontype_t weapon,
qboolean dropped )
2012-11-26 18:58:24 +00:00
{
qboolean gaveammo;
qboolean gaveweapon;
2022-09-05 20:25:33 +00:00
if( ::g->netgame
&& ( ::g->deathmatch != 2 )
&& !dropped )
2012-11-26 18:58:24 +00:00
{
// leave placed weapons forever on net games
2022-09-05 20:25:33 +00:00
if( player->weaponowned[weapon] )
{
2012-11-26 18:58:24 +00:00
return false;
2022-09-05 20:25:33 +00:00
}
2012-11-26 18:58:24 +00:00
player->bonuscount += BONUSADD;
player->weaponowned[weapon] = true;
2022-09-05 20:25:33 +00:00
if( ::g->deathmatch )
{
P_GiveAmmo( player, weaponinfo[weapon].ammo, 5 );
}
2012-11-26 18:58:24 +00:00
else
2022-09-05 20:25:33 +00:00
{
P_GiveAmmo( player, weaponinfo[weapon].ammo, 2 );
}
2012-11-26 18:58:24 +00:00
player->pendingweapon = weapon;
2022-09-05 20:25:33 +00:00
if( player == &::g->players[::g->consoleplayer] )
{
S_StartSound( player->mo, sfx_wpnup );
}
2012-11-26 18:58:24 +00:00
return false;
}
2022-09-05 20:25:33 +00:00
if( weaponinfo[weapon].ammo != am_noammo )
2012-11-26 18:58:24 +00:00
{
// give one clip with a dropped weapon,
// two clips with a found weapon
2022-09-05 20:25:33 +00:00
if( dropped )
{
gaveammo = P_GiveAmmo( player, weaponinfo[weapon].ammo, 1 );
}
2012-11-26 18:58:24 +00:00
else
2022-09-05 20:25:33 +00:00
{
gaveammo = P_GiveAmmo( player, weaponinfo[weapon].ammo, 2 );
}
2012-11-26 18:58:24 +00:00
}
else
2022-09-05 20:25:33 +00:00
{
2012-11-26 18:58:24 +00:00
gaveammo = false;
2022-09-05 20:25:33 +00:00
}
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
if( player->weaponowned[weapon] )
{
2012-11-26 18:58:24 +00:00
gaveweapon = false;
2022-09-05 20:25:33 +00:00
}
2012-11-26 18:58:24 +00:00
else
{
gaveweapon = true;
player->weaponowned[weapon] = true;
player->pendingweapon = weapon;
}
2022-09-05 20:25:33 +00:00
return ( gaveweapon || gaveammo );
2012-11-26 18:58:24 +00:00
}
//
// P_GiveBody
// Returns false if the body isn't needed at all
//
qboolean
P_GiveBody
( player_t* player,
2022-09-05 20:25:33 +00:00
int num )
2012-11-26 18:58:24 +00:00
{
2022-09-05 20:25:33 +00:00
if( player->health >= MAXHEALTH )
{
2012-11-26 18:58:24 +00:00
return false;
2022-09-05 20:25:33 +00:00
}
2012-11-26 18:58:24 +00:00
player->health += num;
2022-09-05 20:25:33 +00:00
if( player->health > MAXHEALTH )
{
2012-11-26 18:58:24 +00:00
player->health = MAXHEALTH;
2022-09-05 20:25:33 +00:00
}
2012-11-26 18:58:24 +00:00
player->mo->health = player->health;
return true;
}
//
// P_GiveArmor
// Returns false if the armor is worse
// than the current armor.
//
qboolean
P_GiveArmor
( player_t* player,
2022-09-05 20:25:33 +00:00
int armortype )
2012-11-26 18:58:24 +00:00
{
int hits;
2022-09-05 20:25:33 +00:00
hits = armortype * 100;
if( player->armorpoints >= hits )
{
return false; // don't pick up
}
2012-11-26 18:58:24 +00:00
player->armortype = armortype;
player->armorpoints = hits;
return true;
}
//
// P_GiveCard
//
2022-09-05 20:25:33 +00:00
void P_GiveCard( player_t* player, card_t card, const char* pickup_message )
{
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
if( ( ::g->demoplayback && ::g->netgame ) || common->IsMultiplayer() )
{
for( int i = 0; i < MAXPLAYERS; i++ )
{
if( ::g->playeringame[i] )
{
player_t* thePlayer = &::g->players[i];
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
if( thePlayer->cards[card] )
{
2012-11-26 18:58:24 +00:00
continue;
2022-09-05 20:25:33 +00:00
}
2012-11-26 18:58:24 +00:00
thePlayer->bonuscount = BONUSADD;
thePlayer->message = pickup_message;
thePlayer->cards[card] = 1;
}
}
2022-09-05 20:25:33 +00:00
}
else
{
if( player->cards[card] )
{
2012-11-26 18:58:24 +00:00
return;
2022-09-05 20:25:33 +00:00
}
2012-11-26 18:58:24 +00:00
player->bonuscount = BONUSADD;
player->message = pickup_message;
player->cards[card] = 1;
}
}
//
// P_GivePower
//
qboolean
P_GivePower
( player_t* player,
2022-09-05 20:25:33 +00:00
int /*powertype_t*/ power )
2012-11-26 18:58:24 +00:00
{
2022-09-05 20:25:33 +00:00
if( power == pw_invulnerability )
2012-11-26 18:58:24 +00:00
{
player->powers[power] = INVULNTICS;
return true;
}
2022-09-05 20:25:33 +00:00
if( power == pw_invisibility )
2012-11-26 18:58:24 +00:00
{
player->powers[power] = INVISTICS;
player->mo->flags |= MF_SHADOW;
return true;
}
2022-09-05 20:25:33 +00:00
if( power == pw_infrared )
2012-11-26 18:58:24 +00:00
{
player->powers[power] = INFRATICS;
return true;
}
2022-09-05 20:25:33 +00:00
if( power == pw_ironfeet )
2012-11-26 18:58:24 +00:00
{
player->powers[power] = IRONTICS;
return true;
}
2022-09-05 20:25:33 +00:00
if( power == pw_strength )
2012-11-26 18:58:24 +00:00
{
2022-09-05 20:25:33 +00:00
P_GiveBody( player, 100 );
2012-11-26 18:58:24 +00:00
player->powers[power] = 1;
return true;
}
2022-09-05 20:25:33 +00:00
if( player->powers[power] )
{
return false; // already got it
}
2012-11-26 18:58:24 +00:00
player->powers[power] = 1;
return true;
}
//
// P_TouchSpecialThing
//
void
P_TouchSpecialThing
( mobj_t* special,
2022-09-05 20:25:33 +00:00
mobj_t* toucher )
2012-11-26 18:58:24 +00:00
{
player_t* player;
int i;
fixed_t delta;
int sound;
delta = special->z - toucher->z;
2022-09-05 20:25:33 +00:00
if( delta > toucher->height
|| delta < -8 * FRACUNIT )
2012-11-26 18:58:24 +00:00
{
// out of reach
return;
}
2022-09-05 20:25:33 +00:00
sound = sfx_itemup;
2012-11-26 18:58:24 +00:00
player = toucher->player;
// Dead thing touching.
// Can happen with a sliding player corpse.
2022-09-05 20:25:33 +00:00
if( toucher->health <= 0 )
{
2012-11-26 18:58:24 +00:00
return;
2022-09-05 20:25:33 +00:00
}
2012-11-26 18:58:24 +00:00
// Identify by sprite.
2022-09-05 20:25:33 +00:00
switch( special->sprite )
2012-11-26 18:58:24 +00:00
{
// armor
2022-09-05 20:25:33 +00:00
case SPR_ARM1:
if( !P_GiveArmor( player, 1 ) )
{
return;
}
player->message = GOTARMOR;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_ARM2:
if( !P_GiveArmor( player, 2 ) )
{
return;
}
player->message = GOTMEGA;
break;
2012-11-26 18:58:24 +00:00
// bonus items
2022-09-05 20:25:33 +00:00
case SPR_BON1:
player->health++; // can go over 100%
if( player->health > 200 )
{
player->health = 200;
}
player->mo->health = player->health;
player->message = GOTHTHBONUS;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_BON2:
player->armorpoints++; // can go over 100%
if( player->armorpoints > 200 )
{
player->armorpoints = 200;
}
if( !player->armortype )
{
player->armortype = 1;
}
player->message = GOTARMBONUS;
break;
case SPR_SOUL:
player->health += 100;
if( player->health > 200 )
{
player->health = 200;
}
player->mo->health = player->health;
player->message = GOTSUPER;
sound = sfx_getpow;
break;
case SPR_MEGA:
if( ::g->gamemode != commercial )
{
return;
}
player->health = 200;
player->mo->health = player->health;
P_GiveArmor( player, 2 );
player->message = GOTMSPHERE;
sound = sfx_getpow;
break;
2012-11-26 18:58:24 +00:00
// cards
// leave cards for everyone
2022-09-05 20:25:33 +00:00
case SPR_BKEY:
//if (!player->cards[it_bluecard])
2012-11-26 18:58:24 +00:00
//player->message = GOTBLUECARD;
2022-09-05 20:25:33 +00:00
P_GiveCard( player, it_bluecard, GOTBLUECARD );
if( !::g->netgame )
{
break;
}
return;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_YKEY:
//if (!player->cards[it_yellowcard])
2012-11-26 18:58:24 +00:00
//player->message = GOTYELWCARD;
2022-09-05 20:25:33 +00:00
P_GiveCard( player, it_yellowcard, GOTYELWCARD );
if( !::g->netgame )
{
break;
}
return;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_RKEY:
//if (!player->cards[it_redcard])
2012-11-26 18:58:24 +00:00
//player->message = GOTREDCARD;
2022-09-05 20:25:33 +00:00
P_GiveCard( player, it_redcard, GOTREDCARD );
if( !::g->netgame )
{
break;
}
return;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_BSKU:
//if (!player->cards[it_blueskull])
2012-11-26 18:58:24 +00:00
//player->message = GOTBLUESKUL;
2022-09-05 20:25:33 +00:00
P_GiveCard( player, it_blueskull, GOTBLUESKUL );
if( !::g->netgame )
{
break;
}
return;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_YSKU:
//if (!player->cards[it_yellowskull])
2012-11-26 18:58:24 +00:00
//player->message = GOTYELWSKUL;
2022-09-05 20:25:33 +00:00
P_GiveCard( player, it_yellowskull, GOTYELWSKUL );
if( !::g->netgame )
{
break;
}
return;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_RSKU:
//if (!player->cards[it_redskull])
2012-11-26 18:58:24 +00:00
//player->message = GOTREDSKULL;
2022-09-05 20:25:33 +00:00
P_GiveCard( player, it_redskull, GOTREDSKULL );
if( !::g->netgame )
{
break;
}
return;
2012-11-26 18:58:24 +00:00
// medikits, heals
2022-09-05 20:25:33 +00:00
case SPR_STIM:
if( !P_GiveBody( player, 10 ) )
{
return;
}
player->message = GOTSTIM;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_MEDI:
if( !P_GiveBody( player, 25 ) )
{
return;
}
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
if( player->health < 25 )
{
player->message = GOTMEDINEED;
}
else
{
player->message = GOTMEDIKIT;
}
break;
2012-11-26 18:58:24 +00:00
// power ups
2022-09-05 20:25:33 +00:00
case SPR_PINV:
if( !P_GivePower( player, pw_invulnerability ) )
{
return;
}
player->message = GOTINVUL;
sound = sfx_getpow;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_PSTR:
if( !P_GivePower( player, pw_strength ) )
{
return;
}
player->message = GOTBERSERK;
if( player->readyweapon != wp_fist )
{
player->pendingweapon = wp_fist;
}
sound = sfx_getpow;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_PINS:
if( !P_GivePower( player, pw_invisibility ) )
{
return;
}
player->message = GOTINVIS;
sound = sfx_getpow;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_SUIT:
if( !P_GivePower( player, pw_ironfeet ) )
{
return;
}
player->message = GOTSUIT;
sound = sfx_getpow;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_PMAP:
if( !P_GivePower( player, pw_allmap ) )
{
2012-11-26 18:58:24 +00:00
return;
2022-09-05 20:25:33 +00:00
}
player->message = GOTMAP;
sound = sfx_getpow;
break;
case SPR_PVIS:
if( !P_GivePower( player, pw_infrared ) )
{
2012-11-26 18:58:24 +00:00
return;
2022-09-05 20:25:33 +00:00
}
player->message = GOTVISOR;
sound = sfx_getpow;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
// 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 = GOTCLIP;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_AMMO:
if( !P_GiveAmmo( player, am_clip, 5 ) )
{
return;
}
player->message = GOTCLIPBOX;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_ROCK:
if( !P_GiveAmmo( player, am_misl, 1 ) )
{
return;
}
player->message = GOTROCKET;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_BROK:
if( !P_GiveAmmo( player, am_misl, 5 ) )
{
return;
}
player->message = GOTROCKBOX;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_CELL:
if( !P_GiveAmmo( player, am_cell, 1 ) )
{
return;
}
player->message = GOTCELL;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_CELP:
if( !P_GiveAmmo( player, am_cell, 5 ) )
{
return;
}
player->message = GOTCELLBOX;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_SHEL:
if( !P_GiveAmmo( player, am_shell, 1 ) )
{
return;
}
player->message = GOTSHELLS;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_SBOX:
if( !P_GiveAmmo( player, am_shell, 5 ) )
{
return;
}
player->message = GOTSHELLBOX;
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, ( ammotype_t )i, 1 );
}
player->message = GOTBACKPACK;
break;
2012-11-26 18:58:24 +00:00
// weapons
2022-09-05 20:25:33 +00:00
case SPR_BFUG:
if( !P_GiveWeapon( player, wp_bfg, false ) )
{
return;
}
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
// DHM - Nerve :: Give achievement
if( !common->IsMultiplayer() )
{
switch( DoomLib::GetGameSKU() )
{
case GAME_SKU_DOOM2_BFG:
{
idAchievementManager::LocalUser_CompleteAchievement( ACHIEVEMENT_DOOM2_REALLY_BIG_GUN_FIND_BFG_SINGLEPLAYER );
}
default:
{
// No unlocks for other SKUs.
break;
}
2012-11-26 18:58:24 +00:00
}
}
2022-09-05 20:25:33 +00:00
player->message = GOTBFG9000;
sound = sfx_wpnup;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_MGUN:
if( !P_GiveWeapon( player, wp_chaingun, special->flags & MF_DROPPED ) )
{
return;
}
player->message = GOTCHAINGUN;
sound = sfx_wpnup;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_CSAW:
if( !P_GiveWeapon( player, wp_chainsaw, false ) )
{
return;
}
player->message = GOTCHAINSAW;
sound = sfx_wpnup;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_LAUN:
if( !P_GiveWeapon( player, wp_missile, false ) )
{
return;
}
player->message = GOTLAUNCHER;
sound = sfx_wpnup;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_PLAS:
if( !P_GiveWeapon( player, wp_plasma, false ) )
{
return;
}
player->message = GOTPLASMA;
sound = sfx_wpnup;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_SHOT:
if( !P_GiveWeapon( player, wp_shotgun, special->flags & MF_DROPPED ) )
{
return;
}
player->message = GOTSHOTGUN;
sound = sfx_wpnup;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case SPR_SGN2:
if( !P_GiveWeapon( player, wp_supershotgun, special->flags & MF_DROPPED ) )
{
return;
}
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
player->message = GOTSHOTGUN2;
sound = sfx_wpnup;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
default:
I_Error( "P_SpecialThing: Unknown gettable thing" );
2012-11-26 18:58:24 +00:00
}
2022-09-05 20:25:33 +00:00
if( special->flags & MF_COUNTITEM )
{
2012-11-26 18:58:24 +00:00
player->itemcount++;
2022-09-05 20:25:33 +00:00
}
P_RemoveMobj( special );
2012-11-26 18:58:24 +00:00
player->bonuscount += BONUSADD;
2022-09-05 20:25:33 +00:00
if( player == &::g->players[::g->consoleplayer] )
{
S_StartSound( player->mo, sound );
}
2012-11-26 18:58:24 +00:00
}
//
// IsOnlineDeathmatchWithLocalProfile
//
// Helper to simplify the online frag stat tracking. Returns the
// master user's profile if successful, NULL if not.
2022-09-05 20:25:33 +00:00
//
idPlayerProfile* IsOnlineDeathmatchWithLocalProfile()
{
if( !MatchTypeIsOnline( session->GetGameLobbyBase().GetMatchParms().matchFlags ) )
{
2012-11-26 18:58:24 +00:00
return NULL;
}
2022-09-05 20:25:33 +00:00
if( !::g )
{
2012-11-26 18:58:24 +00:00
return NULL;
}
2022-09-05 20:25:33 +00:00
if( !::g->deathmatch )
{
2012-11-26 18:58:24 +00:00
return NULL;
}
// Assume that the master local user is the one playing.
2022-09-05 20:25:33 +00:00
idLocalUser* user = session->GetSignInManager().GetMasterLocalUser();
if( user == NULL )
{
2012-11-26 18:58:24 +00:00
return NULL;
}
2022-09-05 20:25:33 +00:00
idPlayerProfile* profile = user->GetProfile();
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
if( profile == NULL )
{
2012-11-26 18:58:24 +00:00
return NULL;
}
2022-09-05 20:25:33 +00:00
2012-11-26 18:58:24 +00:00
return profile;
}
//
// KillMobj
//
void
P_KillMobj
( mobj_t* source,
2022-09-05 20:25:33 +00:00
mobj_t* target )
2012-11-26 18:58:24 +00:00
{
mobjtype_t item;
mobj_t* mo;
2022-09-05 20:25:33 +00:00
target->flags &= ~( MF_SHOOTABLE | MF_FLOAT | MF_SKULLFLY );
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
if( target->type != MT_SKULL )
{
2012-11-26 18:58:24 +00:00
target->flags &= ~MF_NOGRAVITY;
2022-09-05 20:25:33 +00:00
}
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
target->flags |= MF_CORPSE | MF_DROPOFF;
2012-11-26 18:58:24 +00:00
target->height >>= 2;
2022-09-05 20:25:33 +00:00
if( source && source->player )
2012-11-26 18:58:24 +00:00
{
// count for intermission
2022-09-05 20:25:33 +00:00
if( target->flags & MF_COUNTKILL )
{
source->player->killcount++;
}
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
if( target->player )
{
source->player->frags[target->player -::g->players]++;
2012-11-26 18:58:24 +00:00
// Keep track of the local player's total frags for trophy awards.
// Make sure the killing player is the local player
2022-09-05 20:25:33 +00:00
if( source->player == &( ::g->players[::g->consoleplayer] ) )
{
2012-11-26 18:58:24 +00:00
// Make sure this is an online game.
// TODO: PC
}
}
// DHM - Nerve :: Check for killing cyberdemon with fists achievement
// JAF TROPHY int port = gameLocal->GetPortForPlayer( DoomLib::GetPlayer() );
2022-09-05 20:25:33 +00:00
if( source->player->readyweapon == wp_fist && target->type == MT_CYBORG && !common->IsMultiplayer() )
{
switch( DoomLib::GetGameSKU() )
{
case GAME_SKU_DOOM2_BFG:
{
2012-11-26 18:58:24 +00:00
// Removing trophies for DOOM and DOOM II BFG due to point limit.
//gameLocal->UnlockAchievement( Doom2BFG_Trophies::YOU_HAVE_HUGE_GUTS_KILL_CYBERDEMON_WITH_FISTS );
break;
}
2022-09-05 20:25:33 +00:00
case GAME_SKU_DCC:
{
2012-11-26 18:58:24 +00:00
// Not for PC.
//session->GetAchievementSystem().AchievementUnlock( session->GetSignInManager().GetMasterLocalUser(), DOOM_ACHIEVEMENT_KILL_CYBER_DEMON_WITH_FISTS );
break;
}
2022-09-05 20:25:33 +00:00
default:
{
2012-11-26 18:58:24 +00:00
// No unlocks for other SKUs.
break;
}
}
}
// DHM - Nerve :: Chainsaw kills
2022-09-05 20:25:33 +00:00
if( source->player->readyweapon == wp_chainsaw && !common->IsMultiplayer() )
{
2012-11-26 18:58:24 +00:00
source->player->chainsawKills++;
2022-09-05 20:25:33 +00:00
if( source->player->chainsawKills == 20 )
{
switch( DoomLib::GetGameSKU() )
{
case GAME_SKU_DOOM2_BFG:
{
2012-11-26 18:58:24 +00:00
// Removing trophies for DOOM and DOOM II BFG due to point limit.
//gameLocal->UnlockAchievement( Doom2BFG_Trophies::GREAT_COMMUNICATOR_20_CHAINSAW_KILLS );
break;
}
2022-09-05 20:25:33 +00:00
case GAME_SKU_DCC:
{
2012-11-26 18:58:24 +00:00
// Not for PC.
//gameLocal->UnlockAchievement( DOOM_ACHIEVEMENT_20KILLS_CHAINSAW );
break;
}
2022-09-05 20:25:33 +00:00
default:
{
2012-11-26 18:58:24 +00:00
// No unlocks for other SKUs.
break;
}
}
}
}
// DHM - Nerve :: Berserker kills
2022-09-05 20:25:33 +00:00
if( source->player->readyweapon == wp_fist && source->player->powers[pw_strength] && !common->IsMultiplayer() )
{
2012-11-26 18:58:24 +00:00
source->player->berserkKills++;
idLib::Printf( "Player has %d berserk kills\n", source->player->berserkKills );
2022-09-05 20:25:33 +00:00
if( source->player->berserkKills == 20 )
{
switch( DoomLib::GetGameSKU() )
{
case GAME_SKU_DOOM2_BFG:
{
2012-11-26 18:58:24 +00:00
// Removing trophies for DOOM and DOOM II BFG due to point limit.
//gameLocal->UnlockAchievement( Doom2BFG_Trophies::MAN_AND_A_HALF_20_BERSERK_KILLS );
break;
}
2022-09-05 20:25:33 +00:00
case GAME_SKU_DCC:
{
2012-11-26 18:58:24 +00:00
// Not for PC.
//gameLocal->UnlockAchievement( DOOM_ACHIEVEMENT_20KILLS_BERSERKER );
break;
}
2022-09-05 20:25:33 +00:00
default:
{
2012-11-26 18:58:24 +00:00
// No unlocks for other SKUs.
break;
}
2022-09-05 20:25:33 +00:00
}
2012-11-26 18:58:24 +00:00
}
}
}
2022-09-05 20:25:33 +00:00
else if( !::g->netgame && ( target->flags & MF_COUNTKILL ) )
2012-11-26 18:58:24 +00:00
{
// count all monster deaths,
// even those caused by other monsters
::g->players[0].killcount++;
}
2022-09-05 20:25:33 +00:00
if( target->player )
2012-11-26 18:58:24 +00:00
{
// count environment kills against you
2022-09-05 20:25:33 +00:00
if( !source )
{
target->player->frags[target->player -::g->players]++;
}
2012-11-26 18:58:24 +00:00
target->flags &= ~MF_SOLID;
target->player->playerstate = PST_DEAD;
2022-09-05 20:25:33 +00:00
P_DropWeapon( target->player );
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
if( target->player == &::g->players[::g->consoleplayer]
&& ::g->automapactive )
2012-11-26 18:58:24 +00:00
{
// don't die in auto map,
// switch view prior to dying
2022-09-05 20:25:33 +00:00
AM_Stop();
2012-11-26 18:58:24 +00:00
}
}
2022-09-05 20:25:33 +00:00
if( target->health < -target->info->spawnhealth
&& target->info->xdeathstate )
2012-11-26 18:58:24 +00:00
{
2022-09-05 20:25:33 +00:00
P_SetMobjState( target, ( statenum_t )target->info->xdeathstate );
2012-11-26 18:58:24 +00:00
}
else
2022-09-05 20:25:33 +00:00
{
P_SetMobjState( target, ( statenum_t )target->info->deathstate );
}
target->tics -= P_Random() & 3;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
if( target->tics < 1 )
{
2012-11-26 18:58:24 +00:00
target->tics = 1;
2022-09-05 20:25:33 +00:00
}
2012-11-26 18:58:24 +00:00
// I_StartSound (&actor->r, actor->info->deathsound);
// Drop stuff.
// This determines the kind of object spawned
// during the death frame of a thing.
2022-09-05 20:25:33 +00:00
switch( target->type )
2012-11-26 18:58:24 +00:00
{
2022-09-05 20:25:33 +00:00
case MT_WOLFSS:
case MT_POSSESSED:
item = MT_CLIP;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case MT_SHOTGUY:
item = MT_SHOTGUN;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
case MT_CHAINGUY:
item = MT_CHAINGUN;
break;
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
default:
return;
2012-11-26 18:58:24 +00:00
}
2022-09-05 20:25:33 +00:00
mo = P_SpawnMobj( target->x, target->y, ONFLOORZ, item );
2012-11-26 18:58:24 +00:00
mo->flags |= MF_DROPPED; // special versions of items
}
//
// P_DamageMobj
// Damages both enemies and ::g->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,
2022-09-05 20:25:33 +00:00
mobj_t* inflictor,
mobj_t* source,
int damage )
2012-11-26 18:58:24 +00:00
{
unsigned ang;
int saved;
player_t* player;
fixed_t thrust;
int temp;
2022-09-05 20:25:33 +00:00
if( !( target->flags & MF_SHOOTABLE ) )
{
return; // shouldn't happen...
}
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
if( target->health <= 0 )
{
2012-11-26 18:58:24 +00:00
return;
2022-09-05 20:25:33 +00:00
}
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
if( target->flags & MF_SKULLFLY )
2012-11-26 18:58:24 +00:00
{
target->momx = target->momy = target->momz = 0;
}
player = target->player;
2022-09-05 20:25:33 +00:00
if( player && ::g->gameskill == sk_baby )
{
damage >>= 1; // take half damage in trainer mode
}
2012-11-26 18:58:24 +00:00
// Some close combat weapons should not
// inflict thrust and push the victim out of reach,
// thus kick away unless using the chainsaw.
2022-09-05 20:25:33 +00:00
if( inflictor
&& !( target->flags & MF_NOCLIP )
&& ( !source
|| !source->player
|| source->player->readyweapon != wp_chainsaw ) )
2012-11-26 18:58:24 +00:00
{
2022-09-05 20:25:33 +00:00
ang = R_PointToAngle2( inflictor->x,
inflictor->y,
target->x,
target->y );
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
thrust = damage * ( FRACUNIT >> 3 ) * 100 / target->info->mass;
2012-11-26 18:58:24 +00:00
// make fall forwards sometimes
2022-09-05 20:25:33 +00:00
if( damage < 40
&& damage > target->health
&& target->z - inflictor->z > 64 * FRACUNIT
&& ( P_Random() & 1 ) )
2012-11-26 18:58:24 +00:00
{
ang += ANG180;
thrust *= 4;
}
ang >>= ANGLETOFINESHIFT;
2022-09-05 20:25:33 +00:00
target->momx += FixedMul( thrust, finecosine[ang] );
target->momy += FixedMul( thrust, finesine[ang] );
2012-11-26 18:58:24 +00:00
}
// player specific
2022-09-05 20:25:33 +00:00
if( player )
{
2012-11-26 18:58:24 +00:00
// end of game hell hack
2022-09-05 20:25:33 +00:00
if( target->subsector->sector->special == 11
&& damage >= target->health )
2012-11-26 18:58:24 +00:00
{
damage = target->health - 1;
}
float baseShake_High = 0.5f;
int baseShake_High_Dur = 100;
float baseShake_Low = 0.5f;
int baseShake_Low_Dur = 100;
2022-09-05 20:25:33 +00:00
int damageClamp = Min( damage, 100 );
float damageFloat = std::min( ( float )damageClamp / 100.0f, 100.0f );
2012-11-26 18:58:24 +00:00
float additional = 0.5f * damageFloat;
int additional_time = 500.0f * damageFloat;
2022-09-05 20:25:33 +00:00
if( ::g->plyr == player )
{
2012-11-26 18:58:24 +00:00
}
// Below certain threshold,
// ignore damage in GOD mode, or with INVUL power.
2022-09-05 20:25:33 +00:00
if( damage < 1000
&& ( ( player->cheats & CF_GODMODE )
|| player->powers[pw_invulnerability] ) )
2012-11-26 18:58:24 +00:00
{
return;
}
2022-09-05 20:25:33 +00:00
if( player->armortype )
2012-11-26 18:58:24 +00:00
{
2022-09-05 20:25:33 +00:00
if( player->armortype == 1 )
{
saved = damage / 3;
}
2012-11-26 18:58:24 +00:00
else
2022-09-05 20:25:33 +00:00
{
saved = damage / 2;
}
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
if( player->armorpoints <= saved )
2012-11-26 18:58:24 +00:00
{
// armor is used up
saved = player->armorpoints;
player->armortype = 0;
}
player->armorpoints -= saved;
damage -= saved;
}
player->health -= damage; // mirror mobj health here for Dave
2022-09-05 20:25:33 +00:00
if( player->health < 0 )
{
2012-11-26 18:58:24 +00:00
player->health = 0;
2022-09-05 20:25:33 +00:00
}
2012-11-26 18:58:24 +00:00
player->attacker = source;
player->damagecount += damage; // add damage after armor / invuln
2022-09-05 20:25:33 +00:00
if( player->damagecount > 100 )
{
player->damagecount = 100; // teleport stomp does 10k points...
}
2012-11-26 18:58:24 +00:00
temp = damage < 100 ? damage : 100;
}
2022-09-05 20:25:33 +00:00
// do the damage
target->health -= damage;
if( target->health <= 0 )
2012-11-26 18:58:24 +00:00
{
2022-09-05 20:25:33 +00:00
P_KillMobj( source, target );
2012-11-26 18:58:24 +00:00
return;
}
2022-09-05 20:25:33 +00:00
if( ( P_Random() < target->info->painchance )
&& !( target->flags & MF_SKULLFLY ) )
2012-11-26 18:58:24 +00:00
{
target->flags |= MF_JUSTHIT; // fight back!
2022-09-05 20:25:33 +00:00
P_SetMobjState( target, ( statenum_t )target->info->painstate );
2012-11-26 18:58:24 +00:00
}
2022-09-05 20:25:33 +00:00
target->reactiontime = 0; // we're awake now...
2012-11-26 18:58:24 +00:00
2022-09-05 20:25:33 +00:00
if( ( !target->threshold || target->type == MT_VILE )
&& source && source != target
&& source->type != MT_VILE )
2012-11-26 18:58:24 +00:00
{
// if not intent on another player,
// chase after this one
target->target = source;
target->threshold = BASETHRESHOLD;
2022-09-05 20:25:33 +00:00
if( target->state == &::g->states[target->info->spawnstate]
&& target->info->seestate != S_NULL )
{
P_SetMobjState( target, ( statenum_t )target->info->seestate );
}
2012-11-26 18:58:24 +00:00
}
}