mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-12-15 06:31:01 +00:00
cf11cbdb30
SVN r4 (trunk)
2468 lines
70 KiB
C++
2468 lines
70 KiB
C++
#include "a_pickups.h"
|
|
#include "p_local.h"
|
|
#include "m_random.h"
|
|
#include "a_strifeglobal.h"
|
|
#include "s_sound.h"
|
|
#include "p_enemy.h"
|
|
#include "templates.h"
|
|
|
|
// Note: Strife missiles do 1-4 times their damage amount.
|
|
// Doom missiles do 1-8 times their damage amount, so to
|
|
// make the strife missiles do proper damage without
|
|
// hacking more stuff in the executable, be sure to give
|
|
// all Strife missiles the MF4_STRIFEDAMAGE flag.
|
|
|
|
static FRandom pr_jabdagger ("JabDagger");
|
|
static FRandom pr_electric ("FireElectric");
|
|
static FRandom pr_sgunshot ("StrifeGunShot");
|
|
static FRandom pr_minimissile ("MiniMissile");
|
|
static FRandom pr_flamethrower ("FlameThrower");
|
|
static FRandom pr_flamedie ("FlameDie");
|
|
static FRandom pr_mauler1 ("Mauler1");
|
|
static FRandom pr_mauler2 ("Mauler2");
|
|
static FRandom pr_phburn ("PhBurn");
|
|
|
|
void A_LoopActiveSound (AActor *);
|
|
void A_Countdown (AActor *);
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (AStrifeWeapon, Strife, -1, 0)
|
|
PROP_Weapon_Kickback (100)
|
|
END_DEFAULTS
|
|
|
|
// Same as the bullet puff for Doom -----------------------------------------
|
|
|
|
FState AStrifePuff::States[] =
|
|
{
|
|
// When you don't hit an actor
|
|
S_BRIGHT (PUFY, 'A', 4, NULL, &States[1]),
|
|
S_NORMAL (PUFY, 'B', 4, NULL, &States[2]),
|
|
S_NORMAL (PUFY, 'C', 4, NULL, &States[3]),
|
|
S_NORMAL (PUFY, 'D', 4, NULL, NULL),
|
|
|
|
// When you do hit an actor
|
|
S_NORMAL (POW3, 'A', 3, NULL, &States[5]),
|
|
S_NORMAL (POW3, 'B', 3, NULL, &States[6]),
|
|
S_NORMAL (POW3, 'C', 3, NULL, &States[7]),
|
|
S_NORMAL (POW3, 'D', 3, NULL, &States[8]),
|
|
S_NORMAL (POW3, 'E', 3, NULL, &States[9]),
|
|
S_NORMAL (POW3, 'F', 3, NULL, &States[10]),
|
|
S_NORMAL (POW3, 'G', 3, NULL, &States[11]),
|
|
S_NORMAL (POW3, 'H', 3, NULL, NULL),
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AStrifePuff, Strife, -1, 0)
|
|
PROP_SpawnState (4)
|
|
PROP_CrashState (0)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY)
|
|
PROP_Alpha (TRANSLUC25)
|
|
PROP_RenderStyle (STYLE_Translucent)
|
|
END_DEFAULTS
|
|
|
|
// A spark when you hit something that doesn't bleed ------------------------
|
|
// Only used by the dagger.
|
|
|
|
class AStrifeSpark : public AActor
|
|
{
|
|
DECLARE_ACTOR (AStrifeSpark, AActor)
|
|
};
|
|
|
|
FState AStrifeSpark::States[] =
|
|
{
|
|
// When you hit an actor
|
|
S_NORMAL (POW3, 'A', 3, NULL, &States[1]),
|
|
S_NORMAL (POW3, 'B', 3, NULL, &States[2]),
|
|
S_NORMAL (POW3, 'C', 3, NULL, &States[3]),
|
|
S_NORMAL (POW3, 'D', 3, NULL, &States[4]),
|
|
S_NORMAL (POW3, 'E', 3, NULL, &States[5]),
|
|
S_NORMAL (POW3, 'F', 3, NULL, &States[6]),
|
|
S_NORMAL (POW3, 'G', 3, NULL, &States[7]),
|
|
S_NORMAL (POW3, 'H', 3, NULL, NULL),
|
|
|
|
// When you hit something else
|
|
S_NORMAL (POW2, 'A', 4, NULL, &States[9]),
|
|
S_NORMAL (POW2, 'B', 4, NULL, &States[10]),
|
|
S_NORMAL (POW2, 'C', 4, NULL, &States[11]),
|
|
S_NORMAL (POW2, 'D', 4, NULL, NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AStrifeSpark, Strife, -1, 0)
|
|
PROP_SpawnState (0)
|
|
PROP_CrashState (8)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
PROP_Alpha (TRANSLUC25)
|
|
END_DEFAULTS
|
|
|
|
// Punch Dagger -------------------------------------------------------------
|
|
|
|
void A_JabDagger (AActor *);
|
|
|
|
class APunchDagger : public AStrifeWeapon
|
|
{
|
|
DECLARE_ACTOR (APunchDagger, AStrifeWeapon)
|
|
};
|
|
|
|
FState APunchDagger::States[] =
|
|
{
|
|
#define S_PUNCH 0
|
|
S_NORMAL (PNCH, 'A', 1, A_WeaponReady , &States[S_PUNCH]),
|
|
|
|
#define S_PUNCHDOWN (S_PUNCH+1)
|
|
S_NORMAL (PNCH, 'A', 1, A_Lower , &States[S_PUNCHDOWN]),
|
|
|
|
#define S_PUNCHUP (S_PUNCHDOWN+1)
|
|
S_NORMAL (PNCH, 'A', 1, A_Raise , &States[S_PUNCHUP]),
|
|
|
|
#define S_PUNCH1 (S_PUNCHUP+1)
|
|
S_NORMAL (PNCH, 'B', 4, NULL , &States[S_PUNCH1+1]),
|
|
S_NORMAL (PNCH, 'C', 4, A_JabDagger , &States[S_PUNCH1+2]),
|
|
S_NORMAL (PNCH, 'D', 5, NULL , &States[S_PUNCH1+3]),
|
|
S_NORMAL (PNCH, 'C', 4, NULL , &States[S_PUNCH1+4]),
|
|
S_NORMAL (PNCH, 'B', 5, A_ReFire , &States[S_PUNCH])
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (APunchDagger, Strife, -1, 0)
|
|
PROP_Weapon_SelectionOrder (3900)
|
|
PROP_Weapon_Flags (WIF_NOALERT)
|
|
PROP_Weapon_UpState (S_PUNCHUP)
|
|
PROP_Weapon_DownState (S_PUNCHDOWN)
|
|
PROP_Weapon_ReadyState (S_PUNCH)
|
|
PROP_Weapon_AtkState (S_PUNCH1)
|
|
PROP_Weapon_HoldAtkState (S_PUNCH1)
|
|
END_DEFAULTS
|
|
|
|
//============================================================================
|
|
//
|
|
// P_DaggerAlert
|
|
//
|
|
//============================================================================
|
|
|
|
void P_DaggerAlert (AActor *target, AActor *emitter)
|
|
{
|
|
AActor *looker;
|
|
sector_t *sec = emitter->Sector;
|
|
|
|
if (emitter->LastHeard != NULL)
|
|
return;
|
|
if (emitter->health <= 0)
|
|
return;
|
|
if (!(emitter->flags3 & MF3_ISMONSTER))
|
|
return;
|
|
if (emitter->flags4 & MF4_INCOMBAT)
|
|
return;
|
|
emitter->flags4 |= MF4_INCOMBAT;
|
|
|
|
emitter->target = target;
|
|
if (emitter->PainState != NULL)
|
|
{
|
|
emitter->SetState (emitter->PainState);
|
|
}
|
|
|
|
for (looker = sec->thinglist; looker != NULL; looker = looker->snext)
|
|
{
|
|
if (looker == emitter || looker == target)
|
|
continue;
|
|
|
|
if (looker->health <= 0)
|
|
continue;
|
|
|
|
if (!(looker->flags4 & MF4_SEESDAGGERS))
|
|
continue;
|
|
|
|
if (!(looker->flags4 & MF4_INCOMBAT))
|
|
{
|
|
if (!P_CheckSight (looker, target) && !P_CheckSight (looker, emitter))
|
|
continue;
|
|
|
|
looker->target = target;
|
|
if (looker->SeeSound)
|
|
{
|
|
S_SoundID (looker, CHAN_VOICE, looker->SeeSound, 1, ATTN_NORM);
|
|
}
|
|
looker->SetState (looker->SeeState);
|
|
looker->flags4 |= MF4_INCOMBAT;
|
|
}
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_JabDagger
|
|
//
|
|
//============================================================================
|
|
|
|
void A_JabDagger (AActor *actor)
|
|
{
|
|
angle_t angle;
|
|
int damage;
|
|
int pitch;
|
|
int power;
|
|
|
|
power = actor->player->stamina / 10;
|
|
damage = (pr_jabdagger() & (power + 7)) * (power + 2);
|
|
|
|
if (actor->FindInventory<APowerStrength>())
|
|
{
|
|
damage *= 10;
|
|
}
|
|
|
|
angle = actor->angle + (pr_jabdagger.Random2() << 18);
|
|
pitch = P_AimLineAttack (actor, angle, 80*FRACUNIT);
|
|
P_LineAttack (actor, angle, 80*FRACUNIT, pitch, damage, MOD_HIT, RUNTIME_CLASS(AStrifeSpark));
|
|
|
|
// turn to face target
|
|
if (linetarget)
|
|
{
|
|
S_Sound (actor, CHAN_WEAPON,
|
|
linetarget->flags & MF_NOBLOOD ? "misc/metalhit" : "misc/meathit",
|
|
1, ATTN_NORM);
|
|
actor->angle = R_PointToAngle2 (actor->x,
|
|
actor->y,
|
|
linetarget->x,
|
|
linetarget->y);
|
|
actor->flags |= MF_JUSTATTACKED;
|
|
P_DaggerAlert (actor, linetarget);
|
|
}
|
|
else
|
|
{
|
|
S_Sound (actor, CHAN_WEAPON, "misc/swish", 1, ATTN_NORM);
|
|
}
|
|
}
|
|
|
|
// The base for Strife projectiles that die with ZAP1 -----------------------
|
|
|
|
void A_AlertMonsters (AActor *);
|
|
|
|
class AStrifeZap1 : public AActor
|
|
{
|
|
DECLARE_ACTOR (AStrifeZap1, AActor)
|
|
};
|
|
|
|
FState AStrifeZap1::States[] =
|
|
{
|
|
S_NORMAL (ZAP1, 'A', 3, A_AlertMonsters, &States[1]),
|
|
S_NORMAL (ZAP1, 'B', 3, NULL, &States[2]),
|
|
S_NORMAL (ZAP1, 'C', 3, NULL, &States[3]),
|
|
S_NORMAL (ZAP1, 'D', 3, NULL, &States[4]),
|
|
S_NORMAL (ZAP1, 'E', 3, NULL, &States[5]),
|
|
S_NORMAL (ZAP1, 'F', 3, NULL, &States[6]),
|
|
S_NORMAL (ZAP1, 'E', 3, NULL, &States[7]),
|
|
S_NORMAL (ZAP1, 'D', 3, NULL, &States[8]),
|
|
S_NORMAL (ZAP1, 'C', 3, NULL, &States[9]),
|
|
S_NORMAL (ZAP1, 'B', 3, NULL, &States[10]),
|
|
S_NORMAL (ZAP1, 'A', 3, NULL, NULL),
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AStrifeZap1, Strife, -1, 0)
|
|
PROP_DeathState (0)
|
|
|
|
// The spawn state is here just to allow it to be spawned on its own.
|
|
// Strife doesn't contain any actual mobjinfo that will spawn this;
|
|
// it is always the death state for something else.
|
|
PROP_SpawnState (0)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF)
|
|
END_DEFAULTS
|
|
|
|
//============================================================================
|
|
//
|
|
// A_AlertMonsters
|
|
//
|
|
//============================================================================
|
|
|
|
void A_AlertMonsters (AActor *self)
|
|
{
|
|
if (self->target != NULL && self->target->player != NULL)
|
|
{
|
|
P_NoiseAlert (self->target, self);
|
|
}
|
|
}
|
|
|
|
// Electric Bolt ------------------------------------------------------------
|
|
|
|
class AElectricBolt : public AStrifeZap1
|
|
{
|
|
DECLARE_ACTOR (AElectricBolt, AStrifeZap1)
|
|
};
|
|
|
|
FState AElectricBolt::States[] =
|
|
{
|
|
S_NORMAL (AROW, 'A', 10, A_LoopActiveSound, &States[0]),
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AElectricBolt, Strife, -1, 0)
|
|
PROP_SpawnState (0)
|
|
PROP_SpeedFixed (30)
|
|
PROP_RadiusFixed (10)
|
|
PROP_HeightFixed (10)
|
|
PROP_Damage (10)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE)
|
|
PROP_Flags2 (MF2_NOTELEPORT|MF2_PCROSS|MF2_IMPACT)
|
|
PROP_Flags4 (MF4_STRIFEDAMAGE)
|
|
PROP_MaxStepHeight (4)
|
|
PROP_StrifeType (102)
|
|
PROP_SeeSound ("misc/swish")
|
|
PROP_ActiveSound ("misc/swish")
|
|
PROP_DeathSound ("weapons/xbowhit")
|
|
END_DEFAULTS
|
|
|
|
// Poison Bolt --------------------------------------------------------------
|
|
|
|
class APoisonBolt : public AActor
|
|
{
|
|
DECLARE_ACTOR (APoisonBolt, AActor)
|
|
public:
|
|
int DoSpecialDamage (AActor *target, int damage);
|
|
};
|
|
|
|
FState APoisonBolt::States[] =
|
|
{
|
|
S_NORMAL (ARWP, 'A', 10, A_LoopActiveSound, &States[0]),
|
|
|
|
S_NORMAL (AROW, 'A', 1, NULL, NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (APoisonBolt, Strife, -1, 0)
|
|
PROP_SpawnState (0)
|
|
PROP_DeathState (1)
|
|
PROP_SpeedFixed (30)
|
|
PROP_RadiusFixed (10)
|
|
PROP_HeightFixed (10)
|
|
PROP_DamageLong (500)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE)
|
|
PROP_Flags2 (MF2_NOTELEPORT|MF2_PCROSS|MF2_IMPACT)
|
|
PROP_Flags4 (MF4_STRIFEDAMAGE)
|
|
PROP_MaxStepHeight (4)
|
|
PROP_StrifeType (103)
|
|
PROP_SeeSound ("misc/swish")
|
|
PROP_ActiveSound ("misc/swish")
|
|
END_DEFAULTS
|
|
|
|
int APoisonBolt::DoSpecialDamage (AActor *target, int damage)
|
|
{
|
|
if (target->flags & MF_NOBLOOD)
|
|
{
|
|
return -1;
|
|
}
|
|
if (target->health < 1000000)
|
|
{
|
|
return target->health + 10;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
// Strife's Crossbow --------------------------------------------------------
|
|
|
|
void A_XBowReFire (AActor *);
|
|
void A_ClearFlash (AActor *);
|
|
void A_ShowElectricFlash (AActor *);
|
|
void A_FireElectric (AActor *);
|
|
void A_FirePoison (AActor *);
|
|
|
|
class AStrifeCrossbow : public AStrifeWeapon
|
|
{
|
|
DECLARE_ACTOR (AStrifeCrossbow, AStrifeWeapon)
|
|
public:
|
|
const char *PickupMessage ()
|
|
{
|
|
return "You picked up the crossbow";
|
|
}
|
|
};
|
|
|
|
FState AStrifeCrossbow::States[] =
|
|
{
|
|
S_NORMAL (CBOW, 'A', -1, NULL, &States[0]),
|
|
|
|
// Electric
|
|
|
|
#define S_EXBOW 1
|
|
S_NORMAL (XBOW, 'A', 0, A_ShowElectricFlash, &States[S_EXBOW+1]),
|
|
S_NORMAL (XBOW, 'A', 1, A_WeaponReady, &States[S_EXBOW+1]),
|
|
|
|
#define S_EXBOWDOWN (S_EXBOW+2)
|
|
S_NORMAL (XBOW, 'A', 1, A_Lower, &States[S_EXBOWDOWN]),
|
|
|
|
#define S_EXBOWUP (S_EXBOWDOWN+1)
|
|
S_NORMAL (XBOW, 'A', 1, A_Raise, &States[S_EXBOWUP]),
|
|
|
|
#define S_EXBOWATK (S_EXBOWUP+1)
|
|
S_NORMAL (XBOW, 'A', 3, A_ClearFlash, &States[S_EXBOWATK+1]),
|
|
S_NORMAL (XBOW, 'B', 6, A_FireElectric, &States[S_EXBOWATK+2]),
|
|
S_NORMAL (XBOW, 'C', 4, NULL, &States[S_EXBOWATK+3]),
|
|
S_NORMAL (XBOW, 'D', 6, NULL, &States[S_EXBOWATK+4]),
|
|
S_NORMAL (XBOW, 'E', 3, NULL, &States[S_EXBOWATK+5]),
|
|
S_NORMAL (XBOW, 'F', 5, NULL, &States[S_EXBOWATK+6]),
|
|
S_NORMAL (XBOW, 'G', 5, A_XBowReFire, &States[S_EXBOW]),
|
|
|
|
#define S_EXBOWARROWHEAD (S_EXBOWATK+7)
|
|
S_NORMAL (XBOW, 'K', 5, NULL, &States[S_EXBOWARROWHEAD+1]),
|
|
S_NORMAL (XBOW, 'L', 5, NULL, &States[S_EXBOWARROWHEAD+2]),
|
|
S_NORMAL (XBOW, 'M', 5, NULL, &States[S_EXBOWARROWHEAD]),
|
|
|
|
// Poison
|
|
|
|
#define S_PXBOW (S_EXBOWARROWHEAD+3)
|
|
S_NORMAL (XBOW, 'H', 1, A_WeaponReady, &States[S_PXBOW]),
|
|
|
|
#define S_PXBOWDOWN (S_PXBOW+1)
|
|
S_NORMAL (XBOW, 'H', 1, A_Lower, &States[S_PXBOWDOWN]),
|
|
|
|
#define S_PXBOWUP (S_PXBOWDOWN+1)
|
|
S_NORMAL (XBOW, 'H', 1, A_Raise, &States[S_PXBOWUP]),
|
|
|
|
#define S_PXBOWATK (S_PXBOWUP+1)
|
|
S_NORMAL (XBOW, 'H', 3, NULL, &States[S_PXBOWATK+1]),
|
|
S_NORMAL (XBOW, 'B', 6, A_FirePoison, &States[S_PXBOWATK+2]),
|
|
S_NORMAL (XBOW, 'C', 4, NULL, &States[S_PXBOWATK+3]),
|
|
S_NORMAL (XBOW, 'D', 6, NULL, &States[S_PXBOWATK+4]),
|
|
S_NORMAL (XBOW, 'E', 3, NULL, &States[S_PXBOWATK+5]),
|
|
S_NORMAL (XBOW, 'I', 5, NULL, &States[S_PXBOWATK+6]),
|
|
S_NORMAL (XBOW, 'J', 5, A_XBowReFire, &States[S_PXBOW]),
|
|
};
|
|
|
|
// The electric version
|
|
|
|
IMPLEMENT_ACTOR (AStrifeCrossbow, Strife, 2001, 0)
|
|
PROP_Flags (MF_SPECIAL)
|
|
PROP_Flags2 (MF2_FLOORCLIP)
|
|
PROP_SpawnState (0)
|
|
PROP_StrifeType (194)
|
|
PROP_StrifeTeaserType (188)
|
|
PROP_StrifeTeaserType2 (192)
|
|
|
|
PROP_Weapon_SelectionOrder (1200)
|
|
PROP_Weapon_Flags (WIF_NOALERT)
|
|
PROP_Weapon_AmmoUse1 (1)
|
|
PROP_Weapon_AmmoGive1 (8)
|
|
PROP_Weapon_UpState (S_EXBOWUP)
|
|
PROP_Weapon_DownState (S_EXBOWDOWN)
|
|
PROP_Weapon_ReadyState (S_EXBOW)
|
|
PROP_Weapon_AtkState (S_EXBOWATK)
|
|
PROP_Weapon_HoldAtkState (S_EXBOWATK)
|
|
PROP_Weapon_MoveCombatDist (24000000)
|
|
PROP_Weapon_AmmoType1 ("ElectricBolts")
|
|
PROP_Weapon_SisterType ("StrifeCrossbow2")
|
|
PROP_Weapon_ProjectileType ("ElectricBolt")
|
|
|
|
PROP_Inventory_Icon ("CBOWA0")
|
|
PROP_Tag ("crossbow")
|
|
END_DEFAULTS
|
|
|
|
// Poison Crossbow ----------------------------------------------------------
|
|
|
|
class AStrifeCrossbow2 : public AStrifeCrossbow
|
|
{
|
|
DECLARE_STATELESS_ACTOR (AStrifeCrossbow2, AStrifeCrossbow)
|
|
};
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (AStrifeCrossbow2, Strife, -1, 0)
|
|
PROP_Weapon_SelectionOrder (2700)
|
|
PROP_Weapon_Flags (WIF_NOALERT)
|
|
PROP_Weapon_AmmoUse1 (1)
|
|
PROP_Weapon_AmmoGive1 (0)
|
|
PROP_Weapon_UpState (S_PXBOWUP)
|
|
PROP_Weapon_DownState (S_PXBOWDOWN)
|
|
PROP_Weapon_ReadyState (S_PXBOW)
|
|
PROP_Weapon_AtkState (S_PXBOWATK)
|
|
PROP_Weapon_HoldAtkState (S_PXBOWATK)
|
|
PROP_Weapon_AmmoType1 ("PoisonBolts")
|
|
PROP_Weapon_SisterType ("StrifeCrossbow")
|
|
PROP_Weapon_ProjectileType ("PoisonBolt")
|
|
END_DEFAULTS
|
|
|
|
|
|
//============================================================================
|
|
//
|
|
// A_ClearFlash
|
|
//
|
|
//============================================================================
|
|
|
|
void A_ClearFlash (AActor *self)
|
|
{
|
|
player_t *player = self->player;
|
|
|
|
if (player == NULL)
|
|
return;
|
|
|
|
P_SetPsprite (player, ps_flash, NULL);
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_ShowElectricFlash
|
|
//
|
|
//============================================================================
|
|
|
|
void A_ShowElectricFlash (AActor *self)
|
|
{
|
|
if (self->player != NULL)
|
|
{
|
|
P_SetPsprite (self->player, ps_flash, &AStrifeCrossbow::States[S_EXBOWARROWHEAD]);
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_FireElectric
|
|
//
|
|
//============================================================================
|
|
|
|
void A_FireElectric (AActor *self)
|
|
{
|
|
angle_t savedangle;
|
|
|
|
if (self->player == NULL)
|
|
return;
|
|
|
|
AWeapon *weapon = self->player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
|
|
savedangle = self->angle;
|
|
self->angle += pr_electric.Random2 () << (18 - self->player->accuracy * 5 / 100);
|
|
self->player->mo->PlayAttacking2 ();
|
|
P_SpawnPlayerMissile (self, RUNTIME_CLASS(AElectricBolt));
|
|
self->angle = savedangle;
|
|
S_Sound (self, CHAN_WEAPON, "weapons/xbowshoot", 1, ATTN_NORM);
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_FirePoison
|
|
//
|
|
//============================================================================
|
|
|
|
void A_FirePoison (AActor *self)
|
|
{
|
|
angle_t savedangle;
|
|
|
|
if (self->player == NULL)
|
|
return;
|
|
|
|
AWeapon *weapon = self->player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
|
|
savedangle = self->angle;
|
|
self->angle += pr_electric.Random2 () << (18 - self->player->accuracy * 5 / 100);
|
|
self->player->mo->PlayAttacking2 ();
|
|
P_SpawnPlayerMissile (self, RUNTIME_CLASS(APoisonBolt));
|
|
self->angle = savedangle;
|
|
S_Sound (self, CHAN_WEAPON, "weapons/xbowshoot", 1, ATTN_NORM);
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_XBowReFire
|
|
//
|
|
//============================================================================
|
|
|
|
void A_XBowReFire (AActor *self)
|
|
{
|
|
player_t *player = self->player;
|
|
|
|
if (player == NULL)
|
|
return;
|
|
|
|
AWeapon *weapon = player->ReadyWeapon;
|
|
if (weapon == NULL)
|
|
return;
|
|
|
|
weapon->CheckAmmo (weapon->bAltFire ? AWeapon::AltFire : AWeapon::PrimaryFire, true);
|
|
if (weapon->GetClass() == RUNTIME_CLASS(AStrifeCrossbow))
|
|
{
|
|
P_SetPsprite (player, ps_flash, &AStrifeCrossbow::States[S_EXBOWARROWHEAD]);
|
|
}
|
|
}
|
|
|
|
// Assault Gun --------------------------------------------------------------
|
|
|
|
class AAssaultGun : public AStrifeWeapon
|
|
{
|
|
DECLARE_ACTOR (AAssaultGun, AStrifeWeapon)
|
|
public:
|
|
const char *PickupMessage ()
|
|
{
|
|
return "You picked up the assault gun";
|
|
}
|
|
bool HandlePickup (AInventory *item);
|
|
};
|
|
|
|
class AAssaultGunStanding : public AAssaultGun
|
|
{
|
|
DECLARE_ACTOR (AAssaultGunStanding, AAssaultGun)
|
|
public:
|
|
AInventory *CreateCopy (AActor *other);
|
|
};
|
|
|
|
void A_FireAssaultGun (AActor *);
|
|
|
|
FState AAssaultGun::States[] =
|
|
{
|
|
S_NORMAL (RIFL, 'A', -1, NULL, &States[0]),
|
|
|
|
#define S_ASSAULT 1
|
|
S_NORMAL (RIFG, 'A', 1, A_WeaponReady, &States[S_ASSAULT]),
|
|
|
|
#define S_ASSAULTDOWN (S_ASSAULT+1)
|
|
S_NORMAL (RIFG, 'B', 1, A_Lower, &States[S_ASSAULTDOWN]),
|
|
|
|
#define S_ASSAULTUP (S_ASSAULTDOWN+1)
|
|
S_NORMAL (RIFG, 'A', 1, A_Raise, &States[S_ASSAULTUP]),
|
|
|
|
#define S_ASSAULTATK (S_ASSAULTUP+1)
|
|
S_NORMAL (RIFF, 'A', 3, A_FireAssaultGun, &States[S_ASSAULTATK+1]),
|
|
S_NORMAL (RIFF, 'B', 3, A_FireAssaultGun, &States[S_ASSAULTATK+2]),
|
|
S_NORMAL (RIFG, 'D', 3, A_FireAssaultGun, &States[S_ASSAULTATK+3]),
|
|
S_NORMAL (RIFG, 'C', 0, A_ReFire, &States[S_ASSAULTATK+4]),
|
|
S_NORMAL (RIFG, 'B', 2, NULL, &States[S_ASSAULT])
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AAssaultGun, Strife, 2002, 0)
|
|
PROP_Flags (MF_SPECIAL)
|
|
PROP_Flags2 (MF2_FLOORCLIP)
|
|
PROP_SpawnState (0)
|
|
PROP_StrifeType (188)
|
|
PROP_StrifeTeaserType (182)
|
|
PROP_StrifeTeaserType2 (186)
|
|
|
|
PROP_Weapon_SelectionOrder (600)
|
|
PROP_Weapon_AmmoUse1 (1)
|
|
PROP_Weapon_AmmoGive1 (20)
|
|
PROP_Weapon_UpState (S_ASSAULTUP)
|
|
PROP_Weapon_DownState (S_ASSAULTDOWN)
|
|
PROP_Weapon_ReadyState (S_ASSAULT)
|
|
PROP_Weapon_AtkState (S_ASSAULTATK)
|
|
PROP_Weapon_HoldAtkState (S_ASSAULTATK)
|
|
PROP_Weapon_MoveCombatDist (27000000)
|
|
PROP_Weapon_AmmoType1 ("ClipOfBullets")
|
|
|
|
PROP_Inventory_Icon ("RIFLA0")
|
|
PROP_Tag ("assault_gun")
|
|
END_DEFAULTS
|
|
|
|
//============================================================================
|
|
//
|
|
// AAssaultGun :: HandlePickup
|
|
//
|
|
// Picking up the standing assault gun is the same as picking up a regular
|
|
// one.
|
|
//
|
|
//============================================================================
|
|
|
|
bool AAssaultGun::HandlePickup (AInventory *item)
|
|
{
|
|
if (item->GetClass() == RUNTIME_CLASS(AAssaultGunStanding) ||
|
|
item->GetClass() == GetClass())
|
|
{
|
|
if (static_cast<AWeapon *>(item)->PickupForAmmo (this))
|
|
{
|
|
item->ItemFlags |= IF_PICKUPGOOD;
|
|
}
|
|
return true;
|
|
}
|
|
if (Inventory != NULL)
|
|
{
|
|
return Inventory->HandlePickup (item);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// P_StrifeGunShot
|
|
//
|
|
//============================================================================
|
|
|
|
void P_StrifeGunShot (AActor *mo, bool accurate)
|
|
{
|
|
angle_t angle;
|
|
int damage;
|
|
|
|
damage = 4*(pr_sgunshot()%3+1);
|
|
angle = mo->angle;
|
|
|
|
if (mo->player != NULL && !accurate)
|
|
{
|
|
angle += pr_sgunshot.Random2() << (20 - mo->player->accuracy * 5 / 100);
|
|
}
|
|
|
|
P_LineAttack (mo, angle, PLAYERMISSILERANGE, bulletpitch, damage, MOD_UNKNOWN, RUNTIME_CLASS(AStrifePuff));
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_FireAssaultGun
|
|
//
|
|
//============================================================================
|
|
|
|
void A_FireAssaultGun (AActor *self)
|
|
{
|
|
bool accurate;
|
|
|
|
S_Sound (self, CHAN_WEAPON, "weapons/assaultgun", 1, ATTN_NORM);
|
|
|
|
if (self->player != NULL)
|
|
{
|
|
AWeapon *weapon = self->player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
self->player->mo->PlayAttacking2 ();
|
|
accurate = !self->player->refire;
|
|
}
|
|
else
|
|
{
|
|
accurate = true;
|
|
}
|
|
|
|
P_BulletSlope (self);
|
|
P_StrifeGunShot (self, accurate);
|
|
}
|
|
|
|
// Standing variant of the assault gun --------------------------------------
|
|
|
|
FState AAssaultGunStanding::States[] =
|
|
{
|
|
S_NORMAL (RIFL, 'B', -1, NULL, &States[0]),
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AAssaultGunStanding, Strife, 2006, 0)
|
|
PROP_SpawnState (0)
|
|
PROP_StrifeType (189)
|
|
PROP_StrifeTeaserType (183)
|
|
PROP_StrifeTeaserType2 (187)
|
|
// "pulse_rifle" in the Teaser
|
|
END_DEFAULTS
|
|
|
|
//============================================================================
|
|
//
|
|
// AAssaultGunStanding :: CreateCopy
|
|
//
|
|
// This is just a different look for the standard assault gun. It is not a
|
|
// gun in its own right, so give the player an AssaultGun, not this.
|
|
//
|
|
//============================================================================
|
|
|
|
AInventory *AAssaultGunStanding::CreateCopy (AActor *other)
|
|
{
|
|
AAssaultGun *copy = Spawn<AAssaultGun> (0,0,0);
|
|
copy->AmmoGive1 = AmmoGive1;
|
|
copy->AmmoGive2 = AmmoGive2;
|
|
GoAwayAndDie ();
|
|
return copy;
|
|
}
|
|
|
|
// Mini-Missile Launcher ----------------------------------------------------
|
|
|
|
void A_FireMiniMissile (AActor *);
|
|
|
|
class AMiniMissileLauncher : public AStrifeWeapon
|
|
{
|
|
DECLARE_ACTOR (AMiniMissileLauncher, AStrifeWeapon)
|
|
public:
|
|
const char *PickupMessage ()
|
|
{
|
|
return "You picked up the mini missile launcher";
|
|
}
|
|
};
|
|
|
|
FState AMiniMissileLauncher::States[] =
|
|
{
|
|
S_NORMAL (MMSL, 'A', -1, NULL, NULL),
|
|
|
|
#define S_MMISSILE 1
|
|
S_NORMAL (MMIS, 'A', 1, A_WeaponReady, &States[S_MMISSILE]),
|
|
|
|
#define S_MMISSILEDOWN (S_MMISSILE+1)
|
|
S_NORMAL (MMIS, 'A', 1, A_Lower, &States[S_MMISSILEDOWN]),
|
|
|
|
#define S_MMISSILEUP (S_MMISSILEDOWN+1)
|
|
S_NORMAL (MMIS, 'A', 1, A_Raise, &States[S_MMISSILEUP]),
|
|
|
|
#define S_MMISSILEATK (S_MMISSILEUP+1)
|
|
S_NORMAL (MMIS, 'A', 4, A_FireMiniMissile, &States[S_MMISSILEATK+1]),
|
|
S_NORMAL (MMIS, 'B', 4, A_Light1, &States[S_MMISSILEATK+2]),
|
|
S_BRIGHT (MMIS, 'C', 5, NULL, &States[S_MMISSILEATK+3]),
|
|
S_BRIGHT (MMIS, 'D', 2, A_Light2, &States[S_MMISSILEATK+4]),
|
|
S_BRIGHT (MMIS, 'E', 2, NULL, &States[S_MMISSILEATK+5]),
|
|
S_BRIGHT (MMIS, 'F', 2, A_Light0, &States[S_MMISSILEATK+6]),
|
|
S_NORMAL (MMIS, 'F', 0, A_ReFire, &States[S_MMISSILE])
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AMiniMissileLauncher, Strife, 2003, 0)
|
|
PROP_Flags (MF_SPECIAL)
|
|
PROP_Flags2 (MF2_FLOORCLIP)
|
|
PROP_SpawnState (0)
|
|
PROP_StrifeType (192)
|
|
PROP_StrifeTeaserType (186)
|
|
PROP_StrifeTeaserType2 (190)
|
|
|
|
PROP_Weapon_SelectionOrder (1800)
|
|
PROP_Weapon_AmmoUse1 (1)
|
|
PROP_Weapon_AmmoGive1 (8)
|
|
PROP_Weapon_UpState (S_MMISSILEUP)
|
|
PROP_Weapon_DownState (S_MMISSILEDOWN)
|
|
PROP_Weapon_ReadyState (S_MMISSILE)
|
|
PROP_Weapon_AtkState (S_MMISSILEATK)
|
|
PROP_Weapon_HoldAtkState (S_MMISSILEATK)
|
|
PROP_Weapon_MoveCombatDist (18350080)
|
|
PROP_Weapon_AmmoType1 ("MiniMissiles")
|
|
|
|
PROP_Inventory_Icon ("MMSLA0")
|
|
PROP_Tag ("mini_missile_launcher") // "missile_gun" in the Teaser
|
|
END_DEFAULTS
|
|
|
|
// Rocket Trail -------------------------------------------------------------
|
|
|
|
class ARocketTrail : public AActor
|
|
{
|
|
DECLARE_ACTOR (ARocketTrail, AActor);
|
|
};
|
|
|
|
FState ARocketTrail::States[] =
|
|
{
|
|
S_NORMAL (PUFY, 'B', 4, NULL, &States[1]),
|
|
S_NORMAL (PUFY, 'C', 4, NULL, &States[2]),
|
|
S_NORMAL (PUFY, 'B', 4, NULL, &States[3]),
|
|
S_NORMAL (PUFY, 'C', 4, NULL, &States[4]),
|
|
S_NORMAL (PUFY, 'D', 4, NULL, NULL),
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (ARocketTrail, Strife, -1, 0)
|
|
PROP_SpawnState (0)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY)
|
|
PROP_Alpha (TRANSLUC25)
|
|
PROP_RenderStyle (STYLE_Translucent)
|
|
PROP_StrifeType (51)
|
|
PROP_SeeSound ("misc/missileinflight")
|
|
END_DEFAULTS
|
|
|
|
// Rocket Puff --------------------------------------------------------------
|
|
|
|
class AMiniMissilePuff : public AStrifePuff
|
|
{
|
|
DECLARE_STATELESS_ACTOR (AMiniMissilePuff, AStrifePuff)
|
|
};
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (AMiniMissilePuff, Strife, -1, 0)
|
|
PROP_SpawnState (0)
|
|
END_DEFAULTS
|
|
|
|
// Mini Missile -------------------------------------------------------------
|
|
|
|
void A_RocketInFlight (AActor *);
|
|
|
|
class AMiniMissile : public AActor
|
|
{
|
|
DECLARE_ACTOR (AMiniMissile, AActor);
|
|
public:
|
|
void PreExplode ()
|
|
{
|
|
S_StopSound (this, CHAN_VOICE);
|
|
RenderStyle = STYLE_Add;
|
|
}
|
|
void GetExplodeParms (int &damage, int &dist, bool &hurtSource)
|
|
{
|
|
damage = dist = 64;
|
|
}
|
|
};
|
|
|
|
FState AMiniMissile::States[] =
|
|
{
|
|
S_BRIGHT (MICR, 'A', 6, A_RocketInFlight, &States[0]),
|
|
|
|
S_BRIGHT (SMIS, 'A', 5, A_ExplodeAndAlert, &States[2]),
|
|
S_BRIGHT (SMIS, 'B', 5, NULL, &States[3]),
|
|
S_BRIGHT (SMIS, 'C', 4, NULL, &States[4]),
|
|
S_BRIGHT (SMIS, 'D', 2, NULL, &States[5]),
|
|
S_BRIGHT (SMIS, 'E', 2, NULL, &States[6]),
|
|
S_BRIGHT (SMIS, 'F', 2, NULL, &States[7]),
|
|
S_BRIGHT (SMIS, 'G', 2, NULL, NULL),
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AMiniMissile, Strife, -1, 0)
|
|
PROP_SpawnState (0)
|
|
PROP_DeathState (1)
|
|
PROP_SpeedFixed (20)
|
|
PROP_RadiusFixed (10)
|
|
PROP_HeightFixed (14)
|
|
PROP_Damage (10)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE)
|
|
PROP_Flags2 (MF2_NOTELEPORT|MF2_PCROSS|MF2_IMPACT)
|
|
PROP_Flags4 (MF4_STRIFEDAMAGE)
|
|
PROP_MaxStepHeight (4)
|
|
PROP_StrifeType (99)
|
|
PROP_SeeSound ("weapons/minimissile")
|
|
PROP_DeathSound ("weapons/minimissilehit")
|
|
END_DEFAULTS
|
|
|
|
//============================================================================
|
|
//
|
|
// A_FireMiniMissile
|
|
//
|
|
//============================================================================
|
|
|
|
void A_FireMiniMissile (AActor *self)
|
|
{
|
|
player_t *player = self->player;
|
|
angle_t savedangle;
|
|
|
|
if (self->player == NULL)
|
|
return;
|
|
|
|
AWeapon *weapon = self->player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
|
|
savedangle = self->angle;
|
|
self->angle += pr_minimissile.Random2() << (19 - player->accuracy * 5 / 100);
|
|
player->mo->PlayAttacking2 ();
|
|
P_SpawnPlayerMissile (self, RUNTIME_CLASS(AMiniMissile));
|
|
self->angle = savedangle;
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_RocketInFlight
|
|
//
|
|
//============================================================================
|
|
|
|
void A_RocketInFlight (AActor *self)
|
|
{
|
|
AActor *trail;
|
|
|
|
S_Sound (self, CHAN_VOICE, "misc/missileinflight", 1, ATTN_NORM);
|
|
P_SpawnPuff (RUNTIME_CLASS(AMiniMissilePuff), self->x, self->y, self->z, self->angle - ANGLE_180, 2, true);
|
|
trail = Spawn<ARocketTrail> (self->x - self->momx, self->y - self->momy, self->z);
|
|
if (trail != NULL)
|
|
{
|
|
trail->momz = FRACUNIT;
|
|
}
|
|
}
|
|
|
|
// Flame Thrower ------------------------------------------------------------
|
|
|
|
void A_FireFlamer (AActor *);
|
|
|
|
class AFlameThrower : public AStrifeWeapon
|
|
{
|
|
DECLARE_ACTOR (AFlameThrower, AStrifeWeapon)
|
|
public:
|
|
const char *PickupMessage ()
|
|
{
|
|
return "You picked up the flame thrower";
|
|
}
|
|
};
|
|
|
|
FState AFlameThrower::States[] =
|
|
{
|
|
S_NORMAL (FLAM, 'A', -1, NULL, NULL),
|
|
|
|
#define S_FLAMER 1
|
|
S_NORMAL (FLMT, 'A', 3, A_WeaponReady, &States[S_FLAMER+1]),
|
|
S_NORMAL (FLMT, 'B', 3, A_WeaponReady, &States[S_FLAMER+0]),
|
|
|
|
#define S_FLAMERDOWN (S_FLAMER+2)
|
|
S_NORMAL (FLMT, 'A', 1, A_Lower, &States[S_FLAMERDOWN]),
|
|
|
|
#define S_FLAMERUP (S_FLAMERDOWN+1)
|
|
S_NORMAL (FLMT, 'A', 1, A_Raise, &States[S_FLAMERUP]),
|
|
|
|
#define S_FLAMERATK (S_FLAMERUP+1)
|
|
S_NORMAL (FLMF, 'A', 2, A_FireFlamer, &States[S_FLAMERATK+1]),
|
|
S_NORMAL (FLMF, 'B', 3, A_ReFire, &States[S_FLAMER])
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AFlameThrower, Strife, 2005, 0)
|
|
PROP_Flags (MF_SPECIAL)
|
|
PROP_Flags2 (MF2_FLOORCLIP)
|
|
PROP_SpawnState (0)
|
|
PROP_StrifeType (190)
|
|
PROP_StrifeTeaserType (184)
|
|
PROP_StrifeTeaserType2 (188)
|
|
|
|
PROP_Weapon_SelectionOrder (2100)
|
|
PROP_Weapon_Flags (WIF_BOT_MELEE)
|
|
PROP_Weapon_Kickback (0)
|
|
PROP_Weapon_AmmoUse1 (1)
|
|
PROP_Weapon_AmmoGive1 (40)
|
|
PROP_Weapon_UpState (S_FLAMERUP)
|
|
PROP_Weapon_DownState (S_FLAMERDOWN)
|
|
PROP_Weapon_ReadyState (S_FLAMER)
|
|
PROP_Weapon_AtkState (S_FLAMERATK)
|
|
PROP_Weapon_HoldAtkState (S_FLAMERATK)
|
|
PROP_Weapon_UpSound ("weapons/flameidle")
|
|
PROP_Weapon_ReadySound ("weapons/flameidle")
|
|
PROP_Weapon_AmmoType1 ("EnergyPod")
|
|
PROP_Weapon_ProjectileType ("FlameMissile")
|
|
|
|
PROP_Inventory_Icon ("FLAMA0")
|
|
PROP_Tag ("flame_thrower")
|
|
END_DEFAULTS
|
|
|
|
// Flame Thrower Parts ------------------------------------------------------
|
|
|
|
class AFlameThrowerParts : AInventory
|
|
{
|
|
DECLARE_ACTOR (AFlameThrowerParts, AInventory)
|
|
public:
|
|
const char *PickupMessage ()
|
|
{
|
|
return "You picked up the flame thrower parts.";
|
|
}
|
|
};
|
|
|
|
FState AFlameThrowerParts::States[] =
|
|
{
|
|
S_NORMAL (BFLM, 'A', -1, NULL, NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AFlameThrowerParts, Strife, -1, 0)
|
|
PROP_SpawnState (0)
|
|
PROP_Flags (MF_SPECIAL)
|
|
PROP_Flags2 (MF2_FLOORCLIP)
|
|
PROP_StrifeType (191)
|
|
PROP_StrifeTeaserType (185)
|
|
PROP_StrifeTeaserType2 (189)
|
|
PROP_Inventory_Icon ("I_BFLM")
|
|
PROP_Tag ("flame_thrower_parts")
|
|
END_DEFAULTS
|
|
|
|
// Flame Thrower Projectile -------------------------------------------------
|
|
|
|
void A_FlameDie (AActor *);
|
|
|
|
FState AFlameMissile::States[] =
|
|
{
|
|
#define S_FLAME 0
|
|
S_BRIGHT (FRBL, 'A', 3, NULL, &States[S_FLAME+1]),
|
|
S_BRIGHT (FRBL, 'B', 3, NULL, &States[S_FLAME+2]),
|
|
S_BRIGHT (FRBL, 'C', 3, A_Countdown, &States[S_FLAME]),
|
|
|
|
#define S_FLAMEDIE (S_FLAME+3)
|
|
S_BRIGHT (FRBL, 'D', 5, A_FlameDie, &States[S_FLAMEDIE+1]),
|
|
S_BRIGHT (FRBL, 'E', 5, NULL, &States[S_FLAMEDIE+2]),
|
|
S_BRIGHT (FRBL, 'F', 5, NULL, &States[S_FLAMEDIE+3]),
|
|
S_BRIGHT (FRBL, 'G', 5, NULL, &States[S_FLAMEDIE+4]),
|
|
S_BRIGHT (FRBL, 'H', 5, NULL, &States[S_FLAMEDIE+5]),
|
|
S_BRIGHT (FRBL, 'I', 5, NULL, NULL),
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AFlameMissile, Strife, -1, 0)
|
|
PROP_SpawnState (S_FLAME)
|
|
PROP_DeathState (S_FLAMEDIE)
|
|
PROP_SpeedFixed (15)
|
|
PROP_RadiusFixed (8)
|
|
PROP_HeightFixed (11)
|
|
PROP_Mass (10)
|
|
PROP_Damage (4)
|
|
PROP_DamageType (MOD_FIRE)
|
|
PROP_ReactionTime (8)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE)
|
|
PROP_Flags2 (MF2_NOTELEPORT|MF2_PCROSS|MF2_IMPACT)
|
|
PROP_Flags4 (MF4_STRIFEDAMAGE)
|
|
PROP_MaxStepHeight (4)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
PROP_Alpha (OPAQUE)
|
|
PROP_SeeSound ("weapons/flamethrower")
|
|
END_DEFAULTS
|
|
|
|
//============================================================================
|
|
//
|
|
// A_FlameDie
|
|
//
|
|
//============================================================================
|
|
|
|
void A_FlameDie (AActor *self)
|
|
{
|
|
self->flags |= MF_NOGRAVITY;
|
|
self->momz = (pr_flamedie() & 3) << FRACBITS;
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_FireFlamer
|
|
//
|
|
//============================================================================
|
|
|
|
void A_FireFlamer (AActor *self)
|
|
{
|
|
player_t *player = self->player;
|
|
|
|
if (player != NULL)
|
|
{
|
|
AWeapon *weapon = self->player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
player->mo->PlayAttacking2 ();
|
|
}
|
|
|
|
self->angle += pr_flamethrower.Random2() << 18;
|
|
self = P_SpawnPlayerMissile (self, RUNTIME_CLASS(AFlameMissile));
|
|
if (self != NULL)
|
|
{
|
|
self->momz += 5*FRACUNIT;
|
|
}
|
|
}
|
|
|
|
// Mauler -------------------------------------------------------------------
|
|
|
|
void A_FireMauler1 (AActor *);
|
|
void A_FireMauler2Pre (AActor *);
|
|
void A_FireMauler2 (AActor *);
|
|
void A_MaulerTorpedoWave (AActor *);
|
|
|
|
class AMauler : public AStrifeWeapon
|
|
{
|
|
DECLARE_ACTOR (AMauler, AStrifeWeapon)
|
|
public:
|
|
const char *PickupMessage ()
|
|
{
|
|
return "You picked up the mauler";
|
|
}
|
|
};
|
|
|
|
FState AMauler::States[] =
|
|
{
|
|
S_NORMAL (TRPD, 'A', -1, NULL, NULL),
|
|
|
|
#define S_MAULER1 1
|
|
S_NORMAL (MAUL, 'F', 6, A_WeaponReady, &States[S_MAULER1+1]),
|
|
S_NORMAL (MAUL, 'G', 6, A_WeaponReady, &States[S_MAULER1+2]),
|
|
S_NORMAL (MAUL, 'H', 6, A_WeaponReady, &States[S_MAULER1+3]),
|
|
S_NORMAL (MAUL, 'A', 6, A_WeaponReady, &States[S_MAULER1]),
|
|
|
|
#define S_MAULER1DOWN (S_MAULER1+4)
|
|
S_NORMAL (MAUL, 'A', 1, A_Lower, &States[S_MAULER1DOWN]),
|
|
|
|
#define S_MAULER1UP (S_MAULER1DOWN+1)
|
|
S_NORMAL (MAUL, 'A', 1, A_Raise, &States[S_MAULER1UP]),
|
|
|
|
#define S_MAULER1ATK (S_MAULER1UP+1)
|
|
// Why does the firing picture have its own sprite?
|
|
S_BRIGHT (BLSF, 'A', 5, A_FireMauler1, &States[S_MAULER1ATK+1]),
|
|
S_BRIGHT (MAUL, 'B', 3, A_Light1, &States[S_MAULER1ATK+2]),
|
|
S_NORMAL (MAUL, 'C', 2, A_Light2, &States[S_MAULER1ATK+3]),
|
|
S_NORMAL (MAUL, 'D', 2, NULL, &States[S_MAULER1ATK+4]),
|
|
S_NORMAL (MAUL, 'E', 2, NULL, &States[S_MAULER1ATK+5]),
|
|
S_NORMAL (MAUL, 'A', 7, A_Light0, &States[S_MAULER1ATK+6]),
|
|
S_NORMAL (MAUL, 'H', 7, NULL, &States[S_MAULER1ATK+7]),
|
|
S_NORMAL (MAUL, 'G', 7, A_CheckReload, &States[S_MAULER1]),
|
|
|
|
#define S_MAULER2 (S_MAULER1ATK+8)
|
|
S_NORMAL (MAUL, 'I', 7, A_WeaponReady, &States[S_MAULER2+1]),
|
|
S_NORMAL (MAUL, 'J', 7, A_WeaponReady, &States[S_MAULER2+2]),
|
|
S_NORMAL (MAUL, 'K', 7, A_WeaponReady, &States[S_MAULER2+3]),
|
|
S_NORMAL (MAUL, 'L', 7, A_WeaponReady, &States[S_MAULER2]),
|
|
|
|
#define S_MAULER2DOWN (S_MAULER2+4)
|
|
S_NORMAL (MAUL, 'I', 1, A_Lower, &States[S_MAULER2DOWN]),
|
|
|
|
#define S_MAULER2UP (S_MAULER2DOWN+1)
|
|
S_NORMAL (MAUL, 'I', 1, A_Raise, &States[S_MAULER2UP]),
|
|
|
|
#define S_MAULER2ATK (S_MAULER2UP+1)
|
|
S_NORMAL (MAUL, 'I', 20, A_FireMauler2Pre, &States[S_MAULER2ATK+1]),
|
|
S_NORMAL (MAUL, 'J', 10, A_Light1, &States[S_MAULER2ATK+2]),
|
|
S_BRIGHT (BLSF, 'A', 10, A_FireMauler2, &States[S_MAULER2ATK+3]),
|
|
S_BRIGHT (MAUL, 'B', 10, A_Light2, &States[S_MAULER2ATK+4]),
|
|
S_NORMAL (MAUL, 'C', 2, NULL, &States[S_MAULER2ATK+5]),
|
|
S_NORMAL (MAUL, 'D', 2, A_Light0, &States[S_MAULER2ATK+6]),
|
|
S_NORMAL (MAUL, 'E', 2, A_ReFire, &States[S_MAULER2]),
|
|
};
|
|
|
|
// The scatter version
|
|
|
|
IMPLEMENT_ACTOR (AMauler, Strife, 2004, 0)
|
|
PROP_Flags (MF_SPECIAL)
|
|
PROP_Flags2 (MF2_FLOORCLIP)
|
|
PROP_SpawnState (0)
|
|
PROP_StrifeType (193)
|
|
PROP_StrifeTeaserType (187)
|
|
PROP_StrifeTeaserType2 (191)
|
|
|
|
PROP_Weapon_SelectionOrder (300)
|
|
PROP_Weapon_AmmoUse1 (20)
|
|
PROP_Weapon_AmmoGive1 (40)
|
|
PROP_Weapon_UpState (S_MAULER1UP)
|
|
PROP_Weapon_DownState (S_MAULER1DOWN)
|
|
PROP_Weapon_ReadyState (S_MAULER1)
|
|
PROP_Weapon_AtkState (S_MAULER1ATK)
|
|
PROP_Weapon_HoldAtkState (S_MAULER1ATK)
|
|
PROP_Weapon_MoveCombatDist (15000000)
|
|
PROP_Weapon_AmmoType1 ("EnergyPod")
|
|
PROP_Weapon_SisterType ("Mauler2")
|
|
|
|
PROP_Inventory_Icon ("TRPDA0")
|
|
PROP_Tag ("mauler") // "blaster" in the Teaser
|
|
END_DEFAULTS
|
|
|
|
// Mauler Torpedo version ---------------------------------------------------
|
|
|
|
class AMauler2 : public AMauler
|
|
{
|
|
DECLARE_STATELESS_ACTOR (AMauler2, AMauler)
|
|
};
|
|
|
|
// The torpedo version
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (AMauler2, Strife, -1, 0)
|
|
PROP_Weapon_SelectionOrder (3300)
|
|
PROP_Weapon_AmmoUse1 (30)
|
|
PROP_Weapon_AmmoGive1 (0)
|
|
PROP_Weapon_UpState (S_MAULER2UP)
|
|
PROP_Weapon_DownState (S_MAULER2DOWN)
|
|
PROP_Weapon_ReadyState (S_MAULER2)
|
|
PROP_Weapon_AtkState (S_MAULER2ATK)
|
|
PROP_Weapon_HoldAtkState (S_MAULER2ATK)
|
|
PROP_Weapon_MoveCombatDist (10000000)
|
|
PROP_Weapon_AmmoType1 ("EnergyPod")
|
|
PROP_Weapon_SisterType ("Mauler")
|
|
PROP_Weapon_ProjectileType ("MaulerTorpedo")
|
|
END_DEFAULTS
|
|
|
|
// Mauler "Bullet" Puff -----------------------------------------------------
|
|
|
|
class AMaulerPuff : public AActor
|
|
{
|
|
DECLARE_ACTOR (AMaulerPuff, AActor)
|
|
};
|
|
|
|
FState AMaulerPuff::States[] =
|
|
{
|
|
S_NORMAL (MPUF, 'A', 5, NULL, &States[1]),
|
|
S_NORMAL (MPUF, 'B', 5, NULL, &States[2]),
|
|
S_NORMAL (POW1, 'A', 4, NULL, &States[3]),
|
|
S_NORMAL (POW1, 'B', 4, NULL, &States[4]),
|
|
S_NORMAL (POW1, 'C', 4, NULL, &States[5]),
|
|
S_NORMAL (POW1, 'D', 4, NULL, &States[6]),
|
|
S_NORMAL (POW1, 'E', 4, NULL, NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AMaulerPuff, Strife, -1, 0)
|
|
PROP_SpawnState (0)
|
|
PROP_DamageType (MOD_DISINTEGRATE)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY)
|
|
PROP_Flags3 (MF3_PUFFONACTORS)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
END_DEFAULTS
|
|
|
|
// The Mauler's Torpedo -----------------------------------------------------
|
|
|
|
class AMaulerTorpedo : public AActor
|
|
{
|
|
DECLARE_ACTOR (AMaulerTorpedo, AActor)
|
|
};
|
|
|
|
FState AMaulerTorpedo::States[] =
|
|
{
|
|
S_BRIGHT (TORP, 'A', 4, NULL, &States[1]),
|
|
S_BRIGHT (TORP, 'B', 4, NULL, &States[2]),
|
|
S_BRIGHT (TORP, 'C', 4, NULL, &States[3]),
|
|
S_BRIGHT (TORP, 'D', 4, NULL, &States[0]),
|
|
|
|
S_BRIGHT (THIT, 'A', 8, NULL, &States[5]),
|
|
S_BRIGHT (THIT, 'B', 8, NULL, &States[6]),
|
|
S_BRIGHT (THIT, 'C', 8, A_MaulerTorpedoWave, &States[7]),
|
|
S_BRIGHT (THIT, 'D', 8, NULL, &States[8]),
|
|
S_BRIGHT (THIT, 'E', 8, NULL, NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AMaulerTorpedo, Strife, -1, 0)
|
|
PROP_SpawnState (0)
|
|
PROP_DeathState (4)
|
|
PROP_SpeedFixed (20)
|
|
PROP_RadiusFixed (13)
|
|
PROP_HeightFixed (8)
|
|
PROP_Damage (1)
|
|
PROP_DamageType (MOD_DISINTEGRATE)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE)
|
|
PROP_Flags2 (MF2_NOTELEPORT|MF2_PCROSS|MF2_IMPACT)
|
|
PROP_Flags4 (MF4_STRIFEDAMAGE)
|
|
PROP_MaxStepHeight (4)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
PROP_SeeSound ("weapons/mauler2fire")
|
|
PROP_DeathSound ("weapons/mauler2hit")
|
|
END_DEFAULTS
|
|
|
|
// The mini torpedoes shot by the big torpedo --------------------------------
|
|
|
|
class AMaulerTorpedoWave : public AActor
|
|
{
|
|
DECLARE_ACTOR (AMaulerTorpedoWave, AActor)
|
|
};
|
|
|
|
FState AMaulerTorpedoWave::States[] =
|
|
{
|
|
S_BRIGHT (TWAV, 'A', 9, NULL, &States[1]),
|
|
S_BRIGHT (TWAV, 'B', 9, NULL, &States[2]),
|
|
S_BRIGHT (TWAV, 'C', 9, NULL, NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AMaulerTorpedoWave, Strife, -1, 0)
|
|
PROP_SpawnState (0)
|
|
PROP_DeathState (2)
|
|
PROP_SpeedFixed (35)
|
|
PROP_RadiusFixed (13)
|
|
PROP_HeightFixed (13)
|
|
PROP_Damage (10)
|
|
PROP_DamageType (MOD_DISINTEGRATE)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE)
|
|
PROP_Flags2 (MF2_NOTELEPORT|MF2_PCROSS|MF2_IMPACT)
|
|
PROP_Flags4 (MF4_STRIFEDAMAGE)
|
|
PROP_MaxStepHeight (4)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
END_DEFAULTS
|
|
|
|
//============================================================================
|
|
//
|
|
// A_FireMauler1
|
|
//
|
|
// Hey! This is exactly the same as a super shotgun except for the sound
|
|
// and the bullet puffs and the disintegration death.
|
|
//
|
|
//============================================================================
|
|
|
|
void A_FireMauler1 (AActor *self)
|
|
{
|
|
if (self->player != NULL)
|
|
{
|
|
AWeapon *weapon = self->player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
// Strife apparently didn't show the player shooting. Let's fix that.
|
|
self->player->mo->PlayAttacking2 ();
|
|
}
|
|
|
|
S_Sound (self, CHAN_WEAPON, "weapons/mauler1", 1, ATTN_NORM);
|
|
|
|
|
|
P_BulletSlope (self);
|
|
|
|
for (int i = 0; i < 20; ++i)
|
|
{
|
|
int damage = 5 * (pr_mauler1() % 3 + 1);
|
|
angle_t angle = self->angle + (pr_mauler1.Random2() << 19);
|
|
int pitch = bulletpitch + (pr_mauler1.Random2() * 332063);
|
|
|
|
// Strife used a range of 2112 units for the mauler to signal that
|
|
// it should use a different puff. ZDoom's default range is longer
|
|
// than this, so let's not handicap it by being too faithful to the
|
|
// original.
|
|
P_LineAttack (self, angle, PLAYERMISSILERANGE, pitch, damage, MOD_DISINTEGRATE, RUNTIME_CLASS(AMaulerPuff));
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_FireMauler2Pre
|
|
//
|
|
// Makes some noise and moves the psprite.
|
|
//
|
|
//============================================================================
|
|
|
|
void A_FireMauler2Pre (AActor *self)
|
|
{
|
|
S_Sound (self, CHAN_WEAPON, "weapons/mauler2charge", 1, ATTN_NORM);
|
|
|
|
if (self->player != NULL)
|
|
{
|
|
self->player->psprites[ps_weapon].sx += pr_mauler2.Random2() << 10;
|
|
self->player->psprites[ps_weapon].sy += pr_mauler2.Random2() << 10;
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_FireMauler2Pre
|
|
//
|
|
// Fires the torpedo.
|
|
//
|
|
//============================================================================
|
|
|
|
void A_FireMauler2 (AActor *self)
|
|
{
|
|
if (self->player != NULL)
|
|
{
|
|
AWeapon *weapon = self->player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
self->player->mo->PlayAttacking2 ();
|
|
}
|
|
P_SpawnPlayerMissile (self, RUNTIME_CLASS(AMaulerTorpedo));
|
|
P_DamageMobj (self, self, NULL, 20, self->DamageType);
|
|
P_ThrustMobj (self, self->angle + ANGLE_180, 0x7D000);
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_MaulerTorpedoWave
|
|
//
|
|
// Launches lots of balls when the torpedo hits something.
|
|
//
|
|
//============================================================================
|
|
|
|
AActor *P_SpawnSubMissile (AActor *source, TypeInfo *type, AActor *target);
|
|
|
|
void A_MaulerTorpedoWave (AActor *self)
|
|
{
|
|
fixed_t savedz;
|
|
self->angle += ANGLE_180;
|
|
|
|
// If the torpedo hit the ceiling, it should still spawn the wave
|
|
savedz = self->z;
|
|
if (self->ceilingz - self->z < GetDefault<AMaulerTorpedoWave>()->height)
|
|
{
|
|
self->z = self->ceilingz - GetDefault<AMaulerTorpedoWave>()->height;
|
|
}
|
|
|
|
for (int i = 0; i < 80; ++i)
|
|
{
|
|
self->angle += ANGLE_45/10;
|
|
AActor *wave = P_SpawnSubMissile (self, RUNTIME_CLASS(AMaulerTorpedoWave), self->target);
|
|
}
|
|
self->z = savedz;
|
|
}
|
|
|
|
AActor *P_SpawnSubMissile (AActor *source, TypeInfo *type, AActor *target)
|
|
{
|
|
AActor *other = Spawn (type, source->x, source->y, source->z);
|
|
|
|
if (other == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
other->target = target;
|
|
other->angle = source->angle;
|
|
|
|
other->momx = FixedMul (other->Speed, finecosine[source->angle >> ANGLETOFINESHIFT]);
|
|
other->momy = FixedMul (other->Speed, finesine[source->angle >> ANGLETOFINESHIFT]);
|
|
|
|
if (P_CheckMissileSpawn (other))
|
|
{
|
|
angle_t pitch = P_AimLineAttack (source, source->angle, 1024*FRACUNIT);
|
|
other->momz = FixedMul (-finesine[pitch>>ANGLETOFINESHIFT], other->Speed);
|
|
return other;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// High-Explosive Grenade ---------------------------------------------------
|
|
|
|
class AHEGrenade : public AActor
|
|
{
|
|
DECLARE_ACTOR (AHEGrenade, AActor)
|
|
public:
|
|
void PreExplode ();
|
|
void GetExplodeParms (int &damage, int &dist, bool &hurtSource);
|
|
};
|
|
|
|
FState AHEGrenade::States[] =
|
|
{
|
|
S_NORMAL (GRAP, 'A', 3, A_Countdown, &States[1]),
|
|
S_NORMAL (GRAP, 'B', 3, A_Countdown, &States[0]),
|
|
|
|
S_BRIGHT (BNG4, 'A', 2, A_ExplodeAndAlert, &States[3]),
|
|
S_BRIGHT (BNG4, 'B', 3, NULL, &States[4]),
|
|
S_BRIGHT (BNG4, 'C', 3, NULL, &States[5]),
|
|
S_BRIGHT (BNG4, 'D', 3, NULL, &States[6]),
|
|
S_BRIGHT (BNG4, 'E', 3, NULL, &States[7]),
|
|
S_BRIGHT (BNG4, 'F', 3, NULL, &States[8]),
|
|
S_BRIGHT (BNG4, 'G', 3, NULL, &States[9]),
|
|
S_BRIGHT (BNG4, 'H', 3, NULL, &States[10]),
|
|
S_BRIGHT (BNG4, 'I', 3, NULL, &States[11]),
|
|
S_BRIGHT (BNG4, 'J', 3, NULL, &States[12]),
|
|
S_BRIGHT (BNG4, 'K', 3, NULL, &States[13]),
|
|
S_BRIGHT (BNG4, 'L', 3, NULL, &States[14]),
|
|
S_BRIGHT (BNG4, 'M', 3, NULL, &States[15]),
|
|
S_BRIGHT (BNG4, 'N', 3, NULL, NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AHEGrenade, Strife, -1, 0)
|
|
PROP_SpawnState (0)
|
|
PROP_DeathState (2)
|
|
PROP_SpeedFixed (15)
|
|
PROP_RadiusFixed (13)
|
|
PROP_HeightFixed (13)
|
|
PROP_Mass (20)
|
|
PROP_Damage (1)
|
|
PROP_ReactionTime (30)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE)
|
|
PROP_Flags2 (MF2_FLOORCLIP|MF2_NOTELEPORT|MF2_PCROSS|MF2_IMPACT|MF2_DOOMBOUNCE)
|
|
PROP_Flags3 (MF3_CANBOUNCEWATER)
|
|
PROP_Flags4 (MF4_STRIFEDAMAGE)
|
|
PROP_MaxStepHeight (4)
|
|
PROP_StrifeType (106)
|
|
PROP_SeeSound ("weapons/hegrenadeshoot")
|
|
PROP_DeathSound ("weapons/hegrenadebang")
|
|
END_DEFAULTS
|
|
|
|
void AHEGrenade::PreExplode ()
|
|
{
|
|
RenderStyle = STYLE_Add;
|
|
flags |= MF_NOGRAVITY;
|
|
}
|
|
|
|
void AHEGrenade::GetExplodeParms (int &damage, int &dist, bool &hurtSource)
|
|
{
|
|
damage = dist = 192;
|
|
hurtSource = true;
|
|
}
|
|
|
|
// White Phosphorous Grenade ------------------------------------------------
|
|
|
|
void A_SpawnBurn (AActor *);
|
|
|
|
class APhosphorousGrenade : public AActor
|
|
{
|
|
DECLARE_ACTOR (APhosphorousGrenade, AActor)
|
|
};
|
|
|
|
FState APhosphorousGrenade::States[] =
|
|
{
|
|
S_NORMAL (GRIN, 'A', 3, A_Countdown, &States[1]),
|
|
S_NORMAL (GRIN, 'B', 3, A_Countdown, &States[0]),
|
|
|
|
S_BRIGHT (BNG3, 'A', 2, A_SpawnBurn, NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (APhosphorousGrenade, Strife, -1, 0)
|
|
PROP_SpawnState (0)
|
|
PROP_DeathState (2)
|
|
PROP_SpeedFixed (15)
|
|
PROP_RadiusFixed (13)
|
|
PROP_HeightFixed (13)
|
|
PROP_Mass (20)
|
|
PROP_Damage (1)
|
|
PROP_ReactionTime (40)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE)
|
|
PROP_Flags2 (MF2_FLOORCLIP|MF2_NOTELEPORT|MF2_PCROSS|MF2_IMPACT|MF2_DOOMBOUNCE)
|
|
PROP_Flags3 (MF3_CANBOUNCEWATER)
|
|
PROP_Flags4 (MF4_STRIFEDAMAGE)
|
|
PROP_MaxStepHeight (4)
|
|
PROP_StrifeType (107)
|
|
PROP_SeeSound ("weapons/phgrenadeshoot")
|
|
PROP_DeathSound ("weapons/phgrenadebang")
|
|
END_DEFAULTS
|
|
|
|
// Fire from the Phoshorous Grenade -----------------------------------------
|
|
|
|
void A_Burnination (AActor *self);
|
|
|
|
class APhosphorousFire : public AActor
|
|
{
|
|
DECLARE_ACTOR (APhosphorousFire, AActor)
|
|
public:
|
|
int DoSpecialDamage (AActor *target, int damage);
|
|
};
|
|
|
|
void A_BurnArea (AActor *);
|
|
|
|
FState APhosphorousFire::States[] =
|
|
{
|
|
#define S_BURNINATION 0
|
|
S_BRIGHT (BNG3, 'B', 2, A_BurnArea, &States[S_BURNINATION+1]),
|
|
S_BRIGHT (BNG3, 'C', 2, A_Countdown, &States[S_BURNINATION+2]),
|
|
S_BRIGHT (FLBE, 'A', 2, A_Burnination, &States[S_BURNINATION+3]),
|
|
S_BRIGHT (FLBE, 'B', 2, A_Countdown, &States[S_BURNINATION+4]),
|
|
S_BRIGHT (FLBE, 'C', 2, A_BurnArea, &States[S_BURNINATION+5]),
|
|
S_BRIGHT (FLBE, 'D', 3, A_Countdown, &States[S_BURNINATION+6]),
|
|
S_BRIGHT (FLBE, 'E', 3, A_BurnArea, &States[S_BURNINATION+7]),
|
|
S_BRIGHT (FLBE, 'F', 3, A_Countdown, &States[S_BURNINATION+8]),
|
|
S_BRIGHT (FLBE, 'G', 3, A_Burnination, &States[S_BURNINATION+5]),
|
|
|
|
#define S_BURNDWINDLE (S_BURNINATION+9)
|
|
S_BRIGHT (FLBE, 'H', 2, NULL, &States[S_BURNDWINDLE+1]),
|
|
S_BRIGHT (FLBE, 'I', 2, A_Burnination, &States[S_BURNDWINDLE+2]),
|
|
S_BRIGHT (FLBE, 'J', 2, NULL, &States[S_BURNDWINDLE+3]),
|
|
S_BRIGHT (FLBE, 'K', 2, NULL, NULL),
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (APhosphorousFire, Strife, -1, 0)
|
|
PROP_SpawnState (S_BURNINATION)
|
|
PROP_DeathState (S_BURNDWINDLE)
|
|
PROP_ReactionTime (120)
|
|
PROP_DamageType (MOD_FIRE)
|
|
PROP_Flags (MF_NOBLOCKMAP)
|
|
PROP_Flags2 (MF2_FLOORCLIP|MF2_NOTELEPORT)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
END_DEFAULTS
|
|
|
|
int APhosphorousFire::DoSpecialDamage (AActor *target, int damage)
|
|
{
|
|
if (target->flags & MF_NOBLOOD)
|
|
{
|
|
return damage / 2;
|
|
}
|
|
return Super::DoSpecialDamage (target, damage);
|
|
}
|
|
|
|
void A_SpawnBurn (AActor *self)
|
|
{
|
|
Spawn<APhosphorousFire> (self->x, self->y, self->z);
|
|
}
|
|
|
|
void A_BurnArea (AActor *self)
|
|
{
|
|
P_RadiusAttack (self, self->target, 128, 128, self->DamageType, true, true);
|
|
}
|
|
|
|
void A_Burnination (AActor *self)
|
|
{
|
|
self->momz -= 8*FRACUNIT;
|
|
self->momx += (pr_phburn.Random2 (3)) << FRACBITS;
|
|
self->momy += (pr_phburn.Random2 (3)) << FRACBITS;
|
|
S_Sound (self, CHAN_VOICE, "world/largefire", 1, ATTN_NORM);
|
|
|
|
// Only the main fire spawns more.
|
|
if (!(self->flags & MF_DROPPED))
|
|
{
|
|
// Original x and y offsets seemed to be like this:
|
|
// x + (((pr_phburn() + 12) & 31) << FRACBITS);
|
|
//
|
|
// But that creates a lop-sided burn because it won't use negative offsets.
|
|
int xofs = pr_phburn();
|
|
int yofs = pr_phburn();
|
|
|
|
xofs = (xofs - 128);
|
|
if (xofs < 0)
|
|
{
|
|
xofs = clamp (xofs, -31, -12);
|
|
}
|
|
else
|
|
{
|
|
xofs = clamp (xofs, 12, 31);
|
|
}
|
|
|
|
yofs = (yofs - 128);
|
|
if (yofs < 0)
|
|
{
|
|
yofs = clamp (yofs, -31, -12);
|
|
}
|
|
else
|
|
{
|
|
yofs = clamp (yofs, 12, 31);
|
|
}
|
|
|
|
AActor *drop = Spawn<APhosphorousFire> (
|
|
self->x + (xofs << FRACBITS),
|
|
self->y + (yofs << FRACBITS),
|
|
self->z + 4*FRACUNIT);
|
|
if (drop != NULL)
|
|
{
|
|
drop->momx = self->momx + ((pr_phburn.Random2 (7)) << FRACBITS);
|
|
drop->momy = self->momy + ((pr_phburn.Random2 (7)) << FRACBITS);
|
|
drop->momz = self->momz - FRACUNIT;
|
|
drop->reactiontime = (pr_phburn() & 3) + 2;
|
|
drop->flags |= MF_DROPPED;
|
|
}
|
|
}
|
|
}
|
|
|
|
// High-Explosive Grenade Launcher ------------------------------------------
|
|
|
|
void A_FireGrenade (AActor *);
|
|
|
|
class AStrifeGrenadeLauncher : public AStrifeWeapon
|
|
{
|
|
DECLARE_ACTOR (AStrifeGrenadeLauncher, AStrifeWeapon)
|
|
public:
|
|
const char *PickupMessage ()
|
|
{
|
|
return "You picked up the Grenade launcher";
|
|
}
|
|
};
|
|
|
|
FState AStrifeGrenadeLauncher::States[] =
|
|
{
|
|
#define S_HEPICKUP 0
|
|
S_NORMAL (GRND, 'A', -1, NULL, NULL),
|
|
|
|
#define S_HEGRENADE (S_HEPICKUP+1)
|
|
S_NORMAL (GREN, 'A', 1, A_WeaponReady, &States[S_HEGRENADE]),
|
|
|
|
#define S_HEGRENADE_DOWN (S_HEGRENADE+1)
|
|
S_NORMAL (GREN, 'A', 1, A_Lower, &States[S_HEGRENADE_DOWN]),
|
|
|
|
#define S_HEGRENADE_UP (S_HEGRENADE_DOWN+1)
|
|
S_NORMAL (GREN, 'A', 1, A_Raise, &States[S_HEGRENADE_UP]),
|
|
|
|
#define S_HEGRENADE_ATK (S_HEGRENADE_UP+1)
|
|
S_NORMAL (GREN, 'A', 5, A_FireGrenade, &States[S_HEGRENADE_ATK+1]),
|
|
S_NORMAL (GREN, 'B', 10, NULL, &States[S_HEGRENADE_ATK+2]),
|
|
S_NORMAL (GREN, 'A', 5, A_FireGrenade, &States[S_HEGRENADE_ATK+3]),
|
|
S_NORMAL (GREN, 'C', 10, NULL, &States[S_HEGRENADE_ATK+4]),
|
|
S_NORMAL (GREN, 'A', 0, A_ReFire, &States[S_HEGRENADE]),
|
|
|
|
#define S_HEGRENADE_FLASH (S_HEGRENADE_ATK+5)
|
|
S_BRIGHT (GREF, 'A', 5, A_Light1, &AWeapon::States[S_LIGHTDONE]),
|
|
S_NORMAL (GREF, 'A', 10, A_Light0, &AWeapon::States[S_LIGHTDONE]),
|
|
S_BRIGHT (GREF, 'B', 5, A_Light2, &AWeapon::States[S_LIGHTDONE]),
|
|
|
|
|
|
#define S_PHGRENADE (S_HEGRENADE_FLASH+3)
|
|
S_NORMAL (GREN, 'D', 1, A_WeaponReady, &States[S_PHGRENADE]),
|
|
|
|
#define S_PHGRENADE_DOWN (S_PHGRENADE+1)
|
|
S_NORMAL (GREN, 'D', 1, A_Lower, &States[S_PHGRENADE_DOWN]),
|
|
|
|
#define S_PHGRENADE_UP (S_PHGRENADE_DOWN+1)
|
|
S_NORMAL (GREN, 'D', 1, A_Raise, &States[S_PHGRENADE_UP]),
|
|
|
|
#define S_PHGRENADE_ATK (S_PHGRENADE_UP+1)
|
|
S_NORMAL (GREN, 'D', 5, A_FireGrenade, &States[S_PHGRENADE_ATK+1]),
|
|
S_NORMAL (GREN, 'E', 10, NULL, &States[S_PHGRENADE_ATK+2]),
|
|
S_NORMAL (GREN, 'D', 5, A_FireGrenade, &States[S_PHGRENADE_ATK+3]),
|
|
S_NORMAL (GREN, 'F', 10, NULL, &States[S_PHGRENADE_ATK+4]),
|
|
S_NORMAL (GREN, 'A', 0, A_ReFire, &States[S_PHGRENADE]),
|
|
|
|
#define S_PHGRENADE_FLASH (S_PHGRENADE_ATK+5)
|
|
S_BRIGHT (GREF, 'C', 5, A_Light1, &AWeapon::States[S_LIGHTDONE]),
|
|
S_NORMAL (GREF, 'C', 10, A_Light0, &AWeapon::States[S_LIGHTDONE]),
|
|
S_BRIGHT (GREF, 'D', 5, A_Light2, &AWeapon::States[S_LIGHTDONE]),
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AStrifeGrenadeLauncher, Strife, 154, 0)
|
|
PROP_Flags (MF_SPECIAL)
|
|
PROP_Flags2 (MF2_FLOORCLIP)
|
|
PROP_SpawnState (S_HEPICKUP)
|
|
PROP_StrifeType (195)
|
|
PROP_StrifeTeaserType (189)
|
|
PROP_StrifeTeaserType2 (193)
|
|
|
|
PROP_Weapon_SelectionOrder (2400)
|
|
PROP_Weapon_AmmoUse1 (1)
|
|
PROP_Weapon_AmmoGive1 (8)
|
|
PROP_Weapon_UpState (S_HEGRENADE_UP)
|
|
PROP_Weapon_DownState (S_HEGRENADE_DOWN)
|
|
PROP_Weapon_ReadyState (S_HEGRENADE)
|
|
PROP_Weapon_AtkState (S_HEGRENADE_ATK)
|
|
PROP_Weapon_HoldAtkState (S_HEGRENADE_ATK)
|
|
PROP_Weapon_FlashState (S_HEGRENADE_FLASH)
|
|
PROP_Weapon_MoveCombatDist (18350080)
|
|
PROP_Weapon_AmmoType1 ("HEGrenadeRounds")
|
|
PROP_Weapon_SisterType ("StrifeGrenadeLauncher2")
|
|
PROP_Weapon_ProjectileType ("HEGrenade")
|
|
|
|
PROP_Inventory_Icon ("GRNDA0")
|
|
PROP_Tag ("Grenade_launcher")
|
|
END_DEFAULTS
|
|
|
|
// White Phosphorous Grenade Launcher ---------------------------------------
|
|
|
|
class AStrifeGrenadeLauncher2 : public AStrifeGrenadeLauncher
|
|
{
|
|
DECLARE_STATELESS_ACTOR (AStrifeGrenadeLauncher2, AStrifeGrenadeLauncher)
|
|
};
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (AStrifeGrenadeLauncher2, Strife, -1, 0)
|
|
PROP_Weapon_SelectionOrder (3200)
|
|
PROP_Weapon_AmmoUse1 (1)
|
|
PROP_Weapon_AmmoGive1 (0)
|
|
PROP_Weapon_UpState (S_PHGRENADE_UP)
|
|
PROP_Weapon_DownState (S_PHGRENADE_DOWN)
|
|
PROP_Weapon_ReadyState (S_PHGRENADE)
|
|
PROP_Weapon_AtkState (S_PHGRENADE_ATK)
|
|
PROP_Weapon_HoldAtkState (S_PHGRENADE_ATK)
|
|
PROP_Weapon_FlashState (S_PHGRENADE_FLASH)
|
|
PROP_Weapon_AmmoType1 ("PhosphorusGrenadeRounds")
|
|
PROP_Weapon_SisterType ("StrifeGrenadeLauncher")
|
|
PROP_Weapon_ProjectileType ("PhosphorousGrenade")
|
|
END_DEFAULTS
|
|
|
|
//============================================================================
|
|
//
|
|
// A_FireGrenade
|
|
//
|
|
//============================================================================
|
|
|
|
void A_FireGrenade (AActor *self)
|
|
{
|
|
TypeInfo *grenadetype;
|
|
player_t *player = self->player;
|
|
AActor *grenade;
|
|
angle_t an;
|
|
fixed_t tworadii;
|
|
AWeapon *weapon;
|
|
|
|
if (player == NULL)
|
|
return;
|
|
|
|
if ((weapon = player->ReadyWeapon) == NULL)
|
|
return;
|
|
|
|
if (weapon->GetClass() == RUNTIME_CLASS(AStrifeGrenadeLauncher))
|
|
{
|
|
grenadetype = RUNTIME_CLASS(AHEGrenade);
|
|
}
|
|
else
|
|
{
|
|
grenadetype = RUNTIME_CLASS(APhosphorousGrenade);
|
|
}
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
|
|
// Make it flash
|
|
P_SetPsprite (player, ps_flash, weapon->FlashState +
|
|
(player->psprites[ps_weapon].state - weapon->GetAtkState()));
|
|
|
|
self->z += 32*FRACUNIT;
|
|
grenade = P_SpawnSubMissile (self, grenadetype, self);
|
|
self->z -= 32*FRACUNIT;
|
|
if (grenade == NULL)
|
|
return;
|
|
|
|
if (grenade->SeeSound != 0)
|
|
{
|
|
S_SoundID (grenade, CHAN_VOICE, grenade->SeeSound, 1, ATTN_NORM);
|
|
}
|
|
|
|
grenade->momz = FixedMul (finetangent[FINEANGLES/4-(self->pitch>>ANGLETOFINESHIFT)], grenade->Speed) + 8*FRACUNIT;
|
|
|
|
an = self->angle >> ANGLETOFINESHIFT;
|
|
tworadii = self->radius + grenade->radius;
|
|
grenade->x += FixedMul (finecosine[an], tworadii);
|
|
grenade->y += FixedMul (finesine[an], tworadii);
|
|
|
|
if (weapon->GetAtkState() == player->psprites[ps_weapon].state)
|
|
{
|
|
an = self->angle - ANGLE_90;
|
|
}
|
|
else
|
|
{
|
|
an = self->angle + ANGLE_90;
|
|
}
|
|
an >>= ANGLETOFINESHIFT;
|
|
grenade->x += FixedMul (finecosine[an], 15*FRACUNIT);
|
|
grenade->y += FixedMul (finesine[an], 15*FRACUNIT);
|
|
}
|
|
|
|
// The Almighty Sigil! ------------------------------------------------------
|
|
|
|
void A_SelectPiece (AActor *);
|
|
void A_SelectSigilView (AActor *);
|
|
void A_SelectSigilDown (AActor *);
|
|
void A_SelectSigilAttack (AActor *);
|
|
void A_SigilCharge (AActor *);
|
|
void A_FireSigil1 (AActor *);
|
|
void A_FireSigil2 (AActor *);
|
|
void A_FireSigil3 (AActor *);
|
|
void A_FireSigil4 (AActor *);
|
|
void A_FireSigil5 (AActor *);
|
|
void A_LightInverse (AActor *);
|
|
|
|
FState ASigil::States[] =
|
|
{
|
|
S_NORMAL (SIGL, 'A', 0, NULL, &States[1]),
|
|
S_NORMAL (SIGL, 'A', -1, A_SelectPiece, NULL),
|
|
S_NORMAL (SIGL, 'B', -1, NULL, NULL),
|
|
S_NORMAL (SIGL, 'C', -1, NULL, NULL),
|
|
S_NORMAL (SIGL, 'D', -1, NULL, NULL),
|
|
S_NORMAL (SIGL, 'E', -1, NULL, NULL),
|
|
|
|
#define S_SIGIL 6
|
|
S_BRIGHT (SIGH, 'A', 0, A_SelectSigilView, &States[S_SIGIL+1]),
|
|
S_BRIGHT (SIGH, 'A', 1, A_WeaponReady, &States[S_SIGIL+1]),
|
|
S_BRIGHT (SIGH, 'B', 1, A_WeaponReady, &States[S_SIGIL+2]),
|
|
S_BRIGHT (SIGH, 'C', 1, A_WeaponReady, &States[S_SIGIL+3]),
|
|
S_BRIGHT (SIGH, 'D', 1, A_WeaponReady, &States[S_SIGIL+4]),
|
|
S_BRIGHT (SIGH, 'E', 1, A_WeaponReady, &States[S_SIGIL+5]),
|
|
|
|
#define S_SIGILDOWN (S_SIGIL+6)
|
|
S_BRIGHT (SIGH, 'A', 0, A_SelectSigilDown, &States[S_SIGILDOWN+1]),
|
|
S_BRIGHT (SIGH, 'A', 1, A_Lower, &States[S_SIGILDOWN+1]),
|
|
S_BRIGHT (SIGH, 'B', 1, A_Lower, &States[S_SIGILDOWN+2]),
|
|
S_BRIGHT (SIGH, 'C', 1, A_Lower, &States[S_SIGILDOWN+3]),
|
|
S_BRIGHT (SIGH, 'D', 1, A_Lower, &States[S_SIGILDOWN+4]),
|
|
S_BRIGHT (SIGH, 'E', 1, A_Lower, &States[S_SIGILDOWN+5]),
|
|
|
|
#define S_SIGILUP (S_SIGILDOWN+6)
|
|
S_BRIGHT (SIGH, 'A', 0, A_SelectSigilView, &States[S_SIGILUP+1]),
|
|
S_BRIGHT (SIGH, 'A', 1, A_Raise, &States[S_SIGILUP+1]),
|
|
S_BRIGHT (SIGH, 'B', 1, A_Raise, &States[S_SIGILUP+2]),
|
|
S_BRIGHT (SIGH, 'C', 1, A_Raise, &States[S_SIGILUP+3]),
|
|
S_BRIGHT (SIGH, 'D', 1, A_Raise, &States[S_SIGILUP+4]),
|
|
S_BRIGHT (SIGH, 'E', 1, A_Raise, &States[S_SIGILUP+5]),
|
|
|
|
#define S_SIGILATK (S_SIGILUP+6)
|
|
S_BRIGHT (SIGH, 'A', 0, A_SelectSigilAttack, &States[S_SIGILATK+1]),
|
|
|
|
S_BRIGHT (SIGH, 'A', 18, A_SigilCharge, &States[S_SIGILATK+2]),
|
|
S_BRIGHT (SIGH, 'A', 3, A_GunFlash, &States[S_SIGILATK+3]),
|
|
S_NORMAL (SIGH, 'A', 10, A_FireSigil1, &States[S_SIGILATK+4]),
|
|
S_NORMAL (SIGH, 'A', 5, NULL, &States[S_SIGIL]),
|
|
|
|
S_BRIGHT (SIGH, 'B', 18, A_SigilCharge, &States[S_SIGILATK+6]),
|
|
S_BRIGHT (SIGH, 'B', 3, A_GunFlash, &States[S_SIGILATK+7]),
|
|
S_NORMAL (SIGH, 'B', 10, A_FireSigil2, &States[S_SIGILATK+8]),
|
|
S_NORMAL (SIGH, 'B', 5, NULL, &States[S_SIGIL]),
|
|
|
|
S_BRIGHT (SIGH, 'C', 18, A_SigilCharge, &States[S_SIGILATK+10]),
|
|
S_BRIGHT (SIGH, 'C', 3, A_GunFlash, &States[S_SIGILATK+11]),
|
|
S_NORMAL (SIGH, 'C', 10, A_FireSigil3, &States[S_SIGILATK+12]),
|
|
S_NORMAL (SIGH, 'C', 5, NULL, &States[S_SIGIL]),
|
|
|
|
S_BRIGHT (SIGH, 'D', 18, A_SigilCharge, &States[S_SIGILATK+14]),
|
|
S_BRIGHT (SIGH, 'D', 3, A_GunFlash, &States[S_SIGILATK+15]),
|
|
S_NORMAL (SIGH, 'D', 10, A_FireSigil4, &States[S_SIGILATK+16]),
|
|
S_NORMAL (SIGH, 'D', 5, NULL, &States[S_SIGIL]),
|
|
|
|
S_BRIGHT (SIGH, 'E', 18, A_SigilCharge, &States[S_SIGILATK+18]),
|
|
S_BRIGHT (SIGH, 'E', 3, A_GunFlash, &States[S_SIGILATK+19]),
|
|
S_NORMAL (SIGH, 'E', 10, A_FireSigil5, &States[S_SIGILATK+20]),
|
|
S_NORMAL (SIGH, 'E', 5, NULL, &States[S_SIGIL]),
|
|
|
|
#define S_SIGILFLASH (S_SIGILATK+1+4*5)
|
|
S_BRIGHT (SIGF, 'A', 4, A_Light2, &States[S_SIGILFLASH+1]),
|
|
S_BRIGHT (SIGF, 'B', 6, A_LightInverse, &States[S_SIGILFLASH+2]),
|
|
S_BRIGHT (SIGF, 'C', 4, A_Light1, &States[S_SIGILFLASH+3]),
|
|
S_BRIGHT (SIGF, 'C', 0, A_Light0, NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (ASigil, Strife, -1, 0)
|
|
PROP_Weapon_SelectionOrder (4000)
|
|
PROP_Weapon_UpState (S_SIGILUP)
|
|
PROP_Weapon_DownState (S_SIGILDOWN)
|
|
PROP_Weapon_ReadyState (S_SIGIL)
|
|
PROP_Weapon_AtkState (S_SIGILATK)
|
|
PROP_Weapon_HoldAtkState (S_SIGILATK)
|
|
PROP_Weapon_FlashState (S_SIGILFLASH)
|
|
PROP_Sigil_NumPieces (1)
|
|
PROP_SpawnState (0)
|
|
PROP_Flags (MF_SPECIAL)
|
|
PROP_Flags2 (MF2_FLOORCLIP)
|
|
PROP_Weapon_FlagsSet (WIF_CHEATNOTWEAPON)
|
|
PROP_Tag ("SIGIL")
|
|
PROP_Inventory_Icon ("I_SGL1")
|
|
END_DEFAULTS
|
|
|
|
// Sigil 1 ------------------------------------------------------------------
|
|
|
|
class ASigil1 : public ASigil
|
|
{
|
|
DECLARE_STATELESS_ACTOR (ASigil1, ASigil)
|
|
};
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (ASigil1, Strife, 77, 0)
|
|
PROP_Sigil_NumPieces (1)
|
|
PROP_StrifeType (196)
|
|
PROP_StrifeTeaserType (190)
|
|
PROP_StrifeTeaserType2 (194)
|
|
PROP_Tag ("SIGIL")
|
|
PROP_Inventory_Icon ("I_SGL1")
|
|
END_DEFAULTS
|
|
|
|
// Sigil 2 ------------------------------------------------------------------
|
|
|
|
class ASigil2 : public ASigil
|
|
{
|
|
DECLARE_STATELESS_ACTOR (ASigil2, ASigil)
|
|
};
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (ASigil2, Strife, 78, 0)
|
|
PROP_Sigil_NumPieces (2)
|
|
PROP_StrifeType (197)
|
|
PROP_StrifeTeaserType (191)
|
|
PROP_StrifeTeaserType2 (195)
|
|
PROP_Tag ("SIGIL")
|
|
PROP_Inventory_Icon ("I_SGL2")
|
|
END_DEFAULTS
|
|
|
|
// Sigil 3 ------------------------------------------------------------------
|
|
|
|
class ASigil3 : public ASigil
|
|
{
|
|
DECLARE_STATELESS_ACTOR (ASigil3, ASigil)
|
|
};
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (ASigil3, Strife, 79, 0)
|
|
PROP_Sigil_NumPieces (3)
|
|
PROP_StrifeType (198)
|
|
PROP_StrifeTeaserType (192)
|
|
PROP_StrifeTeaserType2 (196)
|
|
PROP_Tag ("SIGIL")
|
|
PROP_Inventory_Icon ("I_SGL3")
|
|
END_DEFAULTS
|
|
|
|
// Sigil 4 ------------------------------------------------------------------
|
|
|
|
class ASigil4 : public ASigil
|
|
{
|
|
DECLARE_STATELESS_ACTOR (ASigil4, ASigil)
|
|
};
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (ASigil4, Strife, 80, 0)
|
|
PROP_Sigil_NumPieces (4)
|
|
PROP_StrifeType (199)
|
|
PROP_StrifeTeaserType (193)
|
|
PROP_StrifeTeaserType2 (197)
|
|
PROP_Tag ("SIGIL")
|
|
PROP_Inventory_Icon ("I_SGL4")
|
|
END_DEFAULTS
|
|
|
|
// Sigil 5 ------------------------------------------------------------------
|
|
|
|
class ASigil5 : public ASigil
|
|
{
|
|
DECLARE_STATELESS_ACTOR (ASigil5, ASigil)
|
|
};
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (ASigil5, Strife, 81, 0)
|
|
PROP_Sigil_NumPieces (5)
|
|
PROP_StrifeType (200)
|
|
PROP_StrifeTeaserType (194)
|
|
PROP_StrifeTeaserType2 (198)
|
|
PROP_Tag ("SIGIL")
|
|
PROP_Inventory_Icon ("I_SGL5")
|
|
END_DEFAULTS
|
|
|
|
//============================================================================
|
|
//
|
|
// ASigil :: Serialize
|
|
//
|
|
//============================================================================
|
|
|
|
void ASigil::Serialize (FArchive &arc)
|
|
{
|
|
Super::Serialize (arc);
|
|
arc << NumPieces << DownPieces;
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// ASigil :: HandlePickup
|
|
//
|
|
//============================================================================
|
|
|
|
bool ASigil::HandlePickup (AInventory *item)
|
|
{
|
|
if (item->IsKindOf (RUNTIME_CLASS(ASigil)))
|
|
{
|
|
int otherPieces = static_cast<ASigil*>(item)->NumPieces;
|
|
if (otherPieces > NumPieces)
|
|
{
|
|
item->ItemFlags |= IF_PICKUPGOOD;
|
|
Icon = item->Icon;
|
|
// If the player is holding the Sigil right now, drop it and bring
|
|
// it back with the new piece(s) in view.
|
|
if (Owner->player != NULL && Owner->player->ReadyWeapon == this)
|
|
{
|
|
DownPieces = NumPieces;
|
|
Owner->player->PendingWeapon = this;
|
|
}
|
|
NumPieces = otherPieces;
|
|
}
|
|
return true;
|
|
}
|
|
if (Inventory != NULL)
|
|
{
|
|
return Inventory->HandlePickup (item);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// ASigil :: CreateCopy
|
|
//
|
|
//============================================================================
|
|
|
|
AInventory *ASigil::CreateCopy (AActor *other)
|
|
{
|
|
ASigil *copy = Spawn<ASigil> (0,0,0);
|
|
copy->Amount = Amount;
|
|
copy->MaxAmount = MaxAmount;
|
|
copy->NumPieces = NumPieces;
|
|
copy->Icon = Icon;
|
|
GoAwayAndDie ();
|
|
return copy;
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// ASigil :: PickupMessage
|
|
//
|
|
//============================================================================
|
|
|
|
const char *ASigil::PickupMessage ()
|
|
{
|
|
return "You picked up the SIGIL.";
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_SelectPiece
|
|
//
|
|
// Decide which sprite frame this Sigil should use as an item, based on how
|
|
// many pieces it represents.
|
|
//
|
|
//============================================================================
|
|
|
|
void A_SelectPiece (AActor *self)
|
|
{
|
|
int pieces = MIN (static_cast<ASigil*>(self)->NumPieces, 5);
|
|
|
|
if (pieces > 1)
|
|
{
|
|
self->SetState (&ASigil::States[pieces]);
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_SelectSigilView
|
|
//
|
|
// Decide which first-person frame this Sigil should show, based on how many
|
|
// pieces it represents. Strife did this by selecting a flash that looked like
|
|
// the Sigil whenever you switched to it and at the end of an attack. I have
|
|
// chosen to make the weapon sprite choose the correct frame and let the flash
|
|
// be a regular flash. It means I need to use more states, but I think it's
|
|
// worth it.
|
|
//
|
|
//============================================================================
|
|
|
|
void A_SelectSigilView (AActor *self)
|
|
{
|
|
int pieces;
|
|
|
|
if (self->player == NULL)
|
|
{
|
|
return;
|
|
}
|
|
pieces = static_cast<ASigil*>(self->player->ReadyWeapon)->NumPieces;
|
|
P_SetPsprite (self->player, ps_weapon,
|
|
self->player->psprites[ps_weapon].state + pieces);
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_SelectSigilDown
|
|
//
|
|
// Same as A_SelectSigilView, except it uses DownPieces. This is so that when
|
|
// you pick up a Sigil, the old one will drop and *then* change to the new
|
|
// one.
|
|
//
|
|
//============================================================================
|
|
|
|
void A_SelectSigilDown (AActor *self)
|
|
{
|
|
int pieces;
|
|
|
|
if (self->player == NULL)
|
|
{
|
|
return;
|
|
}
|
|
pieces = static_cast<ASigil*>(self->player->ReadyWeapon)->DownPieces;
|
|
static_cast<ASigil*>(self->player->ReadyWeapon)->DownPieces = 0;
|
|
if (pieces == 0)
|
|
{
|
|
pieces = static_cast<ASigil*>(self->player->ReadyWeapon)->NumPieces;
|
|
}
|
|
P_SetPsprite (self->player, ps_weapon,
|
|
self->player->psprites[ps_weapon].state + pieces);
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_SelectSigilAttack
|
|
//
|
|
// Same as A_SelectSigilView, but used just before attacking.
|
|
//
|
|
//============================================================================
|
|
|
|
void A_SelectSigilAttack (AActor *self)
|
|
{
|
|
int pieces;
|
|
|
|
if (self->player == NULL)
|
|
{
|
|
return;
|
|
}
|
|
pieces = static_cast<ASigil*>(self->player->ReadyWeapon)->NumPieces;
|
|
P_SetPsprite (self->player, ps_weapon,
|
|
self->player->psprites[ps_weapon].state + 4*pieces - 3);
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_SigilCharge
|
|
//
|
|
//============================================================================
|
|
|
|
void A_SigilCharge (AActor *self)
|
|
{
|
|
S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM);
|
|
if (self->player != NULL)
|
|
{
|
|
self->player->extralight = 2;
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_LightInverse
|
|
//
|
|
//============================================================================
|
|
|
|
void A_LightInverse (AActor *actor)
|
|
{
|
|
if (actor->player != NULL)
|
|
{
|
|
actor->player->extralight = INT_MIN;
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_FireSigil1
|
|
//
|
|
//============================================================================
|
|
|
|
void A_FireSigil1 (AActor *actor)
|
|
{
|
|
AActor *spot;
|
|
player_t *player = actor->player;
|
|
|
|
if (player == NULL || player->ReadyWeapon == NULL)
|
|
return;
|
|
|
|
P_DamageMobj (actor, actor, NULL, 1*4, 0, DMG_NO_ARMOR);
|
|
S_Sound (actor, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM);
|
|
|
|
P_BulletSlope (actor);
|
|
if (linetarget != NULL)
|
|
{
|
|
spot = Spawn<ASpectralLightningSpot> (linetarget->x, linetarget->y, ONFLOORZ);
|
|
if (spot != NULL)
|
|
{
|
|
spot->tracer = linetarget;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
spot = Spawn<ASpectralLightningSpot> (actor->x, actor->y, actor->z);
|
|
if (spot != NULL)
|
|
{
|
|
spot->momx += 28 * finecosine[actor->angle >> ANGLETOFINESHIFT];
|
|
spot->momy += 28 * finesine[actor->angle >> ANGLETOFINESHIFT];
|
|
}
|
|
}
|
|
if (spot != NULL)
|
|
{
|
|
spot->health = -1;
|
|
spot->target = actor;
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_FireSigil2
|
|
//
|
|
//============================================================================
|
|
|
|
void A_FireSigil2 (AActor *actor)
|
|
{
|
|
AActor *spot;
|
|
player_t *player = actor->player;
|
|
|
|
if (player == NULL || player->ReadyWeapon == NULL)
|
|
return;
|
|
|
|
P_DamageMobj (actor, actor, NULL, 2*4, 0, DMG_NO_ARMOR);
|
|
S_Sound (actor, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM);
|
|
|
|
spot = P_SpawnPlayerMissile (actor, RUNTIME_CLASS(ASpectralLightningH1));
|
|
if (spot != NULL)
|
|
{
|
|
spot->health = -1;
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_FireSigil3
|
|
//
|
|
//============================================================================
|
|
|
|
void A_FireSigil3 (AActor *actor)
|
|
{
|
|
AActor *spot;
|
|
player_t *player = actor->player;
|
|
int i;
|
|
|
|
if (player == NULL || player->ReadyWeapon == NULL)
|
|
return;
|
|
|
|
P_DamageMobj (actor, actor, NULL, 3*4, 0, DMG_NO_ARMOR);
|
|
S_Sound (actor, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM);
|
|
|
|
actor->angle -= ANGLE_90;
|
|
for (i = 0; i < 20; ++i)
|
|
{
|
|
actor->angle += ANGLE_180/20;
|
|
spot = P_SpawnSubMissile (actor, RUNTIME_CLASS(ASpectralLightningBall1), actor);
|
|
if (spot != NULL)
|
|
{
|
|
spot->health = -1;
|
|
spot->z = actor->z + 32*FRACUNIT;
|
|
}
|
|
}
|
|
actor->angle -= (ANGLE_180/20)*10;
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_FireSigil4
|
|
//
|
|
//============================================================================
|
|
|
|
void A_FireSigil4 (AActor *actor)
|
|
{
|
|
AActor *spot;
|
|
player_t *player = actor->player;
|
|
|
|
if (player == NULL || player->ReadyWeapon == NULL)
|
|
return;
|
|
|
|
P_DamageMobj (actor, actor, NULL, 4*4, 0, DMG_NO_ARMOR);
|
|
S_Sound (actor, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM);
|
|
|
|
P_BulletSlope (actor);
|
|
if (linetarget != NULL)
|
|
{
|
|
spot = P_SpawnPlayerMissile (actor, RUNTIME_CLASS(ASpectralLightningBigV1));
|
|
if (spot != NULL)
|
|
{
|
|
spot->tracer = linetarget;
|
|
spot->health = -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
spot = P_SpawnPlayerMissile (actor, RUNTIME_CLASS(ASpectralLightningBigV1));
|
|
if (spot != NULL)
|
|
{
|
|
spot->momx += FixedMul (spot->Speed, finecosine[actor->angle >> ANGLETOFINESHIFT]);
|
|
spot->momy += FixedMul (spot->Speed, finesine[actor->angle >> ANGLETOFINESHIFT]);
|
|
spot->health = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_FireSigil5
|
|
//
|
|
//============================================================================
|
|
|
|
void A_FireSigil5 (AActor *actor)
|
|
{
|
|
AActor *spot;
|
|
player_t *player = actor->player;
|
|
|
|
if (player == NULL || player->ReadyWeapon == NULL)
|
|
return;
|
|
|
|
P_DamageMobj (actor, actor, NULL, 5*4, 0, DMG_NO_ARMOR);
|
|
S_Sound (actor, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM);
|
|
|
|
spot = P_SpawnPlayerMissile (actor, RUNTIME_CLASS(ASpectralLightningBigBall1));
|
|
if (spot != NULL)
|
|
{
|
|
spot->health = -1;
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// ASigil :: SpecialDropAction
|
|
//
|
|
// Monsters don't drop Sigil pieces. The Sigil pieces grab hold of the person
|
|
// who killed the dropper and automatically enter their inventory. That's the
|
|
// way it works if you believe Macil, anyway...
|
|
//
|
|
//============================================================================
|
|
|
|
bool ASigil::SpecialDropAction (AActor *dropper)
|
|
{
|
|
// Give a Sigil piece to every player in the game
|
|
for (int i = 0; i < MAXPLAYERS; ++i)
|
|
{
|
|
if (playeringame[i] && players[i].mo != NULL)
|
|
{
|
|
GiveSigilPiece (players[i].mo);
|
|
Destroy ();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// ASigil :: GiveSigilPiece
|
|
//
|
|
// Gives the actor another Sigil piece, up to 5. Returns the number of Sigil
|
|
// pieces the actor previously held.
|
|
//
|
|
//============================================================================
|
|
|
|
int ASigil::GiveSigilPiece (AActor *receiver)
|
|
{
|
|
ASigil *sigil;
|
|
|
|
sigil = receiver->FindInventory<ASigil> ();
|
|
if (sigil == NULL)
|
|
{
|
|
sigil = Spawn<ASigil1> (0,0,0);
|
|
if (!sigil->TryPickup (receiver))
|
|
{
|
|
sigil->Destroy ();
|
|
}
|
|
return 0;
|
|
}
|
|
else if (sigil->NumPieces < 5)
|
|
{
|
|
++sigil->NumPieces;
|
|
static const TypeInfo *const sigils[5] =
|
|
{
|
|
RUNTIME_CLASS(ASigil1),
|
|
RUNTIME_CLASS(ASigil2),
|
|
RUNTIME_CLASS(ASigil3),
|
|
RUNTIME_CLASS(ASigil4),
|
|
RUNTIME_CLASS(ASigil5)
|
|
};
|
|
sigil->Icon = ((AInventory*)GetDefaultByType (sigils[MAX(0,sigil->NumPieces-1)]))->Icon;
|
|
// If the player has the Sigil out, drop it and bring it back up.
|
|
if (sigil->Owner->player != NULL && sigil->Owner->player->ReadyWeapon == sigil)
|
|
{
|
|
sigil->Owner->player->PendingWeapon = sigil;
|
|
sigil->DownPieces = sigil->NumPieces - 1;
|
|
}
|
|
return sigil->NumPieces - 1;
|
|
}
|
|
else
|
|
{
|
|
return 5;
|
|
}
|
|
}
|