mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-14 00:21:34 +00:00
b54b9bad7a
- Reorganized the HackHack code so that the image creation was moved into MakeTexture. This was necessary because Unload deleted the pixel data and broke the whole thing. - Fixed: FPatchTexture::HackHack and FDoomStatusbarTexture::DrawToBar used the obsolete and uninitialized variable Near255. - Removed the span creation code specific to FPatchTexture. It only has an advantage when the lump has already been loaded in memory but since that is no longer the case now the generic version in FTexture is actually better. - Changed: FTexture::CopyToBlock no longer uses the spans but the pixel buffer directly. Since most patches in multipatch textures are non transparent the added overhead from creating the spans far outweighs any savings they might provide. It is also simpler to handle for mirrored or rotated patches now. - Changed: Textures only create the spans when really needed. Flats and native textures, for example, do not and it only created needless overhead that they were always created along with the pixel buffer. - Made use of player and actor variables consistent in a_hereticweaps.cpp. - Fixed: A few calls to P_SpawnPlayerMissile passed 0 as angle SVN r911 (trunk)
2959 lines
83 KiB
C++
2959 lines
83 KiB
C++
#include "templates.h"
|
|
#include "actor.h"
|
|
#include "info.h"
|
|
#include "s_sound.h"
|
|
#include "m_random.h"
|
|
#include "a_pickups.h"
|
|
#include "a_hereticglobal.h"
|
|
#include "d_player.h"
|
|
#include "p_pspr.h"
|
|
#include "p_local.h"
|
|
#include "gstrings.h"
|
|
#include "p_effect.h"
|
|
#include "gstrings.h"
|
|
#include "p_enemy.h"
|
|
#include "gi.h"
|
|
#include "r_translate.h"
|
|
|
|
static FRandom pr_sap ("StaffAtkPL1");
|
|
static FRandom pr_sap2 ("StaffAtkPL2");
|
|
static FRandom pr_fgw ("FireWandPL1");
|
|
static FRandom pr_fgw2 ("FireWandPL2");
|
|
static FRandom pr_boltspark ("BoltSpark");
|
|
static FRandom pr_spawnmace ("SpawnMace");
|
|
static FRandom pr_macerespawn ("MaceRespawn");
|
|
static FRandom pr_maceatk ("FireMacePL1");
|
|
static FRandom pr_gatk ("GauntletAttack");
|
|
static FRandom pr_bfx1 ("BlasterFX1");
|
|
static FRandom pr_ripd ("RipperD");
|
|
static FRandom pr_fb1 ("FireBlasterPL1");
|
|
static FRandom pr_bfx1t ("BlasterFX1Tick");
|
|
static FRandom pr_hrfx2 ("HornRodFX2");
|
|
static FRandom pr_rp ("RainPillar");
|
|
static FRandom pr_fsr1 ("FireSkullRodPL1");
|
|
static FRandom pr_storm ("SkullRodStorm");
|
|
static FRandom pr_impact ("RainImpact");
|
|
static FRandom pr_pfx1 ("PhoenixFX1");
|
|
static FRandom pr_pfx2 ("PhoenixFX2");
|
|
static FRandom pr_fp2 ("FirePhoenixPL2");
|
|
|
|
#define FLAME_THROWER_TICS (10*TICRATE)
|
|
|
|
|
|
#define USE_GWND_AMMO_1 1
|
|
#define USE_GWND_AMMO_2 1
|
|
#define USE_CBOW_AMMO_1 1
|
|
#define USE_CBOW_AMMO_2 1
|
|
#define USE_BLSR_AMMO_1 1
|
|
#define USE_BLSR_AMMO_2 5
|
|
#define USE_SKRD_AMMO_1 1
|
|
#define USE_SKRD_AMMO_2 5
|
|
#define USE_PHRD_AMMO_1 1
|
|
#define USE_PHRD_AMMO_2 1
|
|
#define USE_MACE_AMMO_1 1
|
|
#define USE_MACE_AMMO_2 5
|
|
|
|
extern bool P_AutoUseChaosDevice (player_t *player);
|
|
|
|
// Base Heretic weapon class ------------------------------------------------
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (AHereticWeapon, Heretic, -1, 0)
|
|
PROP_Weapon_Kickback (150)
|
|
END_DEFAULTS
|
|
|
|
// --- Staff ----------------------------------------------------------------
|
|
|
|
void A_StaffAttackPL1 (AActor *);
|
|
void A_StaffAttackPL2 (AActor *);
|
|
|
|
// Staff --------------------------------------------------------------------
|
|
|
|
class AStaff : public AHereticWeapon
|
|
{
|
|
DECLARE_ACTOR (AStaff, AHereticWeapon)
|
|
};
|
|
|
|
class AStaffPowered : public AStaff
|
|
{
|
|
DECLARE_STATELESS_ACTOR (AStaffPowered, AStaff)
|
|
};
|
|
|
|
FState AStaff::States[] =
|
|
{
|
|
#define S_STAFFREADY 0
|
|
S_NORMAL (STFF, 'A', 1, A_WeaponReady , &States[S_STAFFREADY]),
|
|
|
|
#define S_STAFFDOWN (S_STAFFREADY+1)
|
|
S_NORMAL (STFF, 'A', 1, A_Lower , &States[S_STAFFDOWN]),
|
|
|
|
#define S_STAFFUP (S_STAFFDOWN+1)
|
|
S_NORMAL (STFF, 'A', 1, A_Raise , &States[S_STAFFUP]),
|
|
|
|
#define S_STAFFREADY2 (S_STAFFUP+1)
|
|
S_NORMAL (STFF, 'D', 4, A_WeaponReady , &States[S_STAFFREADY2+1]),
|
|
S_NORMAL (STFF, 'E', 4, A_WeaponReady , &States[S_STAFFREADY2+2]),
|
|
S_NORMAL (STFF, 'F', 4, A_WeaponReady , &States[S_STAFFREADY2+0]),
|
|
|
|
#define S_STAFFDOWN2 (S_STAFFREADY2+3)
|
|
S_NORMAL (STFF, 'D', 1, A_Lower , &States[S_STAFFDOWN2]),
|
|
|
|
#define S_STAFFUP2 (S_STAFFDOWN2+1)
|
|
S_NORMAL (STFF, 'D', 1, A_Raise , &States[S_STAFFUP2]),
|
|
|
|
#define S_STAFFATK1 (S_STAFFUP2+1)
|
|
S_NORMAL (STFF, 'B', 6, NULL , &States[S_STAFFATK1+1]),
|
|
S_NORMAL (STFF, 'C', 8, A_StaffAttackPL1 , &States[S_STAFFATK1+2]),
|
|
S_NORMAL (STFF, 'B', 8, A_ReFire , &States[S_STAFFREADY]),
|
|
|
|
#define S_STAFFATK2 (S_STAFFATK1+3)
|
|
S_NORMAL (STFF, 'G', 6, NULL , &States[S_STAFFATK2+1]),
|
|
S_NORMAL (STFF, 'H', 8, A_StaffAttackPL2 , &States[S_STAFFATK2+2]),
|
|
S_NORMAL (STFF, 'G', 8, A_ReFire , &States[S_STAFFREADY2+0])
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AStaff, Heretic, -1, 0)
|
|
PROP_Weapon_SelectionOrder (3800)
|
|
PROP_Flags2Set(MF2_THRUGHOST)
|
|
PROP_Weapon_Flags (WIF_WIMPY_WEAPON|WIF_BOT_MELEE)
|
|
PROP_Weapon_UpState (S_STAFFUP)
|
|
PROP_Weapon_DownState (S_STAFFDOWN)
|
|
PROP_Weapon_ReadyState (S_STAFFREADY)
|
|
PROP_Weapon_AtkState (S_STAFFATK1)
|
|
PROP_Weapon_SisterType ("StaffPowered")
|
|
END_DEFAULTS
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (AStaffPowered, Heretic, -1, 0)
|
|
PROP_Weapon_Flags (WIF_WIMPY_WEAPON|WIF_READYSNDHALF|WIF_POWERED_UP|WIF_BOT_MELEE|WIF_STAFF2_KICKBACK)
|
|
PROP_Weapon_UpState (S_STAFFUP2)
|
|
PROP_Weapon_DownState (S_STAFFDOWN2)
|
|
PROP_Weapon_ReadyState (S_STAFFREADY2)
|
|
PROP_Weapon_AtkState (S_STAFFATK2)
|
|
PROP_Weapon_ReadySound ("weapons/staffcrackle")
|
|
PROP_Weapon_SisterType ("Staff")
|
|
END_DEFAULTS
|
|
|
|
// Staff puff ---------------------------------------------------------------
|
|
|
|
FState AStaffPuff::States[] =
|
|
{
|
|
S_BRIGHT (PUF3, 'A', 4, NULL , &States[1]),
|
|
S_NORMAL (PUF3, 'B', 4, NULL , &States[2]),
|
|
S_NORMAL (PUF3, 'C', 4, NULL , &States[3]),
|
|
S_NORMAL (PUF3, 'D', 4, NULL , NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AStaffPuff, Heretic, -1, 0)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY)
|
|
PROP_Flags3 (MF3_PUFFONACTORS)
|
|
PROP_RenderStyle (STYLE_Translucent)
|
|
PROP_Alpha (HR_SHADOW)
|
|
PROP_SpawnState (0)
|
|
PROP_AttackSound ("weapons/staffhit")
|
|
END_DEFAULTS
|
|
|
|
void AStaffPuff::BeginPlay ()
|
|
{
|
|
Super::BeginPlay ();
|
|
momz = FRACUNIT;
|
|
}
|
|
|
|
// Staff puff 2 -------------------------------------------------------------
|
|
|
|
class AStaffPuff2 : public AStaffPuff
|
|
{
|
|
DECLARE_ACTOR (AStaffPuff2, AStaffPuff)
|
|
public:
|
|
void BeginPlay ();
|
|
};
|
|
|
|
FState AStaffPuff2::States[] =
|
|
{
|
|
S_BRIGHT (PUF4, 'A', 4, NULL , &States[1]),
|
|
S_BRIGHT (PUF4, 'B', 4, NULL , &States[2]),
|
|
S_BRIGHT (PUF4, 'C', 4, NULL , &States[3]),
|
|
S_BRIGHT (PUF4, 'D', 4, NULL , &States[4]),
|
|
S_BRIGHT (PUF4, 'E', 4, NULL , &States[5]),
|
|
S_BRIGHT (PUF4, 'F', 4, NULL , NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AStaffPuff2, Heretic, -1, 0)
|
|
PROP_SpawnState (0)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
PROP_Alpha (OPAQUE)
|
|
PROP_AttackSound ("weapons/staffpowerhit")
|
|
END_DEFAULTS
|
|
|
|
void AStaffPuff2::BeginPlay ()
|
|
{
|
|
Super::BeginPlay ();
|
|
momz = 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_StaffAttackPL1
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_StaffAttackPL1 (AActor *actor)
|
|
{
|
|
angle_t angle;
|
|
int damage;
|
|
int slope;
|
|
player_t *player;
|
|
AActor *linetarget;
|
|
|
|
if (NULL == (player = actor->player))
|
|
{
|
|
return;
|
|
}
|
|
|
|
AWeapon *weapon = player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
damage = 5+(pr_sap()&15);
|
|
angle = actor->angle;
|
|
angle += pr_sap.Random2() << 18;
|
|
slope = P_AimLineAttack (actor, angle, MELEERANGE, &linetarget);
|
|
P_LineAttack (actor, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AStaffPuff), true);
|
|
if (linetarget)
|
|
{
|
|
//S_StartSound(player->mo, sfx_stfhit);
|
|
// turn to face target
|
|
actor->angle = R_PointToAngle2 (actor->x,
|
|
actor->y, linetarget->x, linetarget->y);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_StaffAttackPL2
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_StaffAttackPL2 (AActor *actor)
|
|
{
|
|
angle_t angle;
|
|
int damage;
|
|
int slope;
|
|
player_t *player;
|
|
AActor *linetarget;
|
|
|
|
if (NULL == (player = actor->player))
|
|
{
|
|
return;
|
|
}
|
|
|
|
AWeapon *weapon = player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
// P_inter.c:P_DamageMobj() handles target momentums
|
|
damage = 18+(pr_sap2()&63);
|
|
angle = actor->angle;
|
|
angle += pr_sap2.Random2() << 18;
|
|
slope = P_AimLineAttack (actor, angle, MELEERANGE, &linetarget);
|
|
P_LineAttack (actor, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AStaffPuff2), true);
|
|
if (linetarget)
|
|
{
|
|
//S_StartSound(player->mo, sfx_stfpow);
|
|
// turn to face target
|
|
actor->angle = R_PointToAngle2 (actor->x,
|
|
actor->y, linetarget->x, linetarget->y);
|
|
}
|
|
}
|
|
|
|
// --- Gold wand ------------------------------------------------------------
|
|
|
|
void A_FireGoldWandPL1 (AActor *);
|
|
void A_FireGoldWandPL2 (AActor *);
|
|
|
|
// Gold wand ----------------------------------------------------------------
|
|
|
|
class AGoldWand : public AHereticWeapon
|
|
{
|
|
DECLARE_ACTOR (AGoldWand, AHereticWeapon)
|
|
};
|
|
|
|
class AGoldWandPowered : public AGoldWand
|
|
{
|
|
DECLARE_STATELESS_ACTOR (AGoldWandPowered, AGoldWand)
|
|
};
|
|
|
|
FState AGoldWand::States[] =
|
|
{
|
|
#define S_GOLDWANDREADY 0
|
|
S_NORMAL (GWND, 'A', 1, A_WeaponReady , &States[S_GOLDWANDREADY]),
|
|
|
|
#define S_GOLDWANDDOWN (S_GOLDWANDREADY+1)
|
|
S_NORMAL (GWND, 'A', 1, A_Lower , &States[S_GOLDWANDDOWN]),
|
|
|
|
#define S_GOLDWANDUP (S_GOLDWANDDOWN+1)
|
|
S_NORMAL (GWND, 'A', 1, A_Raise , &States[S_GOLDWANDUP]),
|
|
|
|
#define S_GOLDWANDATK1 (S_GOLDWANDUP+1)
|
|
S_NORMAL (GWND, 'B', 3, NULL , &States[S_GOLDWANDATK1+1]),
|
|
S_NORMAL (GWND, 'C', 5, A_FireGoldWandPL1 , &States[S_GOLDWANDATK1+2]),
|
|
S_NORMAL (GWND, 'D', 3, NULL , &States[S_GOLDWANDATK1+3]),
|
|
S_NORMAL (GWND, 'D', 0, A_ReFire , &States[S_GOLDWANDREADY]),
|
|
|
|
#define S_GOLDWANDATK2 (S_GOLDWANDATK1+4)
|
|
S_NORMAL (GWND, 'B', 3, NULL , &States[S_GOLDWANDATK2+1]),
|
|
S_NORMAL (GWND, 'C', 4, A_FireGoldWandPL2 , &States[S_GOLDWANDATK2+2]),
|
|
S_NORMAL (GWND, 'D', 3, NULL , &States[S_GOLDWANDATK2+3]),
|
|
S_NORMAL (GWND, 'D', 0, A_ReFire , &States[S_GOLDWANDREADY])
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AGoldWand, Heretic, -1, 0)
|
|
PROP_Flags5 (MF5_BLOODSPLATTER)
|
|
PROP_Weapon_SelectionOrder (2000)
|
|
PROP_Weapon_AmmoUse1 (USE_GWND_AMMO_1)
|
|
PROP_Weapon_AmmoGive1 (25)
|
|
PROP_Weapon_UpState (S_GOLDWANDUP)
|
|
PROP_Weapon_DownState (S_GOLDWANDDOWN)
|
|
PROP_Weapon_ReadyState (S_GOLDWANDREADY)
|
|
PROP_Weapon_AtkState (S_GOLDWANDATK1)
|
|
PROP_Weapon_YAdjust (5)
|
|
PROP_Weapon_MoveCombatDist (25000000)
|
|
PROP_Weapon_AmmoType1 ("GoldWandAmmo")
|
|
PROP_Weapon_SisterType ("GoldWandPowered")
|
|
END_DEFAULTS
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (AGoldWandPowered, Heretic, -1, 0)
|
|
PROP_Weapon_Flags (WIF_POWERED_UP)
|
|
PROP_Weapon_AmmoUse1 (USE_GWND_AMMO_2)
|
|
PROP_Weapon_AmmoGive1 (0)
|
|
PROP_Weapon_AtkState (S_GOLDWANDATK2)
|
|
PROP_Weapon_SisterType ("GoldWand")
|
|
END_DEFAULTS
|
|
|
|
// Gold wand FX1 ------------------------------------------------------------
|
|
|
|
class AGoldWandFX1 : public AActor
|
|
{
|
|
DECLARE_ACTOR (AGoldWandFX1, AActor)
|
|
};
|
|
|
|
FState AGoldWandFX1::States[] =
|
|
{
|
|
#define S_GWANDFX1 0
|
|
S_BRIGHT (FX01, 'A', 6, NULL , &States[S_GWANDFX1+1]),
|
|
S_BRIGHT (FX01, 'B', 6, NULL , &States[S_GWANDFX1+0]),
|
|
|
|
#define S_GWANDFXI1 (S_GWANDFX1+2)
|
|
S_BRIGHT (FX01, 'E', 3, NULL , &States[S_GWANDFXI1+1]),
|
|
S_BRIGHT (FX01, 'F', 3, NULL , &States[S_GWANDFXI1+2]),
|
|
S_BRIGHT (FX01, 'G', 3, NULL , &States[S_GWANDFXI1+3]),
|
|
S_BRIGHT (FX01, 'H', 3, NULL , NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AGoldWandFX1, Heretic, -1, 151)
|
|
PROP_RadiusFixed (10)
|
|
PROP_HeightFixed (6)
|
|
PROP_SpeedFixed (22)
|
|
PROP_Damage (2)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY)
|
|
PROP_Flags2 (MF2_NOTELEPORT)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
|
|
PROP_SpawnState (S_GWANDFX1)
|
|
PROP_DeathState (S_GWANDFXI1)
|
|
|
|
PROP_DeathSound ("weapons/wandhit")
|
|
END_DEFAULTS
|
|
|
|
// Gold wand FX2 ------------------------------------------------------------
|
|
|
|
class AGoldWandFX2 : public AGoldWandFX1
|
|
{
|
|
DECLARE_ACTOR (AGoldWandFX2, AGoldWandFX1)
|
|
};
|
|
|
|
FState AGoldWandFX2::States[] =
|
|
{
|
|
S_BRIGHT (FX01, 'C', 6, NULL , &States[1]),
|
|
S_BRIGHT (FX01, 'D', 6, NULL , &States[0])
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AGoldWandFX2, Heretic, -1, 152)
|
|
PROP_SpeedFixed (18)
|
|
PROP_Damage (1)
|
|
|
|
PROP_SpawnState (0)
|
|
|
|
PROP_DeathSound ("")
|
|
END_DEFAULTS
|
|
|
|
// Gold wand puff 1 ---------------------------------------------------------
|
|
|
|
class AGoldWandPuff1 : public AActor
|
|
{
|
|
DECLARE_ACTOR (AGoldWandPuff1, AActor)
|
|
};
|
|
|
|
FState AGoldWandPuff1::States[] =
|
|
{
|
|
S_BRIGHT (PUF2, 'A', 3, NULL , &States[1]),
|
|
S_BRIGHT (PUF2, 'B', 3, NULL , &States[2]),
|
|
S_BRIGHT (PUF2, 'C', 3, NULL , &States[3]),
|
|
S_BRIGHT (PUF2, 'D', 3, NULL , &States[4]),
|
|
S_BRIGHT (PUF2, 'E', 3, NULL , NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AGoldWandPuff1, Heretic, -1, 0)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY)
|
|
PROP_Flags3 (MF3_PUFFONACTORS)
|
|
PROP_SpawnState (0)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
END_DEFAULTS
|
|
|
|
// Gold wand puff 2 ---------------------------------------------------------
|
|
|
|
class AGoldWandPuff2 : public AGoldWandFX1
|
|
{
|
|
DECLARE_STATELESS_ACTOR (AGoldWandPuff2, AGoldWandFX1)
|
|
};
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (AGoldWandPuff2, Heretic, -1, 0)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY)
|
|
PROP_SpawnState (S_GWANDFXI1)
|
|
END_DEFAULTS
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_FireGoldWandPL1
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_FireGoldWandPL1 (AActor *actor)
|
|
{
|
|
angle_t angle;
|
|
int damage;
|
|
player_t *player;
|
|
|
|
if (NULL == (player = actor->player))
|
|
{
|
|
return;
|
|
}
|
|
|
|
AWeapon *weapon = player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
angle_t pitch = P_BulletSlope(actor);
|
|
damage = 7+(pr_fgw()&7);
|
|
angle = actor->angle;
|
|
if (player->refire)
|
|
{
|
|
angle += pr_fgw.Random2() << 18;
|
|
}
|
|
P_LineAttack (actor, angle, PLAYERMISSILERANGE, pitch, damage, NAME_None, RUNTIME_CLASS(AGoldWandPuff1));
|
|
S_Sound (actor, CHAN_WEAPON, "weapons/wandhit", 1, ATTN_NORM);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_FireGoldWandPL2
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_FireGoldWandPL2 (AActor *actor)
|
|
{
|
|
int i;
|
|
angle_t angle;
|
|
int damage;
|
|
fixed_t momz;
|
|
player_t *player;
|
|
|
|
if (NULL == (player = actor->player))
|
|
{
|
|
return;
|
|
}
|
|
|
|
AWeapon *weapon = player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
angle_t pitch = P_BulletSlope(actor);
|
|
momz = FixedMul (GetDefault<AGoldWandFX2>()->Speed,
|
|
finetangent[FINEANGLES/4-((signed)pitch>>ANGLETOFINESHIFT)]);
|
|
P_SpawnMissileAngle (actor, RUNTIME_CLASS(AGoldWandFX2), actor->angle-(ANG45/8), momz);
|
|
P_SpawnMissileAngle (actor, RUNTIME_CLASS(AGoldWandFX2), actor->angle+(ANG45/8), momz);
|
|
angle = actor->angle-(ANG45/8);
|
|
for(i = 0; i < 5; i++)
|
|
{
|
|
damage = 1+(pr_fgw2()&7);
|
|
P_LineAttack (actor, angle, PLAYERMISSILERANGE, pitch, damage, NAME_None, RUNTIME_CLASS(AGoldWandPuff2));
|
|
angle += ((ANG45/8)*2)/4;
|
|
}
|
|
S_Sound (actor, CHAN_WEAPON, "weapons/wandhit", 1, ATTN_NORM);
|
|
}
|
|
|
|
// --- Crossbow -------------------------------------------------------------
|
|
|
|
void A_FireCrossbowPL1 (AActor *);
|
|
void A_FireCrossbowPL2 (AActor *);
|
|
void A_BoltSpark (AActor *);
|
|
|
|
// Crossbow -----------------------------------------------------------------
|
|
|
|
class ACrossbow : public AHereticWeapon
|
|
{
|
|
DECLARE_ACTOR (ACrossbow, AHereticWeapon)
|
|
};
|
|
|
|
class ACrossbowPowered : public ACrossbow
|
|
{
|
|
DECLARE_STATELESS_ACTOR (ACrossbowPowered, ACrossbow)
|
|
};
|
|
|
|
FState ACrossbow::States[] =
|
|
{
|
|
#define S_WBOW 0
|
|
S_NORMAL (WBOW, 'A', -1, NULL , NULL),
|
|
|
|
#define S_CRBOW (S_WBOW+1)
|
|
S_NORMAL (CRBW, 'A', 1, A_WeaponReady , &States[S_CRBOW+1]),
|
|
S_NORMAL (CRBW, 'A', 1, A_WeaponReady , &States[S_CRBOW+2]),
|
|
S_NORMAL (CRBW, 'A', 1, A_WeaponReady , &States[S_CRBOW+3]),
|
|
S_NORMAL (CRBW, 'A', 1, A_WeaponReady , &States[S_CRBOW+4]),
|
|
S_NORMAL (CRBW, 'A', 1, A_WeaponReady , &States[S_CRBOW+5]),
|
|
S_NORMAL (CRBW, 'A', 1, A_WeaponReady , &States[S_CRBOW+6]),
|
|
S_NORMAL (CRBW, 'B', 1, A_WeaponReady , &States[S_CRBOW+7]),
|
|
S_NORMAL (CRBW, 'B', 1, A_WeaponReady , &States[S_CRBOW+8]),
|
|
S_NORMAL (CRBW, 'B', 1, A_WeaponReady , &States[S_CRBOW+9]),
|
|
S_NORMAL (CRBW, 'B', 1, A_WeaponReady , &States[S_CRBOW+10]),
|
|
S_NORMAL (CRBW, 'B', 1, A_WeaponReady , &States[S_CRBOW+11]),
|
|
S_NORMAL (CRBW, 'B', 1, A_WeaponReady , &States[S_CRBOW+12]),
|
|
S_NORMAL (CRBW, 'C', 1, A_WeaponReady , &States[S_CRBOW+13]),
|
|
S_NORMAL (CRBW, 'C', 1, A_WeaponReady , &States[S_CRBOW+14]),
|
|
S_NORMAL (CRBW, 'C', 1, A_WeaponReady , &States[S_CRBOW+15]),
|
|
S_NORMAL (CRBW, 'C', 1, A_WeaponReady , &States[S_CRBOW+16]),
|
|
S_NORMAL (CRBW, 'C', 1, A_WeaponReady , &States[S_CRBOW+17]),
|
|
S_NORMAL (CRBW, 'C', 1, A_WeaponReady , &States[S_CRBOW+0]),
|
|
|
|
#define S_CRBOWDOWN (S_CRBOW+18)
|
|
S_NORMAL (CRBW, 'A', 1, A_Lower , &States[S_CRBOWDOWN]),
|
|
|
|
#define S_CRBOWUP (S_CRBOWDOWN+1)
|
|
S_NORMAL (CRBW, 'A', 1, A_Raise , &States[S_CRBOWUP]),
|
|
|
|
#define S_CRBOWATK1 (S_CRBOWUP+1)
|
|
S_NORMAL (CRBW, 'D', 6, A_FireCrossbowPL1 , &States[S_CRBOWATK1+1]),
|
|
S_NORMAL (CRBW, 'E', 3, NULL , &States[S_CRBOWATK1+2]),
|
|
S_NORMAL (CRBW, 'F', 3, NULL , &States[S_CRBOWATK1+3]),
|
|
S_NORMAL (CRBW, 'G', 3, NULL , &States[S_CRBOWATK1+4]),
|
|
S_NORMAL (CRBW, 'H', 3, NULL , &States[S_CRBOWATK1+5]),
|
|
S_NORMAL (CRBW, 'A', 4, NULL , &States[S_CRBOWATK1+6]),
|
|
S_NORMAL (CRBW, 'B', 4, NULL , &States[S_CRBOWATK1+7]),
|
|
S_NORMAL (CRBW, 'C', 5, A_ReFire , &States[S_CRBOW+0]),
|
|
|
|
#define S_CRBOWATK2 (S_CRBOWATK1+8)
|
|
S_NORMAL (CRBW, 'D', 5, A_FireCrossbowPL2 , &States[S_CRBOWATK2+1]),
|
|
S_NORMAL (CRBW, 'E', 3, NULL , &States[S_CRBOWATK2+2]),
|
|
S_NORMAL (CRBW, 'F', 2, NULL , &States[S_CRBOWATK2+3]),
|
|
S_NORMAL (CRBW, 'G', 3, NULL , &States[S_CRBOWATK2+4]),
|
|
S_NORMAL (CRBW, 'H', 2, NULL , &States[S_CRBOWATK2+5]),
|
|
S_NORMAL (CRBW, 'A', 3, NULL , &States[S_CRBOWATK2+6]),
|
|
S_NORMAL (CRBW, 'B', 3, NULL , &States[S_CRBOWATK2+7]),
|
|
S_NORMAL (CRBW, 'C', 4, A_ReFire , &States[S_CRBOW+0])
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (ACrossbow, Heretic, 2001, 27)
|
|
PROP_Flags (MF_SPECIAL)
|
|
PROP_SpawnState (S_WBOW)
|
|
|
|
PROP_Weapon_SelectionOrder (800)
|
|
PROP_Weapon_AmmoUse1 (USE_CBOW_AMMO_1)
|
|
PROP_Weapon_AmmoGive1 (10)
|
|
PROP_Weapon_UpState (S_CRBOWUP)
|
|
PROP_Weapon_DownState (S_CRBOWDOWN)
|
|
PROP_Weapon_ReadyState (S_CRBOW)
|
|
PROP_Weapon_AtkState (S_CRBOWATK1)
|
|
PROP_Weapon_YAdjust (15)
|
|
PROP_Weapon_MoveCombatDist (24000000)
|
|
PROP_Weapon_AmmoType1 ("CrossbowAmmo")
|
|
PROP_Weapon_SisterType ("CrossbowPowered")
|
|
PROP_Weapon_ProjectileType ("CrossbowFX1")
|
|
PROP_Inventory_PickupMessage("$TXT_WPNCROSSBOW")
|
|
END_DEFAULTS
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (ACrossbowPowered, Heretic, -1, 0)
|
|
PROP_Weapon_Flags (WIF_POWERED_UP)
|
|
PROP_Weapon_AmmoUse1 (USE_CBOW_AMMO_2)
|
|
PROP_Weapon_AmmoGive1 (0)
|
|
PROP_Weapon_AtkState (S_CRBOWATK2)
|
|
PROP_Weapon_SisterType ("Crossbow")
|
|
PROP_Weapon_ProjectileType ("CrossbowFX2")
|
|
END_DEFAULTS
|
|
|
|
// Crossbow FX1 -------------------------------------------------------------
|
|
|
|
class ACrossbowFX1 : public AActor
|
|
{
|
|
DECLARE_ACTOR (ACrossbowFX1, AActor)
|
|
};
|
|
|
|
FState ACrossbowFX1::States[] =
|
|
{
|
|
#define S_CRBOWFX1 0
|
|
S_BRIGHT (FX03, 'B', 1, NULL , &States[S_CRBOWFX1]),
|
|
|
|
#define S_CRBOWFXI1 (S_CRBOWFX1+1)
|
|
S_BRIGHT (FX03, 'H', 8, NULL , &States[S_CRBOWFXI1+1]),
|
|
S_BRIGHT (FX03, 'I', 8, NULL , &States[S_CRBOWFXI1+2]),
|
|
S_BRIGHT (FX03, 'J', 8, NULL , NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (ACrossbowFX1, Heretic, -1, 147)
|
|
PROP_RadiusFixed (11)
|
|
PROP_HeightFixed (8)
|
|
PROP_SpeedFixed (30)
|
|
PROP_Damage (10)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY)
|
|
PROP_Flags2 (MF2_NOTELEPORT|MF2_PCROSS|MF2_IMPACT)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
|
|
PROP_SpawnState (S_CRBOWFX1)
|
|
PROP_DeathState (S_CRBOWFXI1)
|
|
|
|
PROP_SeeSound ("weapons/bowshoot")
|
|
PROP_DeathSound ("weapons/bowhit")
|
|
END_DEFAULTS
|
|
|
|
// Crossbow FX2 -------------------------------------------------------------
|
|
|
|
class ACrossbowFX2 : public ACrossbowFX1
|
|
{
|
|
DECLARE_ACTOR (ACrossbowFX2, ACrossbowFX1)
|
|
};
|
|
|
|
FState ACrossbowFX2::States[] =
|
|
{
|
|
#define S_CRBOWFX2 0
|
|
S_BRIGHT (FX03, 'B', 1, A_BoltSpark , &States[S_CRBOWFX2])
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (ACrossbowFX2, Heretic, -1, 148)
|
|
PROP_SpeedFixed (32)
|
|
PROP_Damage (6)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
PROP_SpawnState (S_CRBOWFX2)
|
|
END_DEFAULTS
|
|
|
|
// Crossbow FX3 -------------------------------------------------------------
|
|
|
|
class ACrossbowFX3 : public ACrossbowFX1
|
|
{
|
|
DECLARE_ACTOR (ACrossbowFX3, ACrossbowFX1)
|
|
};
|
|
|
|
FState ACrossbowFX3::States[] =
|
|
{
|
|
#define S_CRBOWFX3 0
|
|
S_BRIGHT (FX03, 'A', 1, NULL , &States[S_CRBOWFX3]),
|
|
|
|
#define S_CRBOWFXI3 (S_CRBOWFX3+1)
|
|
S_BRIGHT (FX03, 'C', 8, NULL , &States[S_CRBOWFXI3+1]),
|
|
S_BRIGHT (FX03, 'D', 8, NULL , &States[S_CRBOWFXI3+2]),
|
|
S_BRIGHT (FX03, 'E', 8, NULL , NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (ACrossbowFX3, Heretic, -1, 149)
|
|
PROP_SpeedFixed (20)
|
|
PROP_Damage (2)
|
|
PROP_FlagsClear (MF_NOBLOCKMAP)
|
|
PROP_Flags2 (MF2_WINDTHRUST|MF2_THRUGHOST|MF2_NOTELEPORT|MF2_PCROSS|MF2_IMPACT)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
|
|
PROP_SpawnState (S_CRBOWFX3)
|
|
PROP_DeathState (S_CRBOWFXI3)
|
|
|
|
PROP_SeeSound ("")
|
|
END_DEFAULTS
|
|
|
|
// Crossbow FX4 -------------------------------------------------------------
|
|
|
|
class ACrossbowFX4 : public AActor
|
|
{
|
|
DECLARE_ACTOR (ACrossbowFX4, AActor)
|
|
};
|
|
|
|
FState ACrossbowFX4::States[] =
|
|
{
|
|
#define S_CRBOWFX4 0
|
|
S_BRIGHT (FX03, 'F', 8, NULL , &States[S_CRBOWFX4+1]),
|
|
S_BRIGHT (FX03, 'G', 8, NULL , NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (ACrossbowFX4, Heretic, -1, 0)
|
|
PROP_Flags (MF_NOBLOCKMAP)
|
|
PROP_Gravity (FRACUNIT/8)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
PROP_SpawnState (S_CRBOWFX4)
|
|
END_DEFAULTS
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_FireCrossbowPL1
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_FireCrossbowPL1 (AActor *actor)
|
|
{
|
|
player_t *player;
|
|
|
|
if (NULL == (player = actor->player))
|
|
{
|
|
return;
|
|
}
|
|
|
|
AWeapon *weapon = player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
P_SpawnPlayerMissile (actor, RUNTIME_CLASS(ACrossbowFX1));
|
|
P_SpawnPlayerMissile (actor, RUNTIME_CLASS(ACrossbowFX3), actor->angle-(ANG45/10));
|
|
P_SpawnPlayerMissile (actor, RUNTIME_CLASS(ACrossbowFX3), actor->angle+(ANG45/10));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_FireCrossbowPL2
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_FireCrossbowPL2(AActor *actor)
|
|
{
|
|
player_t *player;
|
|
|
|
if (NULL == (player = actor->player))
|
|
{
|
|
return;
|
|
}
|
|
|
|
AWeapon *weapon = actor->player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
P_SpawnPlayerMissile (actor, RUNTIME_CLASS(ACrossbowFX2));
|
|
P_SpawnPlayerMissile (actor, RUNTIME_CLASS(ACrossbowFX2), actor->angle-(ANG45/10));
|
|
P_SpawnPlayerMissile (actor, RUNTIME_CLASS(ACrossbowFX2), actor->angle+(ANG45/10));
|
|
P_SpawnPlayerMissile (actor, RUNTIME_CLASS(ACrossbowFX3), actor->angle-(ANG45/5));
|
|
P_SpawnPlayerMissile (actor, RUNTIME_CLASS(ACrossbowFX3), actor->angle+(ANG45/5));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_BoltSpark
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_BoltSpark (AActor *bolt)
|
|
{
|
|
AActor *spark;
|
|
|
|
if (pr_boltspark() > 50)
|
|
{
|
|
spark = Spawn<ACrossbowFX4> (bolt->x, bolt->y, bolt->z, ALLOW_REPLACE);
|
|
spark->x += pr_boltspark.Random2() << 10;
|
|
spark->y += pr_boltspark.Random2() << 10;
|
|
}
|
|
}
|
|
|
|
// --- Mace -----------------------------------------------------------------
|
|
|
|
#define MAGIC_JUNK 1234
|
|
|
|
void A_FireMacePL1B (AActor *);
|
|
void A_FireMacePL1 (AActor *);
|
|
void A_MacePL1Check (AActor *);
|
|
void A_MaceBallImpact (AActor *);
|
|
void A_MaceBallImpact2 (AActor *);
|
|
void A_FireMacePL2 (AActor *);
|
|
void A_DeathBallImpact (AActor *);
|
|
|
|
// The mace itself ----------------------------------------------------------
|
|
|
|
class AMace : public AHereticWeapon
|
|
{
|
|
DECLARE_ACTOR (AMace, AHereticWeapon)
|
|
HAS_OBJECT_POINTERS
|
|
public:
|
|
void Serialize (FArchive &arc);
|
|
protected:
|
|
bool DoRespawn ();
|
|
int NumMaceSpots;
|
|
TObjPtr<AActor> FirstSpot;
|
|
private:
|
|
|
|
friend void A_SpawnMace (AActor *self);
|
|
};
|
|
|
|
class AMacePowered : public AMace
|
|
{
|
|
DECLARE_STATELESS_ACTOR (AMacePowered, AMace)
|
|
};
|
|
|
|
IMPLEMENT_POINTY_CLASS (AMace)
|
|
DECLARE_POINTER (FirstSpot)
|
|
END_POINTERS
|
|
|
|
void AMace::Serialize (FArchive &arc)
|
|
{
|
|
Super::Serialize (arc);
|
|
arc << NumMaceSpots << FirstSpot;
|
|
}
|
|
|
|
FState AMace::States[] =
|
|
{
|
|
#define S_WMCE 0
|
|
S_NORMAL (WMCE, 'A', -1, NULL , NULL),
|
|
|
|
#define S_MACEREADY (S_WMCE+1)
|
|
S_NORMAL (MACE, 'A', 1, A_WeaponReady , &States[S_MACEREADY]),
|
|
|
|
#define S_MACEDOWN (S_MACEREADY+1)
|
|
S_NORMAL (MACE, 'A', 1, A_Lower , &States[S_MACEDOWN]),
|
|
|
|
#define S_MACEUP (S_MACEDOWN+1)
|
|
S_NORMAL (MACE, 'A', 1, A_Raise , &States[S_MACEUP]),
|
|
|
|
#define S_MACEATK1 (S_MACEUP+1)
|
|
S_NORMAL (MACE, 'B', 4, NULL , &States[S_MACEATK1+1]),
|
|
S_NORMAL (MACE, 'C', 3, A_FireMacePL1 , &States[S_MACEATK1+2]),
|
|
S_NORMAL (MACE, 'D', 3, A_FireMacePL1 , &States[S_MACEATK1+3]),
|
|
S_NORMAL (MACE, 'E', 3, A_FireMacePL1 , &States[S_MACEATK1+4]),
|
|
S_NORMAL (MACE, 'F', 3, A_FireMacePL1 , &States[S_MACEATK1+5]),
|
|
S_NORMAL (MACE, 'C', 4, A_ReFire , &States[S_MACEATK1+6]),
|
|
S_NORMAL (MACE, 'D', 4, NULL , &States[S_MACEATK1+7]),
|
|
S_NORMAL (MACE, 'E', 4, NULL , &States[S_MACEATK1+8]),
|
|
S_NORMAL (MACE, 'F', 4, NULL , &States[S_MACEATK1+9]),
|
|
S_NORMAL (MACE, 'B', 4, NULL , &States[S_MACEREADY]),
|
|
|
|
#define S_MACEATK2 (S_MACEATK1+10)
|
|
S_NORMAL (MACE, 'B', 4, NULL , &States[S_MACEATK2+1]),
|
|
S_NORMAL (MACE, 'D', 4, A_FireMacePL2 , &States[S_MACEATK2+2]),
|
|
S_NORMAL (MACE, 'B', 4, NULL , &States[S_MACEATK2+3]),
|
|
S_NORMAL (MACE, 'A', 8, A_ReFire , &States[S_MACEREADY])
|
|
};
|
|
|
|
BEGIN_DEFAULTS (AMace, Heretic, -1, 0)
|
|
PROP_Flags (MF_SPECIAL)
|
|
PROP_SpawnState (0)
|
|
|
|
PROP_Weapon_SelectionOrder (1400)
|
|
PROP_Weapon_Flags (WIF_BOT_REACTION_SKILL_THING|WIF_BOT_EXPLOSIVE)
|
|
PROP_Weapon_AmmoUse1 (USE_MACE_AMMO_1)
|
|
PROP_Weapon_AmmoGive1 (50)
|
|
PROP_Weapon_UpState (S_MACEUP)
|
|
PROP_Weapon_DownState (S_MACEDOWN)
|
|
PROP_Weapon_ReadyState (S_MACEREADY)
|
|
PROP_Weapon_AtkState (S_MACEATK1)
|
|
PROP_Weapon_HoldAtkState (S_MACEATK1+1)
|
|
PROP_Weapon_YAdjust (15)
|
|
PROP_Weapon_MoveCombatDist (27000000)
|
|
PROP_Weapon_AmmoType1 ("MaceAmmo")
|
|
PROP_Weapon_SisterType ("MacePowered")
|
|
PROP_Weapon_ProjectileType ("MaceFX2")
|
|
PROP_Inventory_PickupMessage("$TXT_WPNMACE")
|
|
END_DEFAULTS
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (AMacePowered, Heretic, -1, 0)
|
|
PROP_Weapon_Flags (WIF_POWERED_UP|WIF_BOT_REACTION_SKILL_THING|WIF_BOT_EXPLOSIVE)
|
|
PROP_Weapon_AmmoUse1 (USE_MACE_AMMO_2)
|
|
PROP_Weapon_AmmoGive1 (0)
|
|
PROP_Weapon_AtkState (S_MACEATK2)
|
|
PROP_Weapon_HoldAtkState (S_MACEATK2)
|
|
PROP_Weapon_SisterType ("Mace")
|
|
PROP_Weapon_ProjectileType ("MaceFX4")
|
|
END_DEFAULTS
|
|
|
|
// Mace FX1 -----------------------------------------------------------------
|
|
|
|
class AMaceFX1 : public AActor
|
|
{
|
|
DECLARE_ACTOR (AMaceFX1, AActor)
|
|
};
|
|
|
|
FState AMaceFX1::States[] =
|
|
{
|
|
#define S_MACEFX1 0
|
|
S_NORMAL (FX02, 'A', 4, A_MacePL1Check , &States[S_MACEFX1+1]),
|
|
S_NORMAL (FX02, 'B', 4, A_MacePL1Check , &States[S_MACEFX1+0]),
|
|
|
|
#define S_MACEFXI1 (S_MACEFX1+2)
|
|
S_BRIGHT (FX02, 'F', 4, A_MaceBallImpact , &States[S_MACEFXI1+1]),
|
|
S_BRIGHT (FX02, 'G', 4, NULL , &States[S_MACEFXI1+2]),
|
|
S_BRIGHT (FX02, 'H', 4, NULL , &States[S_MACEFXI1+3]),
|
|
S_BRIGHT (FX02, 'I', 4, NULL , &States[S_MACEFXI1+4]),
|
|
S_BRIGHT (FX02, 'J', 4, NULL , NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AMaceFX1, Heretic, -1, 154)
|
|
PROP_RadiusFixed (8)
|
|
PROP_HeightFixed (6)
|
|
PROP_SpeedFixed (20)
|
|
PROP_Damage (2)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY)
|
|
PROP_Flags2 (MF2_HERETICBOUNCE|MF2_THRUGHOST|MF2_NOTELEPORT|MF2_PCROSS|MF2_IMPACT)
|
|
PROP_Flags3 (MF3_WARNBOT)
|
|
|
|
PROP_SpawnState (S_MACEFX1)
|
|
PROP_DeathState (S_MACEFXI1)
|
|
|
|
PROP_SeeSound ("weapons/maceshoot")
|
|
END_DEFAULTS
|
|
|
|
// Mace FX2 -----------------------------------------------------------------
|
|
|
|
class AMaceFX2 : public AActor
|
|
{
|
|
DECLARE_ACTOR (AMaceFX2, AActor)
|
|
};
|
|
|
|
FState AMaceFX2::States[] =
|
|
{
|
|
#define S_MACEFX2 0
|
|
S_NORMAL (FX02, 'C', 4, NULL , &States[S_MACEFX2+1]),
|
|
S_NORMAL (FX02, 'D', 4, NULL , &States[S_MACEFX2+0]),
|
|
|
|
#define S_MACEFXI2 (S_MACEFX2+2)
|
|
S_BRIGHT (FX02, 'F', 4, A_MaceBallImpact2 , &AMaceFX1::States[S_MACEFXI1+1])
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AMaceFX2, Heretic, -1, 156)
|
|
PROP_RadiusFixed (8)
|
|
PROP_HeightFixed (6)
|
|
PROP_SpeedFixed (10)
|
|
PROP_Damage (6)
|
|
PROP_Gravity (FRACUNIT/8)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF)
|
|
PROP_Flags2 (MF2_HERETICBOUNCE|MF2_THRUGHOST|MF2_NOTELEPORT|MF2_PCROSS|MF2_IMPACT)
|
|
|
|
PROP_SpawnState (S_MACEFX2)
|
|
PROP_DeathState (S_MACEFXI2)
|
|
END_DEFAULTS
|
|
|
|
// Mace FX3 -----------------------------------------------------------------
|
|
|
|
class AMaceFX3 : public AMaceFX1
|
|
{
|
|
DECLARE_ACTOR (AMaceFX3, AMaceFX1)
|
|
};
|
|
|
|
FState AMaceFX3::States[] =
|
|
{
|
|
#define S_MACEFX3 0
|
|
S_NORMAL (FX02, 'A', 4, NULL , &States[S_MACEFX3+1]),
|
|
S_NORMAL (FX02, 'B', 4, NULL , &States[S_MACEFX3+0])
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AMaceFX3, Heretic, -1, 155)
|
|
PROP_SpeedFixed (7)
|
|
PROP_Damage (4)
|
|
PROP_Gravity (FRACUNIT/8)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF)
|
|
PROP_Flags2 (MF2_HERETICBOUNCE|MF2_THRUGHOST|MF2_NOTELEPORT|MF2_PCROSS|MF2_IMPACT)
|
|
|
|
PROP_SpawnState (S_MACEFX3)
|
|
END_DEFAULTS
|
|
|
|
// Mace FX4 -----------------------------------------------------------------
|
|
|
|
class AMaceFX4 : public AActor
|
|
{
|
|
DECLARE_ACTOR (AMaceFX4, AActor)
|
|
public:
|
|
int DoSpecialDamage (AActor *target, int damage);
|
|
};
|
|
|
|
FState AMaceFX4::States[] =
|
|
{
|
|
#define S_MACEFX4 0
|
|
S_NORMAL (FX02, 'E', 99, NULL , &States[S_MACEFX4+0]),
|
|
|
|
#define S_MACEFXI4 (S_MACEFX4+1)
|
|
S_BRIGHT (FX02, 'C', 4, A_DeathBallImpact , &AMaceFX1::States[S_MACEFXI1+1])
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AMaceFX4, Heretic, -1, 153)
|
|
PROP_RadiusFixed (8)
|
|
PROP_HeightFixed (6)
|
|
PROP_SpeedFixed (7)
|
|
PROP_Damage (18)
|
|
PROP_Gravity (FRACUNIT/8)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF)
|
|
PROP_Flags2 (MF2_HERETICBOUNCE|MF2_THRUGHOST|MF2_TELESTOMP|MF2_PCROSS|MF2_IMPACT)
|
|
|
|
PROP_SpawnState (S_MACEFX4)
|
|
PROP_DeathState (S_MACEFXI4)
|
|
END_DEFAULTS
|
|
|
|
int AMaceFX4::DoSpecialDamage (AActor *target, int damage)
|
|
{
|
|
if ((target->flags2 & MF2_BOSS) || (target->flags3 & MF3_DONTSQUASH) || target->IsTeammate (this->target))
|
|
{ // Don't allow cheap boss kills and don't instagib teammates
|
|
return damage;
|
|
}
|
|
else if (target->player)
|
|
{ // Player specific checks
|
|
if (target->player->mo->flags2 & MF2_INVULNERABLE)
|
|
{ // Can't hurt invulnerable players
|
|
return -1;
|
|
}
|
|
if (P_AutoUseChaosDevice (target->player))
|
|
{ // Player was saved using chaos device
|
|
return -1;
|
|
}
|
|
}
|
|
return 1000000; // Something's gonna die
|
|
}
|
|
|
|
// Mace spawn spot ----------------------------------------------------------
|
|
|
|
void A_SpawnMace (AActor *);
|
|
|
|
class AMaceSpawner : public AActor
|
|
{
|
|
DECLARE_ACTOR (AMaceSpawner, AActor)
|
|
|
|
// Uses target to point to the next mace spawner in the list
|
|
};
|
|
|
|
FState AMaceSpawner::States[] =
|
|
{
|
|
S_NORMAL (TNT1, 'A', 1, NULL, &States[1]),
|
|
S_NORMAL (TNT1, 'A', -1, A_SpawnMace, NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AMaceSpawner, Heretic, 2002, 0)
|
|
PROP_Flags (MF_NOSECTOR|MF_NOBLOCKMAP)
|
|
PROP_SpawnState (0)
|
|
END_DEFAULTS
|
|
|
|
// Every mace spawn spot will execute this action. The first one
|
|
// will build a list of all mace spots in the level and spawn a
|
|
// mace. The rest of the spots will do nothing.
|
|
|
|
void A_SpawnMace (AActor *self)
|
|
{
|
|
if (self->target != NULL)
|
|
{ // Another spot already did it
|
|
return;
|
|
}
|
|
|
|
TThinkerIterator<AMaceSpawner> iterator;
|
|
AActor *spot;
|
|
AMaceSpawner *firstSpot;
|
|
AMace *mace;
|
|
int numspots = 0;
|
|
|
|
spot = firstSpot = iterator.Next ();
|
|
while (spot != NULL)
|
|
{
|
|
numspots++;
|
|
spot->target = iterator.Next ();
|
|
if (spot->target == NULL)
|
|
{
|
|
spot->target = firstSpot;
|
|
spot = NULL;
|
|
}
|
|
else
|
|
{
|
|
spot = spot->target;
|
|
}
|
|
}
|
|
if (numspots == 0)
|
|
{
|
|
return;
|
|
}
|
|
if (!deathmatch && pr_spawnmace() < 64)
|
|
{ // Sometimes doesn't show up if not in deathmatch
|
|
return;
|
|
}
|
|
mace = Spawn<AMace> (self->x, self->y, self->z, ALLOW_REPLACE);
|
|
if (mace)
|
|
{
|
|
mace->FirstSpot = firstSpot;
|
|
mace->NumMaceSpots = numspots;
|
|
mace->DoRespawn ();
|
|
// We want this mace to respawn.
|
|
mace->flags &= ~MF_DROPPED;
|
|
}
|
|
}
|
|
|
|
// AMace::DoRespawn
|
|
// Moves the mace to a different spot when it respawns
|
|
|
|
bool AMace::DoRespawn ()
|
|
{
|
|
if (NumMaceSpots > 0)
|
|
{
|
|
int spotnum = pr_macerespawn () % NumMaceSpots;
|
|
AActor *spot = FirstSpot;
|
|
|
|
while (spotnum > 0)
|
|
{
|
|
spot = spot->target;
|
|
spotnum--;
|
|
}
|
|
|
|
SetOrigin (spot->x, spot->y, spot->z);
|
|
z = floorz;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_FireMacePL1B
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_FireMacePL1B (AActor *actor)
|
|
{
|
|
AActor *ball;
|
|
angle_t angle;
|
|
player_t *player;
|
|
|
|
if (NULL == (player = actor->player))
|
|
{
|
|
return;
|
|
}
|
|
|
|
AWeapon *weapon = player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
ball = Spawn<AMaceFX2> (actor->x, actor->y, actor->z + 28*FRACUNIT
|
|
- actor->floorclip, ALLOW_REPLACE);
|
|
ball->momz = 2*FRACUNIT+/*((player->lookdir)<<(FRACBITS-5))*/
|
|
finetangent[FINEANGLES/4-(actor->pitch>>ANGLETOFINESHIFT)];
|
|
angle = actor->angle;
|
|
ball->target = actor;
|
|
ball->angle = angle;
|
|
ball->z += 2*finetangent[FINEANGLES/4-(actor->pitch>>ANGLETOFINESHIFT)];
|
|
angle >>= ANGLETOFINESHIFT;
|
|
ball->momx = (actor->momx>>1)+FixedMul(ball->Speed, finecosine[angle]);
|
|
ball->momy = (actor->momy>>1)+FixedMul(ball->Speed, finesine[angle]);
|
|
S_Sound (ball, CHAN_BODY, "weapons/maceshoot", 1, ATTN_NORM);
|
|
P_CheckMissileSpawn (ball);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_FireMacePL1
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_FireMacePL1 (AActor *actor)
|
|
{
|
|
AActor *ball;
|
|
player_t *player;
|
|
|
|
if (NULL == (player = actor->player))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (pr_maceatk() < 28)
|
|
{
|
|
A_FireMacePL1B (actor);
|
|
return;
|
|
}
|
|
AWeapon *weapon = player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
player->psprites[ps_weapon].sx = ((pr_maceatk()&3)-2)*FRACUNIT;
|
|
player->psprites[ps_weapon].sy = WEAPONTOP+(pr_maceatk()&3)*FRACUNIT;
|
|
ball = P_SpawnPlayerMissile (actor, RUNTIME_CLASS(AMaceFX1),
|
|
actor->angle+(((pr_maceatk()&7)-4)<<24));
|
|
if (ball)
|
|
{
|
|
ball->special1 = 16; // tics till dropoff
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_MacePL1Check
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_MacePL1Check (AActor *ball)
|
|
{
|
|
if (ball->special1 == 0)
|
|
{
|
|
return;
|
|
}
|
|
ball->special1 -= 4;
|
|
if (ball->special1 > 0)
|
|
{
|
|
return;
|
|
}
|
|
ball->special1 = 0;
|
|
ball->flags &= ~MF_NOGRAVITY;
|
|
ball->gravity = FRACUNIT/8;
|
|
// [RH] Avoid some precision loss by scaling the momentum directly
|
|
#if 0
|
|
angle_t angle = ball->angle>>ANGLETOFINESHIFT;
|
|
ball->momx = FixedMul(7*FRACUNIT, finecosine[angle]);
|
|
ball->momy = FixedMul(7*FRACUNIT, finesine[angle]);
|
|
#else
|
|
float momscale = sqrtf ((float)ball->momx * (float)ball->momx +
|
|
(float)ball->momy * (float)ball->momy);
|
|
momscale = 458752.f / momscale;
|
|
ball->momx = (int)(ball->momx * momscale);
|
|
ball->momy = (int)(ball->momy * momscale);
|
|
#endif
|
|
ball->momz -= ball->momz>>1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_MaceBallImpact
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_MaceBallImpact (AActor *ball)
|
|
{
|
|
if ((ball->health != MAGIC_JUNK) && (ball->flags & MF_INBOUNCE))
|
|
{ // Bounce
|
|
ball->health = MAGIC_JUNK;
|
|
ball->momz = (ball->momz * 192) >> 8;
|
|
ball->flags2 &= ~MF2_BOUNCETYPE;
|
|
ball->SetState (ball->SpawnState);
|
|
S_Sound (ball, CHAN_BODY, "weapons/macebounce", 1, ATTN_NORM);
|
|
}
|
|
else
|
|
{ // Explode
|
|
ball->momx = ball->momy = ball->momz = 0;
|
|
ball->flags |= MF_NOGRAVITY;
|
|
ball->gravity = FRACUNIT;
|
|
S_Sound (ball, CHAN_BODY, "weapons/macehit", 1, ATTN_NORM);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_MaceBallImpact2
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_MaceBallImpact2 (AActor *ball)
|
|
{
|
|
AActor *tiny;
|
|
angle_t angle;
|
|
|
|
if (ball->flags & MF_INBOUNCE)
|
|
{
|
|
fixed_t floordist = ball->z - ball->floorz;
|
|
fixed_t ceildist = ball->ceilingz - ball->z;
|
|
fixed_t vel;
|
|
|
|
if (floordist <= ceildist)
|
|
{
|
|
vel = MulScale32 (ball->momz, ball->Sector->floorplane.c);
|
|
}
|
|
else
|
|
{
|
|
vel = MulScale32 (ball->momz, ball->Sector->ceilingplane.c);
|
|
}
|
|
if (vel < 2)
|
|
{
|
|
goto boom;
|
|
}
|
|
|
|
// Bounce
|
|
ball->momz = (ball->momz * 192) >> 8;
|
|
ball->SetState (ball->SpawnState);
|
|
|
|
tiny = Spawn<AMaceFX3> (ball->x, ball->y, ball->z, ALLOW_REPLACE);
|
|
angle = ball->angle+ANG90;
|
|
tiny->target = ball->target;
|
|
tiny->angle = angle;
|
|
angle >>= ANGLETOFINESHIFT;
|
|
tiny->momx = (ball->momx>>1)+FixedMul(ball->momz-FRACUNIT,
|
|
finecosine[angle]);
|
|
tiny->momy = (ball->momy>>1)+FixedMul(ball->momz-FRACUNIT,
|
|
finesine[angle]);
|
|
tiny->momz = ball->momz;
|
|
P_CheckMissileSpawn (tiny);
|
|
|
|
tiny = Spawn<AMaceFX3> (ball->x, ball->y, ball->z, ALLOW_REPLACE);
|
|
angle = ball->angle-ANG90;
|
|
tiny->target = ball->target;
|
|
tiny->angle = angle;
|
|
angle >>= ANGLETOFINESHIFT;
|
|
tiny->momx = (ball->momx>>1)+FixedMul(ball->momz-FRACUNIT,
|
|
finecosine[angle]);
|
|
tiny->momy = (ball->momy>>1)+FixedMul(ball->momz-FRACUNIT,
|
|
finesine[angle]);
|
|
tiny->momz = ball->momz;
|
|
P_CheckMissileSpawn (tiny);
|
|
}
|
|
else
|
|
{ // Explode
|
|
boom:
|
|
ball->momx = ball->momy = ball->momz = 0;
|
|
ball->flags |= MF_NOGRAVITY;
|
|
ball->flags2 &= ~MF2_BOUNCETYPE;
|
|
ball->gravity = FRACUNIT;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_FireMacePL2
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_FireMacePL2 (AActor *actor)
|
|
{
|
|
AActor *mo;
|
|
player_t *player;
|
|
AActor *linetarget;
|
|
|
|
if (NULL == (player = actor->player))
|
|
{
|
|
return;
|
|
}
|
|
|
|
AWeapon *weapon = player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
mo = P_SpawnPlayerMissile (actor, 0,0,0, RUNTIME_CLASS(AMaceFX4), actor->angle, &linetarget);
|
|
if (mo)
|
|
{
|
|
mo->momx += actor->momx;
|
|
mo->momy += actor->momy;
|
|
mo->momz = 2*FRACUNIT+
|
|
clamp<fixed_t>(finetangent[FINEANGLES/4-(actor->pitch>>ANGLETOFINESHIFT)], -5*FRACUNIT, 5*FRACUNIT);
|
|
if (linetarget)
|
|
{
|
|
mo->tracer = linetarget;
|
|
}
|
|
}
|
|
S_Sound (actor, CHAN_WEAPON, "weapons/maceshoot", 1, ATTN_NORM);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_DeathBallImpact
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_DeathBallImpact (AActor *ball)
|
|
{
|
|
int i;
|
|
AActor *target;
|
|
angle_t angle = 0;
|
|
bool newAngle;
|
|
AActor *linetarget;
|
|
|
|
if ((ball->z <= ball->floorz) && P_HitFloor (ball))
|
|
{ // Landed in some sort of liquid
|
|
ball->Destroy ();
|
|
return;
|
|
}
|
|
if (ball->flags & MF_INBOUNCE)
|
|
{
|
|
fixed_t floordist = ball->z - ball->floorz;
|
|
fixed_t ceildist = ball->ceilingz - ball->z;
|
|
fixed_t vel;
|
|
|
|
if (floordist <= ceildist)
|
|
{
|
|
vel = MulScale32 (ball->momz, ball->Sector->floorplane.c);
|
|
}
|
|
else
|
|
{
|
|
vel = MulScale32 (ball->momz, ball->Sector->ceilingplane.c);
|
|
}
|
|
if (vel < 2)
|
|
{
|
|
goto boom;
|
|
}
|
|
|
|
// Bounce
|
|
newAngle = false;
|
|
target = ball->tracer;
|
|
if (target)
|
|
{
|
|
if (!(target->flags&MF_SHOOTABLE))
|
|
{ // Target died
|
|
ball->tracer = NULL;
|
|
}
|
|
else
|
|
{ // Seek
|
|
angle = R_PointToAngle2(ball->x, ball->y,
|
|
target->x, target->y);
|
|
newAngle = true;
|
|
}
|
|
}
|
|
else
|
|
{ // Find new target
|
|
angle = 0;
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
P_AimLineAttack (ball, angle, 10*64*FRACUNIT, &linetarget);
|
|
if (linetarget && ball->target != linetarget)
|
|
{
|
|
ball->tracer = linetarget;
|
|
angle = R_PointToAngle2 (ball->x, ball->y,
|
|
linetarget->x, linetarget->y);
|
|
newAngle = true;
|
|
break;
|
|
}
|
|
angle += ANGLE_45/2;
|
|
}
|
|
}
|
|
if (newAngle)
|
|
{
|
|
ball->angle = angle;
|
|
angle >>= ANGLETOFINESHIFT;
|
|
ball->momx = FixedMul (ball->Speed, finecosine[angle]);
|
|
ball->momy = FixedMul (ball->Speed, finesine[angle]);
|
|
}
|
|
ball->SetState (ball->SpawnState);
|
|
S_Sound (ball, CHAN_BODY, "weapons/macestop", 1, ATTN_NORM);
|
|
}
|
|
else
|
|
{ // Explode
|
|
boom:
|
|
ball->momx = ball->momy = ball->momz = 0;
|
|
ball->flags |= MF_NOGRAVITY;
|
|
ball->gravity = FRACUNIT;
|
|
S_Sound (ball, CHAN_BODY, "weapons/maceexplode", 1, ATTN_NORM);
|
|
}
|
|
}
|
|
|
|
// --- Gauntlets ------------------------------------------------------------
|
|
|
|
void A_GauntletAttack (AActor *);
|
|
void A_GauntletSound (AActor *);
|
|
|
|
// Gauntlets ----------------------------------------------------------------
|
|
|
|
class AGauntlets : public AHereticWeapon
|
|
{
|
|
DECLARE_ACTOR (AGauntlets, AHereticWeapon)
|
|
};
|
|
|
|
class AGauntletsPowered : public AGauntlets
|
|
{
|
|
DECLARE_STATELESS_ACTOR (AGauntletsPowered, AGauntlets)
|
|
};
|
|
|
|
FState AGauntlets::States[] =
|
|
{
|
|
#define S_WGNT 0
|
|
S_NORMAL (WGNT, 'A', -1, NULL , NULL),
|
|
|
|
#define S_GAUNTLETREADY (S_WGNT+1)
|
|
S_NORMAL (GAUN, 'A', 1, A_WeaponReady , &States[S_GAUNTLETREADY]),
|
|
|
|
#define S_GAUNTLETDOWN (S_GAUNTLETREADY+1)
|
|
S_NORMAL (GAUN, 'A', 1, A_Lower , &States[S_GAUNTLETDOWN]),
|
|
|
|
#define S_GAUNTLETUP (S_GAUNTLETDOWN+1)
|
|
S_NORMAL (GAUN, 'A', 1, A_Raise , &States[S_GAUNTLETUP]),
|
|
|
|
#define S_GAUNTLETREADY2 (S_GAUNTLETUP+1)
|
|
S_NORMAL (GAUN, 'G', 4, A_WeaponReady , &States[S_GAUNTLETREADY2+1]),
|
|
S_NORMAL (GAUN, 'H', 4, A_WeaponReady , &States[S_GAUNTLETREADY2+2]),
|
|
S_NORMAL (GAUN, 'I', 4, A_WeaponReady , &States[S_GAUNTLETREADY2+0]),
|
|
|
|
#define S_GAUNTLETDOWN2 (S_GAUNTLETREADY2+3)
|
|
S_NORMAL (GAUN, 'G', 1, A_Lower , &States[S_GAUNTLETDOWN2]),
|
|
|
|
#define S_GAUNTLETUP2 (S_GAUNTLETDOWN2+1)
|
|
S_NORMAL (GAUN, 'G', 1, A_Raise , &States[S_GAUNTLETUP2]),
|
|
|
|
#define S_GAUNTLETATK1 (S_GAUNTLETUP2+1)
|
|
S_NORMAL (GAUN, 'B', 4, A_GauntletSound , &States[S_GAUNTLETATK1+1]),
|
|
S_NORMAL (GAUN, 'C', 4, NULL , &States[S_GAUNTLETATK1+2]),
|
|
S_BRIGHT (GAUN, 'D', 4, A_GauntletAttack , &States[S_GAUNTLETATK1+3]),
|
|
S_BRIGHT (GAUN, 'E', 4, A_GauntletAttack , &States[S_GAUNTLETATK1+4]),
|
|
S_BRIGHT (GAUN, 'F', 4, A_GauntletAttack , &States[S_GAUNTLETATK1+5]),
|
|
S_NORMAL (GAUN, 'C', 4, A_ReFire , &States[S_GAUNTLETATK1+6]),
|
|
S_NORMAL (GAUN, 'B', 4, A_Light0 , &States[S_GAUNTLETREADY]),
|
|
|
|
#define S_GAUNTLETATK2 (S_GAUNTLETATK1+7)
|
|
S_NORMAL (GAUN, 'J', 4, A_GauntletSound , &States[S_GAUNTLETATK2+1]),
|
|
S_NORMAL (GAUN, 'K', 4, NULL , &States[S_GAUNTLETATK2+2]),
|
|
S_BRIGHT (GAUN, 'L', 4, A_GauntletAttack , &States[S_GAUNTLETATK2+3]),
|
|
S_BRIGHT (GAUN, 'M', 4, A_GauntletAttack , &States[S_GAUNTLETATK2+4]),
|
|
S_BRIGHT (GAUN, 'N', 4, A_GauntletAttack , &States[S_GAUNTLETATK2+5]),
|
|
S_NORMAL (GAUN, 'K', 4, A_ReFire , &States[S_GAUNTLETATK2+6]),
|
|
S_NORMAL (GAUN, 'J', 4, A_Light0 , &States[S_GAUNTLETREADY2+0])
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AGauntlets, Heretic, 2005, 32)
|
|
PROP_Flags (MF_SPECIAL)
|
|
PROP_Flags5 (MF5_BLOODSPLATTER)
|
|
PROP_SpawnState (S_WGNT)
|
|
|
|
PROP_Weapon_SelectionOrder (2300)
|
|
PROP_Weapon_Flags (WIF_WIMPY_WEAPON|WIF_BOT_MELEE)
|
|
PROP_Weapon_UpState (S_GAUNTLETUP)
|
|
PROP_Weapon_DownState (S_GAUNTLETDOWN)
|
|
PROP_Weapon_ReadyState (S_GAUNTLETREADY)
|
|
PROP_Weapon_AtkState (S_GAUNTLETATK1)
|
|
PROP_Weapon_HoldAtkState (S_GAUNTLETATK1+2)
|
|
PROP_Weapon_Kickback (0)
|
|
PROP_Weapon_YAdjust (15)
|
|
PROP_Weapon_UpSound ("weapons/gauntletsactivate")
|
|
PROP_Weapon_SisterType ("GauntletsPowered")
|
|
PROP_Inventory_PickupMessage("$TXT_WPNGAUNTLETS")
|
|
END_DEFAULTS
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (AGauntletsPowered, Heretic, -1, 0)
|
|
PROP_Weapon_Flags (WIF_WIMPY_WEAPON|WIF_POWERED_UP|WIF_BOT_MELEE)
|
|
PROP_Weapon_UpState (S_GAUNTLETUP2)
|
|
PROP_Weapon_DownState (S_GAUNTLETDOWN2)
|
|
PROP_Weapon_ReadyState (S_GAUNTLETREADY2)
|
|
PROP_Weapon_AtkState (S_GAUNTLETATK2)
|
|
PROP_Weapon_HoldAtkState (S_GAUNTLETATK2+2)
|
|
PROP_Weapon_SisterType ("Gauntlets")
|
|
END_DEFAULTS
|
|
|
|
void A_GauntletSound (AActor *actor)
|
|
{
|
|
// Play the sound for the initial gauntlet attack
|
|
S_Sound (actor, CHAN_WEAPON, "weapons/gauntletsuse", 1, ATTN_NORM);
|
|
}
|
|
|
|
// Gauntlet puff 1 ----------------------------------------------------------
|
|
|
|
class AGauntletPuff1 : public AActor
|
|
{
|
|
DECLARE_ACTOR (AGauntletPuff1, AActor)
|
|
public:
|
|
void BeginPlay ();
|
|
};
|
|
|
|
FState AGauntletPuff1::States[] =
|
|
{
|
|
#define S_GAUNTLETPUFF1 0
|
|
S_BRIGHT (PUF1, 'A', 4, NULL , &States[S_GAUNTLETPUFF1+1]),
|
|
S_BRIGHT (PUF1, 'B', 4, NULL , &States[S_GAUNTLETPUFF1+2]),
|
|
S_BRIGHT (PUF1, 'C', 4, NULL , &States[S_GAUNTLETPUFF1+3]),
|
|
S_BRIGHT (PUF1, 'D', 4, NULL , NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AGauntletPuff1, Heretic, -1, 0)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY)
|
|
PROP_Flags3 (MF3_PUFFONACTORS)
|
|
PROP_RenderStyle (STYLE_Translucent)
|
|
PROP_Alpha (HR_SHADOW)
|
|
PROP_SpawnState (S_GAUNTLETPUFF1)
|
|
END_DEFAULTS
|
|
|
|
void AGauntletPuff1::BeginPlay ()
|
|
{
|
|
Super::BeginPlay ();
|
|
momz = FRACUNIT * 8 / 10;
|
|
}
|
|
|
|
// Gauntlett puff 2 ---------------------------------------------------------
|
|
|
|
class AGauntletPuff2 : public AGauntletPuff1
|
|
{
|
|
DECLARE_ACTOR (AGauntletPuff2, AGauntletPuff1)
|
|
};
|
|
|
|
FState AGauntletPuff2::States[] =
|
|
{
|
|
#define S_GAUNTLETPUFF2 0
|
|
S_BRIGHT (PUF1, 'E', 4, NULL , &States[S_GAUNTLETPUFF2+1]),
|
|
S_BRIGHT (PUF1, 'F', 4, NULL , &States[S_GAUNTLETPUFF2+2]),
|
|
S_BRIGHT (PUF1, 'G', 4, NULL , &States[S_GAUNTLETPUFF2+3]),
|
|
S_BRIGHT (PUF1, 'H', 4, NULL , NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AGauntletPuff2, Heretic, -1, 0)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY)
|
|
PROP_RenderStyle (STYLE_Translucent)
|
|
PROP_Alpha (HR_SHADOW)
|
|
|
|
PROP_SpawnState (S_GAUNTLETPUFF2)
|
|
END_DEFAULTS
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// PROC A_GauntletAttack
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void A_GauntletAttack (AActor *actor)
|
|
{
|
|
angle_t angle;
|
|
int damage;
|
|
int slope;
|
|
int randVal;
|
|
fixed_t dist;
|
|
player_t *player;
|
|
const PClass *pufftype;
|
|
AInventory *power;
|
|
AActor *linetarget;
|
|
|
|
if (NULL == (player = actor->player))
|
|
{
|
|
return;
|
|
}
|
|
|
|
AWeapon *weapon = player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
player->psprites[ps_weapon].sx = ((pr_gatk()&3)-2) * FRACUNIT;
|
|
player->psprites[ps_weapon].sy = WEAPONTOP + (pr_gatk()&3) * FRACUNIT;
|
|
angle = actor->angle;
|
|
power = actor->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2));
|
|
if (power)
|
|
{
|
|
damage = pr_gatk.HitDice (2);
|
|
dist = 4*MELEERANGE;
|
|
angle += pr_gatk.Random2() << 17;
|
|
pufftype = RUNTIME_CLASS(AGauntletPuff2);
|
|
}
|
|
else
|
|
{
|
|
damage = pr_gatk.HitDice (2);
|
|
dist = MELEERANGE+1;
|
|
angle += pr_gatk.Random2() << 18;
|
|
pufftype = RUNTIME_CLASS(AGauntletPuff1);
|
|
}
|
|
slope = P_AimLineAttack (actor, angle, dist, &linetarget);
|
|
P_LineAttack (actor, angle, dist, slope, damage, NAME_Melee, pufftype);
|
|
if (!linetarget)
|
|
{
|
|
if (pr_gatk() > 64)
|
|
{
|
|
player->extralight = !player->extralight;
|
|
}
|
|
S_Sound (actor, CHAN_AUTO, "weapons/gauntletson", 1, ATTN_NORM);
|
|
return;
|
|
}
|
|
randVal = pr_gatk();
|
|
if (randVal < 64)
|
|
{
|
|
player->extralight = 0;
|
|
}
|
|
else if (randVal < 160)
|
|
{
|
|
player->extralight = 1;
|
|
}
|
|
else
|
|
{
|
|
player->extralight = 2;
|
|
}
|
|
if (power)
|
|
{
|
|
P_GiveBody (actor, damage>>1);
|
|
S_Sound (actor, CHAN_AUTO, "weapons/gauntletspowhit", 1, ATTN_NORM);
|
|
}
|
|
else
|
|
{
|
|
S_Sound (actor, CHAN_AUTO, "weapons/gauntletshit", 1, ATTN_NORM);
|
|
}
|
|
// turn to face target
|
|
angle = R_PointToAngle2 (actor->x, actor->y,
|
|
linetarget->x, linetarget->y);
|
|
if (angle-actor->angle > ANG180)
|
|
{
|
|
if ((int)(angle-actor->angle) < -ANG90/20)
|
|
actor->angle = angle+ANG90/21;
|
|
else
|
|
actor->angle -= ANG90/20;
|
|
}
|
|
else
|
|
{
|
|
if (angle-actor->angle > ANG90/20)
|
|
actor->angle = angle-ANG90/21;
|
|
else
|
|
actor->angle += ANG90/20;
|
|
}
|
|
actor->flags |= MF_JUSTATTACKED;
|
|
}
|
|
|
|
// --- Blaster (aka Claw) ---------------------------------------------------
|
|
|
|
void A_FireBlasterPL1 (AActor *);
|
|
void A_FireBlasterPL2 (AActor *);
|
|
void A_SpawnRippers (AActor *);
|
|
|
|
// Blaster ------------------------------------------------------------------
|
|
|
|
class ABlaster : public AHereticWeapon
|
|
{
|
|
DECLARE_ACTOR (ABlaster, AHereticWeapon)
|
|
};
|
|
|
|
class ABlasterPowered : public ABlaster
|
|
{
|
|
DECLARE_STATELESS_ACTOR (ABlasterPowered, ABlaster)
|
|
};
|
|
|
|
FState ABlaster::States[] =
|
|
{
|
|
#define S_BLSR 0
|
|
S_NORMAL (WBLS, 'A', -1, NULL , NULL),
|
|
|
|
#define S_BLASTERREADY (S_BLSR+1)
|
|
S_NORMAL (BLSR, 'A', 1, A_WeaponReady , &States[S_BLASTERREADY]),
|
|
|
|
#define S_BLASTERDOWN (S_BLASTERREADY+1)
|
|
S_NORMAL (BLSR, 'A', 1, A_Lower , &States[S_BLASTERDOWN]),
|
|
|
|
#define S_BLASTERUP (S_BLASTERDOWN+1)
|
|
S_NORMAL (BLSR, 'A', 1, A_Raise , &States[S_BLASTERUP]),
|
|
|
|
#define S_BLASTERATK1 (S_BLASTERUP+1)
|
|
S_NORMAL (BLSR, 'B', 3, NULL , &States[S_BLASTERATK1+1]),
|
|
S_NORMAL (BLSR, 'C', 3, NULL , &States[S_BLASTERATK1+2]),
|
|
S_NORMAL (BLSR, 'D', 2, A_FireBlasterPL1 , &States[S_BLASTERATK1+3]),
|
|
S_NORMAL (BLSR, 'C', 2, NULL , &States[S_BLASTERATK1+4]),
|
|
S_NORMAL (BLSR, 'B', 2, NULL , &States[S_BLASTERATK1+5]),
|
|
S_NORMAL (BLSR, 'A', 0, A_ReFire , &States[S_BLASTERREADY]),
|
|
|
|
#define S_BLASTERATK2 (S_BLASTERATK1+6)
|
|
S_NORMAL (BLSR, 'B', 0, NULL , &States[S_BLASTERATK2+1]),
|
|
S_NORMAL (BLSR, 'C', 0, NULL , &States[S_BLASTERATK2+2]),
|
|
S_NORMAL (BLSR, 'D', 3, A_FireBlasterPL2 , &States[S_BLASTERATK2+3]),
|
|
S_NORMAL (BLSR, 'C', 4, NULL , &States[S_BLASTERATK2+4]),
|
|
S_NORMAL (BLSR, 'B', 4, NULL , &States[S_BLASTERATK2+5]),
|
|
S_NORMAL (BLSR, 'A', 0, A_ReFire , &States[S_BLASTERREADY])
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (ABlaster, Heretic, 53, 28)
|
|
PROP_Flags (MF_SPECIAL)
|
|
PROP_Flags5 (MF5_BLOODSPLATTER)
|
|
PROP_SpawnState (S_BLSR)
|
|
|
|
PROP_Weapon_SelectionOrder (500)
|
|
PROP_Weapon_AmmoUse1 (USE_BLSR_AMMO_1)
|
|
PROP_Weapon_AmmoGive1 (30)
|
|
PROP_Weapon_UpState (S_BLASTERUP)
|
|
PROP_Weapon_DownState (S_BLASTERDOWN)
|
|
PROP_Weapon_ReadyState (S_BLASTERREADY)
|
|
PROP_Weapon_AtkState (S_BLASTERATK1)
|
|
PROP_Weapon_HoldAtkState (S_BLASTERATK1+2)
|
|
PROP_Weapon_YAdjust (15)
|
|
PROP_Weapon_MoveCombatDist (27000000)
|
|
PROP_Weapon_AmmoType1 ("BlasterAmmo")
|
|
PROP_Weapon_SisterType ("BlasterPowered")
|
|
PROP_Inventory_PickupMessage("$TXT_WPNBLASTER")
|
|
END_DEFAULTS
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (ABlasterPowered, Heretic, -1, 0)
|
|
PROP_Weapon_Flags (WIF_POWERED_UP)
|
|
PROP_Weapon_AmmoUse1 (USE_BLSR_AMMO_2)
|
|
PROP_Weapon_AmmoGive1 (0)
|
|
PROP_Weapon_AtkState (S_BLASTERATK2)
|
|
PROP_Weapon_HoldAtkState (S_BLASTERATK2+2)
|
|
PROP_Weapon_SisterType ("Blaster")
|
|
PROP_Weapon_ProjectileType ("BlasterFX1")
|
|
END_DEFAULTS
|
|
|
|
// Blaster FX 1 -------------------------------------------------------------
|
|
|
|
class ABlasterFX1 : public AActor
|
|
{
|
|
DECLARE_ACTOR (ABlasterFX1, AActor)
|
|
public:
|
|
void Tick ();
|
|
int DoSpecialDamage (AActor *target, int damage);
|
|
};
|
|
|
|
FState ABlasterFX1::States[] =
|
|
{
|
|
#define S_BLASTERFX1 0
|
|
S_NORMAL (ACLO, 'E', 200, NULL , &States[S_BLASTERFX1+0]),
|
|
|
|
#define S_BLASTERFXI1 (S_BLASTERFX1+1)
|
|
S_BRIGHT (FX18, 'A', 3, A_SpawnRippers , &States[S_BLASTERFXI1+1]),
|
|
S_BRIGHT (FX18, 'B', 3, NULL , &States[S_BLASTERFXI1+2]),
|
|
S_BRIGHT (FX18, 'C', 4, NULL , &States[S_BLASTERFXI1+3]),
|
|
S_BRIGHT (FX18, 'D', 4, NULL , &States[S_BLASTERFXI1+4]),
|
|
S_BRIGHT (FX18, 'E', 4, NULL , &States[S_BLASTERFXI1+5]),
|
|
S_BRIGHT (FX18, 'F', 4, NULL , &States[S_BLASTERFXI1+6]),
|
|
S_BRIGHT (FX18, 'G', 4, NULL , NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (ABlasterFX1, Heretic, -1, 0)
|
|
PROP_RadiusFixed (12)
|
|
PROP_HeightFixed (8)
|
|
PROP_SpeedFixed (184)
|
|
PROP_Damage (2)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY)
|
|
PROP_Flags2 (MF2_NOTELEPORT|MF2_PCROSS|MF2_IMPACT)
|
|
|
|
PROP_SpawnState (S_BLASTERFX1)
|
|
PROP_DeathState (S_BLASTERFXI1)
|
|
|
|
PROP_DeathSound ("weapons/blasterhit")
|
|
END_DEFAULTS
|
|
|
|
int ABlasterFX1::DoSpecialDamage (AActor *target, int damage)
|
|
{
|
|
if (target->IsKindOf (PClass::FindClass ("Ironlich")))
|
|
{ // Less damage to Ironlich bosses
|
|
damage = pr_bfx1() & 1;
|
|
if (!damage)
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
return damage;
|
|
}
|
|
|
|
// Blaster smoke ------------------------------------------------------------
|
|
|
|
class ABlasterSmoke : public AActor
|
|
{
|
|
DECLARE_ACTOR (ABlasterSmoke, AActor)
|
|
};
|
|
|
|
FState ABlasterSmoke::States[] =
|
|
{
|
|
#define S_BLASTERSMOKE 0
|
|
S_NORMAL (FX18, 'H', 4, NULL , &States[S_BLASTERSMOKE+1]),
|
|
S_NORMAL (FX18, 'I', 4, NULL , &States[S_BLASTERSMOKE+2]),
|
|
S_NORMAL (FX18, 'J', 4, NULL , &States[S_BLASTERSMOKE+3]),
|
|
S_NORMAL (FX18, 'K', 4, NULL , &States[S_BLASTERSMOKE+4]),
|
|
S_NORMAL (FX18, 'L', 4, NULL , NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (ABlasterSmoke, Heretic, -1, 0)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY)
|
|
PROP_Flags2 (MF2_NOTELEPORT|MF2_CANNOTPUSH)
|
|
PROP_RenderStyle (STYLE_Translucent)
|
|
PROP_Alpha (HR_SHADOW)
|
|
|
|
PROP_SpawnState (S_BLASTERSMOKE)
|
|
END_DEFAULTS
|
|
|
|
// Ripper -------------------------------------------------------------------
|
|
|
|
class ARipper : public AActor
|
|
{
|
|
DECLARE_ACTOR (ARipper, AActor)
|
|
public:
|
|
int DoSpecialDamage (AActor *target, int damage);
|
|
};
|
|
|
|
FState ARipper::States[] =
|
|
{
|
|
#define S_RIPPER 0
|
|
S_NORMAL (FX18, 'M', 4, NULL , &States[S_RIPPER+1]),
|
|
S_NORMAL (FX18, 'N', 5, NULL , &States[S_RIPPER+0]),
|
|
|
|
#define S_RIPPERX (S_RIPPER+2)
|
|
S_BRIGHT (FX18, 'O', 4, NULL , &States[S_RIPPERX+1]),
|
|
S_BRIGHT (FX18, 'P', 4, NULL , &States[S_RIPPERX+2]),
|
|
S_BRIGHT (FX18, 'Q', 4, NULL , &States[S_RIPPERX+3]),
|
|
S_BRIGHT (FX18, 'R', 4, NULL , &States[S_RIPPERX+4]),
|
|
S_BRIGHT (FX18, 'S', 4, NULL , NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (ARipper, Heretic, -1, 157)
|
|
PROP_RadiusFixed (8)
|
|
PROP_HeightFixed (6)
|
|
PROP_SpeedFixed (14)
|
|
PROP_Damage (1)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY)
|
|
PROP_Flags2 (MF2_NOTELEPORT|MF2_RIP|MF2_PCROSS|MF2_IMPACT)
|
|
PROP_Flags3 (MF3_WARNBOT)
|
|
|
|
PROP_SpawnState (S_RIPPER)
|
|
PROP_DeathState (S_RIPPERX)
|
|
|
|
PROP_DeathSound ("weapons/blasterpowhit")
|
|
END_DEFAULTS
|
|
|
|
int ARipper::DoSpecialDamage (AActor *target, int damage)
|
|
{
|
|
if (target->IsKindOf (PClass::FindClass ("Ironlich")))
|
|
{ // Less damage to Ironlich bosses
|
|
damage = pr_ripd() & 1;
|
|
if (!damage)
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
return damage;
|
|
}
|
|
|
|
// Blaster Puff -------------------------------------------------------------
|
|
|
|
class ABlasterPuff : public AActor
|
|
{
|
|
DECLARE_ACTOR (ABlasterPuff, AActor)
|
|
};
|
|
|
|
FState ABlasterPuff::States[] =
|
|
{
|
|
#define S_BLASTERPUFF1 0
|
|
S_BRIGHT (FX17, 'A', 4, NULL , &States[S_BLASTERPUFF1+1]),
|
|
S_BRIGHT (FX17, 'B', 4, NULL , &States[S_BLASTERPUFF1+2]),
|
|
S_BRIGHT (FX17, 'C', 4, NULL , &States[S_BLASTERPUFF1+3]),
|
|
S_BRIGHT (FX17, 'D', 4, NULL , &States[S_BLASTERPUFF1+4]),
|
|
S_BRIGHT (FX17, 'E', 4, NULL , NULL),
|
|
|
|
#define S_BLASTERPUFF2 (S_BLASTERPUFF1+5)
|
|
S_BRIGHT (FX17, 'F', 3, NULL , &States[S_BLASTERPUFF2+1]),
|
|
S_BRIGHT (FX17, 'G', 3, NULL , &States[S_BLASTERPUFF2+2]),
|
|
S_BRIGHT (FX17, 'H', 4, NULL , &States[S_BLASTERPUFF2+3]),
|
|
S_BRIGHT (FX17, 'I', 4, NULL , &States[S_BLASTERPUFF2+4]),
|
|
S_BRIGHT (FX17, 'J', 4, NULL , &States[S_BLASTERPUFF2+5]),
|
|
S_BRIGHT (FX17, 'K', 4, NULL , &States[S_BLASTERPUFF2+6]),
|
|
S_BRIGHT (FX17, 'L', 4, NULL , NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (ABlasterPuff, Heretic, -1, 0)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY)
|
|
PROP_Flags3 (MF3_PUFFONACTORS)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
|
|
PROP_SpawnState (S_BLASTERPUFF2)
|
|
PROP_CrashState (S_BLASTERPUFF1)
|
|
END_DEFAULTS
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_FireBlasterPL1
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_FireBlasterPL1 (AActor *actor)
|
|
{
|
|
angle_t angle;
|
|
int damage;
|
|
player_t *player;
|
|
|
|
if (NULL == (player = actor->player))
|
|
{
|
|
return;
|
|
}
|
|
|
|
AWeapon *weapon = actor->player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
angle_t pitch = P_BulletSlope(actor);
|
|
damage = pr_fb1.HitDice (4);
|
|
angle = actor->angle;
|
|
if (player->refire)
|
|
{
|
|
angle += pr_fb1.Random2() << 18;
|
|
}
|
|
P_LineAttack (actor, angle, PLAYERMISSILERANGE, pitch, damage, NAME_None, RUNTIME_CLASS(ABlasterPuff));
|
|
S_Sound (actor, CHAN_WEAPON, "weapons/blastershoot", 1, ATTN_NORM);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_FireBlasterPL2
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_FireBlasterPL2 (AActor *actor)
|
|
{
|
|
AActor *mo;
|
|
player_t *player;
|
|
|
|
if (NULL == (player = actor->player))
|
|
{
|
|
return;
|
|
}
|
|
|
|
AWeapon *weapon = actor->player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
mo = P_SpawnPlayerMissile (actor, RUNTIME_CLASS(ABlasterFX1));
|
|
S_Sound (mo, CHAN_WEAPON, "weapons/blastershoot", 1, ATTN_NORM);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_SpawnRippers
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_SpawnRippers (AActor *actor)
|
|
{
|
|
int i;
|
|
angle_t angle;
|
|
AActor *ripper;
|
|
|
|
for(i = 0; i < 8; i++)
|
|
{
|
|
ripper = Spawn<ARipper> (actor->x, actor->y, actor->z, ALLOW_REPLACE);
|
|
angle = i*ANG45;
|
|
ripper->target = actor->target;
|
|
ripper->angle = angle;
|
|
angle >>= ANGLETOFINESHIFT;
|
|
ripper->momx = FixedMul (ripper->Speed, finecosine[angle]);
|
|
ripper->momy = FixedMul (ripper->Speed, finesine[angle]);
|
|
P_CheckMissileSpawn (ripper);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC P_BlasterMobjThinker
|
|
//
|
|
// Thinker for the ultra-fast blaster PL2 ripper-spawning missile.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void ABlasterFX1::Tick ()
|
|
{
|
|
int i;
|
|
fixed_t xfrac;
|
|
fixed_t yfrac;
|
|
fixed_t zfrac;
|
|
int changexy;
|
|
|
|
PrevX = x;
|
|
PrevY = y;
|
|
PrevZ = z;
|
|
|
|
// Handle movement
|
|
if (momx || momy || (z != floorz) || momz)
|
|
{
|
|
xfrac = momx>>3;
|
|
yfrac = momy>>3;
|
|
zfrac = momz>>3;
|
|
changexy = xfrac | yfrac;
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
if (changexy)
|
|
{
|
|
if (!P_TryMove (this, x + xfrac, y + yfrac, true))
|
|
{ // Blocked move
|
|
P_ExplodeMissile (this, BlockingLine, BlockingMobj);
|
|
return;
|
|
}
|
|
}
|
|
z += zfrac;
|
|
if (z <= floorz)
|
|
{ // Hit the floor
|
|
z = floorz;
|
|
P_HitFloor (this);
|
|
P_ExplodeMissile (this, NULL, NULL);
|
|
return;
|
|
}
|
|
if (z + height > ceilingz)
|
|
{ // Hit the ceiling
|
|
z = ceilingz - height;
|
|
P_ExplodeMissile (this, NULL, NULL);
|
|
return;
|
|
}
|
|
if (changexy && (pr_bfx1t() < 64))
|
|
{
|
|
Spawn<ABlasterSmoke> (x, y, MAX<fixed_t> (z - 8 * FRACUNIT, floorz), ALLOW_REPLACE);
|
|
}
|
|
}
|
|
}
|
|
// Advance the state
|
|
if (tics != -1)
|
|
{
|
|
tics--;
|
|
while (!tics)
|
|
{
|
|
if (!SetState (state->GetNextState ()))
|
|
{ // mobj was removed
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Skull rod ------------------------------------------------------------
|
|
|
|
void A_FireSkullRodPL1 (AActor *);
|
|
void A_FireSkullRodPL2 (AActor *);
|
|
void A_SkullRodPL2Seek (AActor *);
|
|
void A_AddPlayerRain (AActor *);
|
|
void A_HideInCeiling (AActor *);
|
|
void A_SkullRodStorm (AActor *);
|
|
void A_RainImpact (AActor *);
|
|
|
|
// Skull (Horn) Rod ---------------------------------------------------------
|
|
|
|
class ASkullRod : public AHereticWeapon
|
|
{
|
|
DECLARE_ACTOR (ASkullRod, AHereticWeapon)
|
|
};
|
|
|
|
class ASkullRodPowered : public ASkullRod
|
|
{
|
|
DECLARE_STATELESS_ACTOR (ASkullRodPowered, ASkullRod)
|
|
};
|
|
|
|
FState ASkullRod::States[] =
|
|
{
|
|
#define S_WSKL 0
|
|
S_NORMAL (WSKL, 'A', -1, NULL , NULL),
|
|
|
|
#define S_HORNRODREADY (S_WSKL+1)
|
|
S_NORMAL (HROD, 'A', 1, A_WeaponReady , &States[S_HORNRODREADY]),
|
|
|
|
#define S_HORNRODDOWN (S_HORNRODREADY+1)
|
|
S_NORMAL (HROD, 'A', 1, A_Lower , &States[S_HORNRODDOWN]),
|
|
|
|
#define S_HORNRODUP (S_HORNRODDOWN+1)
|
|
S_NORMAL (HROD, 'A', 1, A_Raise , &States[S_HORNRODUP]),
|
|
|
|
#define S_HORNRODATK1 (S_HORNRODUP+1)
|
|
S_NORMAL (HROD, 'A', 4, A_FireSkullRodPL1 , &States[S_HORNRODATK1+1]),
|
|
S_NORMAL (HROD, 'B', 4, A_FireSkullRodPL1 , &States[S_HORNRODATK1+2]),
|
|
S_NORMAL (HROD, 'B', 0, A_ReFire , &States[S_HORNRODREADY]),
|
|
|
|
#define S_HORNRODATK2 (S_HORNRODATK1+3)
|
|
S_NORMAL (HROD, 'C', 2, NULL , &States[S_HORNRODATK2+1]),
|
|
S_NORMAL (HROD, 'D', 3, NULL , &States[S_HORNRODATK2+2]),
|
|
S_NORMAL (HROD, 'E', 2, NULL , &States[S_HORNRODATK2+3]),
|
|
S_NORMAL (HROD, 'F', 3, NULL , &States[S_HORNRODATK2+4]),
|
|
S_NORMAL (HROD, 'G', 4, A_FireSkullRodPL2 , &States[S_HORNRODATK2+5]),
|
|
S_NORMAL (HROD, 'F', 2, NULL , &States[S_HORNRODATK2+6]),
|
|
S_NORMAL (HROD, 'E', 3, NULL , &States[S_HORNRODATK2+7]),
|
|
S_NORMAL (HROD, 'D', 2, NULL , &States[S_HORNRODATK2+8]),
|
|
S_NORMAL (HROD, 'C', 2, A_ReFire , &States[S_HORNRODREADY])
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (ASkullRod, Heretic, 2004, 30)
|
|
PROP_Flags (MF_SPECIAL)
|
|
PROP_SpawnState (S_WSKL)
|
|
|
|
PROP_Weapon_SelectionOrder (200)
|
|
PROP_Weapon_AmmoUse1 (USE_SKRD_AMMO_1)
|
|
PROP_Weapon_AmmoGive1 (50)
|
|
PROP_Weapon_UpState (S_HORNRODUP)
|
|
PROP_Weapon_DownState (S_HORNRODDOWN)
|
|
PROP_Weapon_ReadyState (S_HORNRODREADY)
|
|
PROP_Weapon_AtkState (S_HORNRODATK1)
|
|
PROP_Weapon_YAdjust (15)
|
|
PROP_Weapon_MoveCombatDist (27000000)
|
|
PROP_Weapon_AmmoType1 ("SkullRodAmmo")
|
|
PROP_Weapon_SisterType ("SkullRodPowered")
|
|
PROP_Weapon_ProjectileType ("HornRodFX1")
|
|
PROP_Inventory_PickupMessage("$TXT_WPNSKULLROD")
|
|
END_DEFAULTS
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (ASkullRodPowered, Heretic, -1, 0)
|
|
PROP_Weapon_Flags (WIF_POWERED_UP)
|
|
PROP_Weapon_AmmoUse1 (USE_SKRD_AMMO_2)
|
|
PROP_Weapon_AmmoGive1 (0)
|
|
PROP_Weapon_AtkState (S_HORNRODATK2)
|
|
PROP_Weapon_SisterType ("SkullRod")
|
|
PROP_Weapon_ProjectileType ("HornRodFX2")
|
|
END_DEFAULTS
|
|
|
|
// Horn Rod FX 1 ------------------------------------------------------------
|
|
|
|
class AHornRodFX1 : public AActor
|
|
{
|
|
DECLARE_ACTOR (AHornRodFX1, AActor)
|
|
};
|
|
|
|
FState AHornRodFX1::States[] =
|
|
{
|
|
#define S_HRODFX1 0
|
|
S_BRIGHT (FX00, 'A', 6, NULL , &States[S_HRODFX1+1]),
|
|
S_BRIGHT (FX00, 'B', 6, NULL , &States[S_HRODFX1+0]),
|
|
|
|
#define S_HRODFXI1 (S_HRODFX1+2)
|
|
S_BRIGHT (FX00, 'H', 5, NULL , &States[S_HRODFXI1+1]),
|
|
S_BRIGHT (FX00, 'I', 5, NULL , &States[S_HRODFXI1+2]),
|
|
S_BRIGHT (FX00, 'J', 4, NULL , &States[S_HRODFXI1+3]),
|
|
S_BRIGHT (FX00, 'K', 4, NULL , &States[S_HRODFXI1+4]),
|
|
S_BRIGHT (FX00, 'L', 3, NULL , &States[S_HRODFXI1+5]),
|
|
S_BRIGHT (FX00, 'M', 3, NULL , NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AHornRodFX1, Heretic, -1, 160)
|
|
PROP_RadiusFixed (12)
|
|
PROP_HeightFixed (8)
|
|
PROP_SpeedFixed (22)
|
|
PROP_Damage (3)
|
|
PROP_Flags (MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY)
|
|
PROP_Flags2 (MF2_WINDTHRUST|MF2_NOTELEPORT|MF2_PCROSS|MF2_IMPACT)
|
|
PROP_Flags3 (MF3_WARNBOT)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
|
|
PROP_SpawnState (S_HRODFX1)
|
|
PROP_DeathState (S_HRODFXI1)
|
|
|
|
PROP_SeeSound ("weapons/hornrodshoot")
|
|
PROP_DeathSound ("weapons/hornrodhit")
|
|
END_DEFAULTS
|
|
|
|
// Horn Rod FX 2 ------------------------------------------------------------
|
|
|
|
class AHornRodFX2 : public AActor
|
|
{
|
|
DECLARE_ACTOR (AHornRodFX2, AActor)
|
|
public:
|
|
int DoSpecialDamage (AActor *target, int damage);
|
|
};
|
|
|
|
FState AHornRodFX2::States[] =
|
|
{
|
|
#define S_HRODFX2 0
|
|
S_BRIGHT (FX00, 'C', 3, NULL , &States[S_HRODFX2+1]),
|
|
S_BRIGHT (FX00, 'D', 3, A_SkullRodPL2Seek , &States[S_HRODFX2+2]),
|
|
S_BRIGHT (FX00, 'E', 3, NULL , &States[S_HRODFX2+3]),
|
|
S_BRIGHT (FX00, 'F', 3, A_SkullRodPL2Seek , &States[S_HRODFX2+0]),
|
|
|
|
#define S_HRODFXI2 (S_HRODFX2+4)
|
|
S_BRIGHT (FX00, 'H', 5, A_AddPlayerRain , &States[S_HRODFXI2+1]),
|
|
S_BRIGHT (FX00, 'I', 5, NULL , &States[S_HRODFXI2+2]),
|
|
S_BRIGHT (FX00, 'J', 4, NULL , &States[S_HRODFXI2+3]),
|
|
S_BRIGHT (FX00, 'K', 3, NULL , &States[S_HRODFXI2+4]),
|
|
S_BRIGHT (FX00, 'L', 3, NULL , &States[S_HRODFXI2+5]),
|
|
S_BRIGHT (FX00, 'M', 3, NULL , &States[S_HRODFXI2+6]),
|
|
S_NORMAL (FX00, 'G', 1, A_HideInCeiling , &States[S_HRODFXI2+7]),
|
|
S_NORMAL (FX00, 'G', 1, A_SkullRodStorm , &States[S_HRODFXI2+7])
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AHornRodFX2, Heretic, -1, 0)
|
|
PROP_RadiusFixed (12)
|
|
PROP_HeightFixed (8)
|
|
PROP_SpeedFixed (22)
|
|
PROP_Damage (10)
|
|
PROP_SpawnHealth (4*35)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY)
|
|
PROP_Flags2 (MF2_NOTELEPORT|MF2_PCROSS|MF2_IMPACT)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
|
|
PROP_SpawnState (S_HRODFX2)
|
|
PROP_DeathState (S_HRODFXI2)
|
|
|
|
PROP_SeeSound ("weapons/hornrodshoot")
|
|
PROP_DeathSound ("weapons/hornrodpowhit")
|
|
END_DEFAULTS
|
|
|
|
int AHornRodFX2::DoSpecialDamage (AActor *target, int damage)
|
|
{
|
|
if (target->IsKindOf (RUNTIME_CLASS (ASorcerer2)) && pr_hrfx2() < 96)
|
|
{ // D'Sparil teleports away
|
|
P_DSparilTeleport (target);
|
|
return -1;
|
|
}
|
|
return damage;
|
|
}
|
|
|
|
// Rain pillar 1 ------------------------------------------------------------
|
|
|
|
class ARainPillar : public AActor
|
|
{
|
|
DECLARE_ACTOR (ARainPillar, AActor)
|
|
public:
|
|
int DoSpecialDamage (AActor *target, int damage);
|
|
};
|
|
|
|
FState ARainPillar::States[] =
|
|
{
|
|
#define S_RAINPLR 0
|
|
S_BRIGHT (FX22, 'A', -1, NULL , NULL),
|
|
|
|
#define S_RAINPLRX (S_RAINPLR+1)
|
|
S_BRIGHT (FX22, 'B', 4, A_RainImpact , &States[S_RAINPLRX+1]),
|
|
S_BRIGHT (FX22, 'C', 4, NULL , &States[S_RAINPLRX+2]),
|
|
S_BRIGHT (FX22, 'D', 4, NULL , &States[S_RAINPLRX+3]),
|
|
S_BRIGHT (FX22, 'E', 4, NULL , &States[S_RAINPLRX+4]),
|
|
S_BRIGHT (FX22, 'F', 4, NULL , NULL),
|
|
|
|
#define S_RAINAIRXPLR (S_RAINPLRX+5)
|
|
S_BRIGHT (FX22, 'G', 4, NULL , &States[S_RAINAIRXPLR+1]),
|
|
S_BRIGHT (FX22, 'H', 4, NULL , &States[S_RAINAIRXPLR+2]),
|
|
S_BRIGHT (FX22, 'I', 4, NULL , NULL),
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (ARainPillar, Heretic, -1, 0)
|
|
PROP_RadiusFixed (5)
|
|
PROP_HeightFixed (12)
|
|
PROP_SpeedFixed (12)
|
|
PROP_Damage (5)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY)
|
|
PROP_Flags2 (MF2_NOTELEPORT)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
|
|
PROP_SpawnState (S_RAINPLR)
|
|
PROP_DeathState (S_RAINPLRX)
|
|
END_DEFAULTS
|
|
|
|
int ARainPillar::DoSpecialDamage (AActor *target, int damage)
|
|
{
|
|
if (target->flags2 & MF2_BOSS)
|
|
{ // Decrease damage for bosses
|
|
damage = (pr_rp() & 7) + 1;
|
|
}
|
|
return damage;
|
|
}
|
|
|
|
// Rain tracker "inventory" item --------------------------------------------
|
|
|
|
class ARainTracker : public AInventory
|
|
{
|
|
DECLARE_STATELESS_ACTOR (ARainTracker, AInventory)
|
|
public:
|
|
void Serialize (FArchive &arc);
|
|
AActor *Rain1, *Rain2;
|
|
};
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (ARainTracker, Any, -1, 0)
|
|
PROP_Inventory_FlagsSet (IF_UNDROPPABLE)
|
|
END_DEFAULTS
|
|
|
|
void ARainTracker::Serialize (FArchive &arc)
|
|
{
|
|
Super::Serialize (arc);
|
|
arc << Rain1 << Rain2;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_FireSkullRodPL1
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_FireSkullRodPL1 (AActor *actor)
|
|
{
|
|
AActor *mo;
|
|
player_t *player;
|
|
|
|
if (NULL == (player = actor->player))
|
|
{
|
|
return;
|
|
}
|
|
|
|
AWeapon *weapon = player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
mo = P_SpawnPlayerMissile (actor, RUNTIME_CLASS(AHornRodFX1));
|
|
// Randomize the first frame
|
|
if (mo && pr_fsr1() > 128)
|
|
{
|
|
mo->SetState (mo->state->GetNextState());
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_FireSkullRodPL2
|
|
//
|
|
// The special2 field holds the player number that shot the rain missile.
|
|
// The special1 field holds the id of the rain sound.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_FireSkullRodPL2 (AActor *actor)
|
|
{
|
|
player_t *player;
|
|
AActor *MissileActor;
|
|
AActor *linetarget;
|
|
|
|
if (NULL == (player = actor->player))
|
|
{
|
|
return;
|
|
}
|
|
AWeapon *weapon = player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
P_SpawnPlayerMissile (actor, 0,0,0, RUNTIME_CLASS(AHornRodFX2), actor->angle, &linetarget, &MissileActor);
|
|
// Use MissileActor instead of the return value from
|
|
// P_SpawnPlayerMissile because we need to give info to the mobj
|
|
// even if it exploded immediately.
|
|
if (MissileActor != NULL)
|
|
{
|
|
MissileActor->special2 = (int)(player - players);
|
|
if (linetarget)
|
|
{
|
|
MissileActor->tracer = linetarget;
|
|
}
|
|
S_Sound (MissileActor, CHAN_WEAPON, "weapons/hornrodpowshoot", 1, ATTN_NORM);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_SkullRodPL2Seek
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_SkullRodPL2Seek (AActor *actor)
|
|
{
|
|
P_SeekerMissile (actor, ANGLE_1*10, ANGLE_1*30);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_AddPlayerRain
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_AddPlayerRain (AActor *actor)
|
|
{
|
|
ARainTracker *tracker;
|
|
|
|
if (actor->target == NULL || actor->target->health <= 0)
|
|
{ // Shooter is dead or nonexistant
|
|
return;
|
|
}
|
|
|
|
tracker = actor->target->FindInventory<ARainTracker> ();
|
|
|
|
// They player is only allowed two rainstorms at a time. Shooting more
|
|
// than that will cause the oldest one to terminate.
|
|
if (tracker != NULL)
|
|
{
|
|
if (tracker->Rain1 && tracker->Rain2)
|
|
{ // Terminate an active rain
|
|
if (tracker->Rain1->health < tracker->Rain2->health)
|
|
{
|
|
if (tracker->Rain1->health > 16)
|
|
{
|
|
tracker->Rain1->health = 16;
|
|
}
|
|
tracker->Rain1 = NULL;
|
|
}
|
|
else
|
|
{
|
|
if (tracker->Rain2->health > 16)
|
|
{
|
|
tracker->Rain2->health = 16;
|
|
}
|
|
tracker->Rain2 = NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tracker = static_cast<ARainTracker *> (actor->target->GiveInventoryType (RUNTIME_CLASS(ARainTracker)));
|
|
}
|
|
// Add rain mobj to list
|
|
if (tracker->Rain1)
|
|
{
|
|
tracker->Rain2 = actor;
|
|
}
|
|
else
|
|
{
|
|
tracker->Rain1 = actor;
|
|
}
|
|
actor->special1 = S_FindSound ("misc/rain");
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_SkullRodStorm
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_SkullRodStorm (AActor *actor)
|
|
{
|
|
fixed_t x;
|
|
fixed_t y;
|
|
AActor *mo;
|
|
ARainTracker *tracker;
|
|
|
|
if (actor->health-- == 0)
|
|
{
|
|
S_StopSound (actor, CHAN_BODY);
|
|
if (actor->target == NULL)
|
|
{ // Player left the game
|
|
actor->Destroy ();
|
|
return;
|
|
}
|
|
tracker = actor->target->FindInventory<ARainTracker> ();
|
|
if (tracker != NULL)
|
|
{
|
|
if (tracker->Rain1 == actor)
|
|
{
|
|
tracker->Rain1 = NULL;
|
|
}
|
|
else if (tracker->Rain2 == actor)
|
|
{
|
|
tracker->Rain2 = NULL;
|
|
}
|
|
}
|
|
actor->Destroy ();
|
|
return;
|
|
}
|
|
if (pr_storm() < 25)
|
|
{ // Fudge rain frequency
|
|
return;
|
|
}
|
|
x = actor->x + ((pr_storm()&127) - 64) * FRACUNIT;
|
|
y = actor->y + ((pr_storm()&127) - 64) * FRACUNIT;
|
|
mo = Spawn<ARainPillar> (x, y, ONCEILINGZ, ALLOW_REPLACE);
|
|
mo->Translation = multiplayer ?
|
|
TRANSLATION(TRANSLATION_PlayersExtra,actor->special2) : 0;
|
|
mo->target = actor->target;
|
|
mo->momx = 1; // Force collision detection
|
|
mo->momz = -mo->Speed;
|
|
mo->special2 = actor->special2; // Transfer player number
|
|
P_CheckMissileSpawn (mo);
|
|
if (actor->special1 != -1 && !S_IsActorPlayingSomething (actor, CHAN_BODY, -1))
|
|
{
|
|
S_SoundID (actor, CHAN_BODY|CHAN_LOOP, actor->special1, 1, ATTN_NORM);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_RainImpact
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_RainImpact (AActor *actor)
|
|
{
|
|
if (actor->z > actor->floorz)
|
|
{
|
|
actor->SetState (&ARainPillar::States[S_RAINAIRXPLR]);
|
|
}
|
|
else if (pr_impact() < 40)
|
|
{
|
|
P_HitFloor (actor);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_HideInCeiling
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_HideInCeiling (AActor *actor)
|
|
{
|
|
actor->z = actor->ceilingz + 4*FRACUNIT;
|
|
}
|
|
|
|
// --- Phoenix Rod ----------------------------------------------------------
|
|
|
|
void A_FirePhoenixPL1 (AActor *);
|
|
void A_InitPhoenixPL2 (AActor *);
|
|
void A_FirePhoenixPL2 (AActor *);
|
|
void A_ShutdownPhoenixPL2 (AActor *);
|
|
void A_PhoenixPuff (AActor *);
|
|
void A_FlameEnd (AActor *);
|
|
void A_FloatPuff (AActor *);
|
|
|
|
// Phoenix Rod --------------------------------------------------------------
|
|
|
|
class APhoenixRod : public AHereticWeapon
|
|
{
|
|
DECLARE_ACTOR (APhoenixRod, AHereticWeapon)
|
|
public:
|
|
void Serialize (FArchive &arc)
|
|
{
|
|
Super::Serialize (arc);
|
|
arc << FlameCount;
|
|
}
|
|
int FlameCount; // for flamethrower duration
|
|
};
|
|
|
|
class APhoenixRodPowered : public APhoenixRod
|
|
{
|
|
DECLARE_STATELESS_ACTOR (APhoenixRodPowered, APhoenixRod)
|
|
public:
|
|
void EndPowerup ();
|
|
};
|
|
|
|
FState APhoenixRod::States[] =
|
|
{
|
|
#define S_WPHX 0
|
|
S_NORMAL (WPHX, 'A', -1, NULL , NULL),
|
|
|
|
#define S_PHOENIXREADY (S_WPHX+1)
|
|
S_NORMAL (PHNX, 'A', 1, A_WeaponReady , &States[S_PHOENIXREADY]),
|
|
|
|
#define S_PHOENIXDOWN (S_PHOENIXREADY+1)
|
|
S_NORMAL (PHNX, 'A', 1, A_Lower , &States[S_PHOENIXDOWN]),
|
|
|
|
#define S_PHOENIXUP (S_PHOENIXDOWN+1)
|
|
S_NORMAL (PHNX, 'A', 1, A_Raise , &States[S_PHOENIXUP]),
|
|
|
|
#define S_PHOENIXATK1 (S_PHOENIXUP+1)
|
|
S_NORMAL (PHNX, 'B', 5, NULL , &States[S_PHOENIXATK1+1]),
|
|
S_NORMAL (PHNX, 'C', 7, A_FirePhoenixPL1 , &States[S_PHOENIXATK1+2]),
|
|
S_NORMAL (PHNX, 'D', 4, NULL , &States[S_PHOENIXATK1+3]),
|
|
S_NORMAL (PHNX, 'B', 4, NULL , &States[S_PHOENIXATK1+4]),
|
|
S_NORMAL (PHNX, 'B', 0, A_ReFire , &States[S_PHOENIXREADY]),
|
|
|
|
#define S_PHOENIXATK2 (S_PHOENIXATK1+5)
|
|
S_NORMAL (PHNX, 'B', 3, A_InitPhoenixPL2 , &States[S_PHOENIXATK2+1]),
|
|
S_BRIGHT (PHNX, 'C', 1, A_FirePhoenixPL2 , &States[S_PHOENIXATK2+2]),
|
|
S_NORMAL (PHNX, 'B', 4, A_ReFire , &States[S_PHOENIXATK2+3]),
|
|
S_NORMAL (PHNX, 'B', 4, A_ShutdownPhoenixPL2 , &States[S_PHOENIXREADY])
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (APhoenixRod, Heretic, 2003, 29)
|
|
PROP_Flags (MF_SPECIAL)
|
|
PROP_SpawnState (S_WPHX)
|
|
|
|
PROP_Weapon_Flags (WIF_NOAUTOFIRE|WIF_BOT_REACTION_SKILL_THING)
|
|
PROP_Weapon_SelectionOrder (2600)
|
|
PROP_Weapon_AmmoUse1 (USE_PHRD_AMMO_1)
|
|
PROP_Weapon_AmmoGive1 (2)
|
|
PROP_Weapon_UpState (S_PHOENIXUP)
|
|
PROP_Weapon_DownState (S_PHOENIXDOWN)
|
|
PROP_Weapon_ReadyState (S_PHOENIXREADY)
|
|
PROP_Weapon_AtkState (S_PHOENIXATK1)
|
|
PROP_Weapon_YAdjust (15)
|
|
PROP_Weapon_MoveCombatDist (18350080)
|
|
PROP_Weapon_AmmoType1 ("PhoenixRodAmmo")
|
|
PROP_Weapon_SisterType ("PhoenixRodPowered")
|
|
PROP_Weapon_ProjectileType ("PhoenixFX1")
|
|
PROP_Inventory_PickupMessage("$TXT_WPNPHOENIXROD")
|
|
END_DEFAULTS
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (APhoenixRodPowered, Heretic, -1, 0)
|
|
PROP_Weapon_Flags (WIF_NOAUTOFIRE|WIF_POWERED_UP|WIF_BOT_MELEE)
|
|
PROP_Weapon_AmmoUse1 (USE_PHRD_AMMO_2)
|
|
PROP_Weapon_AmmoGive1 (0)
|
|
PROP_Weapon_AtkState (S_PHOENIXATK2)
|
|
PROP_Weapon_HoldAtkState (S_PHOENIXATK2+1)
|
|
PROP_Weapon_MoveCombatDist (0)
|
|
PROP_Weapon_SisterType ("PhoenixRod")
|
|
PROP_Weapon_ProjectileType ("PhoenixFX2")
|
|
END_DEFAULTS
|
|
|
|
void APhoenixRodPowered::EndPowerup ()
|
|
{
|
|
P_SetPsprite (Owner->player, ps_weapon, &APhoenixRod::States[S_PHOENIXREADY]);
|
|
DepleteAmmo (bAltFire);
|
|
Owner->player->refire = 0;
|
|
S_StopSound (Owner, CHAN_WEAPON);
|
|
Owner->player->ReadyWeapon = SisterWeapon;
|
|
}
|
|
|
|
// Phoenix FX 1 -------------------------------------------------------------
|
|
|
|
FState APhoenixFX1::States[] =
|
|
{
|
|
#define S_PHOENIXFX1 0
|
|
S_BRIGHT (FX04, 'A', 4, A_PhoenixPuff , &States[S_PHOENIXFX1+0]),
|
|
|
|
#define S_PHOENIXFXI1 (S_PHOENIXFX1+1)
|
|
S_BRIGHT (FX08, 'A', 6, A_Explode , &States[S_PHOENIXFXI1+1]),
|
|
S_BRIGHT (FX08, 'B', 5, NULL , &States[S_PHOENIXFXI1+2]),
|
|
S_BRIGHT (FX08, 'C', 5, NULL , &States[S_PHOENIXFXI1+3]),
|
|
S_BRIGHT (FX08, 'D', 4, NULL , &States[S_PHOENIXFXI1+4]),
|
|
S_BRIGHT (FX08, 'E', 4, NULL , &States[S_PHOENIXFXI1+5]),
|
|
S_BRIGHT (FX08, 'F', 4, NULL , &States[S_PHOENIXFXI1+6]),
|
|
S_BRIGHT (FX08, 'G', 4, NULL , &States[S_PHOENIXFXI1+7]),
|
|
S_BRIGHT (FX08, 'H', 4, NULL , NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (APhoenixFX1, Heretic, -1, 163)
|
|
PROP_RadiusFixed (11)
|
|
PROP_HeightFixed (8)
|
|
PROP_SpeedFixed (20)
|
|
PROP_Damage (20)
|
|
PROP_DamageType (NAME_Fire)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY)
|
|
PROP_Flags2 (MF2_THRUGHOST|MF2_NOTELEPORT|MF2_PCROSS|MF2_IMPACT)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
|
|
PROP_SpawnState (S_PHOENIXFX1)
|
|
PROP_DeathState (S_PHOENIXFXI1)
|
|
|
|
PROP_SeeSound ("weapons/phoenixshoot")
|
|
PROP_DeathSound ("weapons/phoenixhit")
|
|
END_DEFAULTS
|
|
|
|
int APhoenixFX1::DoSpecialDamage (AActor *target, int damage)
|
|
{
|
|
if (target->IsKindOf (RUNTIME_CLASS (ASorcerer2)) && pr_pfx1() < 96)
|
|
{ // D'Sparil teleports away
|
|
P_DSparilTeleport (target);
|
|
return -1;
|
|
}
|
|
return damage;
|
|
}
|
|
|
|
// Phoenix puff -------------------------------------------------------------
|
|
|
|
FState APhoenixPuff::States[] =
|
|
{
|
|
S_NORMAL (FX04, 'B', 4, NULL , &States[1]),
|
|
S_NORMAL (FX04, 'C', 4, NULL , &States[2]),
|
|
S_NORMAL (FX04, 'D', 4, NULL , &States[3]),
|
|
S_NORMAL (FX04, 'E', 4, NULL , &States[4]),
|
|
S_NORMAL (FX04, 'F', 4, NULL , NULL),
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (APhoenixPuff, Heretic, -1, 0)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY)
|
|
PROP_Flags2 (MF2_NOTELEPORT|MF2_CANNOTPUSH)
|
|
PROP_RenderStyle (STYLE_Translucent)
|
|
PROP_Alpha (HR_SHADOW)
|
|
|
|
PROP_SpawnState (0)
|
|
END_DEFAULTS
|
|
|
|
// Phoenix FX 2 -------------------------------------------------------------
|
|
|
|
class APhoenixFX2 : public AActor
|
|
{
|
|
DECLARE_ACTOR (APhoenixFX2, AActor)
|
|
public:
|
|
int DoSpecialDamage (AActor *target, int damage);
|
|
};
|
|
|
|
FState APhoenixFX2::States[] =
|
|
{
|
|
#define S_PHOENIXFX2 0
|
|
S_BRIGHT (FX09, 'A', 2, NULL , &States[S_PHOENIXFX2+1]),
|
|
S_BRIGHT (FX09, 'B', 2, NULL , &States[S_PHOENIXFX2+2]),
|
|
S_BRIGHT (FX09, 'A', 2, NULL , &States[S_PHOENIXFX2+3]),
|
|
S_BRIGHT (FX09, 'B', 2, NULL , &States[S_PHOENIXFX2+4]),
|
|
S_BRIGHT (FX09, 'A', 2, NULL , &States[S_PHOENIXFX2+5]),
|
|
S_BRIGHT (FX09, 'B', 2, A_FlameEnd , &States[S_PHOENIXFX2+6]),
|
|
S_BRIGHT (FX09, 'C', 2, NULL , &States[S_PHOENIXFX2+7]),
|
|
S_BRIGHT (FX09, 'D', 2, NULL , &States[S_PHOENIXFX2+8]),
|
|
S_BRIGHT (FX09, 'E', 2, NULL , &States[S_PHOENIXFX2+9]),
|
|
S_BRIGHT (FX09, 'F', 2, NULL , NULL),
|
|
|
|
#define S_PHOENIXFXI2 (S_PHOENIXFX2+10)
|
|
S_BRIGHT (FX09, 'G', 3, NULL , &States[S_PHOENIXFXI2+1]),
|
|
S_BRIGHT (FX09, 'H', 3, A_FloatPuff , &States[S_PHOENIXFXI2+2]),
|
|
S_BRIGHT (FX09, 'I', 4, NULL , &States[S_PHOENIXFXI2+3]),
|
|
S_BRIGHT (FX09, 'J', 5, NULL , &States[S_PHOENIXFXI2+4]),
|
|
S_BRIGHT (FX09, 'K', 5, NULL , NULL)
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (APhoenixFX2, Heretic, -1, 0)
|
|
PROP_RadiusFixed (6)
|
|
PROP_HeightFixed (8)
|
|
PROP_SpeedFixed (10)
|
|
PROP_Damage (2)
|
|
PROP_DamageType (NAME_Fire)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY)
|
|
PROP_Flags2 (MF2_NOTELEPORT|MF2_PCROSS|MF2_IMPACT)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
|
|
PROP_SpawnState (S_PHOENIXFX2)
|
|
PROP_DeathState (S_PHOENIXFXI2)
|
|
END_DEFAULTS
|
|
|
|
int APhoenixFX2::DoSpecialDamage (AActor *target, int damage)
|
|
{
|
|
if (target->player && pr_pfx2 () < 128)
|
|
{ // Freeze player for a bit
|
|
target->reactiontime += 4;
|
|
}
|
|
return damage;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_FirePhoenixPL1
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_FirePhoenixPL1 (AActor *actor)
|
|
{
|
|
angle_t angle;
|
|
player_t *player;
|
|
|
|
if (NULL == (player = actor->player))
|
|
{
|
|
return;
|
|
}
|
|
|
|
AWeapon *weapon = actor->player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
P_SpawnPlayerMissile (actor, RUNTIME_CLASS(APhoenixFX1));
|
|
angle = actor->angle + ANG180;
|
|
angle >>= ANGLETOFINESHIFT;
|
|
actor->momx += FixedMul (4*FRACUNIT, finecosine[angle]);
|
|
actor->momy += FixedMul (4*FRACUNIT, finesine[angle]);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_PhoenixPuff
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_PhoenixPuff (AActor *actor)
|
|
{
|
|
AActor *puff;
|
|
angle_t angle;
|
|
|
|
//[RH] Heretic never sets the target for seeking
|
|
//P_SeekerMissile (actor, ANGLE_1*5, ANGLE_1*10);
|
|
puff = Spawn<APhoenixPuff> (actor->x, actor->y, actor->z, ALLOW_REPLACE);
|
|
angle = actor->angle + ANG90;
|
|
angle >>= ANGLETOFINESHIFT;
|
|
puff->momx = FixedMul (FRACUNIT*13/10, finecosine[angle]);
|
|
puff->momy = FixedMul (FRACUNIT*13/10, finesine[angle]);
|
|
puff->momz = 0;
|
|
puff = Spawn<APhoenixPuff> (actor->x, actor->y, actor->z, ALLOW_REPLACE);
|
|
angle = actor->angle - ANG90;
|
|
angle >>= ANGLETOFINESHIFT;
|
|
puff->momx = FixedMul (FRACUNIT*13/10, finecosine[angle]);
|
|
puff->momy = FixedMul (FRACUNIT*13/10, finesine[angle]);
|
|
puff->momz = 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_InitPhoenixPL2
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_InitPhoenixPL2 (AActor *actor)
|
|
{
|
|
if (actor->player != NULL)
|
|
{
|
|
APhoenixRod *flamethrower = static_cast<APhoenixRod *> (actor->player->ReadyWeapon);
|
|
if (flamethrower != NULL)
|
|
{
|
|
flamethrower->FlameCount = FLAME_THROWER_TICS;
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_FirePhoenixPL2
|
|
//
|
|
// Flame thrower effect.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_FirePhoenixPL2 (AActor *actor)
|
|
{
|
|
AActor *mo;
|
|
angle_t angle;
|
|
fixed_t x, y, z;
|
|
fixed_t slope;
|
|
int soundid;
|
|
player_t *player;
|
|
APhoenixRod *flamethrower;
|
|
|
|
if (NULL == (player = actor->player))
|
|
{
|
|
return;
|
|
}
|
|
|
|
soundid = S_FindSound ("weapons/phoenixpowshoot");
|
|
|
|
flamethrower = static_cast<APhoenixRod *> (player->ReadyWeapon);
|
|
if (flamethrower == NULL || --flamethrower->FlameCount == 0)
|
|
{ // Out of flame
|
|
P_SetPsprite (player, ps_weapon, &APhoenixRod::States[S_PHOENIXATK2+3]);
|
|
player->refire = 0;
|
|
S_StopSound (actor, CHAN_WEAPON);
|
|
return;
|
|
}
|
|
angle = actor->angle;
|
|
x = actor->x + (pr_fp2.Random2() << 9);
|
|
y = actor->y + (pr_fp2.Random2() << 9);
|
|
z = actor->z + 26*FRACUNIT + finetangent[FINEANGLES/4-(actor->pitch>>ANGLETOFINESHIFT)];
|
|
z -= actor->floorclip;
|
|
slope = finetangent[FINEANGLES/4-(actor->pitch>>ANGLETOFINESHIFT)] + (FRACUNIT/10);
|
|
mo = Spawn<APhoenixFX2> (x, y, z, ALLOW_REPLACE);
|
|
mo->target = actor;
|
|
mo->angle = angle;
|
|
mo->momx = actor->momx + FixedMul (mo->Speed, finecosine[angle>>ANGLETOFINESHIFT]);
|
|
mo->momy = actor->momy + FixedMul (mo->Speed, finesine[angle>>ANGLETOFINESHIFT]);
|
|
mo->momz = FixedMul (mo->Speed, slope);
|
|
if (!player->refire || !S_IsActorPlayingSomething (actor, CHAN_WEAPON, -1))
|
|
{
|
|
S_SoundID (actor, CHAN_WEAPON|CHAN_LOOP, soundid, 1, ATTN_NORM);
|
|
}
|
|
P_CheckMissileSpawn (mo);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_ShutdownPhoenixPL2
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_ShutdownPhoenixPL2 (AActor *actor)
|
|
{
|
|
player_t *player;
|
|
|
|
if (NULL == (player = actor->player))
|
|
{
|
|
return;
|
|
}
|
|
S_StopSound (actor, CHAN_WEAPON);
|
|
AWeapon *weapon = player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
return;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_FlameEnd
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_FlameEnd (AActor *actor)
|
|
{
|
|
actor->momz += FRACUNIT*3/2;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_FloatPuff
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_FloatPuff (AActor *puff)
|
|
{
|
|
puff->momz += FRACUNIT*18/10;
|
|
}
|
|
|