2006-02-24 04:48:15 +00:00
|
|
|
#include "actor.h"
|
|
|
|
#include "info.h"
|
|
|
|
#include "a_pickups.h"
|
|
|
|
#include "a_artifacts.h"
|
|
|
|
#include "gstrings.h"
|
|
|
|
#include "p_local.h"
|
|
|
|
#include "p_enemy.h"
|
|
|
|
#include "s_sound.h"
|
|
|
|
#include "m_random.h"
|
|
|
|
#include "a_action.h"
|
|
|
|
#include "a_hexenglobal.h"
|
|
|
|
#include "w_wad.h"
|
|
|
|
|
|
|
|
static FRandom pr_poisonbag ("PoisonBag");
|
|
|
|
static FRandom pr_poisoncloud ("PoisonCloud");
|
|
|
|
static FRandom pr_poisoncloudd ("PoisonCloudDamage");
|
|
|
|
|
|
|
|
void A_PoisonBagInit (AActor *);
|
|
|
|
void A_PoisonBagDamage (AActor *);
|
|
|
|
void A_PoisonBagCheck (AActor *);
|
|
|
|
void A_CheckThrowBomb (AActor *);
|
|
|
|
void A_CheckThrowBomb2 (AActor *);
|
|
|
|
|
|
|
|
// Poison Bag (Flechette used by Cleric) ------------------------------------
|
|
|
|
|
|
|
|
class APoisonBag : public AActor
|
|
|
|
{
|
|
|
|
DECLARE_ACTOR (APoisonBag, AActor)
|
|
|
|
};
|
|
|
|
|
|
|
|
FState APoisonBag::States[] =
|
|
|
|
{
|
|
|
|
#define S_POISONBAG1 0
|
|
|
|
S_BRIGHT (PSBG, 'A', 18, NULL , &States[S_POISONBAG1+1]),
|
|
|
|
S_BRIGHT (PSBG, 'B', 4, NULL , &States[S_POISONBAG1+2]),
|
|
|
|
S_NORMAL (PSBG, 'C', 3, NULL , &States[S_POISONBAG1+3]),
|
|
|
|
S_NORMAL (PSBG, 'C', 1, A_PoisonBagInit , NULL),
|
|
|
|
};
|
|
|
|
|
|
|
|
IMPLEMENT_ACTOR (APoisonBag, Hexen, -1, 0)
|
|
|
|
PROP_RadiusFixed (5)
|
|
|
|
PROP_HeightFixed (5)
|
|
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY)
|
|
|
|
|
|
|
|
PROP_SpawnState (S_POISONBAG1)
|
|
|
|
END_DEFAULTS
|
|
|
|
|
|
|
|
// Fire Bomb (Flechette used by Mage) ---------------------------------------
|
|
|
|
|
|
|
|
class AFireBomb : public AActor
|
|
|
|
{
|
|
|
|
DECLARE_ACTOR (AFireBomb, AActor)
|
|
|
|
public:
|
|
|
|
void PreExplode ()
|
|
|
|
{
|
|
|
|
z += 32*FRACUNIT;
|
|
|
|
RenderStyle = STYLE_Normal;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
FState AFireBomb::States[] =
|
|
|
|
{
|
|
|
|
#define S_FIREBOMB1 0
|
|
|
|
S_NORMAL (PSBG, 'A', 20, NULL , &States[S_FIREBOMB1+1]),
|
|
|
|
S_NORMAL (PSBG, 'A', 10, NULL , &States[S_FIREBOMB1+2]),
|
|
|
|
S_NORMAL (PSBG, 'A', 10, NULL , &States[S_FIREBOMB1+3]),
|
|
|
|
S_NORMAL (PSBG, 'B', 4, NULL , &States[S_FIREBOMB1+4]),
|
|
|
|
S_NORMAL (PSBG, 'C', 4, A_Scream , &States[S_FIREBOMB1+5]),
|
|
|
|
S_BRIGHT (XPL1, 'A', 4, A_Explode , &States[S_FIREBOMB1+6]),
|
|
|
|
S_BRIGHT (XPL1, 'B', 4, NULL , &States[S_FIREBOMB1+7]),
|
|
|
|
S_BRIGHT (XPL1, 'C', 4, NULL , &States[S_FIREBOMB1+8]),
|
|
|
|
S_BRIGHT (XPL1, 'D', 4, NULL , &States[S_FIREBOMB1+9]),
|
|
|
|
S_BRIGHT (XPL1, 'E', 4, NULL , &States[S_FIREBOMB1+10]),
|
|
|
|
S_BRIGHT (XPL1, 'F', 4, NULL , NULL),
|
|
|
|
};
|
|
|
|
|
|
|
|
IMPLEMENT_ACTOR (AFireBomb, Hexen, -1, 0)
|
|
|
|
PROP_DamageType (MOD_FIRE)
|
|
|
|
PROP_Flags (MF_NOGRAVITY)
|
|
|
|
PROP_Flags3 (MF3_FOILINVUL)
|
|
|
|
PROP_RenderStyle (STYLE_Translucent)
|
|
|
|
PROP_Alpha (HX_ALTSHADOW)
|
|
|
|
|
|
|
|
PROP_SpawnState (S_FIREBOMB1)
|
|
|
|
|
|
|
|
PROP_DeathSound ("FlechetteExplode")
|
|
|
|
END_DEFAULTS
|
|
|
|
|
|
|
|
// Throwing Bomb (Flechette used by Fighter) --------------------------------
|
|
|
|
|
|
|
|
class AThrowingBomb : public AActor
|
|
|
|
{
|
|
|
|
DECLARE_ACTOR (AThrowingBomb, AActor)
|
|
|
|
};
|
|
|
|
|
|
|
|
FState AThrowingBomb::States[] =
|
|
|
|
{
|
|
|
|
#define S_THROWINGBOMB1 0
|
|
|
|
S_NORMAL (THRW, 'A', 4, A_CheckThrowBomb , &States[S_THROWINGBOMB1+1]),
|
|
|
|
S_NORMAL (THRW, 'B', 3, A_CheckThrowBomb , &States[S_THROWINGBOMB1+2]),
|
|
|
|
S_NORMAL (THRW, 'C', 3, A_CheckThrowBomb , &States[S_THROWINGBOMB1+3]),
|
|
|
|
S_NORMAL (THRW, 'D', 3, A_CheckThrowBomb , &States[S_THROWINGBOMB1+4]),
|
|
|
|
S_NORMAL (THRW, 'E', 3, A_CheckThrowBomb , &States[S_THROWINGBOMB1+5]),
|
|
|
|
S_NORMAL (THRW, 'F', 3, A_CheckThrowBomb2 , &States[S_THROWINGBOMB1]),
|
|
|
|
|
|
|
|
#define S_THROWINGBOMB7 (S_THROWINGBOMB1+6)
|
|
|
|
S_NORMAL (THRW, 'G', 6, A_CheckThrowBomb , &States[S_THROWINGBOMB7+1]),
|
|
|
|
S_NORMAL (THRW, 'F', 4, A_CheckThrowBomb , &States[S_THROWINGBOMB7+2]),
|
|
|
|
S_NORMAL (THRW, 'H', 6, A_CheckThrowBomb , &States[S_THROWINGBOMB7+3]),
|
|
|
|
S_NORMAL (THRW, 'F', 4, A_CheckThrowBomb , &States[S_THROWINGBOMB7+4]),
|
|
|
|
S_NORMAL (THRW, 'G', 6, A_CheckThrowBomb , &States[S_THROWINGBOMB7+5]),
|
|
|
|
S_NORMAL (THRW, 'F', 3, A_CheckThrowBomb , &States[S_THROWINGBOMB7+5]),
|
|
|
|
|
|
|
|
#define S_THROWINGBOMB_X1 (S_THROWINGBOMB7+6)
|
|
|
|
S_BRIGHT (CFCF, 'Q', 4, A_NoGravity , &States[S_THROWINGBOMB_X1+1]),
|
|
|
|
S_BRIGHT (CFCF, 'R', 3, A_Scream , &States[S_THROWINGBOMB_X1+2]),
|
|
|
|
S_BRIGHT (CFCF, 'S', 4, A_Explode , &States[S_THROWINGBOMB_X1+3]),
|
|
|
|
S_BRIGHT (CFCF, 'T', 3, NULL , &States[S_THROWINGBOMB_X1+4]),
|
|
|
|
S_BRIGHT (CFCF, 'U', 4, NULL , &States[S_THROWINGBOMB_X1+5]),
|
|
|
|
S_BRIGHT (CFCF, 'W', 3, NULL , &States[S_THROWINGBOMB_X1+6]),
|
|
|
|
S_BRIGHT (CFCF, 'X', 4, NULL , &States[S_THROWINGBOMB_X1+7]),
|
|
|
|
S_BRIGHT (CFCF, 'Z', 3, NULL , NULL),
|
|
|
|
};
|
|
|
|
|
|
|
|
IMPLEMENT_ACTOR (AThrowingBomb, Hexen, -1, 0)
|
|
|
|
PROP_SpawnHealth (48)
|
|
|
|
PROP_SpeedFixed (12)
|
|
|
|
PROP_RadiusFixed (8)
|
|
|
|
PROP_HeightFixed (10)
|
|
|
|
PROP_DamageType (MOD_FIRE)
|
|
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE)
|
|
|
|
PROP_Flags2 (MF2_HEXENBOUNCE)
|
|
|
|
|
|
|
|
PROP_SpawnState (S_THROWINGBOMB1)
|
|
|
|
PROP_DeathState (S_THROWINGBOMB_X1)
|
|
|
|
|
|
|
|
PROP_SeeSound ("FlechetteBounce")
|
|
|
|
PROP_DeathSound ("FlechetteExplode")
|
|
|
|
END_DEFAULTS
|
|
|
|
|
|
|
|
// Poison Bag Artifact (Flechette) ------------------------------------------
|
|
|
|
|
|
|
|
class AArtiPoisonBag : public AInventory
|
|
|
|
{
|
|
|
|
DECLARE_ACTOR (AArtiPoisonBag, AInventory)
|
|
|
|
public:
|
|
|
|
bool HandlePickup (AInventory *item);
|
|
|
|
AInventory *CreateCopy (AActor *other);
|
|
|
|
void BeginPlay ();
|
|
|
|
};
|
|
|
|
|
|
|
|
FState AArtiPoisonBag::States[] =
|
|
|
|
{
|
|
|
|
S_NORMAL (PSBG, 'A', -1, NULL , NULL),
|
|
|
|
};
|
|
|
|
|
|
|
|
IMPLEMENT_ACTOR (AArtiPoisonBag, Hexen, 8000, 72)
|
|
|
|
PROP_Flags (MF_SPECIAL)
|
|
|
|
PROP_Flags2 (MF2_FLOATBOB)
|
|
|
|
PROP_SpawnState (0)
|
|
|
|
PROP_Inventory_DefMaxAmount
|
|
|
|
PROP_Inventory_FlagsSet (IF_INVBAR|IF_PICKUPFLASH|IF_FANCYPICKUPSOUND)
|
|
|
|
PROP_Inventory_Icon ("ARTIPSBG")
|
|
|
|
PROP_Inventory_PickupSound ("misc/p_pkup")
|
2006-06-17 20:29:41 +00:00
|
|
|
PROP_Inventory_PickupMessage("$TXT_ARTIPOISONBAG")
|
2006-02-24 04:48:15 +00:00
|
|
|
END_DEFAULTS
|
|
|
|
|
|
|
|
// Poison Bag 1 (The Cleric's) ----------------------------------------------
|
|
|
|
|
|
|
|
class AArtiPoisonBag1 : public AArtiPoisonBag
|
|
|
|
{
|
|
|
|
DECLARE_STATELESS_ACTOR (AArtiPoisonBag1, AArtiPoisonBag)
|
|
|
|
public:
|
|
|
|
bool Use (bool pickup);
|
|
|
|
};
|
|
|
|
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (AArtiPoisonBag1, Hexen, -1, 0)
|
|
|
|
PROP_Inventory_Icon ("ARTIPSB1")
|
|
|
|
END_DEFAULTS
|
|
|
|
|
|
|
|
bool AArtiPoisonBag1::Use (bool pickup)
|
|
|
|
{
|
|
|
|
angle_t angle = Owner->angle >> ANGLETOFINESHIFT;
|
|
|
|
AActor *mo;
|
|
|
|
|
|
|
|
mo = Spawn<APoisonBag> (
|
|
|
|
Owner->x+16*finecosine[angle],
|
|
|
|
Owner->y+24*finesine[angle], Owner->z-
|
|
|
|
Owner->floorclip+8*FRACUNIT);
|
|
|
|
if (mo)
|
|
|
|
{
|
|
|
|
mo->target = Owner;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Poison Bag 2 (The Mage's) ------------------------------------------------
|
|
|
|
|
|
|
|
class AArtiPoisonBag2 : public AArtiPoisonBag
|
|
|
|
{
|
|
|
|
DECLARE_STATELESS_ACTOR (AArtiPoisonBag2, AArtiPoisonBag)
|
|
|
|
public:
|
|
|
|
bool Use (bool pickup);
|
|
|
|
};
|
|
|
|
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (AArtiPoisonBag2, Hexen, -1, 0)
|
|
|
|
PROP_Inventory_Icon ("ARTIPSB2")
|
|
|
|
END_DEFAULTS
|
|
|
|
|
|
|
|
bool AArtiPoisonBag2::Use (bool pickup)
|
|
|
|
{
|
|
|
|
angle_t angle = Owner->angle >> ANGLETOFINESHIFT;
|
|
|
|
AActor *mo;
|
|
|
|
|
|
|
|
mo = Spawn<AFireBomb> (
|
|
|
|
Owner->x+16*finecosine[angle],
|
|
|
|
Owner->y+24*finesine[angle], Owner->z-
|
|
|
|
Owner->floorclip+8*FRACUNIT);
|
|
|
|
if (mo)
|
|
|
|
{
|
|
|
|
mo->target = Owner;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Poison Bag 3 (The Fighter's) ---------------------------------------------
|
|
|
|
|
|
|
|
class AArtiPoisonBag3 : public AArtiPoisonBag
|
|
|
|
{
|
|
|
|
DECLARE_STATELESS_ACTOR (AArtiPoisonBag3, AArtiPoisonBag)
|
|
|
|
public:
|
|
|
|
bool Use (bool pickup);
|
|
|
|
};
|
|
|
|
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (AArtiPoisonBag3, Hexen, -1, 0)
|
|
|
|
PROP_Inventory_Icon ("ARTIPSB3")
|
|
|
|
END_DEFAULTS
|
|
|
|
|
|
|
|
bool AArtiPoisonBag3::Use (bool pickup)
|
|
|
|
{
|
|
|
|
AActor *mo;
|
|
|
|
|
|
|
|
mo = Spawn<AThrowingBomb> (Owner->x, Owner->y,
|
2006-05-14 14:30:13 +00:00
|
|
|
Owner->z-Owner->floorclip+35*FRACUNIT + (Owner->player? Owner->player->crouchoffset : 0));
|
2006-02-24 04:48:15 +00:00
|
|
|
if (mo)
|
|
|
|
{
|
|
|
|
angle_t pitch = (angle_t)Owner->pitch >> ANGLETOFINESHIFT;
|
|
|
|
|
|
|
|
mo->angle = Owner->angle+(((pr_poisonbag()&7)-4)<<24);
|
|
|
|
mo->momz = 4*FRACUNIT + 2*finesine[pitch];
|
|
|
|
mo->z += 2*finesine[pitch];
|
|
|
|
P_ThrustMobj (mo, mo->angle, mo->Speed);
|
|
|
|
mo->momx += Owner->momx>>1;
|
|
|
|
mo->momy += Owner->momy>>1;
|
|
|
|
mo->target = Owner;
|
|
|
|
mo->tics -= pr_poisonbag()&3;
|
|
|
|
P_CheckMissileSpawn (mo);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// AArtiPoisonBag :: HandlePickup
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
bool AArtiPoisonBag::HandlePickup (AInventory *item)
|
|
|
|
{
|
|
|
|
// Only do special handling when picking up the base class
|
|
|
|
if (item->GetClass() != RUNTIME_CLASS(AArtiPoisonBag))
|
|
|
|
{
|
|
|
|
return Super::HandlePickup (item);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool matched;
|
|
|
|
|
|
|
|
if (Owner->IsKindOf (RUNTIME_CLASS(AClericPlayer)))
|
|
|
|
{
|
|
|
|
matched = (GetClass() == RUNTIME_CLASS(AArtiPoisonBag1));
|
|
|
|
}
|
|
|
|
else if (Owner->IsKindOf (RUNTIME_CLASS(AMagePlayer)))
|
|
|
|
{
|
|
|
|
matched = (GetClass() == RUNTIME_CLASS(AArtiPoisonBag2));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
matched = (GetClass() == RUNTIME_CLASS(AArtiPoisonBag3));
|
|
|
|
}
|
|
|
|
if (matched)
|
|
|
|
{
|
|
|
|
if (Amount < MaxAmount)
|
|
|
|
{
|
|
|
|
Amount += item->Amount;
|
|
|
|
if (Amount > MaxAmount)
|
|
|
|
{
|
|
|
|
Amount = MaxAmount;
|
|
|
|
}
|
|
|
|
item->ItemFlags |= IF_PICKUPGOOD;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (Inventory != NULL)
|
|
|
|
{
|
|
|
|
return Inventory->HandlePickup (item);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// AArtiPoisonBag :: CreateCopy
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
AInventory *AArtiPoisonBag::CreateCopy (AActor *other)
|
|
|
|
{
|
|
|
|
// Only the base class gets special handling
|
|
|
|
if (GetClass() != RUNTIME_CLASS(AArtiPoisonBag))
|
|
|
|
{
|
|
|
|
return Super::CreateCopy (other);
|
|
|
|
}
|
|
|
|
|
|
|
|
AInventory *copy;
|
2006-05-10 02:40:43 +00:00
|
|
|
const PClass *spawntype;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
if (other->IsKindOf (RUNTIME_CLASS(AClericPlayer)))
|
|
|
|
{
|
|
|
|
spawntype = RUNTIME_CLASS(AArtiPoisonBag1);
|
|
|
|
}
|
|
|
|
else if (other->IsKindOf (RUNTIME_CLASS(AMagePlayer)))
|
|
|
|
{
|
|
|
|
spawntype = RUNTIME_CLASS(AArtiPoisonBag2);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
spawntype = RUNTIME_CLASS(AArtiPoisonBag3);
|
|
|
|
}
|
|
|
|
copy = static_cast<AInventory *>(Spawn (spawntype, 0, 0, 0));
|
|
|
|
copy->Amount = Amount;
|
|
|
|
copy->MaxAmount = MaxAmount;
|
|
|
|
GoAwayAndDie ();
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// AArtiPoisonBag :: BeginPlay
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
void AArtiPoisonBag::BeginPlay ()
|
|
|
|
{
|
|
|
|
Super::BeginPlay ();
|
|
|
|
// If a subclass's specific icon is not defined, let it use the base class's.
|
|
|
|
if (Icon <= 0)
|
|
|
|
{
|
|
|
|
AInventory *defbag;
|
|
|
|
// Why doesn't this work?
|
|
|
|
//defbag = GetDefault<AArtiPoisonBag>();
|
|
|
|
defbag = (AInventory *)GetDefaultByType (RUNTIME_CLASS(AArtiPoisonBag));
|
|
|
|
Icon = defbag->Icon;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Poison Cloud -------------------------------------------------------------
|
|
|
|
|
|
|
|
FState APoisonCloud::States[] =
|
|
|
|
{
|
|
|
|
#define S_POISONCLOUD1 0
|
|
|
|
S_NORMAL (PSBG, 'D', 1, NULL , &States[S_POISONCLOUD1+1]),
|
|
|
|
S_NORMAL (PSBG, 'D', 1, A_Scream , &States[S_POISONCLOUD1+2]),
|
|
|
|
S_NORMAL (PSBG, 'D', 2, A_PoisonBagDamage , &States[S_POISONCLOUD1+3]),
|
|
|
|
S_NORMAL (PSBG, 'E', 2, A_PoisonBagDamage , &States[S_POISONCLOUD1+4]),
|
|
|
|
S_NORMAL (PSBG, 'E', 2, A_PoisonBagDamage , &States[S_POISONCLOUD1+5]),
|
|
|
|
S_NORMAL (PSBG, 'E', 2, A_PoisonBagDamage , &States[S_POISONCLOUD1+6]),
|
|
|
|
S_NORMAL (PSBG, 'F', 2, A_PoisonBagDamage , &States[S_POISONCLOUD1+7]),
|
|
|
|
S_NORMAL (PSBG, 'F', 2, A_PoisonBagDamage , &States[S_POISONCLOUD1+8]),
|
|
|
|
S_NORMAL (PSBG, 'F', 2, A_PoisonBagDamage , &States[S_POISONCLOUD1+9]),
|
|
|
|
S_NORMAL (PSBG, 'G', 2, A_PoisonBagDamage , &States[S_POISONCLOUD1+10]),
|
|
|
|
S_NORMAL (PSBG, 'G', 2, A_PoisonBagDamage , &States[S_POISONCLOUD1+11]),
|
|
|
|
S_NORMAL (PSBG, 'G', 2, A_PoisonBagDamage , &States[S_POISONCLOUD1+12]),
|
|
|
|
S_NORMAL (PSBG, 'H', 2, A_PoisonBagDamage , &States[S_POISONCLOUD1+13]),
|
|
|
|
S_NORMAL (PSBG, 'H', 2, A_PoisonBagDamage , &States[S_POISONCLOUD1+14]),
|
|
|
|
S_NORMAL (PSBG, 'H', 2, A_PoisonBagDamage , &States[S_POISONCLOUD1+15]),
|
|
|
|
S_NORMAL (PSBG, 'I', 2, A_PoisonBagDamage , &States[S_POISONCLOUD1+16]),
|
|
|
|
S_NORMAL (PSBG, 'I', 1, A_PoisonBagDamage , &States[S_POISONCLOUD1+17]),
|
|
|
|
S_NORMAL (PSBG, 'I', 1, A_PoisonBagCheck , &States[S_POISONCLOUD1+3]),
|
|
|
|
|
|
|
|
#define S_POISONCLOUD_X1 (S_POISONCLOUD1+18)
|
|
|
|
S_NORMAL (PSBG, 'H', 7, NULL , &States[S_POISONCLOUD_X1+1]),
|
|
|
|
S_NORMAL (PSBG, 'G', 7, NULL , &States[S_POISONCLOUD_X1+2]),
|
|
|
|
S_NORMAL (PSBG, 'F', 6, NULL , &States[S_POISONCLOUD_X1+3]),
|
|
|
|
S_NORMAL (PSBG, 'D', 6, NULL , NULL)
|
|
|
|
};
|
|
|
|
|
|
|
|
IMPLEMENT_ACTOR (APoisonCloud, Hexen, -1, 0)
|
|
|
|
PROP_Radius (20)
|
|
|
|
PROP_Height (30)
|
|
|
|
PROP_MassLong (0x7fffffff)
|
|
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF)
|
|
|
|
PROP_Flags2 (MF2_NODMGTHRUST)
|
|
|
|
PROP_Flags3 (MF3_DONTSPLASH|MF3_FOILINVUL|MF3_CANBLAST)
|
|
|
|
PROP_RenderStyle (STYLE_Translucent)
|
|
|
|
PROP_Alpha (HX_SHADOW)
|
|
|
|
|
|
|
|
PROP_SpawnState (S_POISONCLOUD1)
|
|
|
|
|
|
|
|
PROP_DeathSound ("PoisonShroomDeath")
|
|
|
|
END_DEFAULTS
|
|
|
|
|
|
|
|
void APoisonCloud::BeginPlay ()
|
|
|
|
{
|
|
|
|
momx = 1; // missile objects must move to impact other objects
|
|
|
|
special1 = 24+(pr_poisoncloud()&7);
|
|
|
|
special2 = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void APoisonCloud::GetExplodeParms (int &damage, int &distance, bool &hurtSource)
|
|
|
|
{
|
|
|
|
damage = 4;
|
|
|
|
distance = 40;
|
|
|
|
}
|
|
|
|
|
|
|
|
int APoisonCloud::DoSpecialDamage (AActor *victim, int damage)
|
|
|
|
{
|
|
|
|
if (victim->player)
|
|
|
|
{
|
|
|
|
bool mate = (target != NULL && victim->player != target->player && victim->IsTeammate (target));
|
|
|
|
bool dopoison;
|
|
|
|
|
|
|
|
if (!mate)
|
|
|
|
{
|
|
|
|
dopoison = victim->player->poisoncount < 4;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dopoison = victim->player->poisoncount < (int)(4.f * teamdamage);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dopoison)
|
|
|
|
{
|
|
|
|
int damage = 15 + (pr_poisoncloudd()&15);
|
|
|
|
if (mate)
|
|
|
|
{
|
|
|
|
damage = (int)((float)damage * teamdamage);
|
|
|
|
}
|
|
|
|
if (damage > 0)
|
|
|
|
{
|
|
|
|
P_PoisonDamage (victim->player, this,
|
|
|
|
15+(pr_poisoncloudd()&15), false); // Don't play painsound
|
|
|
|
P_PoisonPlayer (victim->player, this, this->target, 50);
|
|
|
|
|
|
|
|
S_Sound (victim, CHAN_VOICE, "*poison", 1, ATTN_NORM);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
else if (!(victim->flags3 & MF3_ISMONSTER))
|
|
|
|
{ // only damage monsters/players with the poison cloud
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return damage;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// A_PoisonBagInit
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void A_PoisonBagInit (AActor *actor)
|
|
|
|
{
|
|
|
|
AActor *mo;
|
|
|
|
|
|
|
|
mo = Spawn<APoisonCloud> (actor->x, actor->y, actor->z+28*FRACUNIT);
|
|
|
|
if (mo)
|
|
|
|
{
|
|
|
|
mo->target = actor->target;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// A_PoisonBagCheck
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void A_PoisonBagCheck (AActor *actor)
|
|
|
|
{
|
|
|
|
if (--actor->special1 <= 0)
|
|
|
|
{
|
|
|
|
actor->SetState (&APoisonCloud::States[S_POISONCLOUD_X1]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// A_PoisonBagDamage
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void A_PoisonBagDamage (AActor *actor)
|
|
|
|
{
|
|
|
|
int bobIndex;
|
|
|
|
|
|
|
|
A_Explode (actor);
|
|
|
|
bobIndex = actor->special2;
|
|
|
|
actor->z += FloatBobOffsets[bobIndex]>>4;
|
|
|
|
actor->special2 = (bobIndex+1)&63;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// A_CheckThrowBomb
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void A_CheckThrowBomb (AActor *actor)
|
|
|
|
{
|
|
|
|
if (--actor->health <= 0)
|
|
|
|
{
|
|
|
|
actor->SetState (actor->DeathState);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// A_CheckThrowBomb2
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void A_CheckThrowBomb2 (AActor *actor)
|
|
|
|
{
|
|
|
|
// [RH] Check using actual velocity, although the momz < 2 check still stands
|
|
|
|
//if (abs(actor->momx) < FRACUNIT*3/2 && abs(actor->momy) < FRACUNIT*3/2
|
|
|
|
// && actor->momz < 2*FRACUNIT)
|
|
|
|
if (actor->momz < 2*FRACUNIT &&
|
|
|
|
TMulScale32 (actor->momx, actor->momx, actor->momy, actor->momy, actor->momz, actor->momz)
|
|
|
|
< (3*3)/(2*2))
|
|
|
|
{
|
|
|
|
actor->SetState (&AThrowingBomb::States[S_THROWINGBOMB7]);
|
|
|
|
actor->z = actor->floorz;
|
|
|
|
actor->momz = 0;
|
|
|
|
actor->flags2 &= ~MF2_BOUNCETYPE;
|
|
|
|
actor->flags &= ~MF_MISSILE;
|
|
|
|
}
|
|
|
|
A_CheckThrowBomb (actor);
|
|
|
|
}
|