Files
GTASource/game/weapons/FiringPattern.h
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

405 lines
10 KiB
C++

//
// weapons/firingpattern.h
//
// Copyright (C) 1999-2010 Rockstar North. All Rights Reserved.
//
#ifndef FIRING_PATTERN_H
#define FIRING_PATTERN_H
// Rage headers
#include "atl/array.h"
#include "atl/hashstring.h"
#include "parser/macros.h"
// Framework headers
#include "fwmaths/random.h"
#include "fwtl/pool.h"
#include "fwtl/regdrefs.h"
// Game headers
#include "Peds/Ped.h"
#include "Weapons/WeaponChannel.h"
class CPed;
class CPedDebugVisualiser;
////////////////////////////////////////////////////////////////////////////////
// CFiringPatternInfo
////////////////////////////////////////////////////////////////////////////////
class CFiringPatternInfo : public fwRefAwareBase
{
public:
#if __BANK
friend class CPedDebugVisualiser;
friend class CCombatTextDebugInfo;
#endif
// Construction
CFiringPatternInfo();
// Get the hash
u32 GetHash() const
{
return m_Name.GetHash();
}
s32 GetNumberOfBursts() const
{
weaponAssert(m_NumberOfBurstsMin <= m_NumberOfBurstsMax);
return fwRandom::GetRandomNumberInRange(m_NumberOfBurstsMin, m_NumberOfBurstsMax);
}
s32 GetNumberOfShotsPerBurst() const
{
weaponAssert(m_NumberOfShotsPerBurstMin <= m_NumberOfShotsPerBurstMax);
return fwRandom::GetRandomNumberInRange(m_NumberOfShotsPerBurstMin, m_NumberOfShotsPerBurstMax);
}
f32 GetTimeBetweenShots(f32 fMod) const
{
weaponAssert(m_TimeBetweenShotsMin <= m_TimeBetweenShotsMax);
return Max(fwRandom::GetRandomNumberInRange(m_TimeBetweenShotsMin, m_TimeBetweenShotsMax) * fMod, m_TimeBetweenShotsAbsoluteMin);
}
f32 GetTimeBetweenBursts(f32 fMod) const
{
weaponAssert(m_TimeBetweenBurstsMin <= m_TimeBetweenBurstsMax);
return Max(fwRandom::GetRandomNumberInRange(m_TimeBetweenBurstsMin, m_TimeBetweenBurstsMax) * fMod, m_TimeBetweenBurstsAbsoluteMin);
}
f32 GetTimeBeforeFiring() const
{
weaponAssert(m_TimeBeforeFiringMin <= m_TimeBeforeFiringMax);
return fwRandom::GetRandomNumberInRange(m_TimeBeforeFiringMin, m_TimeBeforeFiringMax);
}
bool GetBurstCooldownOnUnset() const { return m_BurstCooldownOnUnset; }
// Function to sort the array so we can use a binary search
static s32 PairSort(CFiringPatternInfo* const* a, CFiringPatternInfo* const* b) { return ((*a)->m_Name.GetHash() < (*b)->m_Name.GetHash() ? -1 : 1); }
#if !__FINAL
// Get the name from the metadata manager
const char* GetName() const { return m_Name.GetCStr(); }
#endif // !__FINAL
private:
//
// Members
//
atHashWithStringNotFinal m_Name;
s16 m_NumberOfBurstsMin;
s16 m_NumberOfBurstsMax;
s16 m_NumberOfShotsPerBurstMin;
s16 m_NumberOfShotsPerBurstMax;
f32 m_TimeBetweenShotsMin;
f32 m_TimeBetweenShotsMax;
f32 m_TimeBetweenShotsAbsoluteMin;
f32 m_TimeBetweenBurstsMin;
f32 m_TimeBetweenBurstsMax;
f32 m_TimeBetweenBurstsAbsoluteMin;
f32 m_TimeBeforeFiringMin;
f32 m_TimeBeforeFiringMax;
bool m_BurstCooldownOnUnset;
private:
// Not allowed to copy construct or assign
CFiringPatternInfo(const CFiringPatternInfo& other);
CFiringPatternInfo& operator=(const CFiringPatternInfo& other);
PAR_SIMPLE_PARSABLE;
};
////////////////////////////////////////////////////////////////////////////////
// CFiringPatternInfoManager
////////////////////////////////////////////////////////////////////////////////
class CFiringPatternInfoManager
{
public:
// Initialise
static void Init();
// Shutdown
static void Shutdown();
// Access to the firing pattern data
static const CFiringPatternInfo* GetInfo(u32 uNameHash)
{
if(uNameHash != 0)
{
s32 iLow = 0;
s32 iHigh = ms_Instance.m_InfoPtrs.GetCount()-1;
while(iLow <= iHigh)
{
s32 iMid = (iLow + iHigh) >> 1;
if(uNameHash == ms_Instance.m_InfoPtrs[iMid]->GetHash())
{
return ms_Instance.m_InfoPtrs[iMid];
}
else if (uNameHash < ms_Instance.m_InfoPtrs[iMid]->GetHash())
{
iHigh = iMid-1;
}
else
{
iLow = iMid+1;
}
}
weaponAssertf(0, "Firing pattern [%d] not found in data", uNameHash);
}
return NULL;
}
#if __BANK
// Add widgets
static void AddWidgets(bkBank& bank);
#endif // __BANK
private:
// Delete the data
static void Reset();
// Load the data
static void Load();
#if __BANK
// Save the data
static void Save();
#endif // __BANK
//
// Members
//
// The pattern storage
atArray<CFiringPatternInfo*> m_Infos;
// Pointers to infos, sorted
atArray<CFiringPatternInfo*> m_InfoPtrs;
// Static manager object
static CFiringPatternInfoManager ms_Instance;
PAR_SIMPLE_PARSABLE;
};
////////////////////////////////////////////////////////////////////////////////
// CFiringPattern
////////////////////////////////////////////////////////////////////////////////
class CFiringPattern
{
public:
#if __BANK
friend class CPedDebugVisualiser;
friend class CCombatTextDebugInfo;
#endif
CFiringPattern();
CFiringPattern(const CFiringPattern& other);
// Set the active firing pattern - if the firing pattern is new, the data will be updated
void SetFiringPattern(u32 uFiringPatternHash, bool bForceReset = false);
u32 GetFiringPatternHash() { return m_uFiringPatternHash; }
//
// Processing
//
// Should we process the firing pattern?
bool ShouldProcess(const CPed& ped) const;
// Should be called every frame and before any other member functions are called
void PreProcess(const CPed& ped);
// Should be called every frame and after all member functions are called
void PostProcess(float fTimeStep);
// Called when the weapon has been fired
void ProcessFired();
// Called when the weapon has finished its burst
void ProcessBurstFinished();
//
// Querying
//
#if __BANK
const CFiringPatternInfo* GetFiringPatternInfo() const { return m_pFiringPatternInfo; }
#endif // __BANK
// Check if we can fire at all - do we have any shots/bursts remaining?
bool WantsToFire() const
{
if((m_iNumberOfBursts == -1 || m_iNumberOfBursts > 0) && (m_iNumberOfShotsPerBurst == -1 || m_iNumberOfShotsPerBurst > 0))
{
return true;
}
return false;
}
// Check if we are ready to fire - have the timers ticked down?
bool ReadyToFire() const
{
if(m_fTimeToDelayFiring <= 0.0f && m_fTimeTillNextShot <= 0.0f && m_fTimeTillNextBurst <= 0.0f && (!m_pFiringPatternInfo || m_uBurstCooldownOnUnsetPatternHash != m_pFiringPatternInfo->GetHash() || m_fBurstCooldownOnUnsetTimer <= 0.0f))
{
return true;
}
return false;
}
// Check if the burst is finished
bool IsBurstFinished() const { return m_iNumberOfShotsPerBurst == 0; }
bool HasBurstFinishedThisFrame() const { return m_bBurstFinishedThisFrame; }
bool HasBurstCooldownOnUnset() const { return m_pFiringPatternInfo ? m_pFiringPatternInfo->GetBurstCooldownOnUnset() : false; }
//
// Overriding
//
// Change m_fTimeTillNextShotModifier
void SetTimeTillNextShotModifier(f32 fTimeTillNextShotModifier) { m_fTimeTillNextShotModifier = fTimeTillNextShotModifier; }
// Get m_fTimeTillNextShotModifier
f32 GetTimeTillNextShotModifier() const { return m_fTimeTillNextShotModifier; }
f32 GetTimeTillNextBurst() const { return m_fTimeTillNextBurst; }
// Change m_fTimeTillNextBurstModifier
void SetTimeTillNextBurstModifier(f32 fTimeTillNextBurstModifier) { m_fTimeTillNextBurstModifier = fTimeTillNextBurstModifier; }
// Get m_fTimeTillNextBurstModifier
f32 GetTimeTillNextBurstModifier() const { return m_fTimeTillNextBurstModifier; }
// Force the time until next burst to be expired
void ResetTimeUntilNextBurst() { m_fTimeTillNextBurst = 0.0f; }
private:
// Reset the members
void Reset();
//
// Members
//
// Our set firing pattern
u32 m_uFiringPatternHash;
// The weapon our firing pattern is for
atHashWithStringNotFinal m_EquippedWeaponHash;
// Our current firing pattern data
fwRegdRef<const CFiringPatternInfo> m_pFiringPatternInfo;
// Number of bursts to perform
s32 m_iNumberOfBursts;
// Number of shots per burst
s32 m_iNumberOfShotsPerBurst;
// The time before allowing firing
f32 m_fTimeToDelayFiring;
// The time between shots
f32 m_fTimeTillNextShot;
// A modifier that can scale the time between shots
f32 m_fTimeTillNextShotModifier;
// The time between bursts
f32 m_fTimeTillNextBurst;
// A modifier that can scale the time between bursts
f32 m_fTimeTillNextBurstModifier;
// The separate timer used for the firing pattern we've designated as forced
f32 m_fBurstCooldownOnUnsetTimer;
// The hash of the firing pattern we're forcing a burst cooldown on
u32 m_uBurstCooldownOnUnsetPatternHash;
// Flags
bool m_bForceReset : 1;
bool m_bBurstFinishedThisFrame : 1;
//
// Statics
//
static const s32 INFINITE_NUMBER_OF_BURSTS;
static const s32 INFINITE_NUMBER_OF_SHOTS_PER_BURST;
static const s32 DEFAULT_NUMBER_OF_BURSTS;
static const s32 DEFAULT_NUMBER_OF_SHOTS_PER_BURST;
static const f32 DEFAULT_TIME_TO_DELAY_FIRING;
static const f32 DEFAULT_TIME_TILL_NEXT_SHOT;
static const f32 DEFAULT_TIME_TILL_NEXT_SHOT_MOD;
static const f32 DEFAULT_TIME_TILL_NEXT_BURST;
static const f32 DEFAULT_TIME_TILL_NEXT_BURST_MOD;
};
////////////////////////////////////////////////////////////////////////////////
inline bool CFiringPattern::ShouldProcess(const CPed& ped) const
{
if(ped.GetWeaponManager())
{
const CWeaponInfo* pEquippedWeaponInfo = ped.GetWeaponManager()->GetEquippedWeaponInfo();
if(pEquippedWeaponInfo && (pEquippedWeaponInfo->GetIsGunOrCanBeFiredLikeGun() || pEquippedWeaponInfo->GetIsVehicleWeapon()))
{
return true;
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
inline void CFiringPattern::PostProcess(float fTimeStep)
{
// Decrement timers
m_fTimeToDelayFiring -= fTimeStep;
m_fTimeTillNextShot -= fTimeStep;
m_fTimeTillNextBurst -= fTimeStep;
m_fBurstCooldownOnUnsetTimer -= fTimeStep;
// Clear our burst fire finished flag
m_bBurstFinishedThisFrame = false;
// Reset the forced cooldown hash if our timer has expired
if (m_fBurstCooldownOnUnsetTimer < 0.0f)
{
m_uBurstCooldownOnUnsetPatternHash = 0;
}
}
////////////////////////////////////////////////////////////////////////////////
inline void CFiringPattern::Reset()
{
m_iNumberOfBursts = DEFAULT_NUMBER_OF_BURSTS;
m_iNumberOfShotsPerBurst = DEFAULT_NUMBER_OF_SHOTS_PER_BURST;
m_fTimeToDelayFiring = DEFAULT_TIME_TO_DELAY_FIRING;
m_fTimeTillNextShot = DEFAULT_TIME_TILL_NEXT_SHOT;
m_fTimeTillNextBurst = DEFAULT_TIME_TILL_NEXT_BURST;
m_bBurstFinishedThisFrame = false;
}
////////////////////////////////////////////////////////////////////////////////
#endif // FIRING_PATTERN_H