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

1362 lines
44 KiB
C++

// File header
#include "Weapons/Projectiles/ProjectileManager.h"
// Game headers
#include "fwtl/regdrefs.h"
#include "Network/Arrays/NetworkArrayMgr.h"
#include "Network/NetworkInterface.h"
#include "Network/Events/NetworkEventTypes.h"
#include "Network/general/NetworkPendingProjectiles.h"
#include "Peds/Ped.h"
#include "Peds/PedIntelligence.h"
#include "Scene/World/GameWorld.h"
#include "Script/script_areas.h"
#include "Task/Weapons/TaskBomb.h"
#include "Task/Weapons/TaskProjectile.h"
#include "Text/messages.h"
#include "Text/TextFile.h"
#include "Weapons/Info/AmmoInfo.h"
#include "Weapons/Projectiles/Projectile.h"
#include "Weapons/Projectiles/ProjectileFactory.h"
#include "Weapons/Projectiles/ProjectileRocket.h"
// Macro to disable optimisations if set
WEAPON_OPTIMISATIONS()
//////////////////////////////////////////////////////////////////////////
// CProjectileManager
//////////////////////////////////////////////////////////////////////////
// Static variable initialisation
atFixedArray<RegdProjectile, CProjectileManager::MAX_STORAGE> CProjectileManager::ms_projectiles;
atFixedArray<CProjectileManager::CProjectilePtr, CProjectileManager::MAX_STORAGE> CProjectileManager::ms_NetSyncedProjectiles;
atFixedArray<PendingRocketTargetUpdate, CProjectileManager::MAX_PENDING_UPDATE_TARGET_EVENTS> CProjectileManager::ms_pendingProjectileTargetUpdateEvents;
s32 CProjectileManager::m_FlareGunSequenceId = 0;
bool CProjectileManager::m_HideProjectilesInCutscene = false;
#if __BANK
Vector3 CProjectileManager::ms_vLastExplosionPosition(Vector3::ZeroType);
Vector3 CProjectileManager::ms_vLastExplosionNormal(Vector3::ZeroType);
#endif // __BANK
void CProjectileManager::Init()
{
ms_NetSyncedProjectiles.clear();
ms_NetSyncedProjectiles.Reset();
ms_NetSyncedProjectiles.Resize(MAX_STORAGE);
}
void CProjectileManager::Shutdown()
{
RemoveAllProjectiles();
ms_projectiles.Reset();
}
s32 CProjectileManager::GetMaxStickiesPerPed()
{
return NetworkInterface::IsGameInProgress() ? MAX_STICKIES_PER_PED_MP : MAX_STICKIES_PER_PED_SP;
}
s32 CProjectileManager::GetMaxStickToPedProjectilesPerPed()
{
return NetworkInterface::IsGameInProgress() ? MAX_STICK_TO_PED_PROJECTILES_PER_PED_MP : MAX_STICK_TO_PED_PROJECTILES_PER_PED_SP;
}
s32 CProjectileManager::GetMaxFlareGunProjectilesPerPed()
{
return NetworkInterface::IsGameInProgress() ? MAX_FLARE_GUN_PROJECTILES_PER_PED_MP : MAX_FLARE_GUN_PROJECTILES_PER_PED_SP;
}
void CProjectileManager::Process()
{
if (NetworkInterface::IsGameInProgress())
{
UpdatePendingProjectileTargetUpdateEvent();
}
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(!ms_projectiles[i])
{
ms_projectiles.DeleteFast(i);
// The delete will copy the last element in the array over the element we are deleting
// Decrement the iterator so in our next pass we check the element that has just been copied
i--;
}
}
}
void CProjectileManager::PostPreRender()
{
for (s32 i=0; i<ms_projectiles.GetCount(); i++)
{
if (ms_projectiles[i])
{
ms_projectiles[i]->PostPreRender();
}
}
}
/////////////////////////////////////////////////////
//Start of - Network shared array handling functions
/////////////////////////////////////////////////////
void CProjectileManager::ClearAllNetSyncProjectile()
{
RemoveAllProjectiles();
Init();
}
bool CProjectileManager::AddNetSyncProjectile(s32 &refIndex, CProjectile* projectile)
{
CStickyBombsArrayHandler* pArrayHandler = NetworkInterface::IsGameInProgress() ? NetworkInterface::GetArrayManager().GetStickyBombsArrayHandler() : NULL;
if (pArrayHandler)
{
for(s32 i = 0; i < ms_NetSyncedProjectiles.GetCount(); i++)
{
if(!pArrayHandler->IsElementRemotelyArbitrated(i) && !ms_NetSyncedProjectiles[i].Get())
{
refIndex = i;
return AddNetSyncProjectileAtSlot(i, projectile);
}
}
}
return false;
}
bool CProjectileManager::RemoveNetSyncProjectile(CProjectile* projectile)
{
CStickyBombsArrayHandler* pArrayHandler = NetworkInterface::IsGameInProgress() ? NetworkInterface::GetArrayManager().GetStickyBombsArrayHandler() : NULL;
if (pArrayHandler)
{
for(s32 index = 0; index < ms_NetSyncedProjectiles.GetCount(); index++)
{
if( ms_NetSyncedProjectiles[index].Get()==projectile && !IsRemotelyControlled(index))
{
ms_NetSyncedProjectiles[index].Clear();
DirtyNetSyncProjectile(index, projectile->GetIsStuckToPed());
}
}
}
return false;
}
bool CProjectileManager::AddNetSyncProjectileAtSlot(s32 index, CProjectile* projectile)
{
CStickyBombsArrayHandler* pArrayHandler = NetworkInterface::IsGameInProgress() ? NetworkInterface::GetArrayManager().GetStickyBombsArrayHandler() : NULL;
if (pArrayHandler && aiVerifyf(!pArrayHandler->IsElementRemotelyArbitrated(index), "Trying to add a projectile to slot %d, which is still arbitrated by %s", index, pArrayHandler->GetElementArbitration(index)->GetLogName()))
{
aiAssertf(ms_NetSyncedProjectiles[index].Get()==NULL,"Don't expect element %d to have a projectile already",index);
ms_NetSyncedProjectiles[index] = CProjectilePtr(projectile);
DirtyNetSyncProjectile(index);
return true;
}
return false;
}
void CProjectileManager::DirtyNetSyncProjectile(s32 index, bool bStuckToPed)
{
if (NetworkInterface::IsGameInProgress() && NetworkInterface::GetArrayManager().GetStickyBombsArrayHandler())
{
if (aiVerifyf((!IsRemotelyControlled(index) || bStuckToPed), "Trying to dirty a projectile controlled by another machine or not stuck to a ped"))
{
// flag array handler element as dirty so that this projectile gets sent to the other machines
NetworkInterface::GetArrayManager().GetStickyBombsArrayHandler()->SetElementDirty(index);
}
}
}
bool CProjectileManager::MoveNetSyncProjectile(s32 index, s32& newSlot)
{
for(s32 i = 0; i < ms_NetSyncedProjectiles.GetCount(); i++)
{
if(!ms_NetSyncedProjectiles[i].Get() && !IsRemotelyControlled(i))
{
newSlot = i;
ms_NetSyncedProjectiles[newSlot].Copy(ms_NetSyncedProjectiles[index]);
ms_NetSyncedProjectiles[index].Clear();
return true;
}
}
return false;
}
bool CProjectileManager::IsRemotelyControlled(s32 index)
{
if (NetworkInterface::GetArrayManager().GetStickyBombsArrayHandler())
{
return NetworkInterface::GetArrayManager().GetStickyBombsArrayHandler()->IsElementRemotelyArbitrated(index);
}
return false;
}
CProjectile * CProjectileManager::GetExistingNetSyncProjectile(const CNetFXIdentifier& networkIdentifier)
{
for(s32 i = 0; i < ms_NetSyncedProjectiles.GetCount(); i++)
{
if(ms_NetSyncedProjectiles[i].Get() && ms_NetSyncedProjectiles[i].Get()->GetNetworkIdentifier() == networkIdentifier)
{
return ms_NetSyncedProjectiles[i].Get();
}
}
return NULL;
}
CProjectile * CProjectileManager::GetAnyExistingProjectile(const CNetFXIdentifier& networkIdentifier)
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && ms_projectiles[i]->GetNetworkIdentifier() == networkIdentifier)
{
return ms_projectiles[i];
}
}
return NULL;
}
bool CProjectileManager::FireOrPlacePendingProjectile(CPed *ped, int taskSequenceID, CProjectile* pExistingProjectile)
{
if(aiVerifyf(ped,"Invalid ped pointer") && aiVerifyf(taskSequenceID != -1, "Invalid task sequence"))
{
ProjectileInfo* pProjectileInfo = CNetworkPendingProjectiles::GetProjectile(ped, (u32)taskSequenceID, false);
CProjectile* pProjectile = NULL;
if(pProjectileInfo == 0)
{
return false;
}
else
{
if (pProjectileInfo->m_stickyBomb)
{
CEntity* pStickEntity = NULL;
netObject *pNetObjStickEntity = 0;
if (pProjectileInfo->m_stickEntityID != NETWORK_INVALID_OBJECT_ID)
{
pNetObjStickEntity = NetworkInterface::GetObjectManager().GetNetworkObject(pProjectileInfo->m_stickEntityID);
pStickEntity = pNetObjStickEntity ? pNetObjStickEntity->GetEntity() : 0;
if (!pStickEntity)
{
return false;
}
}
pProjectile = pExistingProjectile;
if (AssertVerify(pProjectileInfo->m_stickyBombArraySlot<ms_NetSyncedProjectiles.GetMaxCount()) && !pProjectile)
{
pProjectile = ms_NetSyncedProjectiles[pProjectileInfo->m_stickyBombArraySlot].Get();
}
if (!pProjectile)
{
pProjectile = CProjectileManager::CreateProjectile(pProjectileInfo->m_projectileHash,
pProjectileInfo->m_weaponFiredFromHash,
pProjectileInfo->m_entity,
pProjectileInfo->m_projectileMatrix,
0.0f,
DAMAGE_TYPE_NONE,
pProjectileInfo->m_effectGroup,
NULL,
&pProjectileInfo->m_identifier);
Assertf(pProjectile,"%s Couldn't create sticky bomb m_fxId %d",ped->GetDebugName(), pProjectileInfo->m_identifier.GetFXId());
}
else
{
if (pProjectile->GetIsAttached())
{
pProjectile->DetachFromParent(0);
}
pProjectile->SetNetFXIdentifier(pProjectileInfo->m_identifier);
pProjectile->SetMatrix(pProjectileInfo->m_projectileMatrix, true, true, true);
}
if (!pProjectile || !pProjectile->NetworkStick(pProjectileInfo->m_stickEntity, pStickEntity, pProjectileInfo->m_stickPosition, pProjectileInfo->m_stickOrientation, pProjectileInfo->m_stickComponent, pProjectileInfo->m_stickMaterial))
{
RemoveProjectile(pProjectile);
return false;
}
if (pProjectileInfo->m_stickyBombArraySlot < ms_NetSyncedProjectiles.GetMaxCount())
{
if (pProjectile != ms_NetSyncedProjectiles[pProjectileInfo->m_stickyBombArraySlot].Get())
{
ms_NetSyncedProjectiles[pProjectileInfo->m_stickyBombArraySlot].Clear();
}
ms_NetSyncedProjectiles[pProjectileInfo->m_stickyBombArraySlot] = pProjectile;
}
}
else
{
pProjectile = CProjectileManager::CreateProjectile(pProjectileInfo->m_projectileHash,
pProjectileInfo->m_weaponFiredFromHash,
ped,
pProjectileInfo->m_projectileMatrix,
0.0f,
DAMAGE_TYPE_NONE,
pProjectileInfo->m_effectGroup,
pProjectileInfo->m_targetEntity,
&pProjectileInfo->m_identifier);
// fire projectile
float fLifeTime = -1.0f;
if(taskVerifyf(pProjectile,"%s No projectile hash 0x%x created! taskSequenceID %d GetFXId %d",
ped->GetDebugName(),pProjectileInfo->m_projectileHash,taskSequenceID,pProjectileInfo->m_identifier.GetFXId()))
{
// Activate the projectile
pProjectile->Fire( pProjectileInfo->m_fireDirection,
fLifeTime,
pProjectileInfo->m_fLaunchSpeedOverride,
pProjectileInfo->m_bAllowDamping);
CProjectileRocket* pRocket = pProjectile->GetAsProjectileRocket();
if (pRocket)
{
pRocket->SetWasLockedOnWhenFired(pProjectileInfo->m_bWasLockedOnWhenFired);
}
}
}
if (pProjectile)
{
pProjectile->SetTaskSequenceId(taskSequenceID);
}
pProjectileInfo->m_active = false;
}
return true;
}
return false;
}
/////////////////////////////////////////////////////
// End of - Network shared array handling functions
/////////////////////////////////////////////////////
CProjectile* CProjectileManager::CreateProjectile(u32 uProjectileNameHash, u32 uWeaponFiredFromHash, CEntity* pOwner, const Matrix34& mat, float fDamage, eDamageType damageType, eWeaponEffectGroup effectGroup, const CEntity* pTarget, const CNetFXIdentifier* pNetIdentifier, u32 tintIndex, bool bCreatedFromScript, bool bProjectileCreatedFromGrenadeThrow)
{
CProjectile* pProjectile = NULL;
CPed* pParentPed = NULL;
bool bIncrementStickyCountIfCreated = false;
bool bIncrementStickToPedCountIfCreated = false;
bool bIncrementFlareGunCountIfCreated = false;
#if __ASSERT
aiAssertf(mat.d.IsNonZero(), "Can't create projectile at origin");
#endif
//if close to full, silently delete the oldest projectile and continue
if(pOwner && pOwner->GetIsTypePed())
{
pParentPed = static_cast<CPed*>(pOwner);
if(!pParentPed->IsNetworkClone())
{
const CItemInfo* pBaseInfo = CWeaponInfoManager::GetInfo(uProjectileNameHash);
if(pBaseInfo && pBaseInfo->GetIsClass<CAmmoProjectileInfo>())
{
const CAmmoProjectileInfo* pInfo = static_cast<const CAmmoProjectileInfo*>(pBaseInfo);
if (pInfo && pInfo->GetIsSticky())
{
if (pInfo->GetShouldStickToPeds()) //Separate list of objects for stick-to-ped projectiles
{
if (pParentPed->GetStickToPedProjectileCount() >= GetMaxStickToPedProjectilesPerPed())
{
DestroyOldestProjectileForPed(pParentPed, pInfo);
}
bIncrementStickToPedCountIfCreated = true;
}
else //Sticky bombs
{
if(pInfo->GetPreventMaxProjectileHelpText() && pParentPed->GetStickyCount() >= (GetMaxStickiesPerPed() -1) )
{
char FinalString[60];
char* pMainString = TheText.Get("WM_MAX_STICKY");
CNumberWithinMessage Numbers[1];
Numbers[0].Set(GetMaxStickiesPerPed());
CMessages::InsertNumbersAndSubStringsIntoString(pMainString, Numbers, 1, NULL, 0, FinalString, NELEM(FinalString));
CHelpMessage::SetMessageText(HELP_TEXT_SLOT_STANDARD,FinalString);
}
if (pParentPed->GetStickyCount() >= GetMaxStickiesPerPed())
{
DestroyOldestProjectileForPed(pParentPed, pInfo);
}
bIncrementStickyCountIfCreated = true;
}
}
else if (pInfo && uProjectileNameHash == AMMOTYPE_DLC_FLAREGUN) // Flare gun projectiles
{
if (pParentPed->GetFlareGunProjectileCount() >= GetMaxFlareGunProjectilesPerPed())
{
DestroyOldestProjectileForPed(pParentPed, pInfo);
}
bIncrementFlareGunCountIfCreated = true;
}
}
}
}
if(!ms_projectiles.IsFull() && CObject::GetPool()->GetNoOfFreeSpaces() > 0)
{
pProjectile = ProjectileFactory::Create(uProjectileNameHash, uWeaponFiredFromHash, pOwner, fDamage, damageType, effectGroup, pTarget, pNetIdentifier, bCreatedFromScript);
if(pProjectile)
{
if(m_HideProjectilesInCutscene && NetworkInterface::IsInMPCutscene())
{
pProjectile->SetIsVisibleForModule(SETISVISIBLE_MODULE_NETWORK, false, false);
}
// don't fade up on creation
pProjectile->GetLodData().SetResetDisabled(true);
// If projectile was created from a gun-aim throw, don't allow it to blow up instantly with left d-pad.
// Only allow it to be detonated once the input has been released and re-pressed (flag set to true in CProjectile::ProcessControl and checked in CProjectileManager::CanExplodeTriggeredProjectiles).
if (bProjectileCreatedFromGrenadeThrow)
{
pProjectile->SetCanDetonateInstantly(false);
}
// Move it up slightly to avoid any possible duplicate archetype assert
static dev_float TINY_OFFSET = 0.001f;
Matrix34 projMat(mat);
projMat.d.z += TINY_OFFSET;
projMat.Normalize();
// Set the matrix
pProjectile->SetMatrix(projMat, true, true, true);
if(pOwner)
{
if(pParentPed)
{
if(pParentPed->GetPedConfigFlag( CPED_CONFIG_FLAG_InVehicle ) && pParentPed->GetMyVehicle())
{
// If thrown from a car, don't collide with the car
pProjectile->SetNoCollision(pParentPed->GetMyVehicle(), NO_COLLISION_RESET_WHEN_NO_BBOX);
}
else
{
// Don't collide with the throwing ped
pProjectile->SetNoCollision(pParentPed, NO_COLLISION_RESET_WHEN_NO_IMPACTS);
}
if (pParentPed->IsPlayer())
{
pProjectile->GetPortalTracker()->RequestRescanNextUpdate();
}
}
else
{
// If vehicle has fired weapon then don't collide
pProjectile->SetNoCollision(pOwner, NO_COLLISION_RESET_WHEN_NO_IMPACTS);
}
// Add to the world
CGameWorld::Add(pProjectile, pOwner->GetInteriorLocation());
} else
CGameWorld::Add(pProjectile, CGameWorld::OUTSIDE);
// Store the projectile pointer
ms_projectiles.Push(RegdProjectile(pProjectile));
if (bIncrementStickyCountIfCreated)
{
pParentPed->IncrementStickyCount();
}
if (bIncrementStickToPedCountIfCreated)
{
pParentPed->IncrementStickToPedProjectileCount();
}
if (bIncrementFlareGunCountIfCreated)
{
pParentPed->IncrementFlareGunProjectileCount();
}
pProjectile->SetWeaponTintIndex((u8)tintIndex);
}
}
else
{
weaponWarningf("Failed to create projectile: ms_projectiles:[%d/%d], CObject::GetPool:[%d/%d]", ms_projectiles.GetCount(), ms_projectiles.GetMaxCount(), (int) CObject::GetPool()->GetNoOfUsedSpaces(), (int) CObject::GetPool()->GetSize());
}
return pProjectile;
}
void CProjectileManager::RemoveProjectile(const CProjectile * pProjectile)
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i]==pProjectile)
{
ms_projectiles[i]->Destroy();
}
}
}
void CProjectileManager::RemoveProjectile(const CNetFXIdentifier& networkIdentifier)
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && ms_projectiles[i]->GetNetworkIdentifier() == networkIdentifier)
{
ms_projectiles[i]->Destroy();
}
}
}
const CProjectile * CProjectileManager::GetProjectile(const CNetFXIdentifier& networkIdentifier)
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && ms_projectiles[i]->GetNetworkIdentifier() == networkIdentifier)
{
return ms_projectiles[i];
}
}
return NULL;
}
void CProjectileManager::BreakProjectileHoming(const CNetFXIdentifier& networkIdentifier)
{
CProjectile* projectile = nullptr;
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && ms_projectiles[i]->GetNetworkIdentifier() == networkIdentifier)
{
projectile = ms_projectiles[i];
break;
}
}
if(projectile && projectile->GetAsProjectileRocket())
{
CProjectileRocket* rocket = projectile->GetAsProjectileRocket();
if(rocket)
{
rocket->StopHomingProjectile();
}
}
}
void CProjectileManager::RemoveAllProjectiles()
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && !ms_projectiles[i]->GetIsOrdnance())
{
ms_projectiles[i]->Destroy();
}
}
}
void CProjectileManager::RemoveAllProjectilesByAmmoType(u32 uProjectileNameHash, bool bExplode)
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if( ms_projectiles[i] && (uProjectileNameHash == 0 || ms_projectiles[i]->GetInfo()->GetHash() == uProjectileNameHash))
{
if(bExplode)
ms_projectiles[i]->TriggerExplosion();
else
ms_projectiles[i]->Destroy();
}
}
}
void CProjectileManager::RemoveAllPedProjectilesByAmmoType(const CEntity* pOwner, u32 uProjectileNameHash)
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && (!pOwner || ms_projectiles[i]->GetOwner() == pOwner) && (uProjectileNameHash == 0 || ms_projectiles[i]->GetInfo()->GetHash() == uProjectileNameHash))
{
ms_projectiles[i]->Destroy();
}
}
}
void CProjectileManager::RemoveAllTriggeredPedProjectiles(const CEntity* pOwner)
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && (!pOwner || ms_projectiles[i]->GetOwner() == pOwner))
{
const CWeaponInfo* pWeaponInfo = CWeaponInfoManager::GetInfo<CWeaponInfo>(ms_projectiles[i]->GetWeaponFiredFromHash());
if (pWeaponInfo && pWeaponInfo->GetIsManualDetonation())
{
ms_projectiles[i]->Destroy();
}
}
}
}
void CProjectileManager::RemoveAllProjectilesInBounds(const spdAABB& bounds)
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && !ms_projectiles[i]->GetIsOrdnance() && !ms_projectiles[i]->GetNetworkIdentifier().IsClone())
{
if(bounds.ContainsPoint(ms_projectiles[i]->GetTransform().GetPosition()))
{
ms_projectiles[i]->Destroy();
}
}
}
}
void CProjectileManager::RemoveAllStickyBombsAttachedToEntity(const CEntity* pEntity, bool bInformRemoteMachines, const CPed* pOwner)
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && ms_projectiles[i]->GetInfo()->GetIsSticky() && ms_projectiles[i]->GetAttachParent() == pEntity && (pOwner == NULL || pOwner == ms_projectiles[i]->GetOwner()))
{
if (bInformRemoteMachines && ms_projectiles[i]->GetNetworkIdentifier().IsClone())
{
CRemoveStickyBombEvent::Trigger(ms_projectiles[i]->GetNetworkIdentifier());
}
ms_projectiles[i]->Destroy();
}
}
CNetworkPendingProjectiles::RemoveAllStickyBombsAttachedToEntity(pEntity);
}
void CProjectileManager::ExplodeProjectiles(const CEntity* pOwner, u32 uProjectileNameHash, bool bInstant)
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && (!pOwner || ms_projectiles[i]->GetOwner() == pOwner) && (uProjectileNameHash == 0 || ms_projectiles[i]->GetInfo()->GetHash() == uProjectileNameHash))
{
//If there is more than one
ms_projectiles[i]->TriggerExplosion((i > 0 && !bInstant) ? 150 * i : 0);
}
}
}
void CProjectileManager::ExplodeTriggeredProjectiles(const CEntity* pOwner, bool bInstant)
{
int iNumOfManualDetonationProjectiles = 0;
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && (!pOwner || ms_projectiles[i]->GetOwner() == pOwner))
{
const CWeaponInfo* pWeaponInfo = CWeaponInfoManager::GetInfo<CWeaponInfo>(ms_projectiles[i]->GetWeaponFiredFromHash());
if (pWeaponInfo && pWeaponInfo->GetIsManualDetonation())
{
//If there is more than one
ms_projectiles[i]->TriggerExplosion((i > 0 && !bInstant) ? 150 * iNumOfManualDetonationProjectiles : 0);
iNumOfManualDetonationProjectiles++;
}
}
}
}
bool CProjectileManager::CanExplodeProjectiles(const CEntity* pOwner, u32 uProjectileNameHash)
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && (!pOwner || ms_projectiles[i]->GetOwner() == pOwner) && (uProjectileNameHash == 0 || ms_projectiles[i]->GetInfo()->GetHash() == uProjectileNameHash))
{
return true;
}
}
return false;
}
bool CProjectileManager::CanExplodeTriggeredProjectiles(const CEntity* pOwner)
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && (!pOwner || ms_projectiles[i]->GetOwner() == pOwner))
{
const CWeaponInfo* pWeaponInfo = CWeaponInfoManager::GetInfo<CWeaponInfo>(ms_projectiles[i]->GetWeaponFiredFromHash());
if (pWeaponInfo && pWeaponInfo->GetIsManualDetonation() && ms_projectiles[i]->GetCanDetonateInstantly())
{
return true;
}
}
}
return false;
}
void CProjectileManager::GetProjectilesForOwner(const CEntity* pOwner, atArray<RegdProjectile>& projectileArray)
{
projectileArray.Reset();
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && (ms_projectiles[i]->GetOwner() == pOwner) )
{
projectileArray.PushAndGrow(ms_projectiles[i]);
}
}
}
void CProjectileManager::DisableCrimeReportingForExplosions(const CEntity* pOwner)
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && (ms_projectiles[i]->GetOwner() == pOwner) )
{
ms_projectiles[i]->SetDisableExplosionCrimes(true);
}
}
}
void CProjectileManager::ToggleVisibilityOfAllProjectiles(bool visible)
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i])
{
CProjectile* proj = ms_projectiles[i]->GetAsProjectile();
if(proj)
{
proj->SetIsVisibleForModule(SETISVISIBLE_MODULE_NETWORK, visible, false);
}
}
}
}
void CProjectileManager::DestroyOldestProjectileForPed(CPed* pPed, const CAmmoProjectileInfo* pInfo)
{
bool bSearchSticksToPed = pInfo->GetShouldStickToPeds();
bool bSearchFlareGun = (pInfo->GetHash() == AMMOTYPE_DLC_FLAREGUN);
s32 oldestIndex = -1;
float oldestTime = 0.0f;
//array is unordered so determine age based on the projectile's lifetime
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if (ms_projectiles[i] && ms_projectiles[i]->GetOwner() == pPed)
{
bool bResultSticky = ms_projectiles[i]->GetInfo()->GetIsSticky();
bool bResultSticksToPed = ms_projectiles[i]->GetInfo()->GetShouldStickToPeds();
bool bResultFlareGun = (ms_projectiles[i]->GetInfo()->GetHash() == AMMOTYPE_DLC_FLAREGUN);
if (oldestIndex == -1)
{
if (bResultSticky)
{
if (bSearchSticksToPed && bResultSticksToPed)
{
oldestIndex = i;
oldestTime = ms_projectiles[i]->GetAge();
}
else //normal sticky bomb
{
oldestIndex = i;
oldestTime = ms_projectiles[i]->GetAge();
}
}
else if (bSearchFlareGun && bResultFlareGun)
{
oldestIndex = i;
oldestTime = ms_projectiles[i]->GetAge();
}
}
else
{
if (bResultSticky)
{
if (ms_projectiles[i]->GetAge() > oldestTime && bSearchSticksToPed && bResultSticksToPed)
{
oldestIndex = i;
oldestTime = ms_projectiles[i]->GetAge();
}
else if (ms_projectiles[i]->GetAge() > oldestTime)
{
oldestIndex = i;
oldestTime = ms_projectiles[i]->GetAge();
}
}
else if (ms_projectiles[i]->GetAge() > oldestTime && bSearchFlareGun && bResultFlareGun)
{
oldestIndex = i;
oldestTime = ms_projectiles[i]->GetAge();
}
}
}
}
//if we found a projectile to destroy then do so
if (oldestIndex != -1)
{
ms_projectiles[oldestIndex]->Destroy();
}
}
void CProjectileManager::DestroyAllStickyProjectilesForPed(CPed* pPed)
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if (ms_projectiles[i] &&
ms_projectiles[i]->GetOwner() == pPed &&
ms_projectiles[i]->GetInfo()->GetIsSticky())
{
ms_projectiles[i]->Destroy();
}
}
CNetworkPendingProjectiles::RemoveAllStickyBombsForPed(pPed);
}
CEntity * CProjectileManager::GetProjectileWithinDistance(const CEntity* pOwner, u32 uProjectileNameHash, float distance)
{
if(!pOwner)
{
Assertf(0,"GetProjectileWithinDistance called with NULL pOwner");
return NULL;
}
float distSqr = distance * distance;
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && (ms_projectiles[i]->GetOwner() == pOwner) && (uProjectileNameHash == 0 || ms_projectiles[i]->GetInfo()->GetHash() == uProjectileNameHash))
{
// Get distance to this projectile
Vector3 ownerPos = VEC3V_TO_VECTOR3(pOwner->GetTransform().GetPosition());
Vector3 projectilePos = VEC3V_TO_VECTOR3(ms_projectiles[i]->GetTransform().GetPosition());
float dSqr = projectilePos.Dist2(ownerPos);
if( dSqr <= distSqr )
{
return ms_projectiles[i];
}
}
}
return NULL;
}
CEntity * CProjectileManager::GetProjectileWithinDistance(const Vector3& vPositon, u32 uProjectileNameHash, float distance)
{
float distSqr = distance * distance;
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && vPositon.IsNonZero() && (uProjectileNameHash == 0 || ms_projectiles[i]->GetInfo()->GetHash() == uProjectileNameHash))
{
// Get distance to this projectile
Vector3 projectilePos = VEC3V_TO_VECTOR3(ms_projectiles[i]->GetTransform().GetPosition());
float dSqr = projectilePos.Dist2(vPositon);
if( dSqr <= distSqr )
{
return ms_projectiles[i];
}
}
}
return NULL;
}
CEntity * CProjectileManager::GetNewestProjectileWithinDistance(const CEntity* pOwner, u32 uProjectileNameHash, float distance, bool bStationaryOnly)
{
if(!pOwner)
{
Assertf(0,"GetNewestProjectileWithinDistance called with NULL pOwner");
return NULL;
}
float distSqr = distance * distance;
s32 newestIndex = -1;
float newestTime = 0.0f;
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && (ms_projectiles[i]->GetOwner() == pOwner) && (uProjectileNameHash == 0 || ms_projectiles[i]->GetInfo()->GetHash() == uProjectileNameHash))
{
// Get distance to this projectile
Vector3 ownerPos = VEC3V_TO_VECTOR3(pOwner->GetTransform().GetPosition());
Vector3 projectilePos = VEC3V_TO_VECTOR3(ms_projectiles[i]->GetTransform().GetPosition());
float dSqr = projectilePos.Dist2(ownerPos);
if( dSqr <= distSqr )
{
// Skip moving projectiles if we only care about stationary ones
if (bStationaryOnly && ms_projectiles[i]->GetVelocity().Mag2() >= 0.25f)
{
continue;
}
//We only want to return the youngest
if (newestIndex == -1 || ms_projectiles[i]->GetAge() < newestTime)
{
newestIndex = i;
newestTime = ms_projectiles[i]->GetAge();
}
}
}
}
//if we found a projectile
if (newestIndex != -1)
{
return ms_projectiles[newestIndex];
}
return NULL;
}
bool CProjectileManager::GetIsAnyProjectileInBounds(const spdAABB& bounds, u32 uProjectileNameHash, CEntity* pOwnerFilter)
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && !ms_projectiles[i]->GetIsOrdnance() && (uProjectileNameHash == 0 || ms_projectiles[i]->GetHash() == uProjectileNameHash))
{
CEntity* pOwnerEntity = ms_projectiles[i]->GetOwner();
if( pOwnerEntity && pOwnerEntity->GetIsTypeVehicle() )
{
CVehicle* pVeh = static_cast<CVehicle*>(pOwnerEntity);
pOwnerEntity = pVeh->GetDriver();
}
if (pOwnerFilter == NULL || pOwnerFilter == pOwnerEntity)
{
if(bounds.ContainsPoint(ms_projectiles[i]->GetTransform().GetPosition()))
{
return true;
}
}
}
}
return false;
}
bool CProjectileManager::GetIsAnyProjectileInAngledArea(const Vector3 & vecPoint1, const Vector3 & vecPoint2, float fDistance, u32 uProjectileNameHash, const CEntity* pOwnerFilter)
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && !ms_projectiles[i]->GetIsOrdnance() && (uProjectileNameHash == 0 || ms_projectiles[i]->GetHash() == uProjectileNameHash))
{
Vector3 v1(vecPoint1);
Vector3 v2(vecPoint2);
const CEntity* pOwnerEntity = ms_projectiles[i]->GetOwner();
if (pOwnerFilter == NULL || pOwnerFilter == pOwnerEntity)
{
if(CScriptAreas::IsPointInAngledArea(VEC3V_TO_VECTOR3(ms_projectiles[i]->GetTransform().GetPosition()), v1, v2, fDistance, false, true, false))
{
return true;
}
}
}
}
return false;
}
bool CProjectileManager::GetIsProjectileAttachedToEntity(const CEntity* pOwner, const CEntity* pAttachedTo, u32 uProjectileNameHash, s32 iAttachBone)
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && (uProjectileNameHash == 0 || ms_projectiles[i]->GetHash() == uProjectileNameHash))
{
if(ms_projectiles[i]->GetOwner() == pOwner && ms_projectiles[i]->GetAttachParent() == pAttachedTo)
{
if(iAttachBone == -1 || iAttachBone == ms_projectiles[i]->GetAttachBone())
{
return true;
}
}
}
}
return false;
}
const CEntity * CProjectileManager::GetProjectileInBounds(const spdAABB& bounds, u32 uProjectileNameHash)
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && !ms_projectiles[i]->GetIsOrdnance() && (uProjectileNameHash == 0 || ms_projectiles[i]->GetHash() == uProjectileNameHash))
{
if(bounds.ContainsPoint(ms_projectiles[i]->GetTransform().GetPosition()))
{
return ms_projectiles[i];
}
}
}
return NULL;
}
const CEntity * CProjectileManager::GetProjectileInAngledArea(const Vector3 & vecPoint1, const Vector3 & vecPoint2, float fDistance, u32 uProjectileNameHash)
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i] && !ms_projectiles[i]->GetIsOrdnance() && (uProjectileNameHash == 0 || ms_projectiles[i]->GetHash() == uProjectileNameHash))
{
Vector3 v1(vecPoint1);
Vector3 v2(vecPoint2);
if(CScriptAreas::IsPointInAngledArea(VEC3V_TO_VECTOR3(ms_projectiles[i]->GetTransform().GetPosition()), v1, v2, fDistance, false, true, false))
{
return ms_projectiles[i];
}
}
}
return NULL;
}
void CProjectileManager::GetProjectilesToRedirect(const CEntity* pOwnerOfAttractorProjectile, Vec3V_In vAttractorProjectilePos, atArray<CProjectileRocket*>& projectileArray, float fMinDistanceToTarget, float fMaxDistanceFromAtractor)
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
CProjectileRocket* pRocket = ms_projectiles[i] ? ms_projectiles[i]->GetAsProjectileRocket() : NULL;
if (pRocket && !pRocket->GetIsRedirected() && pRocket->GetTimeProjectileWasFiredMS() != 0)
{
const CWeaponInfo* pWeaponInfo = pRocket ? CWeaponInfoManager::GetInfo<CWeaponInfo>(pRocket->GetWeaponFiredFromHash()) : NULL;
if (pWeaponInfo && pWeaponInfo->GetIsHoming())
{
Vector3 vProjPos = VEC3V_TO_VECTOR3(pRocket->GetTransform().GetPosition());
Vector3 vAttractorOwnerPos = VEC3V_TO_VECTOR3(pOwnerOfAttractorProjectile->GetTransform().GetPosition());
// Cant redirect if rocket is too close to it's target (or to the ped who is shooting the flare.
// If rocket has a target, then check min dist to it, if it doesnt, then check min dist to the owner of the attractor.
const CEntity* pRocketTargetEntity = pRocket->GetTarget();
float fDistToTargetSq = pRocketTargetEntity ? vProjPos.Dist2(VEC3V_TO_VECTOR3(pRocketTargetEntity->GetTransform().GetPosition())) : vProjPos.Dist2(vAttractorOwnerPos);
if (fMinDistanceToTarget > 0.0f && fDistToTargetSq < square(fMinDistanceToTarget))
continue;
// Cant redirect if rocket is too far from the attractor flare.
float fDistToAttractorSq = vProjPos.Dist2(VEC3V_TO_VECTOR3(vAttractorProjectilePos));
if (fMaxDistanceFromAtractor > 0.0f && fDistToAttractorSq > square(fMaxDistanceFromAtractor))
continue;
// Cant redirect if rocket is close to original firing position (e.g. was just fired)
TUNE_GROUP_FLOAT(HOMING_ATTRACTOR, fMinDistFromFirePosToBeRedirected, 15.0f, 0.0f, 100.0f, 0.1f);
float fDistFromCurrentToFirePosSq = vProjPos.Dist2(pRocket->GetPositionFiredFrom());
if (fDistFromCurrentToFirePosSq <= square(fMinDistFromFirePosToBeRedirected))
continue;
projectileArray.PushAndGrow(pRocket);
}
}
}
}
void CProjectileManager::AddPendingProjectileTargetUpdateEvent(PendingRocketTargetUpdate newPendingEvent)
{
if(gnetVerifyf(!ms_pendingProjectileTargetUpdateEvents.IsFull(), "Projectile update event list is full"))
{
ms_pendingProjectileTargetUpdateEvents.Push(newPendingEvent);
}
}
void CProjectileManager::UpdatePendingProjectileTargetUpdateEvent()
{
for(int i = 0; i < ms_pendingProjectileTargetUpdateEvents.GetCount(); i++)
{
if(ms_pendingProjectileTargetUpdateEvents[i].m_eventAddedTime > 0)
{
if(ms_pendingProjectileTargetUpdateEvents[i].m_eventAddedTime + PendingRocketTargetUpdate::MAX_LIFE_TIME < fwTimer::GetTimeInMilliseconds())
{
// if event has timed out, delete this
ms_pendingProjectileTargetUpdateEvents.DeleteFast(i);
i--;
}
else
{
netObject* projectileOwner = NetworkInterface::GetNetworkObject(ms_pendingProjectileTargetUpdateEvents[i].m_projectileOwnerId);
netObject* fromPlayerPed = NetworkInterface::GetNetworkObject(ms_pendingProjectileTargetUpdateEvents[i].m_flareOwnerId);
if(projectileOwner && fromPlayerPed)
{
// First we find the projectile whose target needs to be updated
CProjectileRocket* projectileToModify = nullptr;
atArray<RegdProjectile> rocketProjectiles;
CProjectileManager::GetProjectilesForOwner(projectileOwner->GetEntity(), rocketProjectiles);
for(int r = 0; r < rocketProjectiles.GetCount(); r++)
{
CProjectileRocket* rocket = rocketProjectiles[r]->GetAsProjectileRocket();
if(rocket && rocket->GetTaskSequenceId() == ms_pendingProjectileTargetUpdateEvents[i].m_projectileSequenceId)
{
projectileToModify = rocket;
break;
}
}
// Than find the flare we need to set the projectile to track
if(projectileToModify)
{
atArray<RegdProjectile> flareGunProjectiles;
CProjectileManager::GetProjectilesForOwner(fromPlayerPed->GetEntity(), flareGunProjectiles);
for(int f = 0; f < flareGunProjectiles.GetCount(); f++)
{
CProjectile* flare = flareGunProjectiles[f]->GetAsProjectile();
if(flare && flare->GetTaskSequenceId() == ms_pendingProjectileTargetUpdateEvents[i].m_targetFlareGunSequenceId)
{
gnetDebug3("Modifying rocket (%s)'s target entity to: %s", projectileToModify->GetLogName(), flare->GetLogName());
projectileToModify->SetTarget(flare);
projectileToModify->SetIsRedirected(true);
// if flare is found and set on the rocket, delete this
ms_pendingProjectileTargetUpdateEvents.DeleteFast(i);
i--;
break;
}
}
}
}
}
}
}
}
ObjectId CProjectileManager::CProjectilePtr::ms_ownerId = NETWORK_INVALID_OBJECT_ID;
NetworkFXId CProjectileManager::CProjectilePtr::ms_fxId = 0;
u32 CProjectileManager::CProjectilePtr::ms_taskSequenceId = 0;
u32 CProjectileManager::CProjectilePtr::ms_projectileHash = 0;
u32 CProjectileManager::CProjectilePtr::ms_weaponFiredFromHash = 0;
eWeaponEffectGroup CProjectileManager::CProjectilePtr::ms_effectGroup = NUM_EWEAPONEFFECTGROUP;
Matrix34 CProjectileManager::CProjectilePtr::ms_projectileMatrix;
bool CProjectileManager::CProjectilePtr::ms_stickEntity = false;
ObjectId CProjectileManager::CProjectilePtr::ms_stickEntityID = NETWORK_INVALID_OBJECT_ID;
Vector3 CProjectileManager::CProjectilePtr::ms_stickPosition;
Quaternion CProjectileManager::CProjectilePtr::ms_stickOrientation;
s32 CProjectileManager::CProjectilePtr::ms_stickComponent = 0;
u32 CProjectileManager::CProjectilePtr::ms_stickMaterial = 0;
void CProjectileManager::CProjectilePtr::Serialise(CSyncDataBase& serialiser)
{
const unsigned SIZEOF_TASK_SEQUENCE_ID = 9;
const u32 SIZEOF_PROJECTILE_HASH = sizeof(ms_projectileHash)<<3;
const u32 SIZEOF_FIREDFROM_HASH = sizeof(ms_weaponFiredFromHash)<<3;
const u32 SIZEOF_EFFECT_GROUP = datBitsNeeded<NUM_EWEAPONEFFECTGROUP>::COUNT; // number of bits to effect group
const u32 SIZEOF_FX_ID = sizeof(NetworkFXId)<<3;
const u32 SIZEOF_INIT_POSITION = 30;
const u32 SIZEOF_STICK_POSITION = 17;
const u32 SIZEOF_STICK_ORIENTATION = 16;
const u32 SIZEOF_COMPONENT = 16;
const u32 SIZEOF_MATERIAL = 32;
SERIALISE_OBJECTID(serialiser, ms_ownerId, "Projectile Owner ID");
SERIALISE_UNSIGNED(serialiser, ms_taskSequenceId, SIZEOF_TASK_SEQUENCE_ID, "Task sequence ID");
SERIALISE_UNSIGNED(serialiser, ms_projectileHash, SIZEOF_PROJECTILE_HASH, "Projectile Hash");
SERIALISE_UNSIGNED(serialiser, ms_weaponFiredFromHash, SIZEOF_FIREDFROM_HASH, "Weapon Hash");
SERIALISE_ORIENTATION(serialiser, ms_projectileMatrix, "Projectile Matrix");
SERIALISE_POSITION_SIZE(serialiser, ms_projectileMatrix.d, "Projectile Position", SIZEOF_INIT_POSITION);
SERIALISE_UNSIGNED(serialiser, reinterpret_cast<u32&>(ms_effectGroup), SIZEOF_EFFECT_GROUP, "Effect group");
SERIALISE_UNSIGNED(serialiser, ms_fxId, SIZEOF_FX_ID, "FX ID");
SERIALISE_BOOL(serialiser, ms_stickEntity, "Stick entity");
bool bStickObject = ms_stickEntityID != NETWORK_INVALID_OBJECT_ID;
SERIALISE_BOOL(serialiser, bStickObject, "Stuck to networked entity");
if (bStickObject || serialiser.GetIsMaximumSizeSerialiser())
{
SERIALISE_OBJECTID(serialiser, ms_stickEntityID, "Stick Entity ID");
SERIALISE_VECTOR(serialiser, ms_stickPosition, 40.0f, SIZEOF_STICK_POSITION, "Stick Position");
SERIALISE_QUATERNION(serialiser, ms_stickOrientation, SIZEOF_STICK_ORIENTATION, "Stick orientation");
SERIALISE_UNSIGNED(serialiser, ms_stickComponent, SIZEOF_COMPONENT, "Stick component");
SERIALISE_UNSIGNED(serialiser, ms_stickMaterial, SIZEOF_MATERIAL, "Stick material");
}
else
{
ms_stickEntityID = NETWORK_INVALID_OBJECT_ID;
}
}
void CProjectileManager::CProjectilePtr::Copy(CProjectilePtr &projectilePtr)
{
m_RegdProjectile = projectilePtr.m_RegdProjectile;
ms_stickEntityID = NETWORK_INVALID_OBJECT_ID;
CProjectile* pProjectile = m_RegdProjectile.Get();
if (pProjectile)
{
aiAssertf(!pProjectile->GetInfo() || pProjectile->GetInfo()->GetIsSticky(),"expect only sticky bombs to be serialised here");
netObject* pOwnerNetObj = pProjectile->GetOwner() ? NetworkUtils::GetNetworkObjectFromEntity(pProjectile->GetOwner()) : NULL;
Assertf(pOwnerNetObj, "Attempting to sync a projectile for an owner not registered with the network!");
ms_ownerId = pOwnerNetObj ? pOwnerNetObj->GetObjectID() : NETWORK_INVALID_OBJECT_ID;
ms_taskSequenceId = pProjectile->GetTaskSequenceId();
ms_fxId = pProjectile->GetNetworkIdentifier().GetFXId();
ms_projectileHash = pProjectile->GetHash();
ms_weaponFiredFromHash = pProjectile->GetWeaponFiredFromHash();
ms_effectGroup = pProjectile->GetEffectGroup();
ms_projectileMatrix = MAT34V_TO_MATRIX34(pProjectile->GetTransform().GetMatrix());
ms_stickEntity = false;
ms_stickEntityID = NETWORK_INVALID_OBJECT_ID;
ms_stickPosition.Zero();
ms_stickOrientation.Identity();
ms_stickComponent = 0;
ms_stickMaterial = 0;
const CEntity* pStickEntity = pProjectile->GetStickEntity();
if (pStickEntity)
{
netObject* pStickEntityObj = NetworkUtils::GetNetworkObjectFromEntity(pStickEntity);
if (pStickEntityObj)
{
fwAttachmentEntityExtension *extension = pProjectile->GetAttachmentExtension();
if (extension)
{
netObject *pAttachEntity = NetworkUtils::GetNetworkObjectFromEntity((CEntity*)extension->GetAttachParentForced());
if (pAttachEntity && AssertVerify(pAttachEntity == pStickEntityObj))
{
ms_stickEntity = true;
ms_stickEntityID = pStickEntityObj->GetObjectID();
ms_stickPosition = extension->GetAttachOffset();
ms_stickOrientation = extension->GetAttachQuat();
ms_stickComponent = pProjectile->GetStickComponent();
ms_stickMaterial = pProjectile->GetStickMaterial();
}
}
}
}
}
}
void CProjectileManager::CProjectilePtr::CopyNetworkInfoCreateProjectile(const netPlayer& player, unsigned arrayIndex )
{
CEntity *pProjectileOwner = NULL;
netObject *pNetObjProjectileOwner = 0;
if (AssertVerify(ms_ownerId != NETWORK_INVALID_OBJECT_ID))
{
pNetObjProjectileOwner = NetworkInterface::GetObjectManager().GetNetworkObject(ms_ownerId);
pProjectileOwner = pNetObjProjectileOwner ? pNetObjProjectileOwner->GetEntity() : 0;
}
CNetFXIdentifier netIdentifier;
netIdentifier.Set(player.GetPhysicalPlayerIndex(),ms_fxId);
CNetworkPendingProjectiles::AddStickyBomb(arrayIndex,
pProjectileOwner,
ms_taskSequenceId,
ms_projectileHash,
ms_weaponFiredFromHash,
ms_projectileMatrix,
ms_effectGroup,
netIdentifier,
ms_stickEntity,
ms_stickEntityID,
ms_stickPosition,
ms_stickOrientation,
ms_stickComponent,
ms_stickMaterial);
}
bool CProjectileManager::CProjectilePtr::IsProjectileModelLoaded()
{
const CItemInfo* pInfo = CWeaponInfoManager::GetInfo(ms_weaponFiredFromHash);
if(aiVerifyf(pInfo,"No info for m_weaponFiredFromHash %u",ms_weaponFiredFromHash) && aiVerifyf(pInfo->GetIsClassId(CWeaponInfo::GetStaticClassId())," Expected CWeaponInfo class Id, got %s ",pInfo->GetClassId().GetCStr() ) )
{
// Ensure its streamed in (re-using weapon streaming code)
if (!m_pWeaponItemForStreaming || m_pWeaponItemForStreaming->GetInfo()->GetHash() != ms_weaponFiredFromHash)
{
if (m_pWeaponItemForStreaming)
{
delete m_pWeaponItemForStreaming;
m_pWeaponItemForStreaming = NULL;
}
if (CInventoryItem::GetPool()->GetNoOfFreeSpaces() != 0)
{
m_pWeaponItemForStreaming = rage_new CWeaponItem(0, ms_weaponFiredFromHash, NULL);
}
}
#if __ASSERT
if(!m_pWeaponItemForStreaming)
{
CInventoryItem::SpewPoolUsage();
Assertf(0, "Inventory item pool is full, check tty for pool usage spew!");
}
#endif // __ASSERT
Assert(m_pWeaponItemForStreaming && m_pWeaponItemForStreaming->GetInfo()->GetHash() == ms_weaponFiredFromHash);
if (m_pWeaponItemForStreaming && m_pWeaponItemForStreaming->GetIsStreamedIn())
{
return true;
}
}
return false;
}
void CProjectileManager::CProjectilePtr::Clear(bool bDestroy )
{
if (Get())
{
if(bDestroy)
{
Get()->Destroy();
}
m_RegdProjectile = NULL;
}
}
#if __BANK
bkGroup* CProjectileManager::InitWidgets(bkBank& bank)
{
bkGroup* pProjectilesGroup = bank.PushGroup("Projectiles");
bank.PopGroup(); // "Projectiles"
return pProjectilesGroup;
}
void CProjectileManager::RenderDebug()
{
for(s32 i = 0; i < ms_projectiles.GetCount(); i++)
{
if(ms_projectiles[i])
{
ms_projectiles[i]->RenderDebug();
}
}
#if DEBUG_DRAW
// Render the impact position
static bank_float SPHERE_RADIUS = 0.1f;
grcDebugDraw::Sphere(ms_vLastExplosionPosition, SPHERE_RADIUS, Color_red);
// Render the impact normal
static bank_float NORMAL_LENGTH = 0.2f;
grcDebugDraw::Line(ms_vLastExplosionPosition, ms_vLastExplosionPosition + ms_vLastExplosionNormal * NORMAL_LENGTH, Color_green);
#endif // DEBUG_DRAW
}
void CProjectileManager::SetLastExplosionPoint(const Vector3& vExplosionPosition, const Vector3& vExplosionNormal)
{
ms_vLastExplosionPosition = vExplosionPosition;
ms_vLastExplosionNormal = vExplosionNormal;
}
#endif // __BANK