DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

p_inter.cpp (22946B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 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.
     23 
     24 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.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #include "Precompiled.h"
     30 #include "globaldata.h"
     31 
     32 
     33 // Data.
     34 #include "doomdef.h"
     35 #include "dstrings.h"
     36 #include "sounds.h"
     37 
     38 #include "doomstat.h"
     39 
     40 #include "m_random.h"
     41 #include "i_system.h"
     42 
     43 #include "am_map.h"
     44 
     45 #include "p_local.h"
     46 
     47 #include "s_sound.h"
     48 
     49 #ifdef __GNUG__
     50 #pragma implementation "p_inter.h"
     51 #endif
     52 #include "p_inter.h"
     53 
     54 #include "Main.h"
     55 
     56 #include "sys/sys_signin.h"
     57 
     58 #include "../../neo/d3xp/Game_Local.h"
     59 
     60 // a weapon is found with two clip loads,
     61 // a big item has five clip loads
     62 const int	maxammo[NUMAMMO] = {200, 50, 300, 50};
     63 const int	clipammo[NUMAMMO] = {10, 4, 20, 1};
     64 
     65 
     66 //
     67 // GET STUFF
     68 //
     69 
     70 //
     71 // P_GiveAmmo
     72 // Num is the number of clip loads,
     73 // not the individual count (0= 1/2 clip).
     74 // Returns false if the ammo can't be picked up at all
     75 //
     76 
     77 qboolean
     78 P_GiveAmmo
     79 ( player_t*	player,
     80  ammotype_t	ammo,
     81  int		num )
     82 {
     83 	int		oldammo;
     84 
     85 	if (ammo == am_noammo)
     86 		return false;
     87 
     88 	if (ammo < 0 || ammo > NUMAMMO)
     89 		I_Error ("P_GiveAmmo: bad type %i", ammo);
     90 
     91 	if ( player->ammo[ammo] == player->maxammo[ammo]  )
     92 		return false;
     93 
     94 	if (num)
     95 		num *= clipammo[ammo];
     96 	else
     97 		num = clipammo[ammo]/2;
     98 
     99 	if (::g->gameskill == sk_baby
    100 		|| ::g->gameskill == sk_nightmare)
    101 	{
    102 		// give double ammo in trainer mode,
    103 		// you'll need in nightmare
    104 		num <<= 1;
    105 	}
    106 
    107 
    108 	oldammo = player->ammo[ammo];
    109 	player->ammo[ammo] += num;
    110 
    111 	if (player->ammo[ammo] > player->maxammo[ammo])
    112 		player->ammo[ammo] = player->maxammo[ammo];
    113 
    114 	// If non zero ammo, 
    115 	// don't change up weapons,
    116 	// player was lower on purpose.
    117 	if (oldammo)
    118 		return true;	
    119 
    120 	// We were down to zero,
    121 	// so select a new weapon.
    122 	// Preferences are not user selectable.
    123 	switch (ammo)
    124 	{
    125 	case am_clip:
    126 		if (player->readyweapon == wp_fist)
    127 		{
    128 			if (player->weaponowned[wp_chaingun])
    129 				player->pendingweapon = wp_chaingun;
    130 			else
    131 				player->pendingweapon = wp_pistol;
    132 		}
    133 		break;
    134 
    135 	case am_shell:
    136 		if (player->readyweapon == wp_fist
    137 			|| player->readyweapon == wp_pistol)
    138 		{
    139 			if (player->weaponowned[wp_shotgun])
    140 				player->pendingweapon = wp_shotgun;
    141 		}
    142 		break;
    143 
    144 	case am_cell:
    145 		if (player->readyweapon == wp_fist
    146 			|| player->readyweapon == wp_pistol)
    147 		{
    148 			if (player->weaponowned[wp_plasma])
    149 				player->pendingweapon = wp_plasma;
    150 		}
    151 		break;
    152 
    153 	case am_misl:
    154 		if (player->readyweapon == wp_fist)
    155 		{
    156 			if (player->weaponowned[wp_missile])
    157 				player->pendingweapon = wp_missile;
    158 		}
    159 	default:
    160 		break;
    161 	}
    162 
    163 	return true;
    164 }
    165 
    166 
    167 //
    168 // P_GiveWeapon
    169 // The weapon name may have a MF_DROPPED flag ored in.
    170 //
    171 qboolean
    172 P_GiveWeapon
    173 ( player_t*	player,
    174  weapontype_t	weapon,
    175  qboolean	dropped )
    176 {
    177 	qboolean	gaveammo;
    178 	qboolean	gaveweapon;
    179 
    180 	if (::g->netgame
    181 		&& (::g->deathmatch!=2)
    182 		&& !dropped )
    183 	{
    184 		// leave placed weapons forever on net games
    185 		if (player->weaponowned[weapon])
    186 			return false;
    187 
    188 		player->bonuscount += BONUSADD;
    189 		player->weaponowned[weapon] = true;
    190 
    191 		if (::g->deathmatch)
    192 			P_GiveAmmo (player, weaponinfo[weapon].ammo, 5);
    193 		else
    194 			P_GiveAmmo (player, weaponinfo[weapon].ammo, 2);
    195 		player->pendingweapon = weapon;
    196 
    197 		if (player == &::g->players[::g->consoleplayer])
    198 			S_StartSound (player->mo, sfx_wpnup);
    199 		return false;
    200 	}
    201 
    202 	if (weaponinfo[weapon].ammo != am_noammo)
    203 	{
    204 		// give one clip with a dropped weapon,
    205 		// two clips with a found weapon
    206 		if (dropped)
    207 			gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 1);
    208 		else
    209 			gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 2);
    210 	}
    211 	else
    212 		gaveammo = false;
    213 
    214 	if (player->weaponowned[weapon])
    215 		gaveweapon = false;
    216 	else
    217 	{
    218 		gaveweapon = true;
    219 		player->weaponowned[weapon] = true;
    220 		player->pendingweapon = weapon;
    221 	}
    222 
    223 	return (gaveweapon || gaveammo);
    224 }
    225 
    226 
    227 
    228 //
    229 // P_GiveBody
    230 // Returns false if the body isn't needed at all
    231 //
    232 qboolean
    233 P_GiveBody
    234 ( player_t*	player,
    235  int		num )
    236 {
    237 	if (player->health >= MAXHEALTH)
    238 		return false;
    239 
    240 	player->health += num;
    241 	if (player->health > MAXHEALTH)
    242 		player->health = MAXHEALTH;
    243 	player->mo->health = player->health;
    244 
    245 	return true;
    246 }
    247 
    248 
    249 
    250 //
    251 // P_GiveArmor
    252 // Returns false if the armor is worse
    253 // than the current armor.
    254 //
    255 qboolean
    256 P_GiveArmor
    257 ( player_t*	player,
    258  int		armortype )
    259 {
    260 	int		hits;
    261 
    262 	hits = armortype*100;
    263 	if (player->armorpoints >= hits)
    264 		return false;	// don't pick up
    265 
    266 	player->armortype = armortype;
    267 	player->armorpoints = hits;
    268 
    269 	return true;
    270 }
    271 
    272 
    273 
    274 //
    275 // P_GiveCard
    276 //
    277 void P_GiveCard( player_t* player, card_t card, const char *pickup_message ) {
    278 
    279 	if ( ( ::g->demoplayback && ::g->netgame ) || common->IsMultiplayer() ) {
    280 		for ( int i=0; i < MAXPLAYERS; i++ ) {
    281 			if ( ::g->playeringame[i] ) {
    282 				player_t *thePlayer = &::g->players[i];
    283 
    284 				if (thePlayer->cards[card])
    285 					continue;
    286 
    287 				thePlayer->bonuscount = BONUSADD;
    288 				thePlayer->message = pickup_message;
    289 				thePlayer->cards[card] = 1;
    290 			}
    291 		}
    292 	} else {
    293 		if (player->cards[card])
    294 			return;
    295 
    296 		player->bonuscount = BONUSADD;
    297 		player->message = pickup_message;
    298 		player->cards[card] = 1;
    299 	}
    300 }
    301 
    302 
    303 //
    304 // P_GivePower
    305 //
    306 qboolean
    307 P_GivePower
    308 ( player_t*	player,
    309  int /*powertype_t*/	power )
    310 {
    311 	if (power == pw_invulnerability)
    312 	{
    313 		player->powers[power] = INVULNTICS;
    314 		return true;
    315 	}
    316 
    317 	if (power == pw_invisibility)
    318 	{
    319 		player->powers[power] = INVISTICS;
    320 		player->mo->flags |= MF_SHADOW;
    321 		return true;
    322 	}
    323 
    324 	if (power == pw_infrared)
    325 	{
    326 		player->powers[power] = INFRATICS;
    327 		return true;
    328 	}
    329 
    330 	if (power == pw_ironfeet)
    331 	{
    332 		player->powers[power] = IRONTICS;
    333 		return true;
    334 	}
    335 
    336 	if (power == pw_strength)
    337 	{
    338 		P_GiveBody (player, 100);
    339 		player->powers[power] = 1;
    340 		return true;
    341 	}
    342 
    343 	if (player->powers[power])
    344 		return false;	// already got it
    345 
    346 	player->powers[power] = 1;
    347 	return true;
    348 }
    349 
    350 
    351 
    352 //
    353 // P_TouchSpecialThing
    354 //
    355 void
    356 P_TouchSpecialThing
    357 ( mobj_t*	special,
    358  mobj_t*	toucher )
    359 {
    360 	player_t*	player;
    361 	int		i;
    362 	fixed_t	delta;
    363 	int		sound;
    364 
    365 	delta = special->z - toucher->z;
    366 
    367 	if (delta > toucher->height
    368 		|| delta < -8*FRACUNIT)
    369 	{
    370 		// out of reach
    371 		return;
    372 	}
    373 
    374 
    375 	sound = sfx_itemup;	
    376 	player = toucher->player;
    377 
    378 	// Dead thing touching.
    379 	// Can happen with a sliding player corpse.
    380 	if (toucher->health <= 0)
    381 		return;
    382 
    383 	// Identify by sprite.
    384 	switch (special->sprite)
    385 	{
    386 		// armor
    387 	case SPR_ARM1:
    388 		if (!P_GiveArmor (player, 1))
    389 			return;
    390 		player->message = GOTARMOR;
    391 		break;
    392 
    393 	case SPR_ARM2:
    394 		if (!P_GiveArmor (player, 2))
    395 			return;
    396 		player->message = GOTMEGA;
    397 		break;
    398 
    399 		// bonus items
    400 	case SPR_BON1:
    401 		player->health++;		// can go over 100%
    402 		if (player->health > 200)
    403 			player->health = 200;
    404 		player->mo->health = player->health;
    405 		player->message = GOTHTHBONUS;
    406 		break;
    407 
    408 	case SPR_BON2:
    409 		player->armorpoints++;		// can go over 100%
    410 		if (player->armorpoints > 200)
    411 			player->armorpoints = 200;
    412 		if (!player->armortype)
    413 			player->armortype = 1;
    414 		player->message = GOTARMBONUS;
    415 		break;
    416 
    417 	case SPR_SOUL:
    418 		player->health += 100;
    419 		if (player->health > 200)
    420 			player->health = 200;
    421 		player->mo->health = player->health;
    422 		player->message = GOTSUPER;
    423 		sound = sfx_getpow;
    424 		break;
    425 
    426 	case SPR_MEGA:
    427 		if (::g->gamemode != commercial)
    428 			return;
    429 		player->health = 200;
    430 		player->mo->health = player->health;
    431 		P_GiveArmor (player,2);
    432 		player->message = GOTMSPHERE;
    433 		sound = sfx_getpow;
    434 		break;
    435 
    436 		// cards
    437 		// leave cards for everyone
    438 	case SPR_BKEY:
    439 		//if (!player->cards[it_bluecard])
    440 			//player->message = GOTBLUECARD;
    441 		P_GiveCard (player, it_bluecard, GOTBLUECARD);
    442 		if (!::g->netgame)
    443 			break;
    444 		return;
    445 
    446 	case SPR_YKEY:
    447 		//if (!player->cards[it_yellowcard])
    448 			//player->message = GOTYELWCARD;
    449 		P_GiveCard (player, it_yellowcard, GOTYELWCARD);
    450 		if (!::g->netgame)
    451 			break;
    452 		return;
    453 
    454 	case SPR_RKEY:
    455 		//if (!player->cards[it_redcard])
    456 			//player->message = GOTREDCARD;
    457 		P_GiveCard (player, it_redcard, GOTREDCARD);
    458 		if (!::g->netgame)
    459 			break;
    460 		return;
    461 
    462 	case SPR_BSKU:
    463 		//if (!player->cards[it_blueskull])
    464 			//player->message = GOTBLUESKUL;
    465 		P_GiveCard (player, it_blueskull, GOTBLUESKUL);
    466 		if (!::g->netgame)
    467 			break;
    468 		return;
    469 
    470 	case SPR_YSKU:
    471 		//if (!player->cards[it_yellowskull])
    472 			//player->message = GOTYELWSKUL;
    473 		P_GiveCard (player, it_yellowskull, GOTYELWSKUL);
    474 		if (!::g->netgame)
    475 			break;
    476 		return;
    477 
    478 	case SPR_RSKU:
    479 		//if (!player->cards[it_redskull])
    480 			//player->message = GOTREDSKULL;
    481 		P_GiveCard (player, it_redskull, GOTREDSKULL);
    482 		if (!::g->netgame)
    483 			break;
    484 		return;
    485 
    486 		// medikits, heals
    487 	case SPR_STIM:
    488 		if (!P_GiveBody (player, 10))
    489 			return;
    490 		player->message = GOTSTIM;
    491 		break;
    492 
    493 	case SPR_MEDI:
    494 		if (!P_GiveBody (player, 25))
    495 			return;
    496 
    497 		if (player->health < 25)
    498 			player->message = GOTMEDINEED;
    499 		else
    500 			player->message = GOTMEDIKIT;
    501 		break;
    502 
    503 
    504 		// power ups
    505 	case SPR_PINV:
    506 		if (!P_GivePower (player, pw_invulnerability))
    507 			return;
    508 		player->message = GOTINVUL;
    509 		sound = sfx_getpow;
    510 		break;
    511 
    512 	case SPR_PSTR:
    513 		if (!P_GivePower (player, pw_strength))
    514 			return;
    515 		player->message = GOTBERSERK;
    516 		if (player->readyweapon != wp_fist)
    517 			player->pendingweapon = wp_fist;
    518 		sound = sfx_getpow;
    519 		break;
    520 
    521 	case SPR_PINS:
    522 		if (!P_GivePower (player, pw_invisibility))
    523 			return;
    524 		player->message = GOTINVIS;
    525 		sound = sfx_getpow;
    526 		break;
    527 
    528 	case SPR_SUIT:
    529 		if (!P_GivePower (player, pw_ironfeet))
    530 			return;
    531 		player->message = GOTSUIT;
    532 		sound = sfx_getpow;
    533 		break;
    534 
    535 	case SPR_PMAP:
    536 		if (!P_GivePower (player, pw_allmap))
    537 			return;
    538 		player->message = GOTMAP;
    539 		sound = sfx_getpow;
    540 		break;
    541 
    542 	case SPR_PVIS:
    543 		if (!P_GivePower (player, pw_infrared))
    544 			return;
    545 		player->message = GOTVISOR;
    546 		sound = sfx_getpow;
    547 		break;
    548 
    549 		// ammo
    550 	case SPR_CLIP:
    551 		if (special->flags & MF_DROPPED)
    552 		{
    553 			if (!P_GiveAmmo (player,am_clip,0))
    554 				return;
    555 		}
    556 		else
    557 		{
    558 			if (!P_GiveAmmo (player,am_clip,1))
    559 				return;
    560 		}
    561 		player->message = GOTCLIP;
    562 		break;
    563 
    564 	case SPR_AMMO:
    565 		if (!P_GiveAmmo (player, am_clip,5))
    566 			return;
    567 		player->message = GOTCLIPBOX;
    568 		break;
    569 
    570 	case SPR_ROCK:
    571 		if (!P_GiveAmmo (player, am_misl,1))
    572 			return;
    573 		player->message = GOTROCKET;
    574 		break;
    575 
    576 	case SPR_BROK:
    577 		if (!P_GiveAmmo (player, am_misl,5))
    578 			return;
    579 		player->message = GOTROCKBOX;
    580 		break;
    581 
    582 	case SPR_CELL:
    583 		if (!P_GiveAmmo (player, am_cell,1))
    584 			return;
    585 		player->message = GOTCELL;
    586 		break;
    587 
    588 	case SPR_CELP:
    589 		if (!P_GiveAmmo (player, am_cell,5))
    590 			return;
    591 		player->message = GOTCELLBOX;
    592 		break;
    593 
    594 	case SPR_SHEL:
    595 		if (!P_GiveAmmo (player, am_shell,1))
    596 			return;
    597 		player->message = GOTSHELLS;
    598 		break;
    599 
    600 	case SPR_SBOX:
    601 		if (!P_GiveAmmo (player, am_shell,5))
    602 			return;
    603 		player->message = GOTSHELLBOX;
    604 		break;
    605 
    606 	case SPR_BPAK:
    607 		if (!player->backpack)
    608 		{
    609 			for (i=0 ; i<NUMAMMO ; i++)
    610 				player->maxammo[i] *= 2;
    611 			player->backpack = true;
    612 		}
    613 		for (i=0 ; i<NUMAMMO ; i++)
    614 			P_GiveAmmo (player, (ammotype_t)i, 1);
    615 		player->message = GOTBACKPACK;
    616 		break;
    617 
    618 		// weapons
    619 	case SPR_BFUG:
    620 		if (!P_GiveWeapon (player, wp_bfg, false) )
    621 			return;
    622 
    623 		// DHM - Nerve :: Give achievement
    624 		if ( !common->IsMultiplayer() ) {
    625 			switch( DoomLib::GetGameSKU() ) {
    626 				case GAME_SKU_DOOM2_BFG: {
    627 					idAchievementManager::LocalUser_CompleteAchievement( ACHIEVEMENT_DOOM2_REALLY_BIG_GUN_FIND_BFG_SINGLEPLAYER );
    628 				}
    629 				default: {
    630 					// No unlocks for other SKUs.
    631 					break;
    632 				}
    633 			}
    634 		}
    635 
    636 		player->message = GOTBFG9000;
    637 		sound = sfx_wpnup;	
    638 		break;
    639 
    640 	case SPR_MGUN:
    641 		if (!P_GiveWeapon (player, wp_chaingun, special->flags&MF_DROPPED) )
    642 			return;
    643 		player->message = GOTCHAINGUN;
    644 		sound = sfx_wpnup;	
    645 		break;
    646 
    647 	case SPR_CSAW:
    648 		if (!P_GiveWeapon (player, wp_chainsaw, false) )
    649 			return;
    650 		player->message = GOTCHAINSAW;
    651 		sound = sfx_wpnup;	
    652 		break;
    653 
    654 	case SPR_LAUN:
    655 		if (!P_GiveWeapon (player, wp_missile, false) )
    656 			return;
    657 		player->message = GOTLAUNCHER;
    658 		sound = sfx_wpnup;	
    659 		break;
    660 
    661 	case SPR_PLAS:
    662 		if (!P_GiveWeapon (player, wp_plasma, false) )
    663 			return;
    664 		player->message = GOTPLASMA;
    665 		sound = sfx_wpnup;	
    666 		break;
    667 
    668 	case SPR_SHOT:
    669 		if (!P_GiveWeapon (player, wp_shotgun, special->flags&MF_DROPPED ) )
    670 			return;
    671 		player->message = GOTSHOTGUN;
    672 		sound = sfx_wpnup;	
    673 		break;
    674 
    675 	case SPR_SGN2:
    676 		if (!P_GiveWeapon (player, wp_supershotgun, special->flags&MF_DROPPED ) )
    677 			return;
    678 
    679 		player->message = GOTSHOTGUN2;
    680 		sound = sfx_wpnup;	
    681 		break;
    682 
    683 	default:
    684 		I_Error ("P_SpecialThing: Unknown gettable thing");
    685 	}
    686 
    687 	if (special->flags & MF_COUNTITEM)
    688 		player->itemcount++;
    689 	P_RemoveMobj (special);
    690 	player->bonuscount += BONUSADD;
    691 	if (player == &::g->players[::g->consoleplayer])
    692 		S_StartSound (player->mo, sound);
    693 }
    694 
    695 //
    696 // IsOnlineDeathmatchWithLocalProfile
    697 //
    698 // Helper to simplify the online frag stat tracking. Returns the
    699 // master user's profile if successful, NULL if not.
    700 // 
    701 idPlayerProfile * IsOnlineDeathmatchWithLocalProfile() {
    702 	if ( !MatchTypeIsOnline( session->GetGameLobbyBase().GetMatchParms().matchFlags ) ) {
    703 		return NULL;
    704 	}
    705 
    706 	if ( !::g ) {
    707 		return NULL;
    708 	}
    709 
    710 	if ( !::g->deathmatch ) {
    711 		return NULL;
    712 	}
    713 
    714 	// Assume that the master local user is the one playing.
    715 	idLocalUser * user = session->GetSignInManager().GetMasterLocalUser();
    716 	if ( user == NULL ) {
    717 		return NULL;
    718 	}
    719 
    720 	idPlayerProfile * profile = user->GetProfile();
    721 
    722 	if ( profile == NULL ) {
    723 		return NULL;
    724 	}
    725 	
    726 	return profile;
    727 }
    728 
    729 //
    730 // KillMobj
    731 //
    732 void
    733 P_KillMobj
    734 ( mobj_t*	source,
    735  mobj_t*	target )
    736 {
    737 	mobjtype_t	item;
    738 	mobj_t*	mo;
    739 
    740 	target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY);
    741 
    742 	if (target->type != MT_SKULL)
    743 		target->flags &= ~MF_NOGRAVITY;
    744 
    745 	target->flags |= MF_CORPSE|MF_DROPOFF;
    746 	target->height >>= 2;
    747 
    748 	if (source && source->player)
    749 	{
    750 		// count for intermission
    751 		if (target->flags & MF_COUNTKILL)
    752 			source->player->killcount++;	
    753 
    754 		if (target->player) {
    755 			source->player->frags[target->player-::g->players]++;
    756 
    757 			// Keep track of the local player's total frags for trophy awards.
    758 
    759 			// Make sure the killing player is the local player
    760 			if ( source->player == &(::g->players[::g->consoleplayer]) ) {
    761 				// Make sure this is an online game.
    762 				// TODO: PC
    763 			}
    764 		}
    765 
    766 		// DHM - Nerve :: Check for killing cyberdemon with fists achievement
    767 		// JAF TROPHY int port = gameLocal->GetPortForPlayer( DoomLib::GetPlayer() );
    768 
    769 		if ( source->player->readyweapon == wp_fist && target->type == MT_CYBORG && !common->IsMultiplayer() ) {
    770 			switch( DoomLib::GetGameSKU() ) {
    771 				case GAME_SKU_DOOM2_BFG: {
    772 					// Removing trophies for DOOM and DOOM II BFG due to point limit.
    773 					//gameLocal->UnlockAchievement( Doom2BFG_Trophies::YOU_HAVE_HUGE_GUTS_KILL_CYBERDEMON_WITH_FISTS );
    774 					break;
    775 				}
    776 				case GAME_SKU_DCC: {
    777 					// Not for PC.
    778 					//session->GetAchievementSystem().AchievementUnlock( session->GetSignInManager().GetMasterLocalUser(), DOOM_ACHIEVEMENT_KILL_CYBER_DEMON_WITH_FISTS );
    779 					break;
    780 				}
    781 				default: {
    782 					// No unlocks for other SKUs.
    783 					break;
    784 				}
    785 			}
    786 		}
    787 
    788 		// DHM - Nerve :: Chainsaw kills
    789 		if ( source->player->readyweapon == wp_chainsaw && !common->IsMultiplayer() ) {
    790 			source->player->chainsawKills++;
    791 			if ( source->player->chainsawKills == 20 ) {
    792 				switch( DoomLib::GetGameSKU() ) {
    793 					case GAME_SKU_DOOM2_BFG: {
    794 						// Removing trophies for DOOM and DOOM II BFG due to point limit.
    795 						//gameLocal->UnlockAchievement( Doom2BFG_Trophies::GREAT_COMMUNICATOR_20_CHAINSAW_KILLS );
    796 						break;
    797 					}
    798 					case GAME_SKU_DCC: {
    799 						// Not for PC.
    800 						//gameLocal->UnlockAchievement( DOOM_ACHIEVEMENT_20KILLS_CHAINSAW );
    801 						break;
    802 					}
    803 					default: {
    804 						// No unlocks for other SKUs.
    805 						break;
    806 					}
    807 				}
    808 			}
    809 		}
    810 
    811 		// DHM - Nerve :: Berserker kills
    812 		if ( source->player->readyweapon == wp_fist && source->player->powers[pw_strength] && !common->IsMultiplayer()) {
    813 			source->player->berserkKills++;
    814 			idLib::Printf( "Player has %d berserk kills\n", source->player->berserkKills );
    815 			if ( source->player->berserkKills == 20 ) {
    816 				switch( DoomLib::GetGameSKU() ) {
    817 					case GAME_SKU_DOOM2_BFG: {
    818 						// Removing trophies for DOOM and DOOM II BFG due to point limit.
    819 						//gameLocal->UnlockAchievement( Doom2BFG_Trophies::MAN_AND_A_HALF_20_BERSERK_KILLS );
    820 						break;
    821 					}
    822 					case GAME_SKU_DCC: {
    823 						// Not for PC.
    824 						//gameLocal->UnlockAchievement( DOOM_ACHIEVEMENT_20KILLS_BERSERKER );
    825 						break;
    826 					}
    827 					default: {
    828 						// No unlocks for other SKUs.
    829 						break;
    830 					}
    831 				}				
    832 			}
    833 		}
    834 	}
    835 	else if (!::g->netgame && (target->flags & MF_COUNTKILL) )
    836 	{
    837 		// count all monster deaths,
    838 		// even those caused by other monsters
    839 		::g->players[0].killcount++;
    840 	}
    841 
    842 	if (target->player)
    843 	{
    844 		// count environment kills against you
    845 		if (!source)	
    846 			target->player->frags[target->player-::g->players]++;
    847 
    848 		target->flags &= ~MF_SOLID;
    849 		target->player->playerstate = PST_DEAD;
    850 		P_DropWeapon (target->player);
    851 
    852 		if (target->player == &::g->players[::g->consoleplayer]
    853 		&& ::g->automapactive)
    854 		{
    855 			// don't die in auto map,
    856 			// switch view prior to dying
    857 			AM_Stop ();
    858 		}
    859 
    860 	}
    861 
    862 	if (target->health < -target->info->spawnhealth 
    863 		&& target->info->xdeathstate)
    864 	{
    865 		P_SetMobjState (target, (statenum_t)target->info->xdeathstate);
    866 	}
    867 	else
    868 		P_SetMobjState (target, (statenum_t)target->info->deathstate);
    869 	target->tics -= P_Random()&3;
    870 
    871 	if (target->tics < 1)
    872 		target->tics = 1;
    873 
    874 	//	I_StartSound (&actor->r, actor->info->deathsound);
    875 
    876 
    877 	// Drop stuff.
    878 	// This determines the kind of object spawned
    879 	// during the death frame of a thing.
    880 	switch (target->type)
    881 	{
    882 	case MT_WOLFSS:
    883 	case MT_POSSESSED:
    884 		item = MT_CLIP;
    885 		break;
    886 
    887 	case MT_SHOTGUY:
    888 		item = MT_SHOTGUN;
    889 		break;
    890 
    891 	case MT_CHAINGUY:
    892 		item = MT_CHAINGUN;
    893 		break;
    894 
    895 	default:
    896 		return;
    897 	}
    898 
    899 	mo = P_SpawnMobj (target->x,target->y,ONFLOORZ, item);
    900 	mo->flags |= MF_DROPPED;	// special versions of items
    901 }
    902 
    903 
    904 
    905 
    906 //
    907 // P_DamageMobj
    908 // Damages both enemies and ::g->players
    909 // "inflictor" is the thing that caused the damage
    910 //  creature or missile, can be NULL (slime, etc)
    911 // "source" is the thing to target after taking damage
    912 //  creature or NULL
    913 // Source and inflictor are the same for melee attacks.
    914 // Source can be NULL for slime, barrel explosions
    915 // and other environmental stuff.
    916 //
    917 void
    918 P_DamageMobj
    919 ( mobj_t*	target,
    920  mobj_t*	inflictor,
    921  mobj_t*	source,
    922  int 		damage )
    923 {
    924 	unsigned	ang;
    925 	int		saved;
    926 	player_t*	player;
    927 	fixed_t	thrust;
    928 	int		temp;
    929 
    930 	if ( !(target->flags & MF_SHOOTABLE) )
    931 		return;	// shouldn't happen...
    932 
    933 	if (target->health <= 0)
    934 		return;
    935 
    936 	if ( target->flags & MF_SKULLFLY )
    937 	{
    938 		target->momx = target->momy = target->momz = 0;
    939 	}
    940 
    941 	player = target->player;
    942 	if (player && ::g->gameskill == sk_baby)
    943 		damage >>= 1; 	// take half damage in trainer mode
    944 
    945 
    946 	// Some close combat weapons should not
    947 	// inflict thrust and push the victim out of reach,
    948 	// thus kick away unless using the chainsaw.
    949 	if (inflictor
    950 		&& !(target->flags & MF_NOCLIP)
    951 		&& (!source
    952 		|| !source->player
    953 		|| source->player->readyweapon != wp_chainsaw))
    954 	{
    955 		ang = R_PointToAngle2 ( inflictor->x,
    956 			inflictor->y,
    957 			target->x,
    958 			target->y);
    959 
    960 		thrust = damage*(FRACUNIT>>3)*100/target->info->mass;
    961 
    962 		// make fall forwards sometimes
    963 		if ( damage < 40
    964 			&& damage > target->health
    965 			&& target->z - inflictor->z > 64*FRACUNIT
    966 			&& (P_Random ()&1) )
    967 		{
    968 			ang += ANG180;
    969 			thrust *= 4;
    970 		}
    971 
    972 		ang >>= ANGLETOFINESHIFT;
    973 		target->momx += FixedMul (thrust, finecosine[ang]);
    974 		target->momy += FixedMul (thrust, finesine[ang]);
    975 	}
    976 
    977 	// player specific
    978 	if (player)
    979 	{	
    980 
    981 		// end of game hell hack
    982 		if (target->subsector->sector->special == 11
    983 			&& damage >= target->health)
    984 		{
    985 			damage = target->health - 1;
    986 		}
    987 
    988 		float baseShake_High = 0.5f;
    989 		int baseShake_High_Dur = 100;
    990 		float baseShake_Low = 0.5f;
    991 		int baseShake_Low_Dur = 100;
    992 		int damageClamp = Min( damage, 100 ); 
    993 		float damageFloat = std::min( (float)damageClamp / 100.0f, 100.0f );
    994 		float additional = 0.5f * damageFloat;
    995 		int additional_time = 500.0f * damageFloat;
    996 
    997 		if( ::g->plyr == player ) {
    998 		}
    999 
   1000 
   1001 		// Below certain threshold,
   1002 		// ignore damage in GOD mode, or with INVUL power.
   1003 		if ( damage < 1000
   1004 			&& ( (player->cheats&CF_GODMODE)
   1005 			|| player->powers[pw_invulnerability] ) )
   1006 		{
   1007 			return;
   1008 		}
   1009 
   1010 
   1011 		if (player->armortype)
   1012 		{
   1013 			if (player->armortype == 1)
   1014 				saved = damage/3;
   1015 			else
   1016 				saved = damage/2;
   1017 
   1018 			if (player->armorpoints <= saved)
   1019 			{
   1020 				// armor is used up
   1021 				saved = player->armorpoints;
   1022 				player->armortype = 0;
   1023 			}
   1024 			player->armorpoints -= saved;
   1025 			damage -= saved;
   1026 		}
   1027 		player->health -= damage; 	// mirror mobj health here for Dave
   1028 		if (player->health < 0)
   1029 			player->health = 0;
   1030 
   1031 		player->attacker = source;
   1032 		player->damagecount += damage;	// add damage after armor / invuln
   1033 
   1034 		if (player->damagecount > 100)
   1035 			player->damagecount = 100;	// teleport stomp does 10k points...
   1036 
   1037 		temp = damage < 100 ? damage : 100;
   1038 	}
   1039 
   1040 	// do the damage	
   1041 	target->health -= damage;	
   1042 	if (target->health <= 0)
   1043 	{
   1044 		P_KillMobj (source, target);
   1045 		return;
   1046 	}
   1047 
   1048 	if ( (P_Random () < target->info->painchance)
   1049 		&& !(target->flags&MF_SKULLFLY) )
   1050 	{
   1051 		target->flags |= MF_JUSTHIT;	// fight back!
   1052 
   1053 		P_SetMobjState (target, (statenum_t)target->info->painstate);
   1054 	}
   1055 
   1056 	target->reactiontime = 0;		// we're awake now...	
   1057 
   1058 	if ( (!target->threshold || target->type == MT_VILE)
   1059 		&& source && source != target
   1060 		&& source->type != MT_VILE)
   1061 	{
   1062 		// if not intent on another player,
   1063 		// chase after this one
   1064 		target->target = source;
   1065 		target->threshold = BASETHRESHOLD;
   1066 		if (target->state == &::g->states[target->info->spawnstate]
   1067 		&& target->info->seestate != S_NULL)
   1068 			P_SetMobjState (target, (statenum_t)target->info->seestate);
   1069 	}
   1070 
   1071 }
   1072 
   1073