qzdoom/src/g_hexen/a_fighterhammer.cpp
Christoph Oelckers 063c85b157 - Fixed: The global WeaponSection string was never freed. It has been replaced
with an FString now.
- Fixed: The music strings in the default level info were never freed and
  caused memory leaks when used repeatedly.
- Fixed: The intermusic string in the level info was never freed.
- Fixed: The default fire obituary should only be printed if the damage
  came from the environment. If it comes from a monster the monster specific
  obituary should be used instead.
- Added custom damage types from the floating point test release.
- Changed Pain Elemental's massacre check. Now A_PainDie checks for the damage 
  type and doesn't spawn anything if it is NAME_Massacre. A_PainDie can also 
  be used by other actors so a more generalized approach is needed than hard
  coding it into the Pain Elemental.
- Converted a few of Doom's monsters to DECORATE because I couldn't test the
  first version of the custom state code with the corpses inheriting from them.
- Added custom states from last year's floating point test release and fixed
  some bugs I found in that code. Unfortunately it wasn't all salvageable
  and it was easier to recreate some parts from scratch.



SVN r368 (trunk)
2006-10-31 14:53:21 +00:00

286 lines
8.7 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"
const fixed_t HAMMER_RANGE = MELEERANGE+MELEERANGE/2;
static FRandom pr_atk ("FHammerAtk");
extern void AdjustPlayerAngle (AActor *pmo);
void A_FHammerAttack (AActor *actor);
void A_FHammerThrow (AActor *actor);
void A_HammerSound (AActor *);
void A_BeAdditive (AActor *);
// The Fighter's Hammer -----------------------------------------------------
class AFWeapHammer : public AFighterWeapon
{
DECLARE_ACTOR (AFWeapHammer, AFighterWeapon)
};
FState AFWeapHammer::States[] =
{
#define S_HAMM 0
S_NORMAL (WFHM, 'A', -1, NULL , NULL),
#define S_FHAMMERREADY (S_HAMM+1)
S_NORMAL (FHMR, 'A', 1, A_WeaponReady , &States[S_FHAMMERREADY]),
#define S_FHAMMERDOWN (S_FHAMMERREADY+1)
S_NORMAL (FHMR, 'A', 1, A_Lower , &States[S_FHAMMERDOWN]),
#define S_FHAMMERUP (S_FHAMMERDOWN+1)
S_NORMAL (FHMR, 'A', 1, A_Raise , &States[S_FHAMMERUP]),
#define S_FHAMMERATK (S_FHAMMERUP+1)
S_NORMAL2 (FHMR, 'B', 6, NULL , &States[S_FHAMMERATK+1], 5, 0),
S_NORMAL2 (FHMR, 'C', 3, A_FHammerAttack , &States[S_FHAMMERATK+2], 5, 0),
S_NORMAL2 (FHMR, 'D', 3, NULL , &States[S_FHAMMERATK+3], 5, 0),
S_NORMAL2 (FHMR, 'E', 2, NULL , &States[S_FHAMMERATK+4], 5, 0),
S_NORMAL2 (FHMR, 'E', 10, A_FHammerThrow , &States[S_FHAMMERATK+5], 5, 150),
S_NORMAL2 (FHMR, 'A', 1, NULL , &States[S_FHAMMERATK+6], 0, 60),
S_NORMAL2 (FHMR, 'A', 1, NULL , &States[S_FHAMMERATK+7], 0, 55),
S_NORMAL2 (FHMR, 'A', 1, NULL , &States[S_FHAMMERATK+8], 0, 50),
S_NORMAL2 (FHMR, 'A', 1, NULL , &States[S_FHAMMERATK+9], 0, 45),
S_NORMAL2 (FHMR, 'A', 1, NULL , &States[S_FHAMMERATK+10], 0, 40),
S_NORMAL2 (FHMR, 'A', 1, NULL , &States[S_FHAMMERATK+11], 0, 35),
S_NORMAL (FHMR, 'A', 1, NULL , &States[S_FHAMMERREADY]),
};
IMPLEMENT_ACTOR (AFWeapHammer, Hexen, 123, 28)
PROP_Flags (MF_SPECIAL)
PROP_Flags5 (MF5_BLOODSPLATTER)
PROP_SpawnState (S_HAMM)
PROP_Weapon_SelectionOrder (900)
PROP_Weapon_Flags (WIF_AMMO_OPTIONAL|WIF_BOT_MELEE)
PROP_Weapon_AmmoUse1 (3)
PROP_Weapon_AmmoGive1 (25)
PROP_Weapon_UpState (S_FHAMMERUP)
PROP_Weapon_DownState (S_FHAMMERDOWN)
PROP_Weapon_ReadyState (S_FHAMMERREADY)
PROP_Weapon_AtkState (S_FHAMMERATK)
PROP_Weapon_HoldAtkState (S_FHAMMERATK)
PROP_Weapon_Kickback (150)
PROP_Weapon_YAdjust (0-10)
PROP_Weapon_MoveCombatDist (22000000)
PROP_Weapon_AmmoType1 ("Mana2")
PROP_Weapon_ProjectileType ("HammerMissile")
PROP_Inventory_PickupMessage("$TXT_WEAPON_F3")
END_DEFAULTS
// Hammer Missile -----------------------------------------------------------
class AHammerMissile : public AActor
{
DECLARE_ACTOR (AHammerMissile, AActor)
public:
void GetExplodeParms (int &damage, int &dist, bool &hurtSource);
};
FState AHammerMissile::States[] =
{
#define S_HAMMER_MISSILE_1 0
S_BRIGHT (FHFX, 'A', 2, NULL , &States[S_HAMMER_MISSILE_1+1]),
S_BRIGHT (FHFX, 'B', 2, A_HammerSound , &States[S_HAMMER_MISSILE_1+2]),
S_BRIGHT (FHFX, 'C', 2, NULL , &States[S_HAMMER_MISSILE_1+3]),
S_BRIGHT (FHFX, 'D', 2, NULL , &States[S_HAMMER_MISSILE_1+4]),
S_BRIGHT (FHFX, 'E', 2, NULL , &States[S_HAMMER_MISSILE_1+5]),
S_BRIGHT (FHFX, 'F', 2, NULL , &States[S_HAMMER_MISSILE_1+6]),
S_BRIGHT (FHFX, 'G', 2, NULL , &States[S_HAMMER_MISSILE_1+7]),
S_BRIGHT (FHFX, 'H', 2, NULL , &States[S_HAMMER_MISSILE_1]),
#define S_HAMMER_MISSILE_X1 (S_HAMMER_MISSILE_1+8)
S_BRIGHT (FHFX, 'I', 3, A_BeAdditive , &States[S_HAMMER_MISSILE_X1+1]),
S_BRIGHT (FHFX, 'J', 3, NULL , &States[S_HAMMER_MISSILE_X1+2]),
S_BRIGHT (FHFX, 'K', 3, A_Explode , &States[S_HAMMER_MISSILE_X1+3]),
S_BRIGHT (FHFX, 'L', 3, NULL , &States[S_HAMMER_MISSILE_X1+4]),
S_BRIGHT (FHFX, 'M', 3, NULL , &States[S_HAMMER_MISSILE_X1+5]),
S_NORMAL (FHFX, 'N', 3, NULL , &States[S_HAMMER_MISSILE_X1+6]),
S_BRIGHT (FHFX, 'O', 3, NULL , &States[S_HAMMER_MISSILE_X1+7]),
S_BRIGHT (FHFX, 'P', 3, NULL , &States[S_HAMMER_MISSILE_X1+8]),
S_BRIGHT (FHFX, 'Q', 3, NULL , &States[S_HAMMER_MISSILE_X1+9]),
S_BRIGHT (FHFX, 'R', 3, NULL , NULL),
};
IMPLEMENT_ACTOR (AHammerMissile, Hexen, -1, 0)
PROP_SpeedFixed (25)
PROP_RadiusFixed (14)
PROP_HeightFixed (20)
PROP_Damage (10)
PROP_DamageType (NAME_Fire)
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE)
PROP_Flags2 (MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS)
PROP_SpawnState (S_HAMMER_MISSILE_1)
PROP_DeathState (S_HAMMER_MISSILE_X1)
PROP_DeathSound ("FighterHammerExplode")
END_DEFAULTS
void AHammerMissile::GetExplodeParms (int &damage, int &dist, bool &hurtSource)
{
damage = 128;
hurtSource = false;
}
// Hammer Puff (also used by fist) ------------------------------------------
FState AHammerPuff::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 (AHammerPuff, 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 ("FighterHammerHitThing")
PROP_AttackSound ("FighterHammerHitWall")
PROP_ActiveSound ("FighterHammerMiss")
END_DEFAULTS
void AHammerPuff::BeginPlay ()
{
Super::BeginPlay ();
momz = FRACUNIT*8/10;
}
//============================================================================
//
// A_FHammerAttack
//
//============================================================================
void A_FHammerAttack (AActor *actor)
{
angle_t angle;
int damage;
fixed_t power;
int slope;
int i;
player_t *player;
if (NULL == (player = actor->player))
{
return;
}
AActor *pmo=player->mo;
damage = 60+(pr_atk()&63);
power = 10*FRACUNIT;
for (i = 0; i < 16; i++)
{
angle = pmo->angle + i*(ANG45/32);
slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE);
if (linetarget)
{
P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff));
AdjustPlayerAngle(pmo);
if (linetarget->flags3&MF3_ISMONSTER || linetarget->player)
{
P_ThrustMobj (linetarget, angle, power);
}
pmo->special1 = false; // Don't throw a hammer
goto hammerdone;
}
angle = pmo->angle-i*(ANG45/32);
slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
if(linetarget)
{
P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff));
AdjustPlayerAngle(pmo);
if (linetarget->flags3&MF3_ISMONSTER || linetarget->player)
{
P_ThrustMobj(linetarget, angle, power);
}
pmo->special1 = false; // Don't throw a hammer
goto hammerdone;
}
}
// didn't find any targets in meleerange, so set to throw out a hammer
PuffSpawned = NULL;
angle = pmo->angle;
slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE);
P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff));
if (PuffSpawned)
{
pmo->special1 = false;
}
else
{
pmo->special1 = true;
}
hammerdone:
// Don't spawn a hammer if the player doesn't have enough mana
if (player->ReadyWeapon == NULL ||
!player->ReadyWeapon->CheckAmmo (player->ReadyWeapon->bAltFire ?
AWeapon::AltFire : AWeapon::PrimaryFire, false, true))
{
pmo->special1 = false;
}
return;
}
//============================================================================
//
// A_FHammerThrow
//
//============================================================================
void A_FHammerThrow (AActor *actor)
{
AActor *mo;
player_t *player;
if (NULL == (player = actor->player))
{
return;
}
if (!player->mo->special1)
{
return;
}
AWeapon *weapon = player->ReadyWeapon;
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire, false))
return;
}
mo = P_SpawnPlayerMissile (player->mo, RUNTIME_CLASS(AHammerMissile));
if (mo)
{
mo->special1 = 0;
}
}
//============================================================================
//
// A_HammerSound
//
//============================================================================
void A_HammerSound (AActor *actor)
{
S_Sound (actor, CHAN_BODY, "FighterHammerContinuous", 1, ATTN_NORM);
}