1474 lines
33 KiB
C
1474 lines
33 KiB
C
|
|
// P_inter.c
|
|
|
|
#include "DoomDef.h"
|
|
#include "P_local.h"
|
|
#include "soundst.h"
|
|
|
|
#define BONUSADD 6
|
|
|
|
int WeaponValue[] =
|
|
{
|
|
1, // staff
|
|
3, // goldwand
|
|
4, // crossbow
|
|
5, // blaster
|
|
6, // skullrod
|
|
7, // phoenixrod
|
|
8, // mace
|
|
2, // gauntlets
|
|
0 // beak
|
|
};
|
|
|
|
int maxammo[NUMAMMO] =
|
|
{
|
|
100, // gold wand
|
|
50, // crossbow
|
|
200, // blaster
|
|
200, // skull rod
|
|
20, // phoenix rod
|
|
150 // mace
|
|
};
|
|
|
|
static int GetWeaponAmmo[NUMWEAPONS] =
|
|
{
|
|
0, // staff
|
|
25, // gold wand
|
|
10, // crossbow
|
|
30, // blaster
|
|
50, // skull rod
|
|
2, // phoenix rod
|
|
50, // mace
|
|
0, // gauntlets
|
|
0 // beak
|
|
};
|
|
|
|
static weapontype_t GetAmmoChange[] =
|
|
{
|
|
wp_goldwand,
|
|
wp_crossbow,
|
|
wp_blaster,
|
|
wp_skullrod,
|
|
wp_phoenixrod,
|
|
wp_mace
|
|
};
|
|
|
|
/*
|
|
static boolean GetAmmoChangePL1[NUMWEAPONS][NUMAMMO] =
|
|
{
|
|
// staff
|
|
{wp_goldwand, wp_crossbow, wp_blaster, wp_skullrod, -1, wp_mace},
|
|
// gold wand
|
|
{-1, wp_crossbow, wp_blaster, wp_skullrod, -1, wp_mace},
|
|
// crossbow
|
|
{-1, -1, wp_blaster, wp_skullrod, -1, -1},
|
|
// blaster
|
|
{-1, -1, -1, -1, -1, -1},
|
|
// skull rod
|
|
{-1, -1, -1, -1, -1, -1},
|
|
// phoenix rod
|
|
{-1, -1, -1, -1, -1, -1},
|
|
// mace
|
|
{-1, wp_crossbow, wp_blaster, wp_skullrod, -1, -1},
|
|
// gauntlets
|
|
{-1, wp_crossbow, wp_blaster, wp_skullrod, -1, wp_mace}
|
|
};
|
|
*/
|
|
|
|
/*
|
|
static boolean GetAmmoChangePL2[NUMWEAPONS][NUMAMMO] =
|
|
{
|
|
// staff
|
|
{wp_goldwand, wp_crossbow, wp_blaster, wp_skullrod, wp_phoenixrod,
|
|
wp_mace},
|
|
// gold wand
|
|
{-1, wp_crossbow, wp_blaster, wp_skullrod, wp_phoenixrod, wp_mace},
|
|
// crossbow
|
|
{-1, -1, wp_blaster, wp_skullrod, wp_phoenixrod, -1},
|
|
// blaster
|
|
{-1, -1, -1, wp_skullrod, wp_phoenixrod, -1},
|
|
// skull rod
|
|
{-1, -1, -1, -1, -1, -1},
|
|
// phoenix rod
|
|
{-1, -1, -1, -1, -1, -1},
|
|
// mace
|
|
{-1, wp_crossbow, wp_blaster, wp_skullrod, -1, -1},
|
|
// gauntlets
|
|
{-1, -1, -1, wp_skullrod, wp_phoenixrod, wp_mace}
|
|
};
|
|
*/
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// PROC P_SetMessage
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
boolean ultimatemsg;
|
|
|
|
void P_SetMessage(player_t *player, char *message, boolean ultmsg)
|
|
{
|
|
extern boolean messageson;
|
|
|
|
if((ultimatemsg || !messageson) && !ultmsg)
|
|
{
|
|
return;
|
|
}
|
|
player->message = message;
|
|
player->messageTics = MESSAGETICS;
|
|
BorderTopRefresh = true;
|
|
if(ultmsg)
|
|
{
|
|
ultimatemsg = true;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// FUNC P_GiveAmmo
|
|
//
|
|
// Returns true if the player accepted the ammo, false if it was
|
|
// refused (player has maxammo[ammo]).
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
boolean P_GiveAmmo(player_t *player, ammotype_t ammo, int count)
|
|
{
|
|
int prevAmmo;
|
|
//weapontype_t changeWeapon;
|
|
|
|
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(gameskill == sk_baby || gameskill == sk_nightmare)
|
|
{ // extra ammo in baby mode and nightmare mode
|
|
count += count>>1;
|
|
}
|
|
prevAmmo = player->ammo[ammo];
|
|
|
|
player->ammo[ammo] += count;
|
|
if(player->ammo[ammo] > player->maxammo[ammo])
|
|
{
|
|
player->ammo[ammo] = player->maxammo[ammo];
|
|
}
|
|
if(prevAmmo)
|
|
{
|
|
// Don't attempt to change weapons if the player already had
|
|
// ammo of the type just given
|
|
return(true);
|
|
}
|
|
if(player->readyweapon == wp_staff
|
|
|| player->readyweapon == wp_gauntlets)
|
|
{
|
|
if(player->weaponowned[GetAmmoChange[ammo]])
|
|
{
|
|
player->pendingweapon = GetAmmoChange[ammo];
|
|
}
|
|
}
|
|
/*
|
|
if(player->powers[pw_weaponlevel2])
|
|
{
|
|
changeWeapon = GetAmmoChangePL2[player->readyweapon][ammo];
|
|
}
|
|
else
|
|
{
|
|
changeWeapon = GetAmmoChangePL1[player->readyweapon][ammo];
|
|
}
|
|
if(changeWeapon != -1)
|
|
{
|
|
if(player->weaponowned[changeWeapon])
|
|
{
|
|
player->pendingweapon = changeWeapon;
|
|
}
|
|
}
|
|
*/
|
|
return(true);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// FUNC P_GiveWeapon
|
|
//
|
|
// Returns true if the weapon or its ammo was accepted.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
boolean P_GiveWeapon(player_t *player, weapontype_t weapon)
|
|
{
|
|
boolean gaveAmmo;
|
|
boolean gaveWeapon;
|
|
|
|
if(netgame && !deathmatch)
|
|
{ // Cooperative net-game
|
|
if(player->weaponowned[weapon])
|
|
{
|
|
return(false);
|
|
}
|
|
player->bonuscount += BONUSADD;
|
|
player->weaponowned[weapon] = true;
|
|
P_GiveAmmo(player, wpnlev1info[weapon].ammo,
|
|
GetWeaponAmmo[weapon]);
|
|
player->pendingweapon = weapon;
|
|
if(player == &players[consoleplayer])
|
|
{
|
|
S_StartSound(NULL, sfx_wpnup);
|
|
}
|
|
return(false);
|
|
}
|
|
gaveAmmo = P_GiveAmmo(player, wpnlev1info[weapon].ammo,
|
|
GetWeaponAmmo[weapon]);
|
|
if(player->weaponowned[weapon])
|
|
{
|
|
gaveWeapon = false;
|
|
}
|
|
else
|
|
{
|
|
gaveWeapon = true;
|
|
player->weaponowned[weapon] = true;
|
|
if(WeaponValue[weapon] > WeaponValue[player->readyweapon])
|
|
{ // Only switch to more powerful weapons
|
|
player->pendingweapon = weapon;
|
|
}
|
|
}
|
|
return(gaveWeapon || gaveAmmo);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// FUNC P_GiveBody
|
|
//
|
|
// Returns false if the body isn't needed at all.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
boolean P_GiveBody(player_t *player, int num)
|
|
{
|
|
int max;
|
|
|
|
max = MAXHEALTH;
|
|
if(player->chickenTics)
|
|
{
|
|
max = MAXCHICKENHEALTH;
|
|
}
|
|
if(player->health >= max)
|
|
{
|
|
return(false);
|
|
}
|
|
player->health += num;
|
|
if(player->health > max)
|
|
{
|
|
player->health = max;
|
|
}
|
|
player->mo->health = player->health;
|
|
return(true);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// FUNC P_GiveArmor
|
|
//
|
|
// Returns false if the armor is worse than the current armor.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
boolean P_GiveArmor(player_t *player, int armortype)
|
|
{
|
|
int hits;
|
|
|
|
hits = armortype*100;
|
|
if(player->armorpoints >= hits)
|
|
{
|
|
return(false);
|
|
}
|
|
player->armortype = armortype;
|
|
player->armorpoints = hits;
|
|
return(true);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// PROC P_GiveKey
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void P_GiveKey(player_t *player, keytype_t key)
|
|
{
|
|
extern int playerkeys;
|
|
extern vertex_t KeyPoints[];
|
|
|
|
if(player->keys[key])
|
|
{
|
|
return;
|
|
}
|
|
if(player == &players[consoleplayer])
|
|
{
|
|
playerkeys |= 1<<key;
|
|
KeyPoints[key].x = 0;
|
|
KeyPoints[key].y = 0;
|
|
}
|
|
player->bonuscount = BONUSADD;
|
|
player->keys[key] = true;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// FUNC P_GivePower
|
|
//
|
|
// Returns true if power accepted.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
boolean P_GivePower(player_t *player, powertype_t power)
|
|
{
|
|
if(power == pw_invulnerability)
|
|
{
|
|
if(player->powers[power] > BLINKTHRESHOLD)
|
|
{ // Already have it
|
|
return(false);
|
|
}
|
|
player->powers[power] = INVULNTICS;
|
|
return(true);
|
|
}
|
|
if(power == pw_weaponlevel2)
|
|
{
|
|
if(player->powers[power] > BLINKTHRESHOLD)
|
|
{ // Already have it
|
|
return(false);
|
|
}
|
|
player->powers[power] = WPNLEV2TICS;
|
|
return(true);
|
|
}
|
|
if(power == pw_invisibility)
|
|
{
|
|
if(player->powers[power] > BLINKTHRESHOLD)
|
|
{ // Already have it
|
|
return(false);
|
|
}
|
|
player->powers[power] = INVISTICS;
|
|
player->mo->flags |= MF_SHADOW;
|
|
return(true);
|
|
}
|
|
if(power == pw_flight)
|
|
{
|
|
if(player->powers[power] > BLINKTHRESHOLD)
|
|
{ // Already have it
|
|
return(false);
|
|
}
|
|
player->powers[power] = FLIGHTTICS;
|
|
player->mo->flags2 |= MF2_FLY;
|
|
player->mo->flags |= MF_NOGRAVITY;
|
|
if(player->mo->z <= player->mo->floorz)
|
|
{
|
|
player->flyheight = 10; // thrust the player in the air a bit
|
|
}
|
|
return(true);
|
|
}
|
|
if(power == pw_infrared)
|
|
{
|
|
if(player->powers[power] > BLINKTHRESHOLD)
|
|
{ // Already have it
|
|
return(false);
|
|
}
|
|
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);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// FUNC P_GiveArtifact
|
|
//
|
|
// Returns true if artifact accepted.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
boolean P_GiveArtifact(player_t *player, artitype_t arti, mobj_t *mo)
|
|
{
|
|
int i;
|
|
|
|
i = 0;
|
|
while(player->inventory[i].type != arti && i < player->inventorySlotNum)
|
|
{
|
|
i++;
|
|
}
|
|
if(i == player->inventorySlotNum)
|
|
{
|
|
player->inventory[i].count = 1;
|
|
player->inventory[i].type = arti;
|
|
player->inventorySlotNum++;
|
|
}
|
|
else
|
|
{
|
|
if(player->inventory[i].count >= 16)
|
|
{ // Player already has 16 of this item
|
|
return(false);
|
|
}
|
|
player->inventory[i].count++;
|
|
}
|
|
if(player->artifactCount == 0)
|
|
{
|
|
player->readyArtifact = arti;
|
|
}
|
|
player->artifactCount++;
|
|
if(mo && (mo->flags&MF_COUNTITEM))
|
|
{
|
|
player->itemcount++;
|
|
}
|
|
return(true);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// PROC P_SetDormantArtifact
|
|
//
|
|
// Removes the MF_SPECIAL flag, and initiates the artifact pickup
|
|
// animation.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void P_SetDormantArtifact(mobj_t *arti)
|
|
{
|
|
arti->flags &= ~MF_SPECIAL;
|
|
if(deathmatch && (arti->type != MT_ARTIINVULNERABILITY)
|
|
&& (arti->type != MT_ARTIINVISIBILITY))
|
|
{
|
|
P_SetMobjState(arti, S_DORMANTARTI1);
|
|
}
|
|
else
|
|
{ // Don't respawn
|
|
P_SetMobjState(arti, S_DEADARTI1);
|
|
}
|
|
S_StartSound(arti, sfx_artiup);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// PROC A_RestoreArtifact
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void A_RestoreArtifact(mobj_t *arti)
|
|
{
|
|
arti->flags |= MF_SPECIAL;
|
|
P_SetMobjState(arti, arti->info->spawnstate);
|
|
S_StartSound(arti, sfx_respawn);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC P_HideSpecialThing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void P_HideSpecialThing(mobj_t *thing)
|
|
{
|
|
thing->flags &= ~MF_SPECIAL;
|
|
thing->flags2 |= MF2_DONTDRAW;
|
|
P_SetMobjState(thing, S_HIDESPECIAL1);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// PROC A_RestoreSpecialThing1
|
|
//
|
|
// Make a special thing visible again.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void A_RestoreSpecialThing1(mobj_t *thing)
|
|
{
|
|
if(thing->type == MT_WMACE)
|
|
{ // Do random mace placement
|
|
P_RepositionMace(thing);
|
|
}
|
|
thing->flags2 &= ~MF2_DONTDRAW;
|
|
S_StartSound(thing, sfx_respawn);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// PROC A_RestoreSpecialThing2
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void A_RestoreSpecialThing2(mobj_t *thing)
|
|
{
|
|
thing->flags |= MF_SPECIAL;
|
|
P_SetMobjState(thing, thing->info->spawnstate);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// PROC P_TouchSpecialThing
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher)
|
|
{
|
|
int i;
|
|
player_t *player;
|
|
fixed_t delta;
|
|
int sound;
|
|
boolean respawn;
|
|
|
|
delta = special->z-toucher->z;
|
|
if(delta > toucher->height || delta < -32*FRACUNIT)
|
|
{ // Out of reach
|
|
return;
|
|
}
|
|
if(toucher->health <= 0)
|
|
{ // Toucher is dead
|
|
return;
|
|
}
|
|
sound = sfx_itemup;
|
|
player = toucher->player;
|
|
respawn = true;
|
|
switch(special->sprite)
|
|
{
|
|
// Items
|
|
case SPR_PTN1: // Item_HealingPotion
|
|
if(!P_GiveBody(player, 10))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_ITEMHEALTH, false);
|
|
break;
|
|
case SPR_SHLD: // Item_Shield1
|
|
if(!P_GiveArmor(player, 1))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_ITEMSHIELD1, false);
|
|
break;
|
|
case SPR_SHD2: // Item_Shield2
|
|
if(!P_GiveArmor(player, 2))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_ITEMSHIELD2, false);
|
|
break;
|
|
case SPR_BAGH: // Item_BagOfHolding
|
|
if(!player->backpack)
|
|
{
|
|
for(i = 0; i < NUMAMMO; i++)
|
|
{
|
|
player->maxammo[i] *= 2;
|
|
}
|
|
player->backpack = true;
|
|
}
|
|
P_GiveAmmo(player, am_goldwand, AMMO_GWND_WIMPY);
|
|
P_GiveAmmo(player, am_blaster, AMMO_BLSR_WIMPY);
|
|
P_GiveAmmo(player, am_crossbow, AMMO_CBOW_WIMPY);
|
|
P_GiveAmmo(player, am_skullrod, AMMO_SKRD_WIMPY);
|
|
P_GiveAmmo(player, am_phoenixrod, AMMO_PHRD_WIMPY);
|
|
P_SetMessage(player, TXT_ITEMBAGOFHOLDING, false);
|
|
break;
|
|
case SPR_SPMP: // Item_SuperMap
|
|
if(!P_GivePower(player, pw_allmap))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_ITEMSUPERMAP, false);
|
|
break;
|
|
|
|
// Keys
|
|
case SPR_BKYY: // Key_Blue
|
|
if(!player->keys[key_blue])
|
|
{
|
|
P_SetMessage(player, TXT_GOTBLUEKEY, false);
|
|
}
|
|
P_GiveKey(player, key_blue);
|
|
sound = sfx_keyup;
|
|
if(!netgame)
|
|
{
|
|
break;
|
|
}
|
|
return;
|
|
case SPR_CKYY: // Key_Yellow
|
|
if(!player->keys[key_yellow])
|
|
{
|
|
P_SetMessage(player, TXT_GOTYELLOWKEY, false);
|
|
}
|
|
sound = sfx_keyup;
|
|
P_GiveKey(player, key_yellow);
|
|
if(!netgame)
|
|
{
|
|
break;
|
|
}
|
|
return;
|
|
case SPR_AKYY: // Key_Green
|
|
if(!player->keys[key_green])
|
|
{
|
|
P_SetMessage(player, TXT_GOTGREENKEY, false);
|
|
}
|
|
sound = sfx_keyup;
|
|
P_GiveKey(player, key_green);
|
|
if(!netgame)
|
|
{
|
|
break;
|
|
}
|
|
return;
|
|
|
|
// Artifacts
|
|
case SPR_PTN2: // Arti_HealingPotion
|
|
if(P_GiveArtifact(player, arti_health, special))
|
|
{
|
|
P_SetMessage(player, TXT_ARTIHEALTH, false);
|
|
P_SetDormantArtifact(special);
|
|
}
|
|
return;
|
|
case SPR_SOAR: // Arti_Fly
|
|
if(P_GiveArtifact(player, arti_fly, special))
|
|
{
|
|
P_SetMessage(player, TXT_ARTIFLY, false);
|
|
P_SetDormantArtifact(special);
|
|
}
|
|
return;
|
|
case SPR_INVU: // Arti_Invulnerability
|
|
if(P_GiveArtifact(player, arti_invulnerability, special))
|
|
{
|
|
P_SetMessage(player, TXT_ARTIINVULNERABILITY, false);
|
|
P_SetDormantArtifact(special);
|
|
}
|
|
return;
|
|
case SPR_PWBK: // Arti_TomeOfPower
|
|
if(P_GiveArtifact(player, arti_tomeofpower, special))
|
|
{
|
|
P_SetMessage(player, TXT_ARTITOMEOFPOWER, false);
|
|
P_SetDormantArtifact(special);
|
|
}
|
|
return;
|
|
case SPR_INVS: // Arti_Invisibility
|
|
if(P_GiveArtifact(player, arti_invisibility, special))
|
|
{
|
|
P_SetMessage(player, TXT_ARTIINVISIBILITY, false);
|
|
P_SetDormantArtifact(special);
|
|
}
|
|
return;
|
|
case SPR_EGGC: // Arti_Egg
|
|
if(P_GiveArtifact(player, arti_egg, special))
|
|
{
|
|
P_SetMessage(player, TXT_ARTIEGG, false);
|
|
P_SetDormantArtifact(special);
|
|
}
|
|
return;
|
|
case SPR_SPHL: // Arti_SuperHealth
|
|
if(P_GiveArtifact(player, arti_superhealth, special))
|
|
{
|
|
P_SetMessage(player, TXT_ARTISUPERHEALTH, false);
|
|
P_SetDormantArtifact(special);
|
|
}
|
|
return;
|
|
case SPR_TRCH: // Arti_Torch
|
|
if(P_GiveArtifact(player, arti_torch, special))
|
|
{
|
|
P_SetMessage(player, TXT_ARTITORCH, false);
|
|
P_SetDormantArtifact(special);
|
|
}
|
|
return;
|
|
case SPR_FBMB: // Arti_FireBomb
|
|
if(P_GiveArtifact(player, arti_firebomb, special))
|
|
{
|
|
P_SetMessage(player, TXT_ARTIFIREBOMB, false);
|
|
P_SetDormantArtifact(special);
|
|
}
|
|
return;
|
|
case SPR_ATLP: // Arti_Teleport
|
|
if(P_GiveArtifact(player, arti_teleport, special))
|
|
{
|
|
P_SetMessage(player, TXT_ARTITELEPORT, false);
|
|
P_SetDormantArtifact(special);
|
|
}
|
|
return;
|
|
|
|
// Ammo
|
|
case SPR_AMG1: // Ammo_GoldWandWimpy
|
|
if(!P_GiveAmmo(player, am_goldwand, special->health))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_AMMOGOLDWAND1, false);
|
|
break;
|
|
case SPR_AMG2: // Ammo_GoldWandHefty
|
|
if(!P_GiveAmmo(player, am_goldwand, special->health))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_AMMOGOLDWAND2, false);
|
|
break;
|
|
case SPR_AMM1: // Ammo_MaceWimpy
|
|
if(!P_GiveAmmo(player, am_mace, special->health))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_AMMOMACE1, false);
|
|
break;
|
|
case SPR_AMM2: // Ammo_MaceHefty
|
|
if(!P_GiveAmmo(player, am_mace, special->health))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_AMMOMACE2, false);
|
|
break;
|
|
case SPR_AMC1: // Ammo_CrossbowWimpy
|
|
if(!P_GiveAmmo(player, am_crossbow, special->health))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_AMMOCROSSBOW1, false);
|
|
break;
|
|
case SPR_AMC2: // Ammo_CrossbowHefty
|
|
if(!P_GiveAmmo(player, am_crossbow, special->health))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_AMMOCROSSBOW2, false);
|
|
break;
|
|
case SPR_AMB1: // Ammo_BlasterWimpy
|
|
if(!P_GiveAmmo(player, am_blaster, special->health))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_AMMOBLASTER1, false);
|
|
break;
|
|
case SPR_AMB2: // Ammo_BlasterHefty
|
|
if(!P_GiveAmmo(player, am_blaster, special->health))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_AMMOBLASTER2, false);
|
|
break;
|
|
case SPR_AMS1: // Ammo_SkullRodWimpy
|
|
if(!P_GiveAmmo(player, am_skullrod, special->health))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_AMMOSKULLROD1, false);
|
|
break;
|
|
case SPR_AMS2: // Ammo_SkullRodHefty
|
|
if(!P_GiveAmmo(player, am_skullrod, special->health))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_AMMOSKULLROD2, false);
|
|
break;
|
|
case SPR_AMP1: // Ammo_PhoenixRodWimpy
|
|
if(!P_GiveAmmo(player, am_phoenixrod, special->health))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_AMMOPHOENIXROD1, false);
|
|
break;
|
|
case SPR_AMP2: // Ammo_PhoenixRodHefty
|
|
if(!P_GiveAmmo(player, am_phoenixrod, special->health))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_AMMOPHOENIXROD2, false);
|
|
break;
|
|
|
|
// Weapons
|
|
case SPR_WMCE: // Weapon_Mace
|
|
if(!P_GiveWeapon(player, wp_mace))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_WPNMACE, false);
|
|
sound = sfx_wpnup;
|
|
break;
|
|
case SPR_WBOW: // Weapon_Crossbow
|
|
if(!P_GiveWeapon(player, wp_crossbow))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_WPNCROSSBOW, false);
|
|
sound = sfx_wpnup;
|
|
break;
|
|
case SPR_WBLS: // Weapon_Blaster
|
|
if(!P_GiveWeapon(player, wp_blaster))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_WPNBLASTER, false);
|
|
sound = sfx_wpnup;
|
|
break;
|
|
case SPR_WSKL: // Weapon_SkullRod
|
|
if(!P_GiveWeapon(player, wp_skullrod))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_WPNSKULLROD, false);
|
|
sound = sfx_wpnup;
|
|
break;
|
|
case SPR_WPHX: // Weapon_PhoenixRod
|
|
if(!P_GiveWeapon(player, wp_phoenixrod))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_WPNPHOENIXROD, false);
|
|
sound = sfx_wpnup;
|
|
break;
|
|
case SPR_WGNT: // Weapon_Gauntlets
|
|
if(!P_GiveWeapon(player, wp_gauntlets))
|
|
{
|
|
return;
|
|
}
|
|
P_SetMessage(player, TXT_WPNGAUNTLETS, false);
|
|
sound = sfx_wpnup;
|
|
break;
|
|
default:
|
|
I_Error("P_SpecialThing: Unknown gettable thing");
|
|
}
|
|
if(special->flags&MF_COUNTITEM)
|
|
{
|
|
player->itemcount++;
|
|
}
|
|
if(deathmatch && respawn && !(special->flags&MF_DROPPED))
|
|
{
|
|
P_HideSpecialThing(special);
|
|
}
|
|
else
|
|
{
|
|
P_RemoveMobj(special);
|
|
}
|
|
player->bonuscount += BONUSADD;
|
|
if(player == &players[consoleplayer])
|
|
{
|
|
S_StartSound(NULL, sound);
|
|
SB_PaletteFlash();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// PROC P_KillMobj
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void P_KillMobj(mobj_t *source, mobj_t *target)
|
|
{
|
|
target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY|MF_NOGRAVITY);
|
|
target->flags |= MF_CORPSE|MF_DROPOFF;
|
|
target->flags2 &= ~MF2_PASSMOBJ;
|
|
target->height >>= 2;
|
|
if(source && source->player)
|
|
{
|
|
if(target->flags&MF_COUNTKILL)
|
|
{ // Count for intermission
|
|
source->player->killcount++;
|
|
}
|
|
if(target->player)
|
|
{ // Frag stuff
|
|
if(target == source)
|
|
{ // Self-frag
|
|
target->player->frags[target->player-players]--;
|
|
}
|
|
else
|
|
{
|
|
source->player->frags[target->player-players]++;
|
|
if(source->player == &players[consoleplayer])
|
|
{
|
|
S_StartSound(NULL, sfx_gfrag);
|
|
}
|
|
if(source->player->chickenTics)
|
|
{ // Make a super chicken
|
|
P_GivePower(source->player, pw_weaponlevel2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(!netgame && (target->flags&MF_COUNTKILL))
|
|
{ // Count all monster deaths
|
|
players[0].killcount++;
|
|
}
|
|
if(target->player)
|
|
{
|
|
if(!source)
|
|
{ // Self-frag
|
|
target->player->frags[target->player-players]--;
|
|
}
|
|
target->flags &= ~MF_SOLID;
|
|
target->flags2 &= ~MF2_FLY;
|
|
target->player->powers[pw_flight] = 0;
|
|
target->player->powers[pw_weaponlevel2] = 0;
|
|
target->player->playerstate = PST_DEAD;
|
|
P_DropWeapon(target->player);
|
|
if(target->flags2&MF2_FIREDAMAGE)
|
|
{ // Player flame death
|
|
P_SetMobjState(target, S_PLAY_FDTH1);
|
|
//S_StartSound(target, sfx_hedat1); // Burn sound
|
|
return;
|
|
}
|
|
}
|
|
if(target->health < -(target->info->spawnhealth>>1)
|
|
&& target->info->xdeathstate)
|
|
{ // Extreme death
|
|
P_SetMobjState(target, target->info->xdeathstate);
|
|
}
|
|
else
|
|
{ // Normal death
|
|
P_SetMobjState(target, target->info->deathstate);
|
|
}
|
|
target->tics -= P_Random()&3;
|
|
// I_StartSound(&actor->r, actor->info->deathsound);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// FUNC P_MinotaurSlam
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void P_MinotaurSlam(mobj_t *source, mobj_t *target)
|
|
{
|
|
angle_t angle;
|
|
fixed_t thrust;
|
|
|
|
angle = R_PointToAngle2(source->x, source->y, target->x, target->y);
|
|
angle >>= ANGLETOFINESHIFT;
|
|
thrust = 16*FRACUNIT+(P_Random()<<10);
|
|
target->momx += FixedMul(thrust, finecosine[angle]);
|
|
target->momy += FixedMul(thrust, finesine[angle]);
|
|
P_DamageMobj(target, NULL, NULL, HITDICE(6));
|
|
if(target->player)
|
|
{
|
|
target->reactiontime = 14+(P_Random()&7);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// FUNC P_TouchWhirlwind
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void P_TouchWhirlwind(mobj_t *target)
|
|
{
|
|
int randVal;
|
|
|
|
target->angle += (P_Random()-P_Random())<<20;
|
|
target->momx += (P_Random()-P_Random())<<10;
|
|
target->momy += (P_Random()-P_Random())<<10;
|
|
if(leveltime&16 && !(target->flags2&MF2_BOSS))
|
|
{
|
|
randVal = P_Random();
|
|
if(randVal > 160)
|
|
{
|
|
randVal = 160;
|
|
}
|
|
target->momz += randVal<<10;
|
|
if(target->momz > 12*FRACUNIT)
|
|
{
|
|
target->momz = 12*FRACUNIT;
|
|
}
|
|
}
|
|
if(!(leveltime&7))
|
|
{
|
|
P_DamageMobj(target, NULL, NULL, 3);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// FUNC P_ChickenMorphPlayer
|
|
//
|
|
// Returns true if the player gets turned into a chicken.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
boolean P_ChickenMorphPlayer(player_t *player)
|
|
{
|
|
mobj_t *pmo;
|
|
mobj_t *fog;
|
|
mobj_t *chicken;
|
|
fixed_t x;
|
|
fixed_t y;
|
|
fixed_t z;
|
|
angle_t angle;
|
|
int oldFlags2;
|
|
|
|
if(player->chickenTics)
|
|
{
|
|
if((player->chickenTics < CHICKENTICS-TICSPERSEC)
|
|
&& !player->powers[pw_weaponlevel2])
|
|
{ // Make a super chicken
|
|
P_GivePower(player, pw_weaponlevel2);
|
|
}
|
|
return(false);
|
|
}
|
|
if(player->powers[pw_invulnerability])
|
|
{ // Immune when invulnerable
|
|
return(false);
|
|
}
|
|
pmo = player->mo;
|
|
x = pmo->x;
|
|
y = pmo->y;
|
|
z = pmo->z;
|
|
angle = pmo->angle;
|
|
oldFlags2 = pmo->flags2;
|
|
P_SetMobjState(pmo, S_FREETARGMOBJ);
|
|
fog = P_SpawnMobj(x, y, z+TELEFOGHEIGHT, MT_TFOG);
|
|
S_StartSound(fog, sfx_telept);
|
|
chicken = P_SpawnMobj(x, y, z, MT_CHICPLAYER);
|
|
chicken->special1 = player->readyweapon;
|
|
chicken->angle = angle;
|
|
chicken->player = player;
|
|
player->health = chicken->health = MAXCHICKENHEALTH;
|
|
player->mo = chicken;
|
|
player->armorpoints = player->armortype = 0;
|
|
player->powers[pw_invisibility] = 0;
|
|
player->powers[pw_weaponlevel2] = 0;
|
|
if(oldFlags2&MF2_FLY)
|
|
{
|
|
chicken->flags2 |= MF2_FLY;
|
|
}
|
|
player->chickenTics = CHICKENTICS;
|
|
P_ActivateBeak(player);
|
|
return(true);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// FUNC P_ChickenMorph
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
boolean P_ChickenMorph(mobj_t *actor)
|
|
{
|
|
mobj_t *fog;
|
|
mobj_t *chicken;
|
|
mobj_t *target;
|
|
mobjtype_t moType;
|
|
fixed_t x;
|
|
fixed_t y;
|
|
fixed_t z;
|
|
angle_t angle;
|
|
int ghost;
|
|
|
|
if(actor->player)
|
|
{
|
|
return(false);
|
|
}
|
|
moType = actor->type;
|
|
switch(moType)
|
|
{
|
|
case MT_POD:
|
|
case MT_CHICKEN:
|
|
case MT_HEAD:
|
|
case MT_MINOTAUR:
|
|
case MT_SORCERER1:
|
|
case MT_SORCERER2:
|
|
return(false);
|
|
default:
|
|
break;
|
|
}
|
|
x = actor->x;
|
|
y = actor->y;
|
|
z = actor->z;
|
|
angle = actor->angle;
|
|
ghost = actor->flags&MF_SHADOW;
|
|
target = actor->target;
|
|
P_SetMobjState(actor, S_FREETARGMOBJ);
|
|
fog = P_SpawnMobj(x, y, z+TELEFOGHEIGHT, MT_TFOG);
|
|
S_StartSound(fog, sfx_telept);
|
|
chicken = P_SpawnMobj(x, y, z, MT_CHICKEN);
|
|
chicken->special2 = moType;
|
|
chicken->special1 = CHICKENTICS+P_Random();
|
|
chicken->flags |= ghost;
|
|
chicken->target = target;
|
|
chicken->angle = angle;
|
|
return(true);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// FUNC P_AutoUseChaosDevice
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
boolean P_AutoUseChaosDevice(player_t *player)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < player->inventorySlotNum; i++)
|
|
{
|
|
if(player->inventory[i].type == arti_teleport)
|
|
{
|
|
P_PlayerUseArtifact(player, arti_teleport);
|
|
player->health = player->mo->health = (player->health+1)/2;
|
|
return(true);
|
|
}
|
|
}
|
|
return(false);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// PROC P_AutoUseHealth
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void P_AutoUseHealth(player_t *player, int saveHealth)
|
|
{
|
|
int i;
|
|
int count;
|
|
int normalCount;
|
|
int normalSlot;
|
|
int superCount;
|
|
int superSlot;
|
|
|
|
normalCount = superCount = 0;
|
|
for(i = 0; i < player->inventorySlotNum; i++)
|
|
{
|
|
if(player->inventory[i].type == arti_health)
|
|
{
|
|
normalSlot = i;
|
|
normalCount = player->inventory[i].count;
|
|
}
|
|
else if(player->inventory[i].type == arti_superhealth)
|
|
{
|
|
superSlot = i;
|
|
superCount = player->inventory[i].count;
|
|
}
|
|
}
|
|
if((gameskill == sk_baby) && (normalCount*25 >= saveHealth))
|
|
{ // Use quartz flasks
|
|
count = (saveHealth+24)/25;
|
|
for(i = 0; i < count; i++)
|
|
{
|
|
player->health += 25;
|
|
P_PlayerRemoveArtifact(player, normalSlot);
|
|
}
|
|
}
|
|
else if(superCount*100 >= saveHealth)
|
|
{ // Use mystic urns
|
|
count = (saveHealth+99)/100;
|
|
for(i = 0; i < count; i++)
|
|
{
|
|
player->health += 100;
|
|
P_PlayerRemoveArtifact(player, superSlot);
|
|
}
|
|
}
|
|
else if((gameskill == sk_baby)
|
|
&& (superCount*100+normalCount*25 >= saveHealth))
|
|
{ // Use mystic urns and quartz flasks
|
|
count = (saveHealth+24)/25;
|
|
saveHealth -= count*25;
|
|
for(i = 0; i < count; i++)
|
|
{
|
|
player->health += 25;
|
|
P_PlayerRemoveArtifact(player, normalSlot);
|
|
}
|
|
count = (saveHealth+99)/100;
|
|
for(i = 0; i < count; i++)
|
|
{
|
|
player->health += 100;
|
|
P_PlayerRemoveArtifact(player, normalSlot);
|
|
}
|
|
}
|
|
player->mo->health = player->health;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
=
|
|
= 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 barrel explosions and other environmental stuff
|
|
==================
|
|
*/
|
|
|
|
void P_DamageMobj
|
|
(
|
|
mobj_t *target,
|
|
mobj_t *inflictor,
|
|
mobj_t *source,
|
|
int damage
|
|
)
|
|
{
|
|
unsigned ang;
|
|
int saved;
|
|
player_t *player;
|
|
fixed_t thrust;
|
|
int temp;
|
|
|
|
if(!(target->flags&MF_SHOOTABLE))
|
|
{
|
|
// Shouldn't happen
|
|
return;
|
|
}
|
|
if(target->health <= 0)
|
|
{
|
|
return;
|
|
}
|
|
if(target->flags&MF_SKULLFLY)
|
|
{
|
|
if(target->type == MT_MINOTAUR)
|
|
{ // Minotaur is invulnerable during charge attack
|
|
return;
|
|
}
|
|
target->momx = target->momy = target->momz = 0;
|
|
}
|
|
player = target->player;
|
|
if(player && gameskill == sk_baby)
|
|
{
|
|
// Take half damage in trainer mode
|
|
damage >>= 1;
|
|
}
|
|
// Special damage types
|
|
if(inflictor)
|
|
{
|
|
switch(inflictor->type)
|
|
{
|
|
case MT_EGGFX:
|
|
if(player)
|
|
{
|
|
P_ChickenMorphPlayer(player);
|
|
}
|
|
else
|
|
{
|
|
P_ChickenMorph(target);
|
|
}
|
|
return; // Always return
|
|
case MT_WHIRLWIND:
|
|
P_TouchWhirlwind(target);
|
|
return;
|
|
case MT_MINOTAUR:
|
|
if(inflictor->flags&MF_SKULLFLY)
|
|
{ // Slam only when in charge mode
|
|
P_MinotaurSlam(inflictor, target);
|
|
return;
|
|
}
|
|
break;
|
|
case MT_MACEFX4: // Death ball
|
|
if((target->flags2&MF2_BOSS) || target->type == MT_HEAD)
|
|
{ // Don't allow cheap boss kills
|
|
break;
|
|
}
|
|
else if(target->player)
|
|
{ // Player specific checks
|
|
if(target->player->powers[pw_invulnerability])
|
|
{ // Can't hurt invulnerable players
|
|
break;
|
|
}
|
|
if(P_AutoUseChaosDevice(target->player))
|
|
{ // Player was saved using chaos device
|
|
return;
|
|
}
|
|
}
|
|
damage = 10000; // Something's gonna die
|
|
break;
|
|
case MT_PHOENIXFX2: // Flame thrower
|
|
if(target->player && P_Random() < 128)
|
|
{ // Freeze player for a bit
|
|
target->reactiontime += 4;
|
|
}
|
|
break;
|
|
case MT_RAINPLR1: // Rain missiles
|
|
case MT_RAINPLR2:
|
|
case MT_RAINPLR3:
|
|
case MT_RAINPLR4:
|
|
if(target->flags2&MF2_BOSS)
|
|
{ // Decrease damage for bosses
|
|
damage = (P_Random()&7)+1;
|
|
}
|
|
break;
|
|
case MT_HORNRODFX2:
|
|
case MT_PHOENIXFX1:
|
|
if(target->type == MT_SORCERER2 && P_Random() < 96)
|
|
{ // D'Sparil teleports away
|
|
P_DSparilTeleport(target);
|
|
return;
|
|
}
|
|
break;
|
|
case MT_BLASTERFX1:
|
|
case MT_RIPPER:
|
|
if(target->type == MT_HEAD)
|
|
{ // Less damage to Ironlich bosses
|
|
damage = P_Random()&1;
|
|
if(!damage)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
// Push the target unless source is using the gauntlets
|
|
if(inflictor && (!source || !source->player
|
|
|| source->player->readyweapon != wp_gauntlets)
|
|
&& !(inflictor->flags2&MF2_NODMGTHRUST))
|
|
{
|
|
ang = R_PointToAngle2(inflictor->x, inflictor->y,
|
|
target->x, target->y);
|
|
//thrust = damage*(FRACUNIT>>3)*100/target->info->mass;
|
|
thrust = damage*(FRACUNIT>>3)*150/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;
|
|
if(source && source->player && (source == inflictor)
|
|
&& source->player->powers[pw_weaponlevel2]
|
|
&& source->player->readyweapon == wp_staff)
|
|
{
|
|
// Staff power level 2
|
|
target->momx += FixedMul(10*FRACUNIT, finecosine[ang]);
|
|
target->momy += FixedMul(10*FRACUNIT, finesine[ang]);
|
|
if(!(target->flags&MF_NOGRAVITY))
|
|
{
|
|
target->momz += 5*FRACUNIT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
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;
|
|
//}
|
|
|
|
if(damage < 1000 && ((player->cheats&CF_GODMODE)
|
|
|| player->powers[pw_invulnerability]))
|
|
{
|
|
return;
|
|
}
|
|
if(player->armortype)
|
|
{
|
|
if(player->armortype == 1)
|
|
{
|
|
saved = damage>>1;
|
|
}
|
|
else
|
|
{
|
|
saved = (damage>>1)+(damage>>2);
|
|
}
|
|
if(player->armorpoints <= saved)
|
|
{
|
|
// armor is used up
|
|
saved = player->armorpoints;
|
|
player->armortype = 0;
|
|
}
|
|
player->armorpoints -= saved;
|
|
damage -= saved;
|
|
}
|
|
if(damage >= player->health
|
|
&& ((gameskill == sk_baby) || deathmatch)
|
|
&& !player->chickenTics)
|
|
{ // Try to use some inventory health
|
|
P_AutoUseHealth(player, damage-player->health+1);
|
|
}
|
|
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);
|
|
SB_PaletteFlash();
|
|
}
|
|
}
|
|
|
|
//
|
|
// do the damage
|
|
//
|
|
target->health -= damage;
|
|
if(target->health <= 0)
|
|
{ // Death
|
|
target->special1 = damage;
|
|
if(target->type == MT_POD && source && source->type != MT_POD)
|
|
{ // Make sure players get frags for chain-reaction kills
|
|
target->target = source;
|
|
}
|
|
if(player && inflictor && !player->chickenTics)
|
|
{ // Check for flame death
|
|
if((inflictor->flags2&MF2_FIREDAMAGE)
|
|
|| ((inflictor->type == MT_PHOENIXFX1)
|
|
&& (target->health > -50) && (damage > 25)))
|
|
{
|
|
target->flags2 |= MF2_FIREDAMAGE;
|
|
}
|
|
}
|
|
P_KillMobj(source, target);
|
|
return;
|
|
}
|
|
if((P_Random() < target->info->painchance)
|
|
&& !(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 && source && !(source->flags2&MF2_BOSS)
|
|
&& !(target->type == MT_SORCERER2 && source->type == MT_WIZARD))
|
|
{
|
|
// Target actor is not intent on another actor,
|
|
// so make him chase after source
|
|
target->target = source;
|
|
target->threshold = BASETHRESHOLD;
|
|
if(target->state == &states[target->info->spawnstate]
|
|
&& target->info->seestate != S_NULL)
|
|
{
|
|
P_SetMobjState(target, target->info->seestate);
|
|
}
|
|
}
|
|
}
|