gzdoom/code/P_inter.c

1190 lines
25 KiB
C
Raw Normal View History

1998-04-07 00:00:00 +00:00
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Handling interactions (i.e., collisions).
//
//-----------------------------------------------------------------------------
// 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"
1998-07-14 00:00:00 +00:00
#include "c_consol.h"
1998-04-07 00:00:00 +00:00
#include "p_local.h"
#include "s_sound.h"
#include "p_inter.h"
#define BONUSADD 6
// a weapon is found with two clip loads,
// a big item has five clip loads
int maxammo[NUMAMMO] = {200, 50, 300, 50};
int clipammo[NUMAMMO] = {10, 4, 20, 1};
//
// GET STUFF
//
//
// P_GiveAmmo
// Num is the number of clip loads,
// not the individual count (0= 1/2 clip).
// Returns false if the ammo can't be picked up at all
//
1998-07-14 00:00:00 +00:00
BOOL P_GiveAmmo (player_t *player, ammotype_t ammo, int num)
1998-04-07 00:00:00 +00:00
{
int oldammo;
if (ammo == am_noammo)
return false;
if (ammo < 0 || 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->value == sk_baby
|| gameskill->value == 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.
switch (ammo)
{
case am_clip:
if (player->readyweapon == wp_fist)
{
if (player->weaponowned[wp_chaingun])
player->pendingweapon = wp_chaingun;
else
player->pendingweapon = wp_pistol;
}
break;
case am_shell:
if (player->readyweapon == wp_fist
|| player->readyweapon == wp_pistol)
{
if (player->weaponowned[wp_shotgun])
player->pendingweapon = wp_shotgun;
}
break;
case am_cell:
if (player->readyweapon == wp_fist
|| player->readyweapon == wp_pistol)
{
if (player->weaponowned[wp_plasma])
player->pendingweapon = wp_plasma;
}
break;
case am_misl:
if (player->readyweapon == wp_fist)
{
if (player->weaponowned[wp_missile])
player->pendingweapon = wp_missile;
}
default:
break;
}
return true;
}
//
// P_GiveWeapon
// The weapon name may have a MF_DROPPED flag ored in.
//
1998-07-14 00:00:00 +00:00
BOOL P_GiveWeapon (player_t *player, weapontype_t weapon, BOOL dropped)
1998-04-07 00:00:00 +00:00
{
1998-07-14 00:00:00 +00:00
BOOL gaveammo;
BOOL gaveweapon;
1998-04-07 00:00:00 +00:00
1998-07-14 00:00:00 +00:00
if (netgame && (!deathmatch->value || dmflags & DF_WEAPONS_STAY) && !dropped)
1998-04-07 00:00:00 +00:00
{
// leave placed weapons forever on net games
if (player->weaponowned[weapon])
return false;
player->bonuscount += BONUSADD;
player->weaponowned[weapon] = true;
1998-07-14 00:00:00 +00:00
if (deathmatch->value)
1998-04-07 00:00:00 +00:00
P_GiveAmmo (player, weaponinfo[weapon].ammo, 5);
else
P_GiveAmmo (player, weaponinfo[weapon].ammo, 2);
player->pendingweapon = weapon;
1998-07-14 00:00:00 +00:00
if (player == &players[displayplayer]) // [RH] Not consoleplayer
1998-04-07 00:00:00 +00:00
S_StartSound (ORIGIN_AMBIENT, 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;
if (player->weaponowned[weapon])
gaveweapon = false;
else
{
gaveweapon = true;
player->weaponowned[weapon] = true;
player->pendingweapon = weapon;
}
return (gaveweapon || gaveammo);
}
//
// P_GiveBody
// Returns false if the body isn't needed at all
//
1998-07-14 00:00:00 +00:00
BOOL P_GiveBody (player_t *player, int num)
1998-04-07 00:00:00 +00:00
{
if (player->health >= MAXHEALTH)
return false;
player->health += num;
if (player->health > MAXHEALTH)
player->health = MAXHEALTH;
player->mo->health = player->health;
return true;
}
//
// P_GiveArmor
// Returns false if the armor is worse
// than the current armor.
//
1998-07-14 00:00:00 +00:00
BOOL P_GiveArmor (player_t *player, int armortype)
1998-04-07 00:00:00 +00:00
{
int hits;
hits = armortype*100;
if (player->armorpoints >= hits)
return false; // don't pick up
player->armortype = armortype;
player->armorpoints = hits;
return true;
}
//
// P_GiveCard
//
1998-04-07 00:00:00 +00:00
void P_GiveCard (player_t *player, card_t card)
1998-04-07 00:00:00 +00:00
{
if (player->cards[card])
return;
player->bonuscount = BONUSADD;
player->cards[card] = 1;
}
//
// P_GivePower
//
1998-07-14 00:00:00 +00:00
BOOL P_GivePower (player_t *player, int /*powertype_t*/ power)
1998-04-07 00:00:00 +00:00
{
if (power == pw_invulnerability)
{
player->powers[power] = INVULNTICS;
return true;
}
if (power == pw_invisibility)
{
player->powers[power] = INVISTICS;
player->mo->flags |= MF_SHADOW;
return true;
}
if (power == pw_infrared)
{
player->powers[power] = INFRATICS;
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;
}
if (player->powers[power])
return false; // already got it
player->powers[power] = 1;
return true;
}
//
// P_TouchSpecialThing
//
1998-04-07 00:00:00 +00:00
void P_TouchSpecialThing (mobj_t *special, mobj_t *toucher)
1998-04-07 00:00:00 +00:00
{
player_t* player;
int i;
fixed_t delta;
int sound;
delta = special->z - toucher->z;
if (delta > toucher->height
|| delta < -8*FRACUNIT)
{
// out of reach
return;
}
sound = sfx_itemup;
player = toucher->player;
// Dead thing touching.
// Can happen with a sliding player corpse.
if (toucher->health <= 0)
return;
// Identify by sprite.
switch (special->sprite)
{
// armor
case SPR_ARM1:
1998-04-07 00:00:00 +00:00
if (!P_GiveArmor (player, deh_GreenAC))
1998-04-07 00:00:00 +00:00
return;
player->message = GOTARMOR;
break;
case SPR_ARM2:
1998-04-07 00:00:00 +00:00
if (!P_GiveArmor (player, deh_BlueAC))
1998-04-07 00:00:00 +00:00
return;
player->message = GOTMEGA;
break;
// bonus items
case SPR_BON1:
player->health++; // can go over 100%
1998-07-14 00:00:00 +00:00
if (player->health > deh_MaxSoulsphere)
player->health = deh_MaxSoulsphere;
1998-04-07 00:00:00 +00:00
player->mo->health = player->health;
player->message = GOTHTHBONUS;
break;
case SPR_BON2:
player->armorpoints++; // can go over 100%
1998-04-07 00:00:00 +00:00
if (player->armorpoints > deh_MaxArmor)
player->armorpoints = deh_MaxArmor;
1998-04-07 00:00:00 +00:00
if (!player->armortype)
1998-04-07 00:00:00 +00:00
player->armortype = deh_GreenAC;
1998-04-07 00:00:00 +00:00
player->message = GOTARMBONUS;
break;
case SPR_SOUL:
1998-04-07 00:00:00 +00:00
player->health += deh_SoulsphereHealth;
if (player->health > deh_MaxSoulsphere)
player->health = deh_MaxSoulsphere;
1998-04-07 00:00:00 +00:00
player->mo->health = player->health;
player->message = GOTSUPER;
sound = sfx_getpow;
break;
case SPR_MEGA:
if (gamemode != commercial)
return;
1998-04-07 00:00:00 +00:00
player->health = deh_MegasphereHealth;
1998-04-07 00:00:00 +00:00
player->mo->health = player->health;
1998-04-07 00:00:00 +00:00
P_GiveArmor (player,deh_BlueAC);
1998-04-07 00:00:00 +00:00
player->message = GOTMSPHERE;
sound = sfx_getpow;
break;
// cards
// leave cards for everyone
case SPR_BKEY:
if (!player->cards[it_bluecard])
player->message = GOTBLUECARD;
P_GiveCard (player, it_bluecard);
if (!netgame)
break;
return;
case SPR_YKEY:
if (!player->cards[it_yellowcard])
player->message = GOTYELWCARD;
P_GiveCard (player, it_yellowcard);
if (!netgame)
break;
return;
case SPR_RKEY:
if (!player->cards[it_redcard])
player->message = GOTREDCARD;
P_GiveCard (player, it_redcard);
if (!netgame)
break;
return;
case SPR_BSKU:
if (!player->cards[it_blueskull])
player->message = GOTBLUESKUL;
P_GiveCard (player, it_blueskull);
if (!netgame)
break;
return;
case SPR_YSKU:
if (!player->cards[it_yellowskull])
player->message = GOTYELWSKUL;
P_GiveCard (player, it_yellowskull);
if (!netgame)
break;
return;
case SPR_RSKU:
if (!player->cards[it_redskull])
player->message = GOTREDSKULL;
P_GiveCard (player, it_redskull);
if (!netgame)
break;
return;
// medikits, heals
case SPR_STIM:
if (!P_GiveBody (player, 10))
return;
player->message = GOTSTIM;
break;
case SPR_MEDI:
if (!P_GiveBody (player, 25))
return;
if (player->health < 25)
player->message = GOTMEDINEED;
else
player->message = GOTMEDIKIT;
break;
// power ups
case SPR_PINV:
if (!P_GivePower (player, pw_invulnerability))
return;
player->message = GOTINVUL;
sound = sfx_getpow;
break;
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;
case SPR_PINS:
if (!P_GivePower (player, pw_invisibility))
return;
player->message = GOTINVIS;
sound = sfx_getpow;
break;
case SPR_SUIT:
if (!P_GivePower (player, pw_ironfeet))
return;
player->message = GOTSUIT;
sound = sfx_getpow;
break;
case SPR_PMAP:
if (!P_GivePower (player, pw_allmap))
return;
player->message = GOTMAP;
sound = sfx_getpow;
break;
case SPR_PVIS:
if (!P_GivePower (player, pw_infrared))
return;
player->message = GOTVISOR;
sound = sfx_getpow;
break;
// ammo
case SPR_CLIP:
if (special->flags & MF_DROPPED)
{
if (!P_GiveAmmo (player,am_clip,0))
return;
}
else
{
if (!P_GiveAmmo (player,am_clip,1))
return;
}
player->message = GOTCLIP;
break;
case SPR_AMMO:
if (!P_GiveAmmo (player, am_clip,5))
return;
player->message = GOTCLIPBOX;
break;
case SPR_ROCK:
if (!P_GiveAmmo (player, am_misl,1))
return;
player->message = GOTROCKET;
break;
case SPR_BROK:
if (!P_GiveAmmo (player, am_misl,5))
return;
player->message = GOTROCKBOX;
break;
case SPR_CELL:
if (!P_GiveAmmo (player, am_cell,1))
return;
player->message = GOTCELL;
break;
case SPR_CELP:
if (!P_GiveAmmo (player, am_cell,5))
return;
player->message = GOTCELLBOX;
break;
case SPR_SHEL:
if (!P_GiveAmmo (player, am_shell,1))
return;
player->message = GOTSHELLS;
break;
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, i, 1);
player->message = GOTBACKPACK;
break;
// weapons
case SPR_BFUG:
if (!P_GiveWeapon (player, wp_bfg, false) )
return;
player->message = GOTBFG9000;
sound = sfx_wpnup;
break;
case SPR_MGUN:
if (!P_GiveWeapon (player, wp_chaingun, special->flags&MF_DROPPED) )
return;
player->message = GOTCHAINGUN;
sound = sfx_wpnup;
break;
case SPR_CSAW:
if (!P_GiveWeapon (player, wp_chainsaw, false) )
return;
player->message = GOTCHAINSAW;
sound = sfx_wpnup;
break;
case SPR_LAUN:
if (!P_GiveWeapon (player, wp_missile, false) )
return;
player->message = GOTLAUNCHER;
sound = sfx_wpnup;
break;
case SPR_PLAS:
if (!P_GiveWeapon (player, wp_plasma, false) )
return;
player->message = GOTPLASMA;
sound = sfx_wpnup;
break;
case SPR_SHOT:
if (!P_GiveWeapon (player, wp_shotgun, special->flags&MF_DROPPED ) )
return;
player->message = GOTSHOTGUN;
sound = sfx_wpnup;
break;
case SPR_SGN2:
if (!P_GiveWeapon (player, wp_supershotgun, special->flags&MF_DROPPED ) )
return;
player->message = GOTSHOTGUN2;
sound = sfx_wpnup;
break;
default:
I_Error ("P_SpecialThing: Unknown gettable thing");
}
1998-04-07 00:00:00 +00:00
if (special->flags & MF_COUNTITEM) {
1998-04-07 00:00:00 +00:00
player->itemcount++;
1998-04-07 00:00:00 +00:00
level.found_items++;
}
1998-04-07 00:00:00 +00:00
P_RemoveMobj (special);
player->bonuscount += BONUSADD;
1998-07-14 00:00:00 +00:00
if (player == &players[displayplayer]) { // [RH] Not consoleplayer
1998-04-07 00:00:00 +00:00
if (sound == sfx_getpow)
S_StartSound (ORIGIN_SURROUND3, sound);
else
S_StartSound (ORIGIN_AMBIENT, sound);
}
1998-04-07 00:00:00 +00:00
}
1998-07-14 00:00:00 +00:00
// [RH]
// ClientObituary: Show a message when a player dies
//
void ClientObituary (mobj_t *self, mobj_t *inflictor, mobj_t *attacker)
{
int mod;
char *message;
char *message2;
BOOL friendly;
if (1) {
friendly = MeansOfDeath & MOD_FRIENDLY_FIRE;
mod = MeansOfDeath & ~MOD_FRIENDLY_FIRE;
message = NULL;
message2 = "";
switch (mod) {
case MOD_SUICIDE:
message = "suicides";
break;
case MOD_FALLING:
message = "fell too far";
break;
case MOD_CRUSH:
message = "was squished";
break;
case MOD_EXIT:
message = "tried to leave";
break;
case MOD_WATER:
message = "has no gills";
break;
case MOD_SLIME:
message = "mutated";
break;
case MOD_LAVA:
message = "melted";
break;
case MOD_BARREL:
message = "went boom";
break;
case MOD_SPLASH:
message = "stood in the wrong spot";
break;
}
if (attacker && !message) {
if (attacker == self) {
switch (mod) {
case MOD_R_SPLASH:
case MOD_ROCKET:
message = "should have stood back";
break;
default:
message = "killed himself";
break;
}
} else if (!attacker->player) {
switch (attacker->type) {
case MT_STEALTHBABY:
message = "thought he saw an arachnotron";
break;
case MT_STEALTHVILE:
message = "thought he saw an archvile";
break;
case MT_STEALTHBRUISER:
message = "thought he saw a Baron of Hell";
break;
case MT_STEALTHHEAD:
message = "thought he saw a mancubus";
break;
case MT_STEALTHCHAINGUY:
message = "thought he saw a chaingunner";
break;
case MT_STEALTHSERGEANT:
message = "thought he saw a demon";
break;
case MT_STEALTHKNIGHT:
message = "thought he saw a Hell Knight";
break;
case MT_STEALTHIMP:
message = "thought he saw an imp";
break;
case MT_STEALTHFATSO:
message = "thought he saw a mancubus";
break;
case MT_STEALTHUNDEAD:
message = "thought he saw a revenant";
break;
case MT_STEALTHSHOTGUY:
message = "thought he saw a sargeant";
break;
case MT_STEALTHZOMBIE:
message = "thought he saw a zombieman";
break;
default:
if (mod == MOD_HIT) {
switch (attacker->type) {
case MT_UNDEAD:
message = "was punched by a revenant";
break;
case MT_TROOP:
message = "was slashed by an imp";
break;
case MT_HEAD:
message = "got too close to a mancubus";
break;
case MT_SERGEANT:
message = "was bit by a demon";
break;
case MT_SHADOWS:
message = "was eaten by a spectre";
break;
case MT_BRUISER:
message = "was ripped open by a Baron of Hell";
break;
case MT_KNIGHT:
message = "was gutted by a Hell Knight";
break;
default:
break;
}
} else {
switch (attacker->type) {
case MT_POSSESSED:
message = "was killed by a zombieman";
break;
case MT_SHOTGUY:
message = "was shot by a sargeant";
break;
case MT_VILE:
message = "was incinerated by an archvile";
break;
case MT_UNDEAD:
message = "couldn't evade a revenant's fireball";
break;
case MT_FATSO:
message = "was squashed by a mancubus";
break;
case MT_CHAINGUY:
message = "was perforated by a chaingunner";
break;
case MT_SKULL:
message = "was spooked by a lost soul";
break;
case MT_TROOP:
message = "was burned by an imp";
break;
case MT_HEAD:
message = "was mesmerized by a cacodemon";
break;
case MT_BRUISER:
message = "was bruised by a Baron of Hell";
break;
case MT_KNIGHT:
message = "was splayed by a Hell Knight";
break;
case MT_SPIDER:
message = "stood in awe of the spider mastermind";
break;
case MT_BABY:
message = "let an arachnotron get him";
break;
case MT_CYBORG:
message = "was splattered by a cyberdemon";
break;
case MT_WOLFSS:
message = "becomes Hitler's personal slave";
break;
default:
break;
}
}
break;
}
}
}
if (message) {
Printf ("%s %s.\n", self->player->userinfo->netname, message);
return;
}
if (attacker && attacker->player) {
switch (mod) {
case MOD_FIST:
message = "chewed on";
message2 = "'s fist";
break;
case MOD_CHAINSAW:
message = "was mowed over by";
message2 = "'s chainsaw";
break;
case MOD_PISTOL:
message = "was tickled by";
break;
case MOD_SHOTGUN:
message = "chewed on";
message2 = "'s boomstick";
break;
case MOD_SSHOTGUN:
message = "was splattered by";
message2 = "'s super shotgun";
break;
case MOD_CHAINGUN:
message = "was mowed down by";
break;
case MOD_ROCKET:
message = "rode";
message2 = "'s rocket";
break;
case MOD_R_SPLASH:
message = "almost dodged";
message2 = "'s rocket";
break;
case MOD_PLASMARIFLE:
message = "was melted by";
break;
case MOD_BFG_BOOM:
message = "was splintered by";
message2 = "'s BFG";
break;
case MOD_BFG_SPLASH:
message = "couldn't hide from";
message2 = "'s BFG";
break;
case MOD_TELEFRAG:
message = "was stepped on by";
break;
case MOD_FALLXFER:
message = "was";
message2 = "'s cushion";
break;
}
}
if (message) {
Printf ("%s %s %s%s\n", self->player->userinfo->netname, message,
attacker->player->userinfo->netname, message2);
return;
}
}
Printf ("%s died.\n", self->player->userinfo->netname);
}
1998-04-07 00:00:00 +00:00
//
// KillMobj
//
1998-07-14 00:00:00 +00:00
extern cvar_t *fraglimit;
void P_KillMobj (mobj_t *source, mobj_t *target, mobj_t *inflictor)
1998-04-07 00:00:00 +00:00
{
mobjtype_t item;
mobj_t* mo;
target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY);
if (target->type != MT_SKULL)
target->flags &= ~MF_NOGRAVITY;
target->flags |= MF_CORPSE|MF_DROPOFF;
target->height >>= 2;
if (source && source->player)
{
// count for intermission
1998-04-07 00:00:00 +00:00
if (target->flags & MF_COUNTKILL) {
source->player->killcount++;
level.killed_monsters++;
}
1998-04-07 00:00:00 +00:00
1998-07-14 00:00:00 +00:00
if (target->player) {
1998-04-07 00:00:00 +00:00
source->player->frags[target->player-players]++;
1998-07-14 00:00:00 +00:00
if (target->player == source->player) // [RH] Cumulative frag count
source->player->fragcount--;
else
source->player->fragcount++;
// [RH] Implement fraglimit
if (deathmatch->value && fraglimit->value &&
(int)fraglimit->value == source->player->fragcount) {
Printf ("%s got %d frags.\n", source->player->userinfo->netname, source->player->fragcount);
G_ExitLevel ();
}
}
1998-04-07 00:00:00 +00:00
}
else if (!netgame && (target->flags & MF_COUNTKILL) )
{
// count all monster deaths,
// even those caused by other monsters
players[0].killcount++;
1998-04-07 00:00:00 +00:00
level.killed_monsters++;
1998-04-07 00:00:00 +00:00
}
if (target->player)
{
1998-07-14 00:00:00 +00:00
// [RH] Force a delay between death and respawn
if (!olddemo)
target->player->respawn_time = level.time + TICRATE;
else
target->player->respawn_time = level.time;
1998-04-07 00:00:00 +00:00
// count environment kills against you
1998-07-14 00:00:00 +00:00
if (!source) {
1998-04-07 00:00:00 +00:00
target->player->frags[target->player-players]++;
1998-07-14 00:00:00 +00:00
target->player->fragcount--; // [RH] Cumulative frag count
}
1998-04-07 00:00:00 +00:00
target->flags &= ~MF_SOLID;
target->player->playerstate = PST_DEAD;
P_DropWeapon (target->player);
1998-07-14 00:00:00 +00:00
if (target->player == &players[consoleplayer] && automapactive)
1998-04-07 00:00:00 +00:00
{
// don't die in auto map,
// switch view prior to dying
AM_Stop ();
}
}
if (target->health < -target->info->spawnhealth
&& target->info->xdeathstate)
{
P_SetMobjState (target, target->info->xdeathstate);
}
else
P_SetMobjState (target, target->info->deathstate);
1998-07-14 00:00:00 +00:00
target->tics -= P_Random (pr_killmobj) & 3;
1998-04-07 00:00:00 +00:00
if (target->tics < 1)
target->tics = 1;
// I_StartSound (&actor->r, actor->info->deathsound);
1998-07-14 00:00:00 +00:00
// [RH] Death messages
if (target->player)
ClientObituary (target, inflictor, source);
1998-04-07 00:00:00 +00:00
// Drop stuff.
// This determines the kind of object spawned
// during the death frame of a thing.
switch (target->type)
{
case MT_WOLFSS:
case MT_POSSESSED:
item = MT_CLIP;
break;
case MT_SHOTGUY:
item = MT_SHOTGUN;
break;
case MT_CHAINGUY:
item = MT_CHAINGUN;
break;
default:
return;
}
1998-07-14 00:00:00 +00:00
mo = P_SpawnMobj (target->x,target->y,0, item, ONFLOORZ);
1998-04-07 00:00:00 +00:00
mo->flags |= MF_DROPPED; // special versions of items
1998-07-14 00:00:00 +00:00
1998-04-07 00:00:00 +00:00
}
//
// 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.
//
1998-07-14 00:00:00 +00:00
int MeansOfDeath;
void P_DamageMobj (mobj_t *target, mobj_t *inflictor, mobj_t *source, int damage, int mod)
1998-04-07 00:00:00 +00:00
{
unsigned 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;
1998-07-14 00:00:00 +00:00
MeansOfDeath = mod;
1998-04-07 00:00:00 +00:00
// [RH] Andy Baker's Stealth monsters
if (target->flags & MF_STEALTH)
{
P_BecomeVisible(target);
}
1998-04-07 00:00:00 +00:00
if ( target->flags & MF_SKULLFLY )
{
target->momx = target->momy = target->momz = 0;
}
player = target->player;
if (player && gameskill->value == sk_baby)
damage >>= 1; // take half damage in trainer mode
// Some close combat weapons should not
// inflict thrust and push the victim out of reach,
// thus kick away unless using the chainsaw.
if (inflictor
&& !(target->flags & MF_NOCLIP)
&& (!source
|| !source->player
|| source->player->readyweapon != wp_chainsaw))
{
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
1998-07-14 00:00:00 +00:00
&& (P_Random (pr_damagemobj)&1) )
1998-04-07 00:00:00 +00:00
{
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, or with INVUL power.
if ( damage < 1000
&& ( (player->cheats&CF_GODMODE)
|| player->powers[pw_invulnerability] ) )
{
return;
}
if (player->armortype)
{
1998-04-07 00:00:00 +00:00
if (player->armortype == deh_GreenAC)
1998-04-07 00:00:00 +00:00
saved = damage/3;
else
saved = damage/2;
if (player->armorpoints <= saved)
{
// armor is used up
saved = player->armorpoints;
player->armortype = 0;
}
player->armorpoints -= saved;
damage -= saved;
}
player->health -= damage; // mirror mobj health here for Dave
if (player->health < 0)
player->health = 0;
player->attacker = source;
player->damagecount += damage; // add damage after armor / invuln
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;
if (target->health <= 0)
{
1998-07-14 00:00:00 +00:00
P_KillMobj (source, target, inflictor);
1998-04-07 00:00:00 +00:00
return;
}
1998-07-14 00:00:00 +00:00
if ( (P_Random (pr_damagemobj) < target->info->painchance)
1998-04-07 00:00:00 +00:00
&& !(target->flags&MF_SKULLFLY) )
{
target->flags |= MF_JUSTHIT; // fight back!
P_SetMobjState (target, target->info->painstate);
}
target->reactiontime = 0; // we're awake now...
if ( (!target->threshold || target->type == MT_VILE)
&& source && source != target
&& source->type != MT_VILE)
{
// 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);
}
}
1998-07-14 00:00:00 +00:00
BOOL CheckCheatmode (void);
1998-04-07 00:00:00 +00:00
void Cmd_Kill (player_t *plyr, int argc, char **argv)
{
if (argc > 1 && !stricmp (argv[1], "monsters")) {
// Kill all the monsters
1998-07-14 00:00:00 +00:00
if (CheckCheatmode ())
return;
1998-04-07 00:00:00 +00:00
1998-07-14 00:00:00 +00:00
Net_WriteByte (DEM_GENERICCHEAT);
Net_WriteByte (CHT_MASSACRE);
1998-04-07 00:00:00 +00:00
} else {
// Kill the player
1998-07-14 00:00:00 +00:00
Net_WriteByte (DEM_SUICIDE);
1998-04-07 00:00:00 +00:00
}
C_HideConsole ();
}