Files
GTASource/game/Peds/PedHelmetComponent.cpp
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

953 lines
35 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
// FILE : PedHelmetComponent.cpp
// PURPOSE : A class to hold the mobile phone model/position data for a ped/player
// Pulled out of CPed and CPedPlayer classes.
// AUTHOR : Mike Currington.
// CREATED : 28/10/10
/////////////////////////////////////////////////////////////////////////////////
#include "Peds/PedHelmetComponent.h"
// rage includes
// game includes
#include "Camera/CamInterface.h"
#include "Camera/Cinematic/CinematicDirector.h"
#include "Peds/Ped.h"
#include "peds/ped_channel.h"
#include "scene/ExtraMetadataMgr.h"
#include "vehicles/Metadata/VehicleSeatInfo.h"
#include "bank/bank.h"
using namespace rage;
AI_OPTIMISATIONS()
//
// Constants
const Vector3 HELMET_POS_OFFSET(0.0f, 0.125f, 0.0f);
const Vector3 HELMET_ROT_OFFSET(-1.57079637f, 0.0f, 0.0f);
//
// Statics
atMap<u32, atArray<int> > CPedHelmetComponent::sm_VehicleHashToHelmetPropIndex;
#if __BANK
atHashString CPedHelmetComponent::sm_uVehicleHashString;
int CPedHelmetComponent::sm_iHelmetPropIndex = -1;
#endif // __BANK
CPedHelmetComponent::CPedHelmetComponent(CPed * pParentPed) :
m_pParentPed(pParentPed),
m_fHelmetInactiveDeletionTimer(0.0f),
m_nHelmetVisorUpPropIndex(-1),
m_nHelmetVisorDownPropIndex(-1),
m_bIsVisorUp(false),
m_bSupportsVisors(false),
m_nHelmetPropIndex(-1),
m_nHelmetTexIndex(-1),
m_bUseOverridenHelmetPropIndexOnBiycles(true),
m_iMostRecentVehicleType(-1),
m_nStoredHatPropIdx(-1),
m_nStoredHatTexIdx(-1),
m_nPreLoadedTexture(-1),
m_DesiredPropFlag(PV_FLAG_NONE),
m_CurrentPropFlag(PV_FLAG_NONE),
m_NetworkHelmetIndex(-1),
m_NetworkTextureIndex(-1),
m_bPreLoadingProp(false),
m_bPendingHatRestore(false),
m_nHelmetPropIndexFromHashMap(-1)
{
}
void CPedHelmetComponent::Update(void)
{
// we've been asked to restore a stored hat at a later point by TaskTakeOffHelmet that was aborted.
// The helmet was a "delayed delete" resource so couldn't be deleted while TaskTakeOffHelmet was
// still running and there were no other slots to use (ped has watch, helmet and glasses on = 3 slots)
if(m_pParentPed && m_bPendingHatRestore)
{
RestoreOldHat(true);
if (GetStoredHatPropIndex() == -1 && GetStoredHatTexIndex() == -1)
{
m_bPendingHatRestore = false;
}
}
// B*2214377: Cache last vehicle type. Used in CPedHelmetComponent::GetHelmetPropIndex so we know if we were last on a bicycle (needed for taking off the right helmet).
if (m_pParentPed && m_pParentPed->GetIsInVehicle())
{
CVehicle *pVehicle = m_pParentPed->GetVehiclePedInside();
if (pVehicle)
{
m_iMostRecentVehicleType = (int)pVehicle->GetVehicleType();
}
}
}
void CPedHelmetComponent::UpdateInactive(const bool okToRemoveImmediately)
{
m_fHelmetInactiveDeletionTimer += fwTimer::GetTimeStep();
fwClipSet* pClipSet = fwClipSetManager::GetClipSet(CLIP_SET_TAKE_OFF_HELMET);
if (pClipSet)
pClipSet->Request_DEPRECATED();
if(okToRemoveImmediately || m_fHelmetInactiveDeletionTimer > 5.0f)
{
pedDebugf1("CPedHelmetComponent[%s][%p] - UpdateInactive - removing helmet", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed);
// Delete the helmet if we are not on screen or have had it for more than a certain time
DisableHelmet();
}
}
bool CPedHelmetComponent::IsHelmetEnabled() const
{
if (m_pParentPed->IsNetworkClone() && m_NetworkHelmetIndex == -1)
{
return false;
}
if(m_pParentPed->GetPedConfigFlag( CPED_CONFIG_FLAG_HasHelmet ))
{
return true;
}
return false;
}
bool CPedHelmetComponent::HasPilotHelmetEquippedInAircraftInFPS(bool bTreatBonnetCameraAsFirstPerson) const
{
#if FPS_MODE_SUPPORTED
const bool c_IsValidCamera = ( bTreatBonnetCameraAsFirstPerson && camInterface::GetCinematicDirector().IsRenderingCinematicMountedCamera()) ||
(!bTreatBonnetCameraAsFirstPerson && m_pParentPed->IsInFirstPersonVehicleCamera());
const bool c_HasPilotHelmetOrIsMP = ((CPedPropsMgr::GetPedPropIdx(m_pParentPed, ANCHOR_HEAD) != -1 && CPedPropsMgr::DoesPedHavePropOrComponentWithFlagSet(*m_pParentPed, PV_FLAG_PILOT_HELMET)) || NetworkInterface::IsGameInProgress());
if (c_IsValidCamera
&& !m_pParentPed->GetPedResetFlag(CPED_RESET_FLAG_PuttingOnHelmet) && !m_pParentPed->GetPedResetFlag(CPED_RESET_FLAG_DisableHelmetCullFPS)
&& c_HasPilotHelmetOrIsMP
&& m_pParentPed->GetIsInVehicle() && m_pParentPed->GetIsDrivingVehicle())
{
CVehicle *pVehicle = static_cast<CVehicle*>(m_pParentPed->GetVehiclePedInside());
if (pVehicle && pVehicle->GetIsAircraft())
{
return true;
}
}
#endif
return false;
}
bool CPedHelmetComponent::EnableHelmet(eAnchorPoints anchorOverrideID, bool bTakingOff)
{
pedDebugf1("CPedHelmetComponent[%s][%p] - EnableHelmet - Enable helmet requested", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed);
if(m_pParentPed->CanPutOnHelmet() || bTakingOff )
{
//Nothing has set the desired helmet type so fall back to default, i.e. motorbike helmet.
if(m_DesiredPropFlag == PV_FLAG_NONE)
{
CVehicle* pVehicle = m_pParentPed->GetVehiclePedInside();
if(pVehicle && pVehicle->GetVehicleType() == VEHICLE_TYPE_BICYCLE)
{
m_DesiredPropFlag = PV_FLAG_RANDOM_HELMET;
}
else if (pVehicle && (pVehicle->GetVehicleType() == VEHICLE_TYPE_HELI || pVehicle->GetVehicleType() == VEHICLE_TYPE_PLANE))
{
if (ShouldUsePilotFlightHelmet(m_pParentPed))
{
m_DesiredPropFlag = PV_FLAG_PILOT_HELMET;
}
else
{
m_DesiredPropFlag = PV_FLAG_FLIGHT_HELMET;
}
}
else
{
m_DesiredPropFlag = PV_FLAG_DEFAULT_HELMET;
}
}
s32 nHelmetIndices = GetHelmetPropIndex(m_DesiredPropFlag);
if(nHelmetIndices >= 0)
{
// backup any current head prop (hat), if we don't already have a helmet (we'll be called multiple times) because we are about to enable it
if(!m_pParentPed->GetPedConfigFlag( CPED_CONFIG_FLAG_HasHelmet ) && (GetStoredHatPropIndex() == -1 || GetStoredHatTexIndex() == -1))
{
int nHatPropIdx = CPedPropsMgr::GetPedPropIdx(m_pParentPed, ANCHOR_HEAD);
if(nHatPropIdx != -1)
{
SetStoredHatIndices(nHatPropIdx, CPedPropsMgr::GetPedPropTexIdx(m_pParentPed, ANCHOR_HEAD));
pedDebugf1("CPedHelmetComponent[%s][%p] - EnableHelmet - Storing restore hat prop:%i tex:%i", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed, nHatPropIdx, CPedPropsMgr::GetPedPropTexIdx(m_pParentPed, ANCHOR_HEAD));
}
}
//Vector3 vPosOffset;
//Quaternion qRotOffset;
//if(anchorOverrideID != ANCHOR_NONE)
//{
// m_pParentPed->GetBikeHelmetOffsets(vPosOffset, qRotOffset);
//}
int nTextureIndex = GetHelmetTexIndex(nHelmetIndices);
if(CPedPropsMgr::GetNumActiveProps(m_pParentPed) < MAX_PROPS_PER_PED || CPedPropsMgr::GetPedPropIdx(m_pParentPed, ANCHOR_HEAD) != -1)
{
CPedPropsMgr::SetPedProp(m_pParentPed, ANCHOR_HEAD, nHelmetIndices, nTextureIndex, anchorOverrideID, NULL, NULL);
pedDebugf1("CPedHelmetComponent[%s][%p] - EnableHelmet - Creating helmet, prop:%i tex:%i anchorOverrideID:%i", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed, nHelmetIndices, nTextureIndex, anchorOverrideID);
m_pParentPed->SetPedConfigFlag( CPED_CONFIG_FLAG_HasHelmet, true );
m_CurrentPropFlag = m_DesiredPropFlag;
m_fHelmetInactiveDeletionTimer = 0.0f;
// Set the synced values so the owner will inform the clone what we need....
if(NetworkInterface::IsGameInProgress())
{
if(!m_pParentPed->IsNetworkClone())
{
m_NetworkHelmetIndex = nHelmetIndices;
m_NetworkTextureIndex = nTextureIndex;
}
}
}
}
}
return IsHelmetEnabled();
}
bool CPedHelmetComponent::IsHelmetInHand()
{
if(m_pParentPed->GetPedConfigFlag( CPED_CONFIG_FLAG_HasHelmet ))
{
s32 nHelmetIndex = GetHelmetPropIndex(m_CurrentPropFlag);
if(nHelmetIndex >= 0)
{
if(CPedPropsMgr::GetPedPropIdx(m_pParentPed, ANCHOR_HEAD) == nHelmetIndex)
{
if ( CPedPropsMgr::GetPedPropActualAnchorPoint(m_pParentPed,ANCHOR_HEAD) == ANCHOR_PH_L_HAND)
{
return true;
}
}
}
}
return false;
}
void CPedHelmetComponent::DisableHelmet(bool bDropHelmet, const Vector3* impulse, bool bSafeRestore)
{
pedDebugf1("CPedHelmetComponent[%p][%s] - DisableHelmet - Disable helmet requested, drop:%i", m_pParentPed, m_pParentPed ? m_pParentPed->GetModelName() : "NULL", bDropHelmet);
if(IsHelmetEnabled())
{
if(bDropHelmet)
{
CPedPropsMgr::KnockOffProps(m_pParentPed, false, false, false, true, impulse);
pedDebugf1("CPedHelmetComponent[%s][%p] - DisableHelmet - KnockOffProps", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed);
}
else
{
CPedPropsMgr::ClearPedProp(m_pParentPed, ANCHOR_HEAD);
pedDebugf1("CPedHelmetComponent[%s][%p] - DisableHelmet - ClearPedProp", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed);
}
// restore any previously worn hat
RestoreOldHat(bSafeRestore);
}
m_fHelmetInactiveDeletionTimer = 0.0f;
}
void CPedHelmetComponent::RestoreOldHat(bool bSafeRestore)
{
if (CPedPropsMgr::GetPedPropIdx(m_pParentPed, ANCHOR_HEAD) != GetStoredHatPropIndex() ||
CPedPropsMgr::GetPedPropTexIdx(m_pParentPed, ANCHOR_HEAD) != GetStoredHatTexIndex())
{
if ((GetStoredHatPropIndex() != -1 && GetStoredHatTexIndex() != -1) &&
(!bSafeRestore ||
CPedPropsMgr::GetNumActiveProps(m_pParentPed) < MAX_PROPS_PER_PED || // We can for sure put on old hat in a free slot
!CPedPropsMgr::IsPedPropDelayedDelete(m_pParentPed, ANCHOR_HEAD))) // We cannot override the hat slot due to delayed delete
{
CPedPropsMgr::SetPedProp(m_pParentPed, ANCHOR_HEAD, GetStoredHatPropIndex(), GetStoredHatTexIndex(), ANCHOR_NONE, NULL, NULL);
pedDebugf1("CPedHelmetComponent[%s][%p] - DisableHelmet - Restoring hat prop:%i tex:%i", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed, GetStoredHatPropIndex(), GetStoredHatTexIndex());
}
}
if (!bSafeRestore ||
(CPedPropsMgr::GetPedPropIdx(m_pParentPed, ANCHOR_HEAD) == GetStoredHatPropIndex() &&
CPedPropsMgr::GetPedPropTexIdx(m_pParentPed, ANCHOR_HEAD) == GetStoredHatTexIndex()))
{
pedDebugf1("CPedHelmetComponent[%s][%p] - DisableHelmet - RestoreOldHat : Clearing ped helmet", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed);
m_pParentPed->SetPedConfigFlag( CPED_CONFIG_FLAG_HelmetHasBeenShot, false );
m_pParentPed->ResetNumArmouredHelmetHits();
m_pParentPed->SetPedConfigFlag( CPED_CONFIG_FLAG_HasHelmet, false );
m_CurrentPropFlag = PV_FLAG_NONE;
m_DesiredPropFlag = PV_FLAG_NONE;
SetStoredHatIndices(-1, -1);
// wipe the flags - do this on the clone too...
if(NetworkInterface::IsGameInProgress())
{
m_NetworkHelmetIndex = -1;
m_NetworkTextureIndex = -1;
}
}
}
void CPedHelmetComponent::SetHelmetTexIndex(int nHelmetTexIndex, bool bScriptGiveHelmet)
{
m_nHelmetTexIndex = -1;
if(nHelmetTexIndex >= 0)
{
//B*2872969 - we shouldnt be setting texture if prop ID was not setup before hand, because it doesnt make sense otherwise.
s32 nPropIndices = -1;
if (NetworkInterface::IsGameInProgress() && !bScriptGiveHelmet)
{
nPropIndices = m_nHelmetPropIndex;
}
else
{
// Gonna keep the old behaviour for SP and when this is coming from GIVE_PED_HELMET. This will return random prop id from desired archetype.
// I don't think it's actually working like script expect it to, but don't want to be changing the behaviour at this point in the project.
nPropIndices = GetHelmetPropIndex(m_DesiredPropFlag);
}
if(aiVerifyf(nPropIndices >= 0, "Trying to set helmet texture when prop index is not setup, nPropIndices - %i; bScriptGiveHelmet - %s", nPropIndices, bScriptGiveHelmet ? "true":"false"))
{
Assertf(nHelmetTexIndex >= 0 && nHelmetTexIndex < CPedPropsMgr::GetMaxNumPropsTex(m_pParentPed, ANCHOR_HEAD, nPropIndices),
"Invalid texture index[%i] attempting to be used when putting on a helmet Ped[%s], p_head Index:[%i]",nHelmetTexIndex, m_pParentPed->GetModelName(), nPropIndices );
if(nHelmetTexIndex >= 0 && nHelmetTexIndex < CPedPropsMgr::GetMaxNumPropsTex(m_pParentPed, ANCHOR_HEAD, nPropIndices))
{
m_nHelmetTexIndex = nHelmetTexIndex;
pedDebugf1("CPedHelmetComponent[%s][%p] - SetHelmetTexIndex - Set helmet override texture id tex:%i", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed, m_nHelmetTexIndex);
}
}
}
}
void CPedHelmetComponent::SetHelmetPropIndex(int nHelmetPropIndex, bool bIncludeBicycles)
{
m_nHelmetPropIndex = -1;
if(nHelmetPropIndex >= 0)
{
Assertf(nHelmetPropIndex < (int)CPedPropsMgr::GetMaxNumProps(m_pParentPed, ANCHOR_HEAD), "Invalid prop p_head index:[%i] being set on ped[%s]", nHelmetPropIndex, m_pParentPed->GetModelName() );
if(nHelmetPropIndex < (int)CPedPropsMgr::GetMaxNumProps(m_pParentPed, ANCHOR_HEAD))
{
m_nHelmetPropIndex = nHelmetPropIndex;
m_bUseOverridenHelmetPropIndexOnBiycles = bIncludeBicycles;
pedDebugf1("CPedHelmetComponent[%s][%p] - SetHelmetPropIndex - Set helmet override prop id prop:%i", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed, m_nHelmetPropIndex);
}
}
}
void CPedHelmetComponent::SetVisorPropIndices(bool bSupportsVisors, bool bVisorUp, s32 HelmetVisorUpPropId, s32 HelmetVisorDownPropId)
{
pedDebugf1("CPedHelmetComponent[%s][%p] - SetVisorPropIndices: SupportsVisors - %s; IsVisorUp new - %s; VisorUp id old - %i, new - %i; VisorDown old - %i, new - %i", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed, bSupportsVisors ? "true":"false", bVisorUp ? "true":"false", m_nHelmetVisorUpPropIndex, HelmetVisorUpPropId, m_nHelmetVisorDownPropIndex, HelmetVisorDownPropId);
m_bSupportsVisors = bSupportsVisors;
m_bIsVisorUp = bVisorUp;
m_nHelmetVisorUpPropIndex = HelmetVisorUpPropId;
m_nHelmetVisorDownPropIndex = HelmetVisorDownPropId;
}
void CPedHelmetComponent::SetPropFlag(ePedCompFlags propflag)
{
Assertf(propflag == PV_FLAG_NONE || GetHelmetPropIndex(propflag) >= 0, "Attempting to set the desired helmet type but ped (%s) doesn't any prop set up with this flag\n", m_pParentPed->GetModelName());
m_DesiredPropFlag = propflag;
}
bool CPedHelmetComponent::HasHelmetForVehicle(const CVehicle* pVehicle) const
{
if(pVehicle)
{
if(pVehicle->GetVehicleType() == VEHICLE_TYPE_BICYCLE)
{
return HasHelmetOfType(PV_FLAG_RANDOM_HELMET);
}
else if(pVehicle->GetVehicleType() == VEHICLE_TYPE_BIKE || pVehicle->GetVehicleType() == VEHICLE_TYPE_QUADBIKE || pVehicle->InheritsFromAmphibiousQuadBike())
{
return HasHelmetOfType(PV_FLAG_DEFAULT_HELMET);
}
else if (pVehicle->GetVehicleType() == VEHICLE_TYPE_HELI || pVehicle->GetVehicleType() == VEHICLE_TYPE_PLANE)
{
return HasHelmetOfType(PV_FLAG_FLIGHT_HELMET);
}
Assertf(0, "CPedHelmetComponent::HasHelmetForVehicle - Vehicle:%s currently isn't support", pVehicle->GetModelName() );
}
return false;
}
bool CPedHelmetComponent::IsAlreadyWearingAHelmetProp(const CVehicle* pVehicle) const
{
if(pVehicle)
{
ePedCompFlags propFlag = PV_FLAG_DEFAULT_HELMET;
if(pVehicle->GetVehicleType() == VEHICLE_TYPE_BICYCLE)
{
propFlag = PV_FLAG_RANDOM_HELMET;
}
else if (pVehicle->GetVehicleType() == VEHICLE_TYPE_HELI || pVehicle->GetVehicleType() == VEHICLE_TYPE_PLANE)
{
propFlag = PV_FLAG_FLIGHT_HELMET;
}
//Already wearing a helmet which is flagged as a helmet prop, this won't set CPED_CONFIG_FLAG_HasHelmet so it's not taken off.
if(CPedPropsMgr::GetPedPropIdx(m_pParentPed, ANCHOR_HEAD) != -1)
{
if(CPedPropsMgr::DoesPedHavePropOrComponentWithFlagSet(*m_pParentPed,propFlag))
{
return true;
}
//Don't allow script helmets to be replaced with another motor bike helmet
if(propFlag == PV_FLAG_DEFAULT_HELMET && CPedPropsMgr::DoesPedHavePropOrComponentWithFlagSet(*m_pParentPed, PV_FLAG_SCRIPT_HELMET))
{
return true;
}
//Don't replace the pilot mask (Flight School DLC) with other helmets (motorbike, plane, etc)
if(CPedPropsMgr::DoesPedHavePropOrComponentWithFlagSet(*m_pParentPed, PV_FLAG_PILOT_HELMET))
{
return true;
}
//check for armored helmet (LTS DLC)
if(CPedPropsMgr::CheckPropFlags(m_pParentPed, ANCHOR_HEAD, PV_FLAG_ARMOURED))
{
return true;
}
}
}
return false;
}
bool CPedHelmetComponent::IsWearingHelmetWithGoggles()
{
s32 nVisorPropIndex = GetHelmetPropIndex(m_CurrentPropFlag);
int nVisorTextureIndex = GetHelmetTexIndex(nVisorPropIndex);
if (nVisorPropIndex >= 0 && nVisorTextureIndex >= 0)
{
u32 uPropNameHash = EXTRAMETADATAMGR.GetHashNameForProp(m_pParentPed, ANCHOR_HEAD, (u32)nVisorPropIndex, (u32)nVisorTextureIndex);
return EXTRAMETADATAMGR.DoesShopPedApparelHaveRestrictionTag((u32)uPropNameHash, atHashString("GOGGLES_HELMET",0xF7104C9B));
}
return false;
}
bool CPedHelmetComponent::HasHelmetOfType(ePedCompFlags PropFlag) const
{
return CPedPropsMgr::GetPropIdxWithFlags(m_pParentPed, ANCHOR_HEAD, PropFlag) >= 0;
}
s32 CPedHelmetComponent::GetHelmetPropIndex(ePedCompFlags PropFlag) const
{
if(NetworkInterface::IsGameInProgress())
{
if(m_pParentPed && m_pParentPed->IsNetworkClone() && !m_pParentPed->GetPedConfigFlag(CPED_CONFIG_FLAG_IsSwitchingHelmetVisor))
{
CNetObjPed* netObjPed = static_cast<CNetObjPed*>(m_pParentPed->GetNetworkObject());
if(netObjPed)
{
Assert(m_NetworkHelmetIndex != -1);
return m_NetworkHelmetIndex;
}
}
}
// B*2214377: Allow script to ignore overriden helmet prop index if on/recently on a bicycle.
bool bOnOrRecentlyOnBicycle = ((VehicleType)m_iMostRecentVehicleType == VEHICLE_TYPE_BICYCLE);
//If the prop index has been overriden then use that
//Only use the m_nHelmetPropIndex in mp for bikes and quads and visor switching on foot
if(m_nHelmetPropIndex != -1 && UseOverrideInMP() && (!bOnOrRecentlyOnBicycle || (bOnOrRecentlyOnBicycle && m_bUseOverridenHelmetPropIndexOnBiycles)))
{
pedDebugf1("CPedHelmetComponent[%s][%p] - GetHelmetPropIndex - Found set m_nHelmetPropIndex on ped, returning prop:%i", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed, m_nHelmetPropIndex);
return m_nHelmetPropIndex;
}
if (m_nHelmetPropIndexFromHashMap != -1)
{
pedDebugf1("CPedHelmetComponent[%s][%p] - GetHelmetPropIndex - Found set m_nHelmetPropIndexFromHashMap on ped, returning prop:%i", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed, m_nHelmetPropIndex);
return m_nHelmetPropIndexFromHashMap;
}
// New metadata prop system
pedDebugf1("CPedHelmetComponent[%s][%p] - GetHelmetPropIndex - No previously set PropIndex on ped, returning random helmet from CPedPropsMgr with given flags", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed);
return CPedPropsMgr::GetPropIdxWithFlags(m_pParentPed, ANCHOR_HEAD, PropFlag);
}
bool CPedHelmetComponent::IsHelmetTexValid(CPed* pPed, s32 HelmetTexId, ePedCompFlags PropFlag)
{
s32 nPropIndices = pPed->GetHelmetComponent()->GetHelmetPropIndex(PropFlag);
return HelmetTexId < (int)CPedPropsMgr::GetMaxNumPropsTex(pPed, ANCHOR_HEAD, nPropIndices);
}
int CPedHelmetComponent::GetHelmetTexIndex(int nPropIndex)
{
if(NetworkInterface::IsGameInProgress())
{
if(m_pParentPed && m_pParentPed->IsNetworkClone() && !m_pParentPed->GetPedConfigFlag(CPED_CONFIG_FLAG_IsSwitchingHelmetVisor))
{
CNetObjPed* netObjPed = static_cast<CNetObjPed*>(m_pParentPed->GetNetworkObject());
if(netObjPed)
{
pedDebugf1("CPedHelmetComponent[%s][%p] - GetHelmetTexIndex - Network clone texture index, tex:%i", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed, m_NetworkTextureIndex);
Assert(m_NetworkTextureIndex != -1);
return m_NetworkTextureIndex;
}
}
}
if(m_nHelmetTexIndex != -1 && UseOverrideInMP())
{
pedDebugf1("CPedHelmetComponent[%s][%p] - GetHelmetTexIndex - Using override texture, tex:%i", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed, m_nHelmetTexIndex);
return m_nHelmetTexIndex;
}
if(m_nPreLoadedTexture != -1 )
{
pedDebugf1("CPedHelmetComponent[%s][%p] - GetHelmetTexIndex - Using preloaded texture, tex:%i", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed, m_nPreLoadedTexture);
return m_nPreLoadedTexture;
}
// Random bike helmet texture variant
int nTextureIndex = 0;
if(IsHelmetEnabled())
{
// Currently have a helmet - return its texture index
nTextureIndex = CPedPropsMgr::GetPedPropTexIdx(m_pParentPed, ANCHOR_HEAD);
//If GetPedPropTexIdx returns -1 then use the passed in prop index
if(nTextureIndex == -1)
{
nTextureIndex = fwRandom::GetRandomNumberInRange(0, (int)CPedPropsMgr::GetMaxNumPropsTex(m_pParentPed, ANCHOR_HEAD, nPropIndex));
}
}
else
{
nTextureIndex = fwRandom::GetRandomNumberInRange(0, (int)CPedPropsMgr::GetMaxNumPropsTex(m_pParentPed, ANCHOR_HEAD, nPropIndex));
}
pedDebugf1("CPedHelmetComponent[%s][%p] - GetHelmetTexIndex - Using random texture, tex:%i", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed, nTextureIndex);
return nTextureIndex;
}
void CPedHelmetComponent::SetStoredHatIndices(int nPropIndex, int nTexIndex)
{
Assert(nPropIndex >= -1 && nPropIndex < CPedPropsMgr::GetMaxNumProps(m_pParentPed, ANCHOR_HEAD));
m_nStoredHatPropIdx = Clamp<int>(nPropIndex, -1, CPedPropsMgr::GetMaxNumProps(m_pParentPed, ANCHOR_HEAD));
if(m_nStoredHatPropIdx != -1)
m_nStoredHatTexIdx = nTexIndex;
else
m_nStoredHatTexIdx = -1;
pedDebugf1("CPedHelmetComponent[%s][%p] - SetStoredHatIndices - Storing hat data prop:%i tex:%i", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed, m_nStoredHatPropIdx, m_nStoredHatTexIdx);
}
void CPedHelmetComponent::RestoreStoredHatIfSafe(const float fMinDistance)
{
Assert(m_pParentPed->GetHelmetComponent() == this);
if(GetStoredHatPropIndex() >= CPedPropsMgr::GetMaxNumProps(m_pParentPed, ANCHOR_HEAD))
{
AI_OPTIMISATIONS_OFF_ONLY(Assert(false)); // PRAGMA-OPTIMIZE-ALLOW
// The stored hat prop has become invalid for some reason - so clear it
SetStoredHatIndices(-1, -1);
}
if(!IsHelmetEnabled() && GetStoredHatPropIndex() != -1)
{
// Do a distance check to the camera, so we don't pop hats on in front of player
const Vector3& vCamPosition = camInterface::GetPos();
if(m_pParentPed->IsLocalPlayer() || m_pParentPed->PopTypeIsMission() || NetworkInterface::IsGameInProgress() || ((vCamPosition - VEC3V_TO_VECTOR3(m_pParentPed->GetTransform().GetPosition())).Mag2() > square(fMinDistance)))
{
RestoreStoredHat();
}
}
}
bool CPedHelmetComponent::RestoreStoredHat()
{
bool bRestored = false;
if (GetStoredHatPropIndex() != -1)
{
CPedPropsMgr::SetPedProp(m_pParentPed, ANCHOR_HEAD, GetStoredHatPropIndex(), GetStoredHatTexIndex(), ANCHOR_NONE, NULL, NULL);
pedDebugf1("CPedHelmetComponent[%s][%p] - RestoreStoredHat - Restoring hat prop:%i tex:%i", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed, GetStoredHatPropIndex(), GetStoredHatTexIndex());
bRestored = true;
}
SetStoredHatIndices(-1, -1);
return bRestored;
}
bool CPedHelmetComponent::RequestPreLoadProp(bool bRestoreHat)
{
s32 nHelmetIndices = -1;
int nTextureIndex = -1;
if(!bRestoreHat)
{
ePedCompFlags propFlag = m_DesiredPropFlag;
if(propFlag == PV_FLAG_NONE)
{
CVehicle* pVehicle = m_pParentPed->GetVehiclePedInside();
if(pVehicle)
{
if(pVehicle->GetVehicleType() == VEHICLE_TYPE_BICYCLE)
{
propFlag = PV_FLAG_RANDOM_HELMET;
}
else if(pVehicle->GetVehicleType() == VEHICLE_TYPE_BIKE || pVehicle->GetVehicleType() == VEHICLE_TYPE_QUADBIKE || pVehicle->InheritsFromAmphibiousQuadBike())
{
propFlag = PV_FLAG_DEFAULT_HELMET;
}
else if (pVehicle->GetVehicleType() == VEHICLE_TYPE_HELI)
{
propFlag = PV_FLAG_FLIGHT_HELMET;
}
}
}
Assertf(propFlag != PV_FLAG_NONE, "CPedHelmetComponent::RequestPreLoadProp - Invalid PropFlag");
nHelmetIndices = m_pParentPed->GetHelmetComponent()->GetHelmetPropIndex(m_DesiredPropFlag);
if(nHelmetIndices >= 0)
{
nTextureIndex = GetHelmetTexIndex(nHelmetIndices);
}
}
else
{
nHelmetIndices = GetStoredHatPropIndex();
nTextureIndex = GetStoredHatTexIndex();
}
if(nHelmetIndices >= 0 && nTextureIndex >= 0)
{
CPedPropsMgr::SetPreloadProp(m_pParentPed, ANCHOR_HEAD, nHelmetIndices, nTextureIndex);
pedDebugf1("CPedHelmetComponent[%s][%p] - RequestPreLoadProp - Requesting preload prop:%i tex:%i", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed, nHelmetIndices, nTextureIndex);
//Sort the texture for preloaded prop
m_nPreLoadedTexture = nTextureIndex;
m_bPreLoadingProp = true;
// record which texture we've preloaded for the network...
if(NetworkInterface::IsGameInProgress())
{
// if we're putting a helmet on, sync the prop / tex indices as soon as we start preloading so the clone can start.
// if we're putting a hat back on after taking the helmet off, don't sync otherwise the clone helmet and hat models
// can swap at inappropriate times. The clone stores the correct hat and texture index in GetStoredHat<Prop/Tex>Index()
// locally anyway.
if(!bRestoreHat)
{
if(!m_pParentPed->IsNetworkClone())
{
m_NetworkHelmetIndex = nHelmetIndices;
m_NetworkTextureIndex = nTextureIndex;
}
}
}
return true;
}
return false;
}
bool CPedHelmetComponent::IsPreLoadingProp()
{
return m_bPreLoadingProp;
}
bool CPedHelmetComponent::HasPreLoadedProp()
{
if(IsPreLoadingProp() && CPedPropsMgr::HasPreloadPropsFinished(m_pParentPed))
{
m_bPreLoadingProp = false;
return true;
}
return false;
}
void CPedHelmetComponent::ClearPreLoadedProp()
{
m_nPreLoadedTexture = -1;
m_bPreLoadingProp = false;
CPedPropsMgr::CleanUpPreloadProps(m_pParentPed);
pedDebugf1("CPedHelmetComponent[%s][%p] - ClearPreLoadedProp - Clearing preload prop", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed);
}
bool CPedHelmetComponent::UseOverrideInMP() const
{
if(NetworkInterface::IsGameInProgress())
{
//Override for motorcycles, quadbikes. Originally implemented to fix url:bugstar:1523777 and submitted to dev in CL 4569275 (colivant), modification for bifta/golf-carts/etc follow on (lavalley).
//Also override when ped has a helmet that supports visor switching (pbernotas) - B*2907088
//Portions extraced from CPed::SetPedInVehicle where it does similiar processing (but not exactly the same)
CVehicle* pVehicle = m_pParentPed->GetVehiclePedInside();
bool bHelmetSupportsVisor = m_pParentPed->GetHelmetComponent() && m_pParentPed->GetHelmetComponent()->GetCurrentHelmetSupportsVisors();
bool bTakingOffHelmet = m_pParentPed->GetPedResetFlag(CPED_RESET_FLAG_IsRemovingHelmet);
if (!pVehicle && !bHelmetSupportsVisor && !bTakingOffHelmet)
{
pedDebugf1("CPedHelmetComponent[%s][%p] - UseOverrideInMP failed - not in vehicle and not visor switching on foot.", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed);
return false;
}
if (pVehicle)
{
//never override for these vehicles - use the vehicle specific headgear
if (pVehicle->InheritsFromPlane() || pVehicle->InheritsFromHeli() || pVehicle->InheritsFromAutogyro() || pVehicle->InheritsFromBlimp())
{
pedDebugf1("CPedHelmetComponent[%s][%p] - UseOverrideInMP failed - in a plane/heli/autogyro/blimp", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed);
return false;
}
//always override for these vehicles - getting the player custom headgear
if (pVehicle->InheritsFromBike() || pVehicle->InheritsFromQuadBike() || pVehicle->InheritsFromAmphibiousQuadBike())
return true;
//further determine below if the headgear should be retained or not...
// HACK: FLAG_PEDS_INSIDE_CAN_BE_SET_ON_FIRE_MP is tagged on vehicles that have open tops (caddy, dune, mower, etc.), only flag we have to identify these.
bool KeepHatOnInOpenTopVehicles = pVehicle->GetVehicleModelInfo()->GetVehicleFlag(CVehicleModelInfoFlags::FLAG_PEDS_INSIDE_CAN_BE_SET_ON_FIRE_MP);
bool KeepHeadProp = KeepHatOnInOpenTopVehicles;
if (!KeepHeadProp)
{
//do some extra evaluation
s32 iPedsSeatIndex = pVehicle ? pVehicle->GetSeatManager()->GetPedsSeatIndex(m_pParentPed) : -1;
const CVehicleSeatInfo* pSeatInfo = (iPedsSeatIndex != -1) ? pVehicle->GetSeatInfo(iPedsSeatIndex) : NULL;
KeepHeadProp = (pSeatInfo && pSeatInfo->GetKeepOnHeadProp());
}
if (KeepHatOnInOpenTopVehicles)
{
// HACK: Only remove hats on the BIFTA if we have a roof mod.
static const u32 biftaHash = ATSTRINGHASH("bifta", 0xeb298297);
const u32 vehModelHash = pVehicle->GetVehicleModelInfo()->GetModelNameHash();
if (vehModelHash == biftaHash)
{
const CVehicleVariationInstance& variation = pVehicle->GetVariationInstance();
if (variation.GetModIndex(VMT_ROOF) != INVALID_MOD)
KeepHeadProp = false;
}
}
// Remove helmet if not getting on a bike
if(!KeepHeadProp && pVehicle->GetVehicleType() != VEHICLE_TYPE_BIKE && pVehicle->GetVehicleType() != VEHICLE_TYPE_QUADBIKE && pVehicle->GetVehicleType() != VEHICLE_TYPE_BICYCLE && pVehicle->GetVehicleType() != VEHICLE_TYPE_AMPHIBIOUS_QUADBIKE && IsHelmetEnabled())
{
pedDebugf1("CPedHelmetComponent[%s][%p] - UseOverrideInMP failed - not on a bike", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed);
return false;
}
}
}
return true;
}
// B*2216490: Sets an override helmet prop index from the hash map if available for the current vehicle.
void CPedHelmetComponent::SetHelmetIndexFromHashMap()
{
// B*2216490: If ped is in a vehicle which has had a prop index specified vehicle-helmet hashmap, use that.
if (m_nHelmetPropIndex == -1 && m_nHelmetPropIndexFromHashMap == -1 && m_pParentPed && m_pParentPed->GetIsInVehicle())
{
const CVehicle *pVehicle = m_pParentPed->GetVehiclePedInside();
if (pVehicle && pVehicle->GetBaseModelInfo())
{
const u32 uVehicleHash = pVehicle->GetBaseModelInfo()->GetModelNameHash();
// Ensure an entry exists for this vehicle.
if (sm_VehicleHashToHelmetPropIndex.Access(uVehicleHash))
{
atArray<int> *propIndexArray = sm_VehicleHashToHelmetPropIndex.Access(uVehicleHash);
// Pick a random prop index from the array.
const int iNumOfProps = propIndexArray->GetCount();
const int iPropToSelect = fwRandom::GetRandomNumberInRange(0, iNumOfProps);
const int iHelmetPropIndex = (*propIndexArray)[iPropToSelect];
// Cache prop flag (used in CPedHelmetComponent::GetHelmetPropIndex).
m_nHelmetPropIndexFromHashMap = iHelmetPropIndex;
pedDebugf1("CPedHelmetComponent[%s][%p] - SetHelmetIndexFromHashMap - Set helmet override prop id from vehicle-helmet hashmap prop:%i", m_pParentPed ? m_pParentPed->GetModelName() : "NULL", m_pParentPed, m_nHelmetPropIndexFromHashMap);
}
}
}
}
// B*2216490: Functions accessed from script to define vehicle specific helmet prop indexes.
void CPedHelmetComponent::AddVehicleHelmetAssociation(const u32 uVehicleHash, const int iHelmetPropIndex)
{
if (uVehicleHash != 0 && iHelmetPropIndex != -1.0f)
{
// Already have an entry for this vehicle hash, so just add the helmet index to the array.
if (sm_VehicleHashToHelmetPropIndex.Access(uVehicleHash))
{
// Don't add the helmet index if it's already been added.
if (sm_VehicleHashToHelmetPropIndex.Access(uVehicleHash)->Find(iHelmetPropIndex) == -1)
{
sm_VehicleHashToHelmetPropIndex.Access(uVehicleHash)->PushAndGrow(iHelmetPropIndex);
}
}
else
{
// We haven't created an entry for this vehicle yet, so initialize it and the helmet array.
atArray<int> helmetPropIndexArray;
helmetPropIndexArray.Reset();
helmetPropIndexArray.PushAndGrow(iHelmetPropIndex);
sm_VehicleHashToHelmetPropIndex.Insert(uVehicleHash, helmetPropIndexArray);
}
}
}
void CPedHelmetComponent::ClearVehicleHelmetAssociation(const u32 uVehicleHash)
{
if (uVehicleHash != 0)
{
if (sm_VehicleHashToHelmetPropIndex.Access(uVehicleHash))
{
sm_VehicleHashToHelmetPropIndex.Delete(uVehicleHash);
}
}
}
void CPedHelmetComponent::ClearAllVehicleHelmetAssociations()
{
sm_VehicleHashToHelmetPropIndex.Reset();
}
bool CPedHelmetComponent::ShouldUsePilotFlightHelmet(const CPed *pPed)
{
if (!pPed)
return false;
CVehicle *pVehicle = static_cast<CVehicle*>(pPed->GetVehiclePedInside());
if (!pVehicle)
return false;
// In some cases, we want to use the regular flight helmet even if the seat has weapons.
if (pVehicle->GetVehicleModelInfo()->GetVehicleFlag(CVehicleModelInfoFlags::FLAG_USE_STANDARD_FLIGHT_HELMET))
return false;
// Only allow driver or passengers with an available vehicle weapon to use the pilot helmet.
s32 iSeatIndex = pVehicle->GetSeatManager()->GetPedsSeatIndex(pPed);
const bool bSeatHasWeapons = pVehicle->GetSeatManager() && pVehicle->GetSeatHasWeaponsOrTurrets(iSeatIndex);
bool bSeatHasValidWeapon = bSeatHasWeapons;
if (bSeatHasWeapons)
{
// B*2295117: Loop over vehicle weapons. Don't equip pilot helmet if VEHICLE_WEAPON_SEARCHLIGHT is the only weapon available.
CVehicleWeaponMgr* pWeaponMgr = pVehicle->GetVehicleWeaponMgr();
if (pWeaponMgr)
{
bool bFoundSearchLight = false;
bool bFoundOtherWeapon = false;
static const atHashWithStringNotFinal searchLightWeaponName("VEHICLE_WEAPON_SEARCHLIGHT",0xCDAC517D);
for (int i = 0; i < pWeaponMgr->GetNumWeaponsForSeat(iSeatIndex); i++)
{
CVehicleWeapon *pVehWeapon = pWeaponMgr->GetVehicleWeapon(i);
if (pVehWeapon)
{
if (pVehWeapon->GetHash() == searchLightWeaponName)
{
bFoundSearchLight = true;
}
else
{
bFoundOtherWeapon = true;
}
}
}
if (bFoundSearchLight && !bFoundOtherWeapon)
{
bSeatHasValidWeapon = false;
}
}
}
const CVehicleSeatInfo* pSeatInfo = pVehicle->IsSeatIndexValid(iSeatIndex) ? pVehicle->GetSeatInfo(iSeatIndex) : NULL;
bool bGivePilotHelmetForSeat = pSeatInfo && pSeatInfo->GetGivePilotHelmetForSeat();
if ((bGivePilotHelmetForSeat || pPed->GetIsDrivingVehicle() || bSeatHasWeapons) && (pVehicle->GetVehicleType() == VEHICLE_TYPE_HELI || pVehicle->GetVehicleType() == VEHICLE_TYPE_PLANE))
{
CVehicleModelInfo* pVehModelInfo = pVehicle->GetVehicleModelInfo();
if (bSeatHasValidWeapon || (pVehModelInfo && pVehModelInfo->GetVehicleFlag(CVehicleModelInfoFlags::FLAG_USE_PILOT_HELMET)))
{
return true;
}
}
return false;
}
fwMvClipSetId CPedHelmetComponent::GetAircraftPutOnTakeOffHelmetFPSClipSet(const CVehicle* pVehicle)
{
if (aiVerify(pVehicle && pVehicle->GetIsAircraft()))
{
if (pVehicle->GetIsHeli())
{
const fwClipSet* pHeliClipSet = fwClipSetManager::GetClipSet(CLIP_SET_PUT_ON_TAKE_OFF_HELMET_FPS_HELI);
if (pHeliClipSet && (pHeliClipSet->GetClipDictionaryIndex() != -1))
{
return CLIP_SET_PUT_ON_TAKE_OFF_HELMET_FPS_HELI;
}
}
return CLIP_SET_PUT_ON_TAKE_OFF_HELMET_FPS;
}
return CLIP_SET_ID_INVALID;
}
#if __BANK
void CPedHelmetComponent::InitWidgets()
{
bkBank& bank = BANKMGR.CreateBank("Ped Helmets");
bank.PushGroup("Vehicle-Helmet Hashmap", false);
bank.AddText("Vehicle Hash:", &sm_uVehicleHashString, false);
bank.AddSlider("Helmet Prop Index:", &sm_iHelmetPropIndex, -1, 40, 1);
bank.AddButton("Add Vehicle-Helmet Association", WidgetAddVehicleHelmetAssociation);
bank.AddButton("Clear Vehicle-Helmet Association", WidgetClearVehicleHelmetAssociation);
bank.AddButton("Clear All Vehicle-Helmet Associations", WidgetClearAllVehicleHelmetAssociations);
bank.PopGroup();
}
void CPedHelmetComponent::WidgetAddVehicleHelmetAssociation()
{
CPedHelmetComponent::AddVehicleHelmetAssociation(sm_uVehicleHashString.GetHash(), sm_iHelmetPropIndex);
}
void CPedHelmetComponent::WidgetClearVehicleHelmetAssociation()
{
CPedHelmetComponent::ClearVehicleHelmetAssociation(sm_uVehicleHashString.GetHash());
}
void CPedHelmetComponent::WidgetClearAllVehicleHelmetAssociations()
{
CPedHelmetComponent::ClearAllVehicleHelmetAssociations();
}
#endif // __BANK