CHeli and CRopes done

This commit is contained in:
aap 2020-07-26 23:41:01 +02:00
parent 7fea567eb2
commit 90fdc4328b
7 changed files with 314 additions and 50 deletions

169
src/core/Ropes.cpp Normal file
View File

@ -0,0 +1,169 @@
#include "common.h"
#include "Timer.h"
#include "ModelIndices.h"
#include "Streaming.h"
#include "CopPed.h"
#include "Population.h"
#include "RenderBuffer.h"
#include "Camera.h"
#include "Ropes.h"
CRope CRopes::aRopes[8];
RwImVertexIndex RopeIndices[64] = {
0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7,
7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15,
15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23,
23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31,
31, 32 // unused
};
void
CRope::Update(void)
{
int i;
float step = Pow(0.85f, CTimer::GetTimeStep());
if(!m_bWasRegistered && CTimer::GetTimeInMilliseconds() > m_updateTimer){
m_speed[0].z -= 0.0015f*CTimer::GetTimeStep();
m_pos[0] += m_speed[0]*CTimer::GetTimeStep();
}
for(i = 1; i < ARRAY_SIZE(m_pos); i++){
CVector prevPos = m_pos[i];
m_pos[i] += m_speed[i]*step*CTimer::GetTimeStep();
m_pos[0].z -= 0.05f*CTimer::GetTimeStep();
CVector dist = m_pos[i] - m_pos[i-1];
m_pos[i] = m_pos[i-1] + dist/dist.Magnitude()*0.625f;
m_speed[i] = (m_pos[i] - prevPos)/CTimer::GetTimeStep();
}
if(!m_bWasRegistered && m_pos[0].z < 0.0f)
m_bActive = false;
m_bWasRegistered = true;
}
void
CRope::Render(void)
{
int i;
int numVerts = 0;
if(!TheCamera.IsSphereVisible(m_pos[16], 20.0f))
return;
for(i = 0; i < ARRAY_SIZE(m_pos); i++){
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[i], 128, 128, 128, 100);
RwIm3DVertexSetPos(&TempBufferRenderVertices[i], m_pos[i].x, m_pos[i].y, m_pos[i].z);
}
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
if(RwIm3DTransform(TempBufferRenderVertices, ARRAY_SIZE(m_pos), nil, rwIM3D_VERTEXXYZ|rwIM3D_VERTEXRGBA)){
RwIm3DRenderIndexedPrimitive(rwPRIMTYPELINELIST, RopeIndices, 2*(ARRAY_SIZE(m_pos)-1));
RwIm3DEnd();
}
}
void
CRopes::Init(void)
{
int i;
for(i = 0; i < ARRAY_SIZE(aRopes); i++)
aRopes[i].m_bActive = false;
}
void
CRopes::Update(void)
{
int i;
for(i = 0; i < ARRAY_SIZE(aRopes); i++)
if(aRopes[i].m_bActive)
aRopes[i].Update();
}
void
CRopes::Render(void)
{
int i;
for(i = 0; i < ARRAY_SIZE(aRopes); i++)
if(aRopes[i].m_bActive)
aRopes[i].Render();
}
bool
CRopes::RegisterRope(uintptr id, CVector pos, bool setUpdateTimer)
{
int i, j;
for(i = 0; i < ARRAY_SIZE(aRopes); i++){
if(aRopes[i].m_bActive && aRopes[i].m_id == id){
aRopes[i].m_pos[0] = pos;
aRopes[i].m_speed[0] = CVector(0.0f, 0.0f, 0.0f);
aRopes[i].m_bWasRegistered = true;
return true;
}
}
for(i = 0; i < ARRAY_SIZE(aRopes); i++)
if(!aRopes[i].m_bActive){
aRopes[i].m_id = id;
aRopes[i].m_pos[0] = pos;
aRopes[i].m_speed[0] = CVector(0.0f, 0.0f, 0.0f);
aRopes[i].m_unk = false;
aRopes[i].m_bWasRegistered = true;
aRopes[i].m_updateTimer = setUpdateTimer ? CTimer::GetTimeInMilliseconds() + 20000 : 0;
for(j = 1; j < ARRAY_SIZE(CRope::m_pos); j++){
if(j & 1)
aRopes[i].m_pos[j] = aRopes[i].m_pos[j-1] + CVector(0.0f, 0.0f, 0.625f);
else
aRopes[i].m_pos[j] = aRopes[i].m_pos[j-1] - CVector(0.0f, 0.0f, 0.625f);
aRopes[i].m_speed[j] = CVector(0.0f, 0.0f, 0.0f);
}
aRopes[i].m_bActive = true;
return true;
}
return false;
}
void
CRopes::SetSpeedOfTopNode(uintptr id, CVector speed)
{
int i;
for(i = 0; i < ARRAY_SIZE(aRopes); i++)
if(aRopes[i].m_bActive && aRopes[i].m_id == id){
aRopes[i].m_speed[0] = speed;
return;
}
}
bool
CRopes::FindCoorsAlongRope(uintptr id, float t, CVector *coors)
{
int i, j;
float f;
for(i = 0; i < ARRAY_SIZE(aRopes); i++)
if(aRopes[i].m_bActive && aRopes[i].m_id == id){
t = (ARRAY_SIZE(CRope::m_pos)-1)*clamp(t, 0.0f, 0.999f);
j = t;
f = t - j;
*coors = (1.0f-f)*aRopes[i].m_pos[j] + f*aRopes[i].m_pos[j+1];
return true;
}
return false;
}
bool
CRopes::CreateRopeWithSwatComingDown(CVector pos)
{
static uint32 ropeId = 0;
if(!CStreaming::HasModelLoaded(MI_SWAT) || !RegisterRope(ropeId+100, pos, true))
return false;
CCopPed *swat = (CCopPed*)CPopulation::AddPed(PEDTYPE_COP, COP_ARMY, pos);
swat->bUsesCollision = false;
swat->m_pRopeEntity = (CEntity*)1;
swat->m_nRopeID = 100 + ropeId;
CAnimManager::BlendAnimation(swat->GetClump(), ASSOCGRP_STD, ANIM_ABSEIL, 4.0f);
ropeId++;
return true;
}

31
src/core/Ropes.h Normal file
View File

@ -0,0 +1,31 @@
#pragma once
class CRope
{
public:
bool m_bActive;
bool m_bWasRegistered;
bool m_unk;
uintptr m_id;
uint32 m_updateTimer;
CVector m_pos[32];
CVector m_speed[32];
void Update(void);
void Render(void);
};
class CRopes
{
static CRope aRopes[8];
public:
static void Init(void);
static void Update(void);
static void Render(void);
static bool RegisterRope(uintptr id, CVector pos, bool setUpdateTimer);
static void SetSpeedOfTopNode(uintptr id, CVector speed);
static bool FindCoorsAlongRope(uintptr id, float t, CVector *coors);
static bool CreateRopeWithSwatComingDown(CVector pos);
};

View File

@ -84,6 +84,7 @@ CCopPed::CCopPed(eCopType copType, int32 modifier) : CPed(PEDTYPE_COP)
m_nRoadblockNode = -1; // TODO(Miami): this will be nil m_nRoadblockNode = -1; // TODO(Miami): this will be nil
m_bThrowsSpikeTrap = false; m_bThrowsSpikeTrap = false;
field_5FF = 0; field_5FF = 0;
m_pRopeEntity = nil;
m_fAbseilPos = 0.0f; m_fAbseilPos = 0.0f;
m_bBeatingSuspect = false; m_bBeatingSuspect = false;
m_pPointGunAt = nil; m_pPointGunAt = nil;

View File

@ -26,6 +26,8 @@ public:
float m_fAbseilPos; float m_fAbseilPos;
eCopType m_nCopType; eCopType m_nCopType;
bool m_bThrowsSpikeTrap; bool m_bThrowsSpikeTrap;
CEntity *m_pRopeEntity; // CHeli or 1
uintptr m_nRopeID;
int32 field_624; int32 field_624;
int8 field_628; int8 field_628;

View File

@ -65,7 +65,7 @@ CPlaneTrail::Render(float visibility)
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
if(RwIm3DTransform(TempBufferRenderVertices, numVerts, nil, rwIM3D_VERTEXXYZ|rwIM3D_VERTEXUV)){ if(RwIm3DTransform(TempBufferRenderVertices, numVerts, nil, rwIM3D_VERTEXXYZ|rwIM3D_VERTEXRGBA)){
RwIm3DRenderIndexedPrimitive(rwPRIMTYPELINELIST, TrailIndices, (numVerts-1)*2); RwIm3DRenderIndexedPrimitive(rwPRIMTYPELINELIST, TrailIndices, (numVerts-1)*2);
RwIm3DEnd(); RwIm3DEnd();
} }
@ -238,7 +238,7 @@ CPlaneBanner::Render(void)
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpRubbishTexture[2])); RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpRubbishTexture[2]));
#ifdef FIX_BUGS #ifdef FIX_BUGS
if(RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, rwIM3D_VERTEXXYZ|rwIM3D_VERTEXUV)){ if(RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, rwIM3D_VERTEXXYZ|rwIM3D_VERTEXUV|rwIM3D_VERTEXRGBA)){
#else #else
if(RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, 0)){ if(RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, 0)){
#endif #endif

View File

@ -14,20 +14,26 @@
#include "Shadows.h" #include "Shadows.h"
#include "Coronas.h" #include "Coronas.h"
#include "Explosion.h" #include "Explosion.h"
#include "WindModifiers.h"
#include "Timecycle.h" #include "Timecycle.h"
#include "TempColModels.h" #include "TempColModels.h"
#include "World.h" #include "World.h"
#include "WaterLevel.h" #include "WaterLevel.h"
#include "Population.h"
#include "PlayerPed.h" #include "PlayerPed.h"
#include "CopPed.h"
#include "Wanted.h" #include "Wanted.h"
#include "DMAudio.h" #include "DMAudio.h"
#include "Object.h" #include "Object.h"
#include "HandlingMgr.h" #include "HandlingMgr.h"
#include "Ropes.h"
#include "Heli.h" #include "Heli.h"
#ifdef FIX_BUGS #ifdef FIX_BUGS
#include "Replay.h" #include "Replay.h"
#endif #endif
//--MIAMI: done
enum enum
{ {
HELI_STATUS_HOVER, HELI_STATUS_HOVER,
@ -40,7 +46,6 @@ enum
CHeli *CHeli::pHelis[NUM_HELIS]; CHeli *CHeli::pHelis[NUM_HELIS];
int16 CHeli::NumRandomHelis; int16 CHeli::NumRandomHelis;
uint32 CHeli::TestForNewRandomHelisTimer; uint32 CHeli::TestForNewRandomHelisTimer;
int16 CHeli::NumScriptHelis; // unused
bool CHeli::CatalinaHeliOn; bool CHeli::CatalinaHeliOn;
bool CHeli::CatalinaHasBeenShotDown; bool CHeli::CatalinaHasBeenShotDown;
bool CHeli::ScriptHeliOn; bool CHeli::ScriptHeliOn;
@ -67,6 +72,9 @@ CHeli::CHeli(int32 id, uint8 CreatedBy)
m_nBulletDamage = 0; m_nBulletDamage = 0;
m_fAngularSpeed = 0.0f; m_fAngularSpeed = 0.0f;
m_fRotation = 0.0f; m_fRotation = 0.0f;
m_numSwat = 4;
m_nSearchLightTimer = CTimer::GetTimeInMilliseconds(); m_nSearchLightTimer = CTimer::GetTimeInMilliseconds();
for(i = 0; i < 6; i++){ for(i = 0; i < 6; i++){
m_aSearchLightHistoryX[i] = 0.0f; m_aSearchLightHistoryX[i] = 0.0f;
@ -82,6 +90,8 @@ CHeli::CHeli(int32 id, uint8 CreatedBy)
m_fTargetOffset = 0.0f; m_fTargetOffset = 0.0f;
m_fSearchLightX = m_fSearchLightY = 0.0f; m_fSearchLightX = m_fSearchLightY = 0.0f;
m_aSwatState[0] = m_aSwatState[1] = m_aSwatState[2] = m_aSwatState[3] = 0;
// BUG: not in game but gets initialized to CDCDCDCD in debug // BUG: not in game but gets initialized to CDCDCDCD in debug
m_nLastShotTime = 0; m_nLastShotTime = 0;
} }
@ -120,6 +130,8 @@ CHeli::ProcessControl(void)
if(gbModelViewer) if(gbModelViewer)
return; return;
CWindModifiers::RegisterOne(GetPosition(), 1);
// Find target // Find target
CVector target(0.0f, 0.0f, 0.0f); CVector target(0.0f, 0.0f, 0.0f);
CVector2D vTargetDist; CVector2D vTargetDist;
@ -266,7 +278,9 @@ CHeli::ProcessControl(void)
if(fTargetDist > targetHeight) if(fTargetDist > targetHeight)
m_heliStatus = HELI_STATUS_CHASE_PLAYER; m_heliStatus = HELI_STATUS_CHASE_PLAYER;
} }
// fall through, BUG? if(m_numSwat)
SendDownSwat();
break;
case HELI_STATUS_CHASE_PLAYER:{ case HELI_STATUS_CHASE_PLAYER:{
float targetHeight; float targetHeight;
if(m_heliType == HELI_TYPE_CATALINA) if(m_heliType == HELI_TYPE_CATALINA)
@ -277,6 +291,7 @@ CHeli::ProcessControl(void)
fTargetDist < targetHeight && CWorld::GetIsLineOfSightClear(GetPosition(), FindPlayerCoors(), true, false, false, false, false, false)) fTargetDist < targetHeight && CWorld::GetIsLineOfSightClear(GetPosition(), FindPlayerCoors(), true, false, false, false, false, false))
m_heliStatus = HELI_STATUS_HOVER; m_heliStatus = HELI_STATUS_HOVER;
} }
break;
} }
// Find xy speed // Find xy speed
@ -346,13 +361,6 @@ CHeli::ProcessControl(void)
if(m_fTargetOffset >= 2.0f) if(m_fTargetOffset >= 2.0f)
m_fTargetOffset -= 2.0f; m_fTargetOffset -= 2.0f;
if(m_heliType == HELI_TYPE_CATALINA)
if(m_pathState == 9 || m_pathState == 11 || m_pathState == 10){
float f = Pow(0.997f, CTimer::GetTimeStep());
m_vecMoveSpeed.x *= f;
m_vecMoveSpeed.y *= f;
}
CVector2D speedDir = targetSpeed - m_vecMoveSpeed; CVector2D speedDir = targetSpeed - m_vecMoveSpeed;
float speedDiff = speedDir.Magnitude(); float speedDiff = speedDir.Magnitude();
if(speedDiff != 0.0f) if(speedDiff != 0.0f)
@ -457,7 +465,7 @@ CHeli::ProcessControl(void)
else if (searchLightDist < 40.0f) else if (searchLightDist < 40.0f)
m_fSearchLightIntensity = 1.0f; m_fSearchLightIntensity = 1.0f;
else else
m_fSearchLightIntensity = 1.0f - (40.0f - searchLightDist) / 40.0f; m_fSearchLightIntensity = 1.0f - (40.0f - searchLightDist) / (60.0f-40.0f);
if (m_fSearchLightIntensity < 0.9f || sq(FindPlayerCoors().x - m_fSearchLightX) + sq(FindPlayerCoors().y - m_fSearchLightY) > sq(7.0f)) if (m_fSearchLightIntensity < 0.9f || sq(FindPlayerCoors().x - m_fSearchLightX) + sq(FindPlayerCoors().y - m_fSearchLightY) > sq(7.0f))
m_nShootTimer = CTimer::GetTimeInMilliseconds(); m_nShootTimer = CTimer::GetTimeInMilliseconds();
@ -524,28 +532,17 @@ CHeli::ProcessControl(void)
} }
} }
// Drop Catalina's bombs // Process ropes
if(m_heliType == HELI_TYPE_CATALINA && m_pathState > 8 && (CTimer::GetTimeInMilliseconds()>>9) != (CTimer::GetPreviousTimeInMilliseconds()>>9)){ for(i = 0; i < 4; i++){
CVector bombPos = GetPosition() - 60.0f*m_vecMoveSpeed; if(m_aSwatState[i] == 0)
if(sq(FindPlayerCoors().x-bombPos.x) + sq(FindPlayerCoors().y-bombPos.y) < sq(35.0f)){ continue;
bool found;
float groundZ = CWorld::FindGroundZFor3DCoord(bombPos.x, bombPos.y, bombPos.z, &found); m_aSwatState[i]--;
float waterZ; CRopes::RegisterRope((uintptr)this + i, GetMatrix()*FindSwatPositionRelativeToHeli(i), false);
if(!CWaterLevel::GetWaterLevelNoWaves(bombPos.x, bombPos.y, bombPos.z, &waterZ)) if(m_aSwatState[i] == 0){
waterZ = 0.0f; CVector speed = Multiply3x3(GetMatrix(), 0.05f*FindSwatPositionRelativeToHeli(i));
if(groundZ > waterZ){ speed.z = 0.0f;
bombPos.z = groundZ + 2.0f; CRopes::SetSpeedOfTopNode((uintptr)this + i, speed);
CExplosion::AddExplosion(nil, this, EXPLOSION_HELI_BOMB, bombPos, 0);
}else{
bombPos.z = waterZ;
CVector dir;
for(i = 0; i < 16; i++){
dir.x = ((CGeneral::GetRandomNumber()&0xFF)-127)*0.001f;
dir.y = ((CGeneral::GetRandomNumber()&0xFF)-127)*0.001f;
dir.z = 0.5f;
CParticle::AddParticle(PARTICLE_BOAT_SPLASH, bombPos, dir, nil, 0.2f);
}
}
} }
} }
@ -664,6 +661,7 @@ CHeli::SpawnFlyingComponent(int32 component)
RpAtomicSetFrame(atomic, frame); RpAtomicSetFrame(atomic, frame);
CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil); CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
obj->AttachToRwObject((RwObject*)atomic); obj->AttachToRwObject((RwObject*)atomic);
obj->bDontStream = true;
// init object // init object
obj->m_fMass = 10.0f; obj->m_fMass = 10.0f;
@ -709,6 +707,42 @@ CHeli::SpawnFlyingComponent(int32 component)
return obj; return obj;
} }
CVector
CHeli::FindSwatPositionRelativeToHeli(int n)
{
switch(n){
case 0: return CVector(-1.2f, -1.0f, -0.5f);
case 1: return CVector( 1.2f, -1.0f, -0.5f);
case 2: return CVector(-1.2f, 1.0f, -0.5f);
case 3: return CVector( 1.2f, 1.0f, -0.5f);
default: return CVector(0.0f, 0.0f, 0.0f);
}
}
bool
CHeli::SendDownSwat(void)
{
if(m_numSwat == 0 || !CStreaming::HasModelLoaded(MI_SWAT) ||
CGeneral::GetRandomNumber() & 0x7F || (GetPosition() - FindPlayerCoors()).Magnitude() > 50.0f)
return false;
CMatrix mat(GetMatrix());
CVector pos = Multiply3x3(mat, FindSwatPositionRelativeToHeli(m_numSwat-1)) + GetPosition();
float groundZ = CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z, nil);
if(Abs(FindPlayerCoors().z - groundZ) < 2.5f && CRopes::RegisterRope((uintptr)this + m_numSwat-1, pos, false)){
CCopPed *swat = (CCopPed*)CPopulation::AddPed(PEDTYPE_COP, COP_ARMY, pos);
swat->bUsesCollision = false;
swat->m_pRopeEntity = this;
RegisterReference(&swat->m_pRopeEntity);
m_numSwat--;
swat->m_nRopeID = m_numSwat;
m_aSwatState[m_numSwat] = 255;
CAnimManager::BlendAnimation(swat->GetClump(), ASSOCGRP_STD, ANIM_ABSEIL, 4.0f);
return true;
}
return false;
}
void void
@ -718,7 +752,6 @@ CHeli::InitHelis(void)
NumRandomHelis = 0; NumRandomHelis = 0;
TestForNewRandomHelisTimer = 0; TestForNewRandomHelisTimer = 0;
NumScriptHelis = 0;
CatalinaHeliOn = false; CatalinaHeliOn = false;
ScriptHeliOn = false; ScriptHeliOn = false;
for(i = 0; i < NUM_HELIS; i++) for(i = 0; i < NUM_HELIS; i++)
@ -734,17 +767,20 @@ GenerateHeli(bool catalina)
CVector heliPos; CVector heliPos;
int i; int i;
heli = new CHeli(MI_CHOPPER, PERMANENT_VEHICLE); if(catalina)
assert(0 && "can't create catalina's heli");
else
heli = new CHeli(MI_CHOPPER, PERMANENT_VEHICLE);
if(catalina) if(catalina)
heliPos = CVector(-224.0f, 201.0f, 83.0f); heliPos = CVector(-224.0f, 201.0f, 83.0f);
else{ else{
heliPos = FindPlayerCoors(); heliPos = FindPlayerCoors();
float angle = (float)(CGeneral::GetRandomNumber() & 0xFF)/0xFF * 6.28f; float angle = (float)(CGeneral::GetRandomNumber() & 0xFF)/0x100 * 6.28f;
heliPos.x += 250.0f*Sin(angle); heliPos.x += 250.0f*Sin(angle);
heliPos.y += 250.0f*Cos(angle); heliPos.y += 250.0f*Cos(angle);
if(heliPos.x < -2000.0f || heliPos.x > 2000.0f || heliPos.y < -2000.0f || heliPos.y > 2000.0f){ if(heliPos.x < -2000.0f-400.0f || heliPos.x > 2000.0f-400.0f || heliPos.y < -2000.0f || heliPos.y > 2000.0f){
// directly above player heliPos = FindPlayerCoors();
heliPos.x -= 250.0f*Sin(angle); heliPos.x -= 250.0f*Sin(angle);
heliPos.y -= 250.0f*Cos(angle); heliPos.y -= 250.0f*Cos(angle);
} }
@ -755,6 +791,7 @@ GenerateHeli(bool catalina)
heli->GetMatrix().SetRotateZOnly(DEGTORAD(270.0f)); // game actually uses 3.14 here heli->GetMatrix().SetRotateZOnly(DEGTORAD(270.0f)); // game actually uses 3.14 here
heli->SetStatus(STATUS_ABANDONED); heli->SetStatus(STATUS_ABANDONED);
heli->bIsLocked = true;
int id = -1; int id = -1;
bool found = false; bool found = false;
@ -783,6 +820,8 @@ CHeli::UpdateHelis(void)
CReplay::IsPlayingBack() ? 0 : CReplay::IsPlayingBack() ? 0 :
#endif #endif
FindPlayerPed()->m_pWanted->NumOfHelisRequired(); FindPlayerPed()->m_pWanted->NumOfHelisRequired();
if(CCullZones::PlayerNoRain() || CGame::IsInInterior())
numHelisRequired = 0;
if(CStreaming::HasModelLoaded(MI_CHOPPER) && CTimer::GetTimeInMilliseconds() > TestForNewRandomHelisTimer){ if(CStreaming::HasModelLoaded(MI_CHOPPER) && CTimer::GetTimeInMilliseconds() > TestForNewRandomHelisTimer){
// Spawn a police heli // Spawn a police heli
TestForNewRandomHelisTimer = CTimer::GetTimeInMilliseconds() + 15000; TestForNewRandomHelisTimer = CTimer::GetTimeInMilliseconds() + 15000;
@ -831,7 +870,7 @@ CHeli::UpdateHelis(void)
TheCamera.CamShake(0.7f, pHelis[i]->GetPosition().x, pHelis[i]->GetPosition().y, pHelis[i]->GetPosition().z); TheCamera.CamShake(0.7f, pHelis[i]->GetPosition().x, pHelis[i]->GetPosition().y, pHelis[i]->GetPosition().z);
colors[0] = CRGBA(0, 0, 0, 255); colors[0] = CRGBA(0, 0, 0, 255);
colors[1] = CRGBA(224, 230, 238, 255); colors[1] = CRGBA(224, 224, 224, 255);
colors[2] = CRGBA(0, 0, 0, 255); colors[2] = CRGBA(0, 0, 0, 255);
colors[3] = CRGBA(0, 0, 0, 255); colors[3] = CRGBA(0, 0, 0, 255);
colors[4] = CRGBA(66, 162, 252, 255); colors[4] = CRGBA(66, 162, 252, 255);
@ -851,7 +890,7 @@ CHeli::UpdateHelis(void)
int f = ++nFrameGen & 3; int f = ++nFrameGen & 3;
CParticle::AddParticle(PARTICLE_HELI_DEBRIS, pos, dir, CParticle::AddParticle(PARTICLE_HELI_DEBRIS, pos, dir,
nil, CGeneral::GetRandomNumberInRange(0.1f, 1.0f), nil, CGeneral::GetRandomNumberInRange(0.1f, 1.0f),
colors[nFrameGen], rotSpeed, 0, f, 0); colors[nFrameGen&7], rotSpeed, 0, f, 0);
} }
CExplosion::AddExplosion(nil, nil, EXPLOSION_HELI, pos, 0); CExplosion::AddExplosion(nil, nil, EXPLOSION_HELI, pos, 0);
@ -869,8 +908,7 @@ CHeli::UpdateHelis(void)
if(i == HELI_CATALINA) if(i == HELI_CATALINA)
CatalinaHasBeenShotDown = true; CatalinaHasBeenShotDown = true;
CStats::HelisDestroyed++; CStats::PeopleKilledByPlayer += 2;
CStats::PeopleKilledByOthers += 2;
CStats::PedsKilledOfThisType[PEDTYPE_COP] += 2; CStats::PedsKilledOfThisType[PEDTYPE_COP] += 2;
CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 250; CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 250;
pos = CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetPosition(); pos = CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetPosition();
@ -888,8 +926,8 @@ CHeli::UpdateHelis(void)
TheCamera.CamShake(0.4f, pHelis[i]->GetPosition().x, pHelis[i]->GetPosition().y, pHelis[i]->GetPosition().z); TheCamera.CamShake(0.4f, pHelis[i]->GetPosition().x, pHelis[i]->GetPosition().y, pHelis[i]->GetPosition().z);
CVector pos = pHelis[i]->GetPosition() - 2.5f*pHelis[i]->GetUp(); CVector pos = pHelis[i]->GetPosition() - 2.5f*pHelis[i]->GetForward();
CExplosion::AddExplosion(nil, nil, EXPLOSION_HELI, pos, 0); CExplosion::AddExplosion(nil, nil, EXPLOSION_HELI2, pos, 0);
}else }else
pHelis[i]->m_fAngularSpeed *= 1.03f; pHelis[i]->m_fAngularSpeed *= 1.03f;
} }
@ -904,7 +942,7 @@ CHeli::UpdateHelis(void)
pHelis[i]->m_heliStatus = HELI_STATUS_FLY_AWAY; pHelis[i]->m_heliStatus = HELI_STATUS_FLY_AWAY;
} }
// Remove all helis if in a tunnel // Remove all helis if in a tunnel or under water
if(FindPlayerCoors().z < - 2.0f) if(FindPlayerCoors().z < - 2.0f)
for(i = 0; i < NUM_HELIS; i++) for(i = 0; i < NUM_HELIS; i++)
if(pHelis[i] && pHelis[i]->m_heliStatus != HELI_STATUS_SHOT_DOWN) if(pHelis[i] && pHelis[i]->m_heliStatus != HELI_STATUS_SHOT_DOWN)
@ -949,7 +987,7 @@ CHeli::TestBulletCollision(CVector *line0, CVector *line1, CVector *bulletPos, i
float distToHeli = (pHelis[i]->GetPosition() - *line0).Magnitude(); float distToHeli = (pHelis[i]->GetPosition() - *line0).Magnitude();
CVector line = (*line1 - *line0); CVector line = (*line1 - *line0);
float lineLength = line.Magnitude(); float lineLength = line.Magnitude();
*bulletPos = *line0 + line*Max(1.0f, distToHeli-5.0f); *bulletPos = *line0 + line*Max(1.0f, distToHeli-5.0f)/lineLength;
pHelis[i]->m_nBulletDamage += damage; pHelis[i]->m_nBulletDamage += damage;
@ -965,6 +1003,26 @@ CHeli::TestBulletCollision(CVector *line0, CVector *line1, CVector *bulletPos, i
return hit; return hit;
} }
bool
CHeli::TestSniperCollision(CVector *line0, CVector *line1)
{
int i;
bool hit = false;
for(i = 0; i < NUM_HELIS; i++){
CVector pilotPos = pHelis[i]->GetMatrix() * CVector(-0.43f, 1.49f, 1.5f);
if(pHelis[i] && !pHelis[i]->bBulletProof && CCollision::DistToLine(line0, line1, &pilotPos) < 0.8f){
pHelis[i]->m_fAngularSpeed = CGeneral::GetRandomTrueFalse() ? 0.05f : -0.05f;
pHelis[i]->m_heliStatus = HELI_STATUS_SHOT_DOWN;
pHelis[i]->m_nExplosionTimer = CTimer::GetTimeInMilliseconds() + 9999999;
pHelis[i]->m_numSwat = 0;
hit = true;
}
}
return hit;
}
void CHeli::StartCatalinaFlyBy(void) void CHeli::StartCatalinaFlyBy(void)
{ {
CatalinaHeliOn = true; CatalinaHeliOn = true;

View File

@ -21,7 +21,7 @@ enum
HELI_RANDOM0, HELI_RANDOM0,
HELI_RANDOM1, HELI_RANDOM1,
HELI_SCRIPT, HELI_SCRIPT,
HELI_CATALINA, HELI_CATALINA, // TODO 2 in VC
NUM_HELIS NUM_HELIS
}; };
@ -36,7 +36,6 @@ enum
class CHeli : public CVehicle class CHeli : public CVehicle
{ {
public: public:
// 0x288
RwFrame *m_aHeliNodes[NUM_HELI_NODES]; RwFrame *m_aHeliNodes[NUM_HELI_NODES];
int8 m_heliStatus; int8 m_heliStatus;
float m_fSearchLightX; float m_fSearchLightX;
@ -49,6 +48,8 @@ public:
int8 m_nHeliId; int8 m_nHeliId;
int8 m_heliType; int8 m_heliType;
int8 m_pathState; int8 m_pathState;
int8 m_numSwat;
uint8 m_aSwatState[4];
float m_aSearchLightHistoryX[6]; float m_aSearchLightHistoryX[6];
float m_aSearchLightHistoryY[6]; float m_aSearchLightHistoryY[6];
uint32 m_nSearchLightTimer; uint32 m_nSearchLightTimer;
@ -64,7 +65,6 @@ public:
static CHeli *pHelis[NUM_HELIS]; static CHeli *pHelis[NUM_HELIS];
static int16 NumRandomHelis; static int16 NumRandomHelis;
static uint32 TestForNewRandomHelisTimer; static uint32 TestForNewRandomHelisTimer;
static int16 NumScriptHelis; // unused
static bool CatalinaHeliOn; static bool CatalinaHeliOn;
static bool CatalinaHasBeenShotDown; static bool CatalinaHasBeenShotDown;
static bool ScriptHeliOn; static bool ScriptHeliOn;
@ -79,12 +79,15 @@ public:
void PreRenderAlways(void); void PreRenderAlways(void);
CObject *SpawnFlyingComponent(int32 component); CObject *SpawnFlyingComponent(int32 component);
CVector FindSwatPositionRelativeToHeli(int n);
bool SendDownSwat(void);
static void InitHelis(void); static void InitHelis(void);
static void UpdateHelis(void); static void UpdateHelis(void);
static void SpecialHeliPreRender(void); static void SpecialHeliPreRender(void);
static bool TestRocketCollision(CVector *coors); static bool TestRocketCollision(CVector *coors);
static bool TestBulletCollision(CVector *line0, CVector *line1, CVector *bulletPos, int32 damage); static bool TestBulletCollision(CVector *line0, CVector *line1, CVector *bulletPos, int32 damage);
static bool TestSniperCollision(CVector *line0, CVector *line1);
static void StartCatalinaFlyBy(void); static void StartCatalinaFlyBy(void);
static void RemoveCatalinaHeli(void); static void RemoveCatalinaHeli(void);