diff options
| author | claude-bot <[email protected]> | 2026-07-13 12:27:07 +0000 |
|---|---|---|
| committer | claude-bot <[email protected]> | 2026-07-13 12:27:07 +0000 |
| commit | 9f61c9e6ac6b1ac5692cf6352d2ebbd47a31a686 (patch) | |
| tree | a84756b82513739a2672db3a1f0ec579db6d18ff /src/weapons/ProjectileInfo.cpp | |
| download | re3-miami.tar.gz re3-miami.zip | |
Snapshot import (no upstream history) into git.ancap.in.ua/claude, per @lzcnt.
Source: https://github.com/Cai1Hsu/re3 branch miami.
Diffstat (limited to 'src/weapons/ProjectileInfo.cpp')
| -rw-r--r-- | src/weapons/ProjectileInfo.cpp | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/src/weapons/ProjectileInfo.cpp b/src/weapons/ProjectileInfo.cpp new file mode 100644 index 0000000..10aa3ef --- /dev/null +++ b/src/weapons/ProjectileInfo.cpp @@ -0,0 +1,437 @@ +#include "common.h" + +#include "Camera.h" +#include "General.h" +#include "Heli.h" +#include "ModelIndices.h" +#include "Particle.h" +#include "Ped.h" +#include "Plane.h" +#include "ProjectileInfo.h" +#include "Projectile.h" +#include "Explosion.h" +#include "Weapon.h" +#include "World.h" + +#ifdef SQUEEZE_PERFORMANCE +uint32 projectileInUse; +#endif + +CProjectileInfo gaProjectileInfo[NUM_PROJECTILES]; +CProjectile *CProjectileInfo::ms_apProjectile[NUM_PROJECTILES]; + +#define PROJECTILE_BOUNDARY_MIN_X -2390.0f +#define PROJECTILE_BOUNDARY_MAX_X 1590.0f +#define PROJECTILE_BOUNDARY_MIN_Y -1990.0f +#define PROJECTILE_BOUNDARY_MAX_Y 1990.0f + +void +CProjectileInfo::Initialise() +{ + debug("Initialising CProjectileInfo...\n"); + + for (int i = 0; i < ARRAY_SIZE(ms_apProjectile); i++) { + ms_apProjectile[i] = nil; + gaProjectileInfo[i].m_eWeaponType = WEAPONTYPE_GRENADE; + gaProjectileInfo[i].m_pSource = nil; + gaProjectileInfo[i].m_nExplosionTime = 0; + gaProjectileInfo[i].m_bInUse = false; + } + + debug("CProjectileInfo ready\n"); + +#ifdef SQUEEZE_PERFORMANCE + projectileInUse = 0; +#endif +} + +void +CProjectileInfo::Shutdown() +{ + debug("Shutting down CProjectileInfo...\n"); + debug("CProjectileInfo shut down\n"); +} + +CProjectileInfo* +CProjectileInfo::GetProjectileInfo(int32 id) +{ + return &gaProjectileInfo[id]; +} + +bool +CProjectileInfo::AddProjectile(CEntity *entity, eWeaponType weapon, CVector pos, float speed) +{ + int8 SpecialCollisionResponseCase = COLLRESPONSE_NONE; + bool gravity = true; + CMatrix matrix; + float elasticity = 0.75f; + CPed* ped = (CPed*)entity; + int time; + CVector velocity; + + switch (weapon) + { + case WEAPONTYPE_ROCKET: + { + float vy = 0.35f; + time = CTimer::GetTimeInMilliseconds() + 2000; + if (entity->GetModelIndex() == MI_SPARROW || entity->GetModelIndex() == MI_HUNTER || entity->GetModelIndex() == MI_SENTINEL) { + matrix = ped->GetMatrix(); + matrix.GetPosition() = pos; + CVector vecSpeed = ((CPhysical*)entity)->m_vecMoveSpeed; + vy += Max(0.0f, DotProduct(vecSpeed, entity->GetForward())) + Max(0.0f, DotProduct(vecSpeed, entity->GetUp())); + } else { + if (ped->IsPlayer()) { + matrix.GetForward() = TheCamera.Cams[TheCamera.ActiveCam].Front; + matrix.GetUp() = TheCamera.Cams[TheCamera.ActiveCam].Up; + matrix.GetRight() = CrossProduct(TheCamera.Cams[TheCamera.ActiveCam].Up, TheCamera.Cams[TheCamera.ActiveCam].Front); + matrix.GetPosition() = pos; + } else if (ped->m_pSeekTarget != nil) { + float ry = CGeneral::GetRadianAngleBetweenPoints(1.0f, ped->m_pSeekTarget->GetPosition().z, 1.0f, pos.z); + float rz = Atan2(-ped->GetForward().x, ped->GetForward().y); + vy = 0.35f * speed + 0.15f; + matrix.SetTranslate(0.0f, 1.0f, 1.0f); + matrix.Rotate(0.0f, ry, rz); + matrix.GetPosition() += pos; + } else { + matrix = ped->GetMatrix(); + } + } + velocity = Multiply3x3(matrix, CVector(0.0f, vy, 0.0f)); + gravity = false; + break; + } + case WEAPONTYPE_MOLOTOV: + { + time = CTimer::GetTimeInMilliseconds() + 2000; + float scale = 0.22f * speed + 0.15f; + if (scale < 0.2f) + scale = 0.2f; + float angle = Atan2(-ped->GetForward().x, ped->GetForward().y); + matrix.SetTranslate(0.0f, 0.0f, 0.0f); + matrix.RotateZ(angle); + matrix.GetPosition() += pos; + velocity.x = -1.0f * scale * Sin(angle); + velocity.y = scale * Cos(angle); + velocity.z = (0.2f * speed + 0.4f) * scale; + break; + } + case WEAPONTYPE_TEARGAS: + { + time = CTimer::GetTimeInMilliseconds() + 20000; + float scale = 0.0f; + if (speed != 0.0f) + scale = 0.22f * speed + 0.15f; + float angle = Atan2(-ped->GetForward().x, ped->GetForward().y); + matrix.SetTranslate(0.0f, 0.0f, 0.0f); + matrix.RotateZ(angle); + matrix.GetPosition() += pos; + SpecialCollisionResponseCase = COLLRESPONSE_UNKNOWN5; + velocity.x = -1.0f * scale * Sin(angle); + velocity.y = scale * Cos(angle); + velocity.z = (0.4f * speed + 0.4f) * scale; + elasticity = 0.5f; + break; + } + case WEAPONTYPE_GRENADE: + case WEAPONTYPE_DETONATOR_GRENADE: + { + time = CTimer::GetTimeInMilliseconds() + 2000; + float scale = 0.0f; + if (speed != 0.0f) + scale = 0.22f * speed + 0.15f; + float angle = Atan2(-ped->GetForward().x, ped->GetForward().y); + matrix.SetTranslate(0.0f, 0.0f, 0.0f); + matrix.RotateZ(angle); + matrix.GetPosition() += pos; + SpecialCollisionResponseCase = COLLRESPONSE_UNKNOWN5; + velocity.x = -1.0f * scale * Sin(angle); + velocity.y = scale * Cos(angle); + velocity.z = (0.4f * speed + 0.4f) * scale; + elasticity = 0.5f; + break; + } + default: + Error("Undefined projectile type, AddProjectile, ProjectileInfo.cpp"); + break; + } + + int i = 0; +#ifdef FIX_BUGS + while (i < ARRAY_SIZE(gaProjectileInfo) && gaProjectileInfo[i].m_bInUse) i++; +#else + // array overrun is UB + while (gaProjectileInfo[i].m_bInUse && i < ARRAY_SIZE(gaProjectileInfo)) i++; +#endif + if (i == ARRAY_SIZE(gaProjectileInfo)) + return false; + + switch (weapon) + { + case WEAPONTYPE_ROCKET: + ms_apProjectile[i] = new CProjectile(MI_MISSILE); + break; + case WEAPONTYPE_TEARGAS: + ms_apProjectile[i] = new CProjectile(MI_TEARGAS); + break; + case WEAPONTYPE_MOLOTOV: + ms_apProjectile[i] = new CProjectile(MI_MOLOTOV); + break; + case WEAPONTYPE_GRENADE: + case WEAPONTYPE_DETONATOR_GRENADE: + ms_apProjectile[i] = new CProjectile(MI_GRENADE); + break; + default: break; + } + + if (ms_apProjectile[i] == nil) + return false; + + gaProjectileInfo[i].m_eWeaponType = weapon; + gaProjectileInfo[i].m_pSource = ped; + ms_apProjectile[i]->GetMatrix() = matrix; + ms_apProjectile[i]->SetMoveSpeed(velocity); + ms_apProjectile[i]->bAffectedByGravity = gravity; + + gaProjectileInfo[i].m_nExplosionTime = time; + ms_apProjectile[i]->m_fElasticity = elasticity; + ms_apProjectile[i]->m_nSpecialCollisionResponseCases = SpecialCollisionResponseCase; + +#ifdef SQUEEZE_PERFORMANCE + projectileInUse++; +#endif + + gaProjectileInfo[i].m_bInUse = true; + CWorld::Add(ms_apProjectile[i]); + + gaProjectileInfo[i].m_vecPos = ms_apProjectile[i]->GetPosition(); + + if (entity && entity->IsPed() && !ped->m_pCollidingEntity) { + ped->m_pCollidingEntity = ms_apProjectile[i]; + } + return true; +} + +void +CProjectileInfo::RemoveProjectile(CProjectileInfo *info, CProjectile *projectile) +{ + // TODO(Miami): New parameter: 1 + switch (info->m_eWeaponType) { + case WEAPONTYPE_GRENADE: + CExplosion::AddExplosion(nil, info->m_pSource, EXPLOSION_GRENADE, projectile->GetPosition(), 0); + break; + case WEAPONTYPE_MOLOTOV: + CExplosion::AddExplosion(nil, info->m_pSource, EXPLOSION_MOLOTOV, projectile->GetPosition(), 0); + break; + case WEAPONTYPE_ROCKET: + CExplosion::AddExplosion(nil, info->m_pSource->IsVehicle() ? ((CVehicle*)info->m_pSource)->pDriver : info->m_pSource, EXPLOSION_ROCKET, projectile->GetPosition(), 0); + break; + } +#ifdef SQUEEZE_PERFORMANCE + projectileInUse--; +#endif + + info->m_bInUse = false; + CWorld::Remove(projectile); + delete projectile; +} + +void +CProjectileInfo::RemoveNotAdd(CEntity *entity, eWeaponType weaponType, CVector pos) +{ + // TODO(Miami): New parameter: 1 + switch (weaponType) { + case WEAPONTYPE_GRENADE: + CExplosion::AddExplosion(nil, entity, EXPLOSION_GRENADE, pos, 0); + break; + case WEAPONTYPE_MOLOTOV: + CExplosion::AddExplosion(nil, entity, EXPLOSION_MOLOTOV, pos, 0); + break; + case WEAPONTYPE_ROCKET: + CExplosion::AddExplosion(nil, entity, EXPLOSION_ROCKET, pos, 0); + break; + } +} + +void +CProjectileInfo::Update() +{ +#ifdef SQUEEZE_PERFORMANCE + if (projectileInUse == 0) + return; +#endif + + int tearGasOffset = -0.0f; // unused + + for (int i = 0; i < ARRAY_SIZE(gaProjectileInfo); i++) { + if (!gaProjectileInfo[i].m_bInUse) continue; + + CPed *ped = (CPed*)gaProjectileInfo[i].m_pSource; + if (ped != nil && ped->IsPed() && !ped->IsPointerValid()) + gaProjectileInfo[i].m_pSource = nil; + + if (ms_apProjectile[i] == nil) { +#ifdef SQUEEZE_PERFORMANCE + projectileInUse--; +#endif + + gaProjectileInfo[i].m_bInUse = false; + continue; + } + if ( (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_DETONATOR_GRENADE || gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_TEARGAS) && ms_apProjectile[i]->m_fElasticity > 0.1f ) { + if ( Abs(ms_apProjectile[i]->m_vecMoveSpeed.x) < 0.05f && Abs(ms_apProjectile[i]->m_vecMoveSpeed.y) < 0.05f && Abs(ms_apProjectile[i]->m_vecMoveSpeed.z) < 0.05f ) { + ms_apProjectile[i]->m_fElasticity = 0.03f; + } + } + const CVector &projectilePos = ms_apProjectile[i]->GetPosition(); + CVector nextPos = CTimer::GetTimeStep() * ms_apProjectile[i]->m_vecMoveSpeed + projectilePos; + + if ( nextPos.x <= PROJECTILE_BOUNDARY_MIN_X || nextPos.x >= PROJECTILE_BOUNDARY_MAX_X || nextPos.y <= PROJECTILE_BOUNDARY_MIN_Y || nextPos.y >= PROJECTILE_BOUNDARY_MAX_Y ) { + // Not RemoveProjectile, because we don't want no explosion + gaProjectileInfo[i].m_bInUse = false; + CWorld::Remove(ms_apProjectile[i]); + delete ms_apProjectile[i]; + continue; + } + if ( gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_TEARGAS && CTimer::GetTimeInMilliseconds() > gaProjectileInfo[i].m_nExplosionTime - 19500 ) { + CParticle::AddParticle(PARTICLE_TEARGAS, projectilePos, CVector(0.2f, tearGasOffset, 0.0f), 0, 0.0f, 0, 0, 0, 0); + CParticle::AddParticle(PARTICLE_TEARGAS, projectilePos, CVector(-0.2f, tearGasOffset, 0.0f), 0, 0.0f, 0, 0, 0, 0); + CParticle::AddParticle(PARTICLE_TEARGAS, projectilePos, CVector(tearGasOffset, tearGasOffset, 0.0f), 0, 0.0f, 0, 0, 0, 0); + + if ( CTimer::GetTimeInMilliseconds() & 0x200 ) + CWorld::SetPedsChoking(projectilePos.x, projectilePos.y, projectilePos.z, 6.0f, gaProjectileInfo[i].m_pSource); + } + + if (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_ROCKET) { + CParticle::AddParticlesAlongLine(PARTICLE_ROCKET_SMOKE, gaProjectileInfo[i].m_vecPos, projectilePos, CVector(0.0f, 0.0f, 0.0f), 0.7f, 0, 0, 0, 3000); + } + + if (CTimer::GetTimeInMilliseconds() <= gaProjectileInfo[i].m_nExplosionTime || gaProjectileInfo[i].m_nExplosionTime == 0) { + if (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_ROCKET) { + CVector pos = ms_apProjectile[i]->GetPosition(); + CWorld::pIgnoreEntity = ms_apProjectile[i]; + if (ms_apProjectile[i]->bHasCollided + || !CWorld::GetIsLineOfSightClear(gaProjectileInfo[i].m_vecPos, pos, true, true, true, true, false, false) + || CHeli::TestRocketCollision(&pos) || CPlane::TestRocketCollision(&pos)) { + RemoveProjectile(&gaProjectileInfo[i], ms_apProjectile[i]); + } + CWorld::pIgnoreEntity = nil; + ms_apProjectile[i]->m_vecMoveSpeed *= 1.07f; + + } else if (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_MOLOTOV) { + CVector pos = ms_apProjectile[i]->GetPosition(); + CWorld::pIgnoreEntity = ms_apProjectile[i]; + + if (gaProjectileInfo[i].m_pSource == nil + || ((gaProjectileInfo[i].m_vecPos - gaProjectileInfo[i].m_pSource->GetPosition()).MagnitudeSqr() >= 2.0f)) + { + if (ms_apProjectile[i]->bHasCollided + || !CWorld::GetIsLineOfSightClear(gaProjectileInfo[i].m_vecPos, pos, true, true, true, true, false, false)) { + RemoveProjectile(&gaProjectileInfo[i], ms_apProjectile[i]); + } + } + CWorld::pIgnoreEntity = nil; + } + } else { + if (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_DETONATOR_GRENADE) { + CEntity *ent = gaProjectileInfo[i].m_pSource; + if (ent->IsPed() && ((CPed*)ped)->IsPlayer()) { + CPed *ped = (CPed*)ent; + if (ped->GetWeapon(ped->GetWeaponSlot(WEAPONTYPE_DETONATOR)).m_eWeaponType != WEAPONTYPE_DETONATOR + || ped->GetWeapon(ped->GetWeaponSlot(WEAPONTYPE_DETONATOR)).m_nAmmoTotal == 0) { + gaProjectileInfo[i].m_nExplosionTime = 0; + } + } + } else { + RemoveProjectile(&gaProjectileInfo[i], ms_apProjectile[i]); + } + } + + gaProjectileInfo[i].m_vecPos = ms_apProjectile[i]->GetPosition(); + } +} + +bool +CProjectileInfo::IsProjectileInRange(float x1, float x2, float y1, float y2, float z1, float z2, bool remove) +{ + bool result = false; + for (int i = 0; i < ARRAY_SIZE(ms_apProjectile); i++) { + if (gaProjectileInfo[i].m_bInUse) { + if (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_ROCKET || gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_MOLOTOV || gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_GRENADE) { + const CVector &pos = ms_apProjectile[i]->GetPosition(); + if (pos.x >= x1 && pos.x <= x2 && pos.y >= y1 && pos.y <= y2 && pos.z >= z1 && pos.z <= z2) { + result = true; + if (remove) { +#ifdef SQUEEZE_PERFORMANCE + projectileInUse--; +#endif + + gaProjectileInfo[i].m_bInUse = false; + CWorld::Remove(ms_apProjectile[i]); + delete ms_apProjectile[i]; + } + } + } + } + } + return result; +} + +void +CProjectileInfo::RemoveDetonatorProjectiles() +{ + for (int i = 0; i < ARRAY_SIZE(ms_apProjectile); i++) { + if (gaProjectileInfo[i].m_bInUse && gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_DETONATOR_GRENADE) { + CExplosion::AddExplosion(nil, gaProjectileInfo[i].m_pSource, EXPLOSION_GRENADE, gaProjectileInfo[i].m_vecPos, 0); // TODO(Miami): New parameter: 1 + gaProjectileInfo[i].m_bInUse = false; + CWorld::Remove(ms_apProjectile[i]); + delete ms_apProjectile[i]; + } + } +} + +void +CProjectileInfo::RemoveAllProjectiles() +{ +#ifdef SQUEEZE_PERFORMANCE + if (projectileInUse == 0) + return; +#endif + + for (int i = 0; i < ARRAY_SIZE(ms_apProjectile); i++) { + if (gaProjectileInfo[i].m_bInUse) { +#ifdef SQUEEZE_PERFORMANCE + projectileInUse--; +#endif + + gaProjectileInfo[i].m_bInUse = false; + CWorld::Remove(ms_apProjectile[i]); + delete ms_apProjectile[i]; + } + } +} + +bool +CProjectileInfo::RemoveIfThisIsAProjectile(CObject *object) +{ +#ifdef SQUEEZE_PERFORMANCE + if (projectileInUse == 0) + return false; +#endif + + int i = 0; + while (ms_apProjectile[i++] != object) { + if (i >= ARRAY_SIZE(ms_apProjectile)) + return false; + } + +#ifdef SQUEEZE_PERFORMANCE + projectileInUse--; +#endif + + gaProjectileInfo[i].m_bInUse = false; + CWorld::Remove(ms_apProjectile[i]); + delete ms_apProjectile[i]; + ms_apProjectile[i] = nil; + return true; +} |
