vkdoom_m/src/g_hexen/a_fighteraxe.cpp
Christoph Oelckers 1bd6ac028b - Converted a_doomhealth.cpp to DECORATE.
- Added a PickupMessage property to the internal actor parser, replaced
  most of the virtual PickupMessages with it and placed the code that
  reads the metadata into AInventory::PickupMessage. Now the
  PickupMessage method is truly virtual and I can do:
   Added a Health.LowMessage property to define double message items like
   Doom's medikit in DECORATE.
- Since defining Mana3 as an ammo type and then overriding the TryPickup
  method means that this item defeats all ammo checks in the game it might
  as well be defined as a CustomInventory item. At least this fixes the
  amount given in easy and very hard skills.
- Converted all ammo items to DECORATE.
- Changed internal property setting of ammo types and sister weapons
  to use fuglyname as for DECORATE definitions. This allows to export
  the ammo definitions into DECORATE definitions without doing it for
  the weapons themselves.
- Replaced obituary methods with actor properties.
- Fixed: The secret map check didn't work for maps inside Zips.



SVN r196 (trunk)
2006-06-17 20:29:41 +00:00

470 lines
13 KiB
C++

#include "actor.h"
#include "gi.h"
#include "m_random.h"
#include "s_sound.h"
#include "d_player.h"
#include "a_action.h"
#include "p_local.h"
#include "p_enemy.h"
#include "a_action.h"
#include "p_pspr.h"
#include "gstrings.h"
#include "a_hexenglobal.h"
#include "p_effect.h"
#define AXERANGE ((fixed_t)(2.25*MELEERANGE))
static FRandom pr_atk ("FAxeAtk");
static FRandom pr_splat ("FAxeSplatter");
void A_FAxeCheckReady (AActor *actor);
void A_FAxeCheckUp (AActor *actor);
void A_FAxeCheckAtk (AActor *actor);
void A_FAxeCheckReadyG (AActor *actor);
void A_FAxeCheckUpG (AActor *actor);
void A_FAxeAttack (AActor *actor);
extern void AdjustPlayerAngle (AActor *pmo);
EXTERN_CVAR (Int, cl_bloodtype)
// The Fighter's Axe --------------------------------------------------------
class AFWeapAxe : public AFighterWeapon
{
DECLARE_ACTOR (AFWeapAxe, AFighterWeapon)
public:
FState *GetUpState ();
FState *GetDownState ();
FState *GetReadyState ();
FState *GetAtkState ();
FState *GetHoldAtkState ();
};
FState AFWeapAxe::States[] =
{
#define S_AXE 0
S_NORMAL (WFAX, 'A', -1, NULL , NULL),
#define S_FAXEREADY (S_AXE+1)
S_NORMAL (FAXE, 'A', 1, A_FAxeCheckReady , &States[S_FAXEREADY]),
#define S_FAXEDOWN (S_FAXEREADY+1)
S_NORMAL (FAXE, 'A', 1, A_Lower , &States[S_FAXEDOWN]),
#define S_FAXEUP (S_FAXEDOWN+1)
S_NORMAL (FAXE, 'A', 1, A_FAxeCheckUp , &States[S_FAXEUP]),
#define S_FAXEATK (S_FAXEUP+1)
S_NORMAL2 (FAXE, 'B', 4, A_FAxeCheckAtk , &States[S_FAXEATK+1], 15, 32),
S_NORMAL2 (FAXE, 'C', 3, NULL , &States[S_FAXEATK+2], 15, 32),
S_NORMAL2 (FAXE, 'D', 2, NULL , &States[S_FAXEATK+3], 15, 32),
S_NORMAL2 (FAXE, 'D', 1, A_FAxeAttack , &States[S_FAXEATK+4], -5, 70),
S_NORMAL2 (FAXE, 'D', 2, NULL , &States[S_FAXEATK+5], -25, 90),
S_NORMAL2 (FAXE, 'E', 1, NULL , &States[S_FAXEATK+6], 15, 32),
S_NORMAL2 (FAXE, 'E', 2, NULL , &States[S_FAXEATK+7], 10, 54),
S_NORMAL2 (FAXE, 'E', 7, NULL , &States[S_FAXEATK+8], 10, 150),
S_NORMAL2 (FAXE, 'A', 1, A_ReFire , &States[S_FAXEATK+9], 0, 60),
S_NORMAL2 (FAXE, 'A', 1, NULL , &States[S_FAXEATK+10], 0, 52),
S_NORMAL2 (FAXE, 'A', 1, NULL , &States[S_FAXEATK+11], 0, 44),
S_NORMAL2 (FAXE, 'A', 1, NULL , &States[S_FAXEATK+12], 0, 36),
S_NORMAL (FAXE, 'A', 1, NULL , &States[S_FAXEREADY]),
#define S_FAXEREADY_G (S_FAXEATK+13)
S_NORMAL (FAXE, 'L', 1, A_FAxeCheckReadyG , &States[S_FAXEREADY_G+1]),
S_NORMAL (FAXE, 'L', 1, A_FAxeCheckReadyG , &States[S_FAXEREADY_G+2]),
S_NORMAL (FAXE, 'L', 1, A_FAxeCheckReadyG , &States[S_FAXEREADY_G+3]),
S_NORMAL (FAXE, 'M', 1, A_FAxeCheckReadyG , &States[S_FAXEREADY_G+4]),
S_NORMAL (FAXE, 'M', 1, A_FAxeCheckReadyG , &States[S_FAXEREADY_G+5]),
S_NORMAL (FAXE, 'M', 1, A_FAxeCheckReadyG , &States[S_FAXEREADY_G]),
#define S_FAXEDOWN_G (S_FAXEREADY_G+6)
S_NORMAL (FAXE, 'L', 1, A_Lower , &States[S_FAXEDOWN_G]),
#define S_FAXEUP_G (S_FAXEDOWN_G+1)
S_NORMAL (FAXE, 'L', 1, A_FAxeCheckUpG , &States[S_FAXEUP_G]),
#define S_FAXEATK_G (S_FAXEUP_G+1)
S_NORMAL2 (FAXE, 'N', 4, NULL , &States[S_FAXEATK_G+1], 15, 32),
S_NORMAL2 (FAXE, 'O', 3, NULL , &States[S_FAXEATK_G+2], 15, 32),
S_NORMAL2 (FAXE, 'P', 2, NULL , &States[S_FAXEATK_G+3], 15, 32),
S_NORMAL2 (FAXE, 'P', 1, A_FAxeAttack , &States[S_FAXEATK_G+4], -5, 70),
S_NORMAL2 (FAXE, 'P', 2, NULL , &States[S_FAXEATK_G+5], -25, 90),
S_NORMAL2 (FAXE, 'Q', 1, NULL , &States[S_FAXEATK_G+6], 15, 32),
S_NORMAL2 (FAXE, 'Q', 2, NULL , &States[S_FAXEATK_G+7], 10, 54),
S_NORMAL2 (FAXE, 'Q', 7, NULL , &States[S_FAXEATK_G+8], 10, 150),
S_NORMAL2 (FAXE, 'A', 1, A_ReFire , &States[S_FAXEATK_G+9], 0, 60),
S_NORMAL2 (FAXE, 'A', 1, NULL , &States[S_FAXEATK_G+10], 0, 52),
S_NORMAL2 (FAXE, 'A', 1, NULL , &States[S_FAXEATK_G+11], 0, 44),
S_NORMAL2 (FAXE, 'A', 1, NULL , &States[S_FAXEATK_G+12], 0, 36),
S_NORMAL (FAXE, 'A', 1, NULL , &States[S_FAXEREADY_G]),
};
IMPLEMENT_ACTOR (AFWeapAxe, Hexen, 8010, 27)
PROP_Flags (MF_SPECIAL)
PROP_SpawnState (S_AXE)
PROP_Weapon_SelectionOrder (1500)
PROP_Weapon_Flags (WIF_AXEBLOOD|WIF_AMMO_OPTIONAL|WIF_BOT_MELEE)
PROP_Weapon_AmmoUse1 (2)
PROP_Weapon_AmmoGive1 (25)
PROP_Weapon_UpState (S_FAXEUP)
PROP_Weapon_DownState (S_FAXEDOWN)
PROP_Weapon_ReadyState (S_FAXEREADY)
PROP_Weapon_AtkState (S_FAXEATK)
PROP_Weapon_HoldAtkState (S_FAXEATK)
PROP_Weapon_Kickback (150)
PROP_Weapon_YAdjust (0-12)
PROP_Weapon_AmmoType1 ("Mana1")
END_DEFAULTS
FState *AFWeapAxe::GetUpState ()
{
return Ammo1->Amount ? &States[S_FAXEUP_G] : UpState;
}
FState *AFWeapAxe::GetDownState ()
{
return Ammo1->Amount ? &States[S_FAXEDOWN_G] : DownState;
}
FState *AFWeapAxe::GetReadyState ()
{
return Ammo1->Amount ? &States[S_FAXEREADY_G] : ReadyState;
}
FState *AFWeapAxe::GetAtkState ()
{
return Ammo1->Amount ? &States[S_FAXEATK_G] : AtkState;
}
FState *AFWeapAxe::GetHoldAtkState ()
{
return Ammo1->Amount ? &States[S_FAXEATK_G] : HoldAtkState;
}
// Axe Puff -----------------------------------------------------------------
class AAxePuff : public AActor
{
DECLARE_ACTOR (AAxePuff, AActor)
};
FState AAxePuff::States[] =
{
S_NORMAL (FHFX, 'S', 4, NULL , &States[1]),
S_NORMAL (FHFX, 'T', 4, NULL , &States[2]),
S_NORMAL (FHFX, 'U', 4, NULL , &States[3]),
S_NORMAL (FHFX, 'V', 4, NULL , &States[4]),
S_NORMAL (FHFX, 'W', 4, NULL , NULL),
};
IMPLEMENT_ACTOR (AAxePuff, Hexen, -1, 0)
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY)
PROP_Flags3 (MF3_PUFFONACTORS)
PROP_RenderStyle (STYLE_Translucent)
PROP_Alpha (HX_SHADOW)
PROP_SpawnState (0)
PROP_SeeSound ("FighterAxeHitThing")
PROP_AttackSound ("FighterHammerHitWall")
PROP_ActiveSound ("FighterHammerMiss")
PROP_Inventory_PickupMessage("$TXT_WEAPON_F2")
END_DEFAULTS
// Glowing Axe Puff ---------------------------------------------------------
class AAxePuffGlow : public AAxePuff
{
DECLARE_ACTOR (AAxePuffGlow, AAxePuff)
};
FState AAxePuffGlow::States[] =
{
S_BRIGHT (FAXE, 'R', 4, NULL , &States[1]),
S_BRIGHT (FAXE, 'S', 4, NULL , &States[2]),
S_BRIGHT (FAXE, 'T', 4, NULL , &States[3]),
S_BRIGHT (FAXE, 'U', 4, NULL , &States[4]),
S_BRIGHT (FAXE, 'V', 4, NULL , &States[5]),
S_BRIGHT (FAXE, 'W', 4, NULL , &States[6]),
S_BRIGHT (FAXE, 'X', 4, NULL , NULL),
};
IMPLEMENT_ACTOR (AAxePuffGlow, Hexen, -1, 0)
PROP_Flags3 (MF3_PUFFONACTORS)
PROP_RenderStyle (STYLE_Add)
PROP_Alpha (OPAQUE)
PROP_SpawnState (0)
END_DEFAULTS
// Axe Blood ----------------------------------------------------------------
class AAxeBlood : public AActor
{
DECLARE_ACTOR (AAxeBlood, AActor)
};
FState AAxeBlood::States[] =
{
S_NORMAL (FAXE, 'F', 3, NULL , &States[1]),
S_NORMAL (FAXE, 'G', 3, NULL , &States[2]),
S_NORMAL (FAXE, 'H', 3, NULL , &States[3]),
S_NORMAL (FAXE, 'I', 3, NULL , &States[4]),
S_NORMAL (FAXE, 'J', 3, NULL , &States[5]),
S_NORMAL (FAXE, 'K', 3, NULL , NULL),
};
IMPLEMENT_ACTOR (AAxeBlood, Hexen, -1, 0)
PROP_Mass (5)
PROP_RadiusFixed (2)
PROP_HeightFixed (4)
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF)
PROP_Flags2 (MF2_NOTELEPORT|MF2_CANNOTPUSH)
PROP_SpawnState (0)
PROP_DeathState (5)
END_DEFAULTS
//============================================================================
//
// A_FAxeCheckReady
//
//============================================================================
void A_FAxeCheckReady (AActor *actor)
{
player_t *player;
if (NULL == (player = actor->player))
{
return;
}
if (player->ReadyWeapon->Ammo1->Amount)
{
P_SetPsprite (player, ps_weapon, &AFWeapAxe::States[S_FAXEREADY_G]);
}
else
{
A_WeaponReady (actor);
}
}
//============================================================================
//
// A_FAxeCheckReadyG
//
//============================================================================
void A_FAxeCheckReadyG (AActor *actor)
{
player_t *player;
if (NULL == (player = actor->player))
{
return;
}
if (player->ReadyWeapon->Ammo1->Amount <= 0)
{
P_SetPsprite (player, ps_weapon, &AFWeapAxe::States[S_FAXEREADY]);
}
else
{
A_WeaponReady (actor);
}
}
//============================================================================
//
// A_FAxeCheckUp
//
//============================================================================
void A_FAxeCheckUp (AActor *actor)
{
player_t *player;
if (NULL == (player = actor->player))
{
return;
}
if (player->ReadyWeapon->Ammo1->Amount)
{
P_SetPsprite (player, ps_weapon, &AFWeapAxe::States[S_FAXEUP_G]);
}
else
{
A_Raise (actor);
}
}
//============================================================================
//
// A_FAxeCheckUpG
//
//============================================================================
void A_FAxeCheckUpG (AActor *actor)
{
player_t *player;
if (NULL == (player = actor->player))
{
return;
}
if (player->ReadyWeapon->Ammo1->Amount <= 0)
{
P_SetPsprite (player, ps_weapon, &AFWeapAxe::States[S_FAXEUP]);
}
else
{
A_Raise (actor);
}
}
//============================================================================
//
// A_FAxeCheckAtk
//
//============================================================================
void A_FAxeCheckAtk (AActor *actor)
{
player_t *player;
if (NULL == (player = actor->player))
{
return;
}
if (player->ReadyWeapon->Ammo1->Amount)
{
P_SetPsprite (player, ps_weapon, &AFWeapAxe::States[S_FAXEATK_G]);
}
}
//============================================================================
//
// A_FAxeAttack
//
//============================================================================
void A_FAxeAttack (AActor *actor)
{
angle_t angle;
fixed_t power;
int damage;
int slope;
int i;
int useMana;
player_t *player;
AWeapon *weapon;
const PClass *pufftype;
if (NULL == (player = actor->player))
{
return;
}
AActor *pmo=player->mo;
damage = 40+(pr_atk()&15);
damage += pr_atk()&7;
power = 0;
weapon = player->ReadyWeapon;
if (player->ReadyWeapon->Ammo1->Amount > 0)
{
damage <<= 1;
power = 6*FRACUNIT;
pufftype = RUNTIME_CLASS(AAxePuffGlow);
useMana = 1;
}
else
{
pufftype = RUNTIME_CLASS(AAxePuff);
useMana = 0;
}
for (i = 0; i < 16; i++)
{
angle = pmo->angle+i*(ANG45/16);
slope = P_AimLineAttack (pmo, angle, AXERANGE);
if (linetarget)
{
P_LineAttack (pmo, angle, AXERANGE, slope, damage, MOD_HIT, pufftype);
if (linetarget->flags3&MF3_ISMONSTER || linetarget->player)
{
P_ThrustMobj (linetarget, angle, power);
}
AdjustPlayerAngle (pmo);
useMana++;
goto axedone;
}
angle = pmo->angle-i*(ANG45/16);
slope = P_AimLineAttack (pmo, angle, AXERANGE);
if (linetarget)
{
P_LineAttack (pmo, angle, AXERANGE, slope, damage, MOD_HIT, pufftype);
if (linetarget->flags3&MF3_ISMONSTER)
{
P_ThrustMobj (linetarget, angle, power);
}
AdjustPlayerAngle (pmo);
useMana++;
goto axedone;
}
}
// didn't find any creatures, so try to strike any walls
pmo->special1 = 0;
angle = pmo->angle;
slope = P_AimLineAttack (pmo, angle, MELEERANGE);
P_LineAttack (pmo, angle, MELEERANGE, slope, damage, MOD_HIT, pufftype);
axedone:
if (useMana == 2)
{
AWeapon *weapon = player->ReadyWeapon;
if (weapon != NULL)
{
weapon->DepleteAmmo (weapon->bAltFire, false);
if ((weapon->Ammo1 == NULL || weapon->Ammo1->Amount == 0) &&
(!(weapon->WeaponFlags & WIF_PRIMARY_USES_BOTH) ||
weapon->Ammo2 == NULL || weapon->Ammo2->Amount == 0))
{
P_SetPsprite (player, ps_weapon, &AFWeapAxe::States[S_FAXEATK+5]);
}
}
}
return;
}
//===========================================================================
//
// P_BloodSplatter2
//
//===========================================================================
void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator)
{
PalEntry bloodcolor = (PalEntry)originator->GetClass()->Meta.GetMetaInt(AMETA_BloodColor);
if (cl_bloodtype <= 1)
{
AActor *mo;
x += ((pr_splat()-128)<<11);
y += ((pr_splat()-128)<<11);
mo = Spawn<AAxeBlood> (x, y, z);
mo->target = originator;
// colorize the blood!
if (bloodcolor != 0)
{
mo->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a);
}
}
if (cl_bloodtype >= 1)
{
P_DrawSplash2 (100, x, y, z, R_PointToAngle2 (0, 0, originator->x - x, originator->y - y), 2, bloodcolor);
}
}