summaryrefslogtreecommitdiffstats
path: root/src/vehicles
diff options
context:
space:
mode:
Diffstat (limited to 'src/vehicles')
-rw-r--r--src/vehicles/Automobile.cpp8
-rw-r--r--src/vehicles/Bike.cpp2
-rw-r--r--src/vehicles/Boat.cpp959
-rw-r--r--src/vehicles/Boat.h28
-rw-r--r--src/vehicles/CarGen.cpp17
-rw-r--r--src/vehicles/CarGen.h2
-rw-r--r--src/vehicles/Cranes.cpp6
-rw-r--r--src/vehicles/Floater.cpp177
-rw-r--r--src/vehicles/Floater.h2
-rw-r--r--src/vehicles/Heli.cpp148
-rw-r--r--src/vehicles/Heli.h9
-rw-r--r--src/vehicles/Plane.cpp273
-rw-r--r--src/vehicles/Plane.h14
-rw-r--r--src/vehicles/Vehicle.cpp18
-rw-r--r--src/vehicles/Vehicle.h2
15 files changed, 1194 insertions, 471 deletions
diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp
index b643e336..08f14d68 100644
--- a/src/vehicles/Automobile.cpp
+++ b/src/vehicles/Automobile.cpp
@@ -1349,7 +1349,7 @@ CAutomobile::ProcessControl(void)
if(!IsAlarmOn())
ReduceHornCounter();
}else{
- if(UsesSiren(GetModelIndex())){
+ if(UsesSiren()){
if(Pads[0].bHornHistory[Pads[0].iCurrHornHistory]){
if(Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % 5] &&
Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+3) % 5])
@@ -1559,7 +1559,7 @@ CAutomobile::ProcessControl(void)
if(m_bSirenOrAlarm && (CTimer::GetFrameCounter()&7) == 5 &&
- UsesSiren(GetModelIndex()) && GetModelIndex() != MI_MRWHOOP)
+ UsesSiren() && GetModelIndex() != MI_MRWHOOP)
CCarAI::MakeWayForCarWithSiren(this);
@@ -2527,7 +2527,7 @@ CAutomobile::PreRender(void)
if(GetModelIndex() == MI_RCGOBLIN || GetModelIndex() == MI_RCRAIDER)
radius = 3.0f;
if(GetPosition().z - groundZ < radius)
- HeliDustGenerate(this, radius-(GetPosition().z - groundZ), groundZ, ceilf(rnd));
+ HeliDustGenerate(this, radius-(GetPosition().z - groundZ), groundZ, Ceil(rnd));
}
CMatrix mat;
@@ -3800,7 +3800,7 @@ void
CAutomobile::DoDriveByShootings(void)
{
CAnimBlendAssociation *anim = nil;
- CPlayerInfo* playerInfo = ((CPlayerPed*)this)->GetPlayerInfoForThisPlayerPed();
+ CPlayerInfo* playerInfo = ((CPlayerPed*)pDriver)->GetPlayerInfoForThisPlayerPed();
if (playerInfo && !playerInfo->m_bDriveByAllowed)
return;
diff --git a/src/vehicles/Bike.cpp b/src/vehicles/Bike.cpp
index 169bde73..c32e72bc 100644
--- a/src/vehicles/Bike.cpp
+++ b/src/vehicles/Bike.cpp
@@ -1989,7 +1989,7 @@ void
CBike::DoDriveByShootings(void)
{
CAnimBlendAssociation *anim;
- CPlayerInfo* playerInfo = ((CPlayerPed*)this)->GetPlayerInfoForThisPlayerPed();
+ CPlayerInfo* playerInfo = ((CPlayerPed*)pDriver)->GetPlayerInfoForThisPlayerPed();
if (playerInfo && !playerInfo->m_bDriveByAllowed)
return;
diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp
index 673372b0..ae437f56 100644
--- a/src/vehicles/Boat.cpp
+++ b/src/vehicles/Boat.cpp
@@ -2,6 +2,7 @@
#include "General.h"
#include "Timecycle.h"
+#include "Weather.h"
#include "HandlingMgr.h"
#include "CarAI.h"
#include "CarCtrl.h"
@@ -13,9 +14,11 @@
#include "Darkel.h"
#include "Explosion.h"
#include "Particle.h"
+#include "ParticleObject.h"
#include "WaterLevel.h"
#include "Floater.h"
#include "World.h"
+#include "Stats.h"
#include "Pools.h"
#include "Pad.h"
#include "Boat.h"
@@ -23,6 +26,8 @@
#include "RpAnimBlend.h"
#include "Record.h"
+//--MIAMI: file done
+
#define INVALID_ORIENTATION (-9999.99f)
float fShapeLength = 0.4f;
@@ -51,11 +56,15 @@ CBoat::CBoat(int mi, uint8 owner) : CVehicle(owner)
m_fBrake = 0.0f;
m_fSteeringLeftRight = 0.0f;
m_nPadID = 0;
- m_fMovingHiRotation = 0.0f;
+ m_fMovingRotation = 0.0f;
+ m_fMovingSpeed = 0.0f;
+ m_skimmerThingTimer = 0.0f;
+ m_nPoliceShoutTimer = CTimer::GetTimeInMilliseconds();
SetModelIndex(mi);
pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)minfo->m_handlingId);
pFlyingHandling = mod_HandlingManager.GetFlyingPointer((eHandlingId)minfo->m_handlingId);
+ pBoatHandling = mod_HandlingManager.GetBoatPointer((eHandlingId)minfo->m_handlingId);
minfo->ChooseVehicleColour(m_currentColour1, m_currentColour2);
m_fMass = pHandling->fMass;
@@ -68,11 +77,7 @@ CBoat::CBoat(int mi, uint8 owner) : CVehicle(owner)
m_fGasPedal = 0.0f;
m_fBrakePedal = 0.0f;
- m_fPropellerZ = 0.25f;
- m_fPropellerY = 0.35f;
- m_waterMoveDrag = CVector(0.7f, 0.998f, 0.999f);
- m_waterTurnDrag = CVector(0.85f, 0.96f, 0.96f);
- _unk2 = false;
+ m_boat_unused3 = false;
m_fVolumeUnderWater = 7.0f;
m_fPrevVolumeUnderWater = 7.0f;
@@ -85,6 +90,7 @@ CBoat::CBoat(int mi, uint8 owner) : CVehicle(owner)
bIsInWater = true;
m_phys_unused1 = 0.0f;
+ m_boat_unused2 = 0;
m_bIsAnchored = true;
m_fOrientation = INVALID_ORIENTATION;
bTouchingWater = true;
@@ -96,6 +102,11 @@ CBoat::CBoat(int mi, uint8 owner) : CVehicle(owner)
m_afWakePointLifeTime[i] = 0.0f;
m_nAmmoInClip = 20;
+
+ if(GetModelIndex() == MI_MARQUIS)
+ m_boom.Init(-PI/10.0f, PI/10.0f, 0, 2);
+ else
+ m_boom.Init(-PI/5.0f, PI/5.0f, 0, 2);
}
void
@@ -118,32 +129,51 @@ CBoat::ProcessControl(void)
PruneWakeTrail();
+ if(bRenderScorched)
+ m_fBuoyancy *= 0.99f;
+
+ if(FindPlayerPed()->m_pWanted->m_nWantedLevel > 0 && GetModelIndex() == MI_PREDATOR){
+ CVehicle *playerVeh = FindPlayerVehicle();
+ if(playerVeh && playerVeh->GetVehicleAppearance() == VEHICLE_APPEARANCE_BOAT &&
+ (AutoPilot.m_nCarMission == MISSION_RAMPLAYER_FARAWAY ||
+ AutoPilot.m_nCarMission == MISSION_RAMPLAYER_CLOSE ||
+ AutoPilot.m_nCarMission == MISSION_BLOCKPLAYER_FARAWAY ||
+ AutoPilot.m_nCarMission == MISSION_BLOCKPLAYER_CLOSE ||
+ AutoPilot.m_nCarMission == MISSION_ATTACKPLAYER) &&
+ CTimer::GetTimeInMilliseconds() > m_nPoliceShoutTimer){
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_115, 0.0f);
+ m_nPoliceShoutTimer = CTimer::GetTimeInMilliseconds() + 4500 + (CGeneral::GetRandomNumber()&0xFFF);
+ }
+ }
+
int r, g, b;
+ RwRGBA dropColor = { 0, 0, 0, 0 };
RwRGBA splashColor, jetColor;
- r = 114.75f*(CTimeCycle::GetAmbientRed() + 0.5f*CTimeCycle::GetDirectionalRed());
- g = 114.75f*(CTimeCycle::GetAmbientGreen() + 0.5f*CTimeCycle::GetDirectionalGreen());
- b = 114.75f*(CTimeCycle::GetAmbientBlue() + 0.5f*CTimeCycle::GetDirectionalBlue());
+ r = 127.5f*(CTimeCycle::GetAmbientRed_Obj() + 0.5f*CTimeCycle::GetDirectionalRed());
+ g = 127.5f*(CTimeCycle::GetAmbientGreen_Obj() + 0.5f*CTimeCycle::GetDirectionalGreen());
+ b = 127.5f*(CTimeCycle::GetAmbientBlue_Obj() + 0.5f*CTimeCycle::GetDirectionalBlue());
r = clamp(r, 0, 255);
g = clamp(g, 0, 255);
b = clamp(b, 0, 255);
splashColor.red = r;
splashColor.green = g;
splashColor.blue = b;
- splashColor.alpha = CGeneral::GetRandomNumberInRange(128, 150);
+ splashColor.alpha = CGeneral::GetRandomNumberInRange(160, 196);
- r = 242.25f*(CTimeCycle::GetAmbientRed() + 0.5f*CTimeCycle::GetDirectionalRed());
- g = 242.25f*(CTimeCycle::GetAmbientGreen() + 0.5f*CTimeCycle::GetDirectionalGreen());
- b = 242.25f*(CTimeCycle::GetAmbientBlue() + 0.5f*CTimeCycle::GetDirectionalBlue());
+ r = 229.5f*(CTimeCycle::GetAmbientRed() + 0.85f*CTimeCycle::GetDirectionalRed());
+ g = 229.5f*(CTimeCycle::GetAmbientGreen() + 0.85f*CTimeCycle::GetDirectionalGreen());
+ b = 229.5f*(CTimeCycle::GetAmbientBlue() + 0.85f*CTimeCycle::GetDirectionalBlue());
r = clamp(r, 0, 255);
g = clamp(g, 0, 255);
b = clamp(b, 0, 255);
jetColor.red = r;
jetColor.green = g;
jetColor.blue = b;
- jetColor.alpha = CGeneral::GetRandomNumberInRange(96, 128);
+ jetColor.alpha = CGeneral::GetRandomNumberInRange(196, 228);
CGeneral::GetRandomNumber(); // unused
+ UpdateClumpAlpha();
ProcessCarAlarm();
switch(GetStatus()){
@@ -181,7 +211,7 @@ CBoat::ProcessControl(void)
bIsHandbrakeOn = false;
m_fBrakePedal = 0.5f;
m_fGasPedal = 0.0f;
- if((GetPosition() - CWorld::Players[CWorld::PlayerInFocus].GetPos()).Magnitude() > 150.0f){
+ if((GetPosition() - FindPlayerCentreOfWorld_NoSniperShift()).Magnitude() > 150.0f){
m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
return;
@@ -192,33 +222,42 @@ CBoat::ProcessControl(void)
float collisionDamage = pHandling->fCollisionDamageMultiplier * m_fDamageImpulse;
#ifdef FIX_BUGS
- if (collisionDamage > 25.0f && GetStatus() != STATUS_WRECKED && m_fHealth >= 150.0f && !bCollisionProof) {
+ if(GetStatus() == STATUS_PLAYER && CStats::GetPercentageProgress() >= 100.0f)
+ collisionDamage *= 0.5f;
+ if (collisionDamage > 25.0f && GetStatus() != STATUS_WRECKED && !bCollisionProof) {
#else
- if(collisionDamage > 25.0f && GetStatus() != STATUS_WRECKED && m_fHealth >= 150.0f){
+ if(collisionDamage > 25.0f && GetStatus() != STATUS_WRECKED){
#endif
float prevHealth = m_fHealth;
- if(this == FindPlayerVehicle()){
- if(bTakeLessDamage)
- m_fHealth -= (collisionDamage-25.0f)/6.0f;
- else
- m_fHealth -= (collisionDamage-25.0f)/2.0f;
- }else{
- if(collisionDamage > 60.0f && pDriver)
- pDriver->Say(SOUND_PED_CAR_COLLISION);
- if(bTakeLessDamage)
- m_fHealth -= (collisionDamage-25.0f)/12.0f;
- else
- m_fHealth -= (collisionDamage-25.0f)/4.0f;
- }
+ if(prevHealth >= 250.0f){
+#ifndef FIX_BUGS
+ // if collisionDamage < 50 we actually increase health here...
+ if(GetStatus() == STATUS_PLAYER && CStats::GetPercentageProgress() >= 100.0f)
+ collisionDamage *= 0.5f;
+#endif
+ if(this == FindPlayerVehicle()){
+ if(bTakeLessDamage)
+ m_fHealth -= (collisionDamage-25.0f)/6.0f;
+ else
+ m_fHealth -= (collisionDamage-25.0f)/2.0f;
+ }else{
+ if(collisionDamage > 60.0f && pDriver)
+ pDriver->Say(SOUND_PED_CAR_COLLISION);
+ if(bTakeLessDamage)
+ m_fHealth -= (collisionDamage-25.0f)/12.0f;
+ else
+ m_fHealth -= (collisionDamage-25.0f)/4.0f;
+ }
- if(m_fHealth <= 0.0f && prevHealth > 0.0f){
- m_fHealth = 1.0f;
- m_pSetOnFireEntity = m_pDamageEntity;
+ if(m_fHealth <= 0.0f && prevHealth > 0.0f){
+ m_fHealth = 1.0f;
+ m_pSetOnFireEntity = m_pDamageEntity;
+ }
}
}
// Damage particles
- if(m_fHealth <= 600.0f && GetStatus() != STATUS_WRECKED &&
+ if(m_fHealth <= 460.0f && GetStatus() != STATUS_WRECKED &&
Abs(GetPosition().x - TheCamera.GetPosition().x) < 200.0f &&
Abs(GetPosition().y - TheCamera.GetPosition().y) < 200.0f){
float speedSq = m_vecMoveSpeed.MagnitudeSqr();
@@ -244,7 +283,7 @@ CBoat::ProcessControl(void)
smokePos = GetMatrix() * smokePos;
// On fire
- if(m_fHealth < 150.0f){
+ if(m_fHealth < 250.0f){
CParticle::AddParticle(PARTICLE_CARFLAME, smokePos,
CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(2.25f/200.0f, 0.09f)),
nil, 0.9f);
@@ -261,23 +300,26 @@ CBoat::ProcessControl(void)
if(speedSq < 0.25f && (CTimer::GetFrameCounter() + m_randomSeed) & 1)
CParticle::AddParticle(PARTICLE_ENGINE_STEAM, smokePos, smokeDir);
- if(speedSq < 0.25f && m_fHealth <= 350.0f)
+ if(speedSq < 0.25f && m_fHealth <= 390.0f)
CParticle::AddParticle(PARTICLE_ENGINE_SMOKE, smokePos, 1.25f*smokeDir);
}
+ bool bSeparateTurnForce = bHasHitWall;
CPhysical::ProcessControl();
CVector buoyanceImpulse(0.0f, 0.0f, 0.0f);
CVector buoyancePoint(0.0f, 0.0f, 0.0f);
- if(mod_Buoyancy.ProcessBuoyancy(this, pHandling->fBuoyancy, &buoyancePoint, &buoyanceImpulse)){
+ if(mod_Buoyancy.ProcessBuoyancyBoat(this, pHandling->fBuoyancy, &buoyancePoint, &buoyanceImpulse, bSeparateTurnForce)){
// Process boat in water
if(0.1f * m_fMass * GRAVITY*CTimer::GetTimeStep() < buoyanceImpulse.z){
bBoatInWater = true;
bIsInWater = true;
if (GetUp().z < -0.6f && Abs(GetMoveSpeed().x) < 0.05 && Abs(GetMoveSpeed().y) < 0.05) {
bIsDrowning = true;
- if (pDriver)
+ if (pDriver){
+ pDriver->bTouchingWater = true;
pDriver->InflictDamage(nil, WEAPONTYPE_DROWNING, CTimer::GetTimeStep(), PEDPIECE_TORSO, 0);
+ }
}
else
bIsDrowning = false;
@@ -289,32 +331,61 @@ CBoat::ProcessControl(void)
m_fVolumeUnderWater = mod_Buoyancy.m_volumeUnderWater;
m_vecBuoyancePoint = buoyancePoint;
- ApplyMoveForce(buoyanceImpulse);
- if(!onLand)
- ApplyTurnForce(buoyanceImpulse, buoyancePoint);
+ if(GetModelIndex() == MI_SKIMMER && GetUp().z < -0.5f && Abs(m_vecMoveSpeed.x) < 0.2f && Abs(m_vecMoveSpeed.y) < 0.2f)
+ ApplyMoveForce(0.03f*buoyanceImpulse);
+ else
+ ApplyMoveForce(buoyanceImpulse);
+ if(bSeparateTurnForce)
+ ApplyTurnForce(0.4f*buoyanceImpulse, buoyancePoint);
+
+ // TODO: what is this?
+ if(GetModelIndex() == MI_SKIMMER)
+ if(m_skimmerThingTimer != 0.0f ||
+ GetForward().z < -0.5f && GetUp().z > -0.5f && m_vecMoveSpeed.z < -0.15f &&
+ buoyanceImpulse.z > 0.01f*m_fMass * GRAVITY*CTimer::GetTimeStep() &&
+ buoyanceImpulse.z < 0.4f*m_fMass * GRAVITY*CTimer::GetTimeStep()){
+ float turnImpulse = -0.00017f*GetForward().z*buoyanceImpulse.z * m_fMass*CTimer::GetTimeStep();
+ ApplyTurnForce(turnImpulse*GetForward(), GetUp());
+ bBoatInWater = false;
+ //BUG? aren't we forgetting the timestep here?
+ float moveImpulse = -0.5f*DotProduct(m_vecMoveSpeed, GetForward()) * m_fMass;
+ ApplyMoveForce(moveImpulse*GetForward());
+ if(m_skimmerThingTimer == 0.0f)
+ m_skimmerThingTimer = CTimer::GetTimeInMilliseconds() + 300.0f;
+ else if(m_skimmerThingTimer < CTimer::GetTimeInMilliseconds())
+ m_skimmerThingTimer = 0.0f;
+ }
if(!onLand && bBoatInWater && GetUp().z > 0.0f){
- float impulse;
- if(m_fGasPedal > 0.05f)
- impulse = m_vecMoveSpeed.MagnitudeSqr()*pHandling->fSuspensionForceLevel*buoyanceImpulse.z*CTimer::GetTimeStep()*0.5f*m_fGasPedal;
+ float impulse = m_vecMoveSpeed.MagnitudeSqr()*pBoatHandling->fAqPlaneForce*buoyanceImpulse.z*CTimer::GetTimeStep()*0.5f;
+ if(GetModelIndex() == MI_SKIMMER)
+ impulse *= 1.0f + m_fGasPedal;
+ else if(m_fGasPedal > 0.05f)
+ impulse *= m_fGasPedal;
else
impulse = 0.0f;
- impulse = Min(impulse, GRAVITY*pHandling->fSuspensionDampingLevel*m_fMass*CTimer::GetTimeStep());
+ impulse = Min(impulse, GRAVITY*pBoatHandling->fAqPlaneLimit*m_fMass*CTimer::GetTimeStep());
ApplyMoveForce(impulse*GetUp());
- ApplyTurnForce(impulse*GetUp(), buoyancePoint - pHandling->fSuspensionBias*GetForward());
+ ApplyTurnForce(impulse*GetUp(), buoyancePoint - pBoatHandling->fAqPlaneOffset*GetForward());
}
// Handle boat moving forward
- if(Abs(m_fGasPedal) > 0.05f || m_vecMoveSpeed.Magnitude() > 0.01f){
- if(bBoatInWater)
+ float fwdSpeed = 1.0f;
+ if(Abs(m_fGasPedal) > 0.05f || (fwdSpeed = m_vecMoveSpeed.Magnitude2D()) > 0.01f){
+ if(bBoatInWater && fwdSpeed > 0.05f)
AddWakePoint(GetPosition());
- float steerFactor = 1.0f - DotProduct(m_vecMoveSpeed, GetForward());
-// if (GetModelIndex() == MI_GHOST)
-// steerFactor = 1.0f - DotProduct(m_vecMoveSpeed, GetForward())*0.3f;
- if(steerFactor < 0.0f) steerFactor = 0.0f;
+ float steerFactor = 1.0f;
+ if(GetStatus() == STATUS_PLAYER){
+ float steerLoss = DotProduct(m_vecMoveSpeed, GetForward())*pHandling->fTractionBias;
+ if(CPad::GetPad(0)->GetHandBrake())
+ steerLoss *= 0.5f;
+ steerFactor -= steerLoss;
+ steerFactor = clamp(steerFactor, 0.0f, 1.0f);
+ }
- CVector propeller(0.0f, -pHandling->Dimension.y*m_fPropellerY, -pHandling->Dimension.z*m_fPropellerZ);
+ CVector boundMin = GetColModel()->boundingBox.min;
+ CVector propeller(0.0f, boundMin.y*pBoatHandling->fThrustY, boundMin.z*pBoatHandling->fThrustZ);
propeller = Multiply3x3(GetMatrix(), propeller);
CVector propellerWorld = GetPosition() + propeller;
@@ -330,7 +401,11 @@ CBoat::ProcessControl(void)
propellerDepth = SQR(propellerDepth);
bPropellerInWater = true;
- if(Abs(m_fGasPedal) > 0.05f){
+ bool bSlowAhead = false;
+ if(Abs(m_fGasPedal) > 0.01f && GetModelIndex() != MI_SKIMMER){
+ if(Abs(m_fGasPedal) < 0.05f)
+ bSlowAhead = true;
+
CVector forceDir = Multiply3x3(GetMatrix(), CVector(-steerSin, steerCos, -Abs(m_fSteerAngle)));
CVector force = propellerDepth * m_fGasPedal * 40.0f * pHandling->Transmission.fEngineAcceleration * pHandling->fMass * forceDir;
if(force.z > 0.2f)
@@ -345,80 +420,75 @@ CBoat::ProcessControl(void)
ApplyMoveForce(force * CTimer::GetTimeStep());
}else{
ApplyMoveForce(force * CTimer::GetTimeStep());
- ApplyTurnForce(force * CTimer::GetTimeStep(), propeller - pHandling->fTractionBias*GetUp());
- float rightForce = DotProduct(GetRight(), force);
- ApplyTurnForce(-rightForce*GetRight() * CTimer::GetTimeStep(), GetUp());
+ ApplyTurnForce(force * CTimer::GetTimeStep(), propeller - pBoatHandling->fThrustAppZ*GetUp());
+ float rightForce = -DotProduct(GetRight(), force)*pHandling->fTractionMultiplier;
+ ApplyTurnForce(rightForce*GetRight() * CTimer::GetTimeStep(), GetUp());
}
// Spray some particles
CVector jetDir = -0.04f * force;
if(m_fGasPedal > 0.0f){
if(GetStatus() == STATUS_PLAYER){
- bool cameraHack = TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN ||
- TheCamera.WhoIsInControlOfTheCamera == CAMCONTROL_OBBE;
CVector sternPos = GetColModel()->boundingBox.min;
sternPos.x = 0.0f;
sternPos.z = 0.0f;
sternPos = Multiply3x3(GetMatrix(), sternPos);
- CVector jetPos = GetPosition() + sternPos;
- if(cameraHack)
- jetPos.z = 1.0f;
- else
- jetPos.z = 0.0f;
-
-#ifdef PC_PARTICLE
- CVector wakePos = GetPosition() + sternPos;
- wakePos.z -= 0.65f;
-#else
CVector wakePos = GetPosition() + sternPos;
- wakePos.z = -0.3f;
-#endif
-
- CVector wakeDir = 0.75f * jetDir;
-
- CParticle::AddParticle(PARTICLE_BOAT_THRUSTJET, jetPos, jetDir, nil, 0.0f, jetColor);
-#ifdef PC_PARTICLE
- CParticle::AddParticle(PARTICLE_CAR_SPLASH, jetPos, 0.25f * jetDir, nil, 1.0f, splashColor,
- CGeneral::GetRandomNumberInRange(0, 30),
- CGeneral::GetRandomNumberInRange(0, 90), 3);
-#endif
- //TODO: MIAMI:
- //if(!cameraHack)
- // CParticle::AddParticle(PARTICLE_BOAT_WAKE, wakePos, wakeDir, nil, 0.0f, jetColor);
- }else if((CTimer::GetFrameCounter() + m_randomSeed) & 1){
-#ifdef PC_PARTICLE
- jetDir.z = 0.018f;
- jetDir.x *= 0.01f;
- jetDir.y *= 0.01f;
- propellerWorld.z += 1.5f;
-
- CParticle::AddParticle(PARTICLE_BOAT_SPLASH, propellerWorld, jetDir, nil, 1.5f, jetColor);
-#else
- jetDir.z = 0.018f;
- jetDir.x *= 0.03f;
- jetDir.y *= 0.03f;
- propellerWorld.z += 1.0f;
+ // no actual particles for player...
+ }else if(IsVisible() && ((CTimer::GetFrameCounter() + m_randomSeed) & 1) &&
+ CVisibilityPlugins::GetDistanceSquaredFromCamera((RwV3d*)&propellerWorld) < SQR(70.0f * TheCamera.GenerationDistMultiplier)){
+ jetDir.z = 0.015f;
+ jetDir.x *= 3.5f;
+ jetDir.y *= 3.5f;
+ propellerWorld.z += 0.5f;
- CParticle::AddParticle(PARTICLE_BOAT_SPLASH, propellerWorld, jetDir, nil, 0.0f, jetColor);
-#endif
+ CParticle::AddParticle(PARTICLE_BOAT_SPLASH, propellerWorld, jetDir, nil, 1.25f, jetColor,
+ CGeneral::GetRandomNumberInRange(0, 5),
+ CGeneral::GetRandomNumberInRange(0, 90), 1, 500);
-#ifdef PC_PARTICLE
- CParticle::AddParticle(PARTICLE_CAR_SPLASH, propellerWorld, 0.1f * jetDir, nil, 0.5f, splashColor,
+ CParticle::AddParticle(PARTICLE_CAR_SPLASH, propellerWorld, 0.75f * jetDir, nil, 0.5f, splashColor,
CGeneral::GetRandomNumberInRange(0, 30),
- CGeneral::GetRandomNumberInRange(0, 90), 3);
-#endif
+ CGeneral::GetRandomNumberInRange(0, 45), 3, 500);
}
}
- }else if(!onLand){
- float force = 50.0f*DotProduct(m_vecMoveSpeed, GetForward());
- if(force > 10.0f) force = 10.0f;
+ }else
+ bSlowAhead = true;
+
+ if(!onLand && bSlowAhead){
+ float force = pHandling->fTractionLoss*DotProduct(m_vecMoveSpeed, GetForward());
+ force = Min(force, 0.01f*m_fTurnMass);
+ if(m_fGasPedal > 0.01f){
+ if(GetStatus() == STATUS_PLAYER)
+ force *= (0.55f - Abs(m_fGasPedal)) * 1.3f;
+ else
+ force *= (0.55f - Abs(m_fGasPedal)) * 2.5f;
+ }
+ if(m_fGasPedal < 0.0f && force > 0.0f || m_fGasPedal > 0.0f && force < 0.0f)
+ force *= -1.0f;
CVector propellerForce = propellerDepth * Multiply3x3(GetMatrix(), force*CVector(-steerSin, 0.0f, 0.0f));
- ApplyMoveForce(propellerForce * CTimer::GetTimeStep()*0.5f);
- ApplyTurnForce(propellerForce * CTimer::GetTimeStep()*0.5f, propeller);
+ ApplyMoveForce(propellerForce * CTimer::GetTimeStep());
+ ApplyTurnForce(propellerForce * CTimer::GetTimeStep(), propeller);
+ float rightForce = -steerSin * force * 0.75f/steerFactor * Max(CTimer::GetTimeStep(), 0.01f);
+ ApplyTurnForce(GetRight() * rightForce, GetUp());
}
}else
bPropellerInWater = false;
+
+ if(pHandling->fSuspensionBias != 0.0f){
+ CVector right = CrossProduct(GetForward(), CVector(0.0f, 0.0f, 1.0f));
+ float rightSpeed = DotProduct(m_vecMoveSpeed, right);
+ float impulse = 0.1f*pHandling->fSuspensionBias * m_fMass * m_fVolumeUnderWater * rightSpeed * CTimer::GetTimeStep();
+ ApplyMoveForce(right - impulse * 0.3f * CVector(-right.y, right.x, 0.0f));
+ }
+
+ if(GetStatus() == STATUS_PLAYER && CPad::GetPad(0)->GetHandBrake()){
+ float fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward());
+ if(fwdSpeed > 0.0f){
+ float impulse = -0.1f*pHandling->fSuspensionLowerLimit * m_fMass * m_fVolumeUnderWater * fwdSpeed * CTimer::GetTimeStep();
+ ApplyMoveForce(impulse * GetForward());
+ }
+ }
}
// Slow down or push down boat as it approaches the world limits
@@ -427,111 +497,249 @@ CBoat::ProcessControl(void)
m_vecMoveSpeed.y = Min(m_vecMoveSpeed.y, -(GetPosition().y - (WORLD_MAX_Y-100.0f))*0.01f); // north
m_vecMoveSpeed.y = Max(m_vecMoveSpeed.y, -(GetPosition().y - (WORLD_MIN_Y+100.0f))*0.01f); // south
- if(!onLand && bBoatInWater)
+ if(!onLand && bBoatInWater && !bSeparateTurnForce)
ApplyWaterResistance();
- // No idea what exactly is going on here besides drag in YZ
- float fx = Pow(m_waterTurnDrag.x, CTimer::GetTimeStep());
- float fy = Pow(m_waterTurnDrag.y, CTimer::GetTimeStep());
- float fz = Pow(m_waterTurnDrag.z, CTimer::GetTimeStep());
- m_vecTurnSpeed = Multiply3x3(m_vecTurnSpeed, GetMatrix()); // invert - to local space
- // TODO: figure this out
- float magic = 1.0f/(1000.0f * SQR(m_vecTurnSpeed.x) + 1.0f) * fx;
- m_vecTurnSpeed.y *= fy;
- m_vecTurnSpeed.z *= fz;
- float forceUp = (magic - 1.0f) * m_vecTurnSpeed.x * m_fTurnMass;
- m_vecTurnSpeed = Multiply3x3(GetMatrix(), m_vecTurnSpeed); // back to world
- CVector com = Multiply3x3(GetMatrix(), m_vecCentreOfMass);
- ApplyTurnForce(CVector(0.0f, 0.0f, forceUp), com + GetForward());
+ if((GetModelIndex() != MI_SKIMMER || m_skimmerThingTimer == 0.0f) && !bSeparateTurnForce){
+ // No idea what exactly is going on here besides drag in YZ
+ float fx = Pow(pBoatHandling->vecTurnRes.x, CTimer::GetTimeStep());
+ float fy = Pow(pBoatHandling->vecTurnRes.y, CTimer::GetTimeStep());
+ float fz = Pow(pBoatHandling->vecTurnRes.z, CTimer::GetTimeStep());
+ m_vecTurnSpeed = Multiply3x3(m_vecTurnSpeed, GetMatrix()); // invert - to local space
+ // TODO: figure this out
+ float magic = 1.0f/(1000.0f * SQR(m_vecTurnSpeed.x) + 1.0f) * fx;
+ m_vecTurnSpeed.y *= fy;
+ m_vecTurnSpeed.z *= fz;
+ float forceUp = (magic - 1.0f) * m_vecTurnSpeed.x * m_fTurnMass;
+ m_vecTurnSpeed = Multiply3x3(GetMatrix(), m_vecTurnSpeed); // back to world
+ CVector com = Multiply3x3(GetMatrix(), m_vecCentreOfMass);
+ ApplyTurnForce(forceUp*GetUp(), com + GetForward());
+ }
m_nDeltaVolumeUnderWater = (m_fVolumeUnderWater-m_fPrevVolumeUnderWater)*10000;
// Falling into water
- if(!onLand && bBoatInWater && GetUp().z > 0.0f && m_nDeltaVolumeUnderWater > 200){
- DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_SPLASH, m_nDeltaVolumeUnderWater);
-
- float speedUp = m_vecMoveSpeed.MagnitudeSqr() * m_nDeltaVolumeUnderWater * 0.0004f;
- if(speedUp + m_vecMoveSpeed.z > pHandling->fBrakeDeceleration)
- speedUp = pHandling->fBrakeDeceleration - m_vecMoveSpeed.z;
- if(speedUp < 0.0f) speedUp = 0.0f;
- float speedFwd = DotProduct(m_vecMoveSpeed, GetForward());
- speedFwd *= -m_nDeltaVolumeUnderWater * 0.01f * pHandling->fBrakeBias;
- CVector speed = speedFwd*GetForward() + CVector(0.0f, 0.0f, speedUp);
- CVector splashImpulse = speed * m_fMass;
- ApplyMoveForce(splashImpulse);
- ApplyTurnForce(splashImpulse, buoyancePoint);
+ if(!onLand && bBoatInWater && GetUp().z > 0.0f){
+ float splashVol = m_nDeltaVolumeUnderWater*pBoatHandling->fWaveAudioMult;
+ if(splashVol > 200.0f)
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_SPLASH, splashVol);
+
+ if(m_nDeltaVolumeUnderWater > 200){
+ float speedUp = m_vecMoveSpeed.MagnitudeSqr() * m_nDeltaVolumeUnderWater * 0.001f;
+ if(speedUp + m_vecMoveSpeed.z > pHandling->fBrakeDeceleration)
+ speedUp = pHandling->fBrakeDeceleration - m_vecMoveSpeed.z;
+ if(speedUp < 0.0f) speedUp = 0.0f;
+ float speedFwd = DotProduct(m_vecMoveSpeed, GetForward());
+ speedFwd *= -m_nDeltaVolumeUnderWater * 0.01f * pHandling->fBrakeBias;
+ CVector speed = speedFwd*GetForward() + CVector(0.0f, 0.0f, speedUp);
+ CVector splashImpulse = speed * m_fMass;
+ ApplyMoveForce(splashImpulse);
+ ApplyTurnForce(splashImpulse, buoyancePoint);
+ }
}
- // Spray particles on sides of boat
-#ifdef PC_PARTICLE
- if(m_nDeltaVolumeUnderWater > 75)
-#else
- if(m_nDeltaVolumeUnderWater > 120)
-#endif
- {
- float speed = m_vecMoveSpeed.Magnitude();
- float splash1Size = speed;
- float splash2Size = float(m_nDeltaVolumeUnderWater) * 0.005f * 0.2f;
- float front = 0.9f * GetColModel()->boundingBox.max.y;
- if(splash1Size > 0.75f) splash1Size = 0.75f;
-
- CVector dir, pos;
-
- // right
-#ifdef PC_PARTICLE
- dir = -0.5f*m_vecMoveSpeed;
- dir.z += 0.1f*speed;
- dir += 0.5f*GetRight()*speed;
- pos = front*GetForward() + 0.5f*GetRight() + GetPosition() + m_vecBuoyancePoint;
- CWaterLevel::GetWaterLevel(pos, &pos.z, true);
-#else
- dir = 0.3f*m_vecMoveSpeed;
- dir.z += 0.05f*speed;
- dir += 0.5f*GetRight()*speed;
- pos = (GetPosition() + m_vecBuoyancePoint) + (1.5f*GetRight());
-#endif
-
-#ifdef PC_PARTICLE
- CParticle::AddParticle(PARTICLE_CAR_SPLASH, pos, 0.75f * dir, nil, splash1Size, splashColor,
- CGeneral::GetRandomNumberInRange(0, 30),
- CGeneral::GetRandomNumberInRange(0, 90), 1);
- CParticle::AddParticle(PARTICLE_BOAT_SPLASH, pos, dir, nil, splash2Size, jetColor);
-#else
- CParticle::AddParticle(PARTICLE_BOAT_SPLASH, pos, dir, nil, splash2Size);
-#endif
-
-
- // left
-#ifdef PC_PARTICLE
- dir = -0.5f*m_vecMoveSpeed;
- dir.z += 0.1f*speed;
- dir -= 0.5f*GetRight()*speed;
- pos = front*GetForward() - 0.5f*GetRight() + GetPosition() + m_vecBuoyancePoint;
- CWaterLevel::GetWaterLevel(pos, &pos.z, true);
-#else
- dir = 0.3f*m_vecMoveSpeed;
- dir.z += 0.05f*speed;
- dir -= 0.5f*GetRight()*speed;
- pos = (GetPosition() + m_vecBuoyancePoint) - (1.5f*GetRight());
-#endif
-
-#ifdef PC_PARTICLE
- CParticle::AddParticle(PARTICLE_CAR_SPLASH, pos, 0.75f * dir, nil, splash1Size, splashColor,
- CGeneral::GetRandomNumberInRange(0, 30),
- CGeneral::GetRandomNumberInRange(0, 90), 1);
- CParticle::AddParticle(PARTICLE_BOAT_SPLASH, pos, dir, nil, splash2Size, jetColor);
-#else
- CParticle::AddParticle(PARTICLE_BOAT_SPLASH, pos, dir, nil, splash2Size);
-#endif
+ // Splashes
+ float speed = m_vecMoveSpeed.Magnitude();
+ if(speed > 0.05f && GetUp().x > 0.0f && !TheCamera.GetLookingForwardFirstPerson() && IsVisible() &&
+ (AutoPilot.m_nCarMission != MISSION_CRUISE || (CTimer::GetFrameCounter()&2) == 0)){
+ CVector splashPos, splashDir;
+ float splashSize, front, waterLevel;
+
+ switch(GetModelIndex()){
+ case MI_RIO:
+ splashSize = speed;
+ front = 0.9f * GetColModel()->boundingBox.max.y;
+ splashDir = -0.5f * m_vecMoveSpeed;
+ splashDir.z += 0.25f*speed;
+ splashDir += 0.35f*speed*GetRight();
+ splashPos = GetPosition() + 1.85f*GetRight() + front*GetForward();
+ splashPos.z += 0.5f;
+ break;
+ case MI_SQUALO:
+ splashSize = speed;
+ front = 0.75f * GetColModel()->boundingBox.max.y;
+ splashDir = -0.125f * m_vecMoveSpeed;
+ splashDir.z += 0.15f*speed;
+ splashDir += 0.25f*speed*GetRight();
+ splashPos = GetPosition() + m_vecBuoyancePoint + 0.5f*GetRight() + front*GetForward();
+ splashPos.z += 0.5f;
+ break;
+ case MI_REEFER:
+ splashSize = speed;
+ front = 0.75f * GetColModel()->boundingBox.max.y;
+ splashDir = -0.5f * m_vecMoveSpeed;
+ splashDir.z += 0.15f*speed;
+ splashDir += 0.5f*speed*GetRight();
+ splashPos = GetPosition() + m_vecBuoyancePoint + 1.3f*GetRight() + front*GetForward();
+ break;
+ case MI_COASTG:
+ splashSize = 0.25f*speed;
+ front = 0.8f * GetColModel()->boundingBox.max.y;
+ splashDir = 0.165f * m_vecMoveSpeed;
+ splashDir.z += 0.25f*speed;
+ splashDir += 0.15f*speed*GetRight();
+ splashPos = GetPosition() + 0.65f*GetRight() + front*GetForward();
+ splashPos.z += 0.5f;
+ break;
+ case MI_DINGHY:
+ splashSize = 0.25f*speed;
+ front = 0.9f * GetColModel()->boundingBox.max.y;
+ splashDir = 0.35f * m_vecMoveSpeed;
+ splashDir.z += 0.25f*speed;
+ splashDir += 0.25f*speed*GetRight();
+ splashPos = GetPosition() + 0.6f*GetRight() + front*GetForward();
+ splashPos.z += 0.5f;
+ break;
+ default:
+ splashSize = speed;
+ front = 0.9f * GetColModel()->boundingBox.max.y;
+ splashDir = -0.5f * m_vecMoveSpeed;
+ splashDir.z += 0.25f*speed;
+ splashDir += 0.35f*speed*GetRight();
+ splashPos = GetPosition() + m_vecBuoyancePoint + 0.5f*GetRight() + front*GetForward();
+ break;
+ }
+ if(splashSize > 0.75f) splashSize = 0.75f;
+ if(AutoPilot.m_nCarMission == MISSION_CRUISE)
+ splashDir *= 1.5f;
+ static float lifeMult = 1000.0f;
+ static float lifeBase = 300.0f;
+ splashDir.z += 0.0003f*m_nDeltaVolumeUnderWater;
+ CWaterLevel::GetWaterLevel(splashPos, &waterLevel, true);
+ if(splashPos.z-waterLevel < 3.0f &&
+ CVisibilityPlugins::GetDistanceSquaredFromCamera((RwV3d*)&splashPos) < SQR(70.0f * TheCamera.GenerationDistMultiplier)){
+ splashPos.z = waterLevel + 0.1f;
+ CParticle::AddParticle(PARTICLE_CAR_SPLASH, splashPos, 0.75f*splashDir, nil, splashSize+0.1f, splashColor,
+ CGeneral::GetRandomNumberInRange(0.0f, 10.0f), CGeneral::GetRandomNumberInRange(0.0f, 90.0f),
+ 1, lifeBase + splashDir.z*lifeMult);
+ CParticle::AddParticle(PARTICLE_BOAT_SPLASH, splashPos, splashDir, nil, splashSize, jetColor,
+ CGeneral::GetRandomNumberInRange(0.0f, 0.4f), CGeneral::GetRandomNumberInRange(0.0f, 45.0f),
+ 0, lifeBase + splashDir.z*lifeMult);
+ }
+
+ switch(GetModelIndex()){
+ case MI_RIO:
+ splashDir = -0.5f * m_vecMoveSpeed;
+ splashDir.z += 0.25f*speed;
+ splashDir -= 0.35f*speed*GetRight();
+ splashPos = GetPosition() - 1.85f*GetRight() + front*GetForward();
+ splashPos.z += 0.5f;
+ break;
+ case MI_SQUALO:
+ splashDir = -0.125f * m_vecMoveSpeed;
+ splashDir.z += 0.15f*speed;
+ splashDir -= 0.25f*speed*GetRight();
+ splashPos = GetPosition() + m_vecBuoyancePoint - 0.5f*GetRight() + front*GetForward();
+ splashPos.z += 0.5f;
+ break;
+ case MI_REEFER:
+ splashDir = -0.5f * m_vecMoveSpeed;
+ splashDir.z += 0.15f*speed;
+ splashDir -= 0.5f*speed*GetRight();
+ splashPos = GetPosition() + m_vecBuoyancePoint - 1.3f*GetRight() + front*GetForward();
+ break;
+ case MI_COASTG:
+ splashDir = 0.165f * m_vecMoveSpeed;
+ splashDir.z += 0.25f*speed;
+ splashDir -= 0.15f*speed*GetRight();
+ splashPos = GetPosition() - 0.65f*GetRight() + front*GetForward();
+ splashPos.z += 0.5f;
+ break;
+ case MI_DINGHY:
+ splashDir = 0.35f * m_vecMoveSpeed;
+ splashDir.z += 0.25f*speed;
+ splashDir -= 0.25f*speed*GetRight();
+ splashPos = GetPosition() - 0.6f*GetRight() + front*GetForward();
+ splashPos.z += 0.5f;
+ break;
+ default:
+ splashDir = -0.5f * m_vecMoveSpeed;
+ splashDir.z += 0.25f*speed;
+ splashDir -= 0.35f*speed*GetRight();
+ splashPos = GetPosition() + m_vecBuoyancePoint - 0.5f*GetRight() + front*GetForward();
+ break;
+ }
+ if(AutoPilot.m_nCarMission == MISSION_CRUISE)
+ splashDir *= 1.5f;
+ splashDir.z += 0.0003f*m_nDeltaVolumeUnderWater;
+ CWaterLevel::GetWaterLevel(splashPos, &waterLevel, true);
+ if(splashPos.z-waterLevel < 3.0f &&
+ CVisibilityPlugins::GetDistanceSquaredFromCamera((RwV3d*)&splashPos) < SQR(70.0f * TheCamera.GenerationDistMultiplier)){
+ splashPos.z = waterLevel + 0.1f;
+ CParticle::AddParticle(PARTICLE_CAR_SPLASH, splashPos, 0.75f*splashDir, nil, splashSize+0.1f, splashColor,
+ CGeneral::GetRandomNumberInRange(0.0f, 10.0f), CGeneral::GetRandomNumberInRange(0.0f, 90.0f),
+ 1, lifeBase + splashDir.z*lifeMult);
+ CParticle::AddParticle(PARTICLE_BOAT_SPLASH, splashPos, splashDir, nil, splashSize, jetColor,
+ CGeneral::GetRandomNumberInRange(0.0f, 0.4f), CGeneral::GetRandomNumberInRange(0.0f, 45.0f),
+ 0, lifeBase + splashDir.z*lifeMult);
+ }
+ }
+
+ // Spray waterdrops on screen
+ if(TheCamera.GetLookingForwardFirstPerson() && FindPlayerVehicle() && FindPlayerVehicle()->IsBoat() &&
+ m_nDeltaVolumeUnderWater > 0 && numWaterDropOnScreen < 20){
+ CVector dropPos;
+ CVector dropDir(CGeneral::GetRandomNumberInRange(-0.25f, 0.25f), CGeneral::GetRandomNumberInRange(1.0f, 0.75f), 0.0f);
+
+ int frm = CGeneral::GetRandomNumber() & 1;
+ if(TheCamera.m_CameraAverageSpeed < 0.35f){
+ dropPos.x = CGeneral::GetRandomNumberInRange(50, (int)SCREEN_WIDTH-50);
+ dropPos.y = CGeneral::GetRandomNumberInRange(50, (int)SCREEN_HEIGHT-50);
+ }else{
+ dropPos.x = CGeneral::GetRandomNumberInRange(200, (int)SCREEN_WIDTH-200);
+ dropPos.y = CGeneral::GetRandomNumberInRange(150, (int)SCREEN_HEIGHT-150);
+ }
+ dropPos.z = 1.0f;
+
+ if(TheCamera.m_CameraAverageSpeed > 0.35f){
+ if((int)SCREEN_WIDTH / 2 < dropPos.x)
+ dropPos.x += CGeneral::GetRandomNumberInRange(0.35f, TheCamera.m_CameraAverageSpeed)*7.5f;
+ else
+ dropPos.x -= CGeneral::GetRandomNumberInRange(0.35f, TheCamera.m_CameraAverageSpeed)*7.5f;
+
+ if((int)SCREEN_HEIGHT / 2 < dropPos.y)
+ dropPos.y += CGeneral::GetRandomNumberInRange(0.35f, TheCamera.m_CameraAverageSpeed)*7.5f;
+ else
+ dropPos.y -= CGeneral::GetRandomNumberInRange(0.35f, TheCamera.m_CameraAverageSpeed)*7.5f;
+ }
+
+ if(CParticle::AddParticle(PARTICLE_WATERDROP, dropPos, dropDir, nil,
+ CGeneral::GetRandomNumberInRange(0.1f, 0.15f), dropColor, 0, 0, frm))
+ numWaterDropOnScreen++;
+ }
+
+ if(m_fPrevVolumeUnderWater == 0.0f && m_fVolumeUnderWater > 0.0f && GetModelIndex() == MI_SKIMMER){
+ CVector splashDir(0.0f, 0.0f, 0.25f*speed);
+ CVector splashPos = GetPosition();
+ float level;
+ CWaterLevel::GetWaterLevel(splashPos, &level, true);
+ splashPos.z = level;
+ CParticleObject::AddObject(POBJECT_CAR_WATER_SPLASH, splashPos, splashDir, 0.0f, 65, splashColor, true);
}
m_fPrevVolumeUnderWater = m_fVolumeUnderWater;
}else{
bBoatInWater = false;
bIsInWater = false;
+#ifdef FIX_BUGS
bIsDrowning = false;
+#endif
}
+ if(m_modelIndex == MI_SKIMMER && CTimer::GetTimeStep() > 0.0f){
+ if(GetStatus() == STATUS_PLAYER){
+ if(m_fMovingSpeed < 0.22f)
+ m_fMovingSpeed += 0.001f*CTimer::GetTimeStep();
+ FlyingControl(FLIGHT_MODEL_SEAPLANE);
+ }else{
+ if(m_fMovingSpeed > 0.0005f*CTimer::GetTimeStep())
+ m_fMovingSpeed -= 0.0005f*CTimer::GetTimeStep();
+ else
+ m_fMovingSpeed = 0.0f;
+ }
+ }else if(bCheat8)
+ FlyingControl(FLIGHT_MODEL_PLANE);
+
if(m_bIsAnchored){
m_vecMoveSpeed.x = 0.0f;
m_vecMoveSpeed.y = 0.0f;
@@ -542,29 +750,7 @@ CBoat::ProcessControl(void)
// is this some inlined CPlaceable method?
CVector pos = GetPosition();
GetMatrix().RotateZ(m_fOrientation - GetForward().Heading());
- GetMatrix().GetPosition() = pos;
- }
- }
-
- if (m_modelIndex == MI_SKIMMER && CTimer::GetTimeStep() > 0.0f) {
- if (GetStatus() == STATUS_PLAYER) {
- if (m_fPropellerY <= CTimer::GetTimeStep() * 0.0005f) {
- m_fPropellerY = 0.0f;
- }
- else {
- m_fPropellerY -= CTimer::GetTimeStep() * 0.0005f;
- }
- }
- else {
- if (m_fPropellerY < 0.22f) {
- m_fPropellerY += CTimer::GetTimeStep() * 0.001f;
- }
- FlyingControl(FLIGHT_MODEL_SEAPLANE);
- }
- }
- else {
- if (bCheat8) {
- FlyingControl(FLIGHT_MODEL_PLANE);
+ GetMatrix().SetTranslateOnly(pos);
}
}
@@ -596,17 +782,21 @@ CBoat::ProcessControlInputs(uint8 pad)
m_fGasPedal = m_fAccelerate;
}
+float fSeaPlaneWaterResistance = 30.0f;
+
void
CBoat::ApplyWaterResistance(void)
{
- float fwdSpeed = DotProduct(GetMoveSpeed(), GetForward());
// TODO: figure out how this works
- float magic = (SQR(fwdSpeed) + 0.05f) * (0.001f * SQR(m_fVolumeUnderWater) * m_fMass) + 1.0f;
+ float resistance = 0.001f * pHandling->fSuspensionForceLevel * SQR(m_fVolumeUnderWater) * m_fMass;
+ if(GetModelIndex() == MI_SKIMMER)
+ resistance *= fSeaPlaneWaterResistance;
+ float fwdSpeed = DotProduct(GetMoveSpeed(), GetForward());
+ float magic = (SQR(fwdSpeed) + 0.05f) * resistance + 1.0f;
magic = Abs(magic);
- // FRAMETIME
- float fx = Pow(m_waterMoveDrag.x/magic, 0.5f*CTimer::GetTimeStep());
- float fy = Pow(m_waterMoveDrag.y/magic, 0.5f*CTimer::GetTimeStep());
- float fz = Pow(m_waterMoveDrag.z/magic, 0.5f*CTimer::GetTimeStep());
+ float fx = Pow(pBoatHandling->vecMoveRes.x/magic, 0.5f*CTimer::GetTimeStep());
+ float fy = Pow(pBoatHandling->vecMoveRes.y/magic, 0.5f*CTimer::GetTimeStep());
+ float fz = Pow(pBoatHandling->vecMoveRes.z/magic, 0.5f*CTimer::GetTimeStep());
m_vecMoveSpeed = Multiply3x3(m_vecMoveSpeed, GetMatrix()); // invert - to local space
m_vecMoveSpeed.x *= fx;
@@ -655,19 +845,14 @@ CBoat::BlowUpCar(CEntity *culprit)
m_nBombTimer = 0;
TheCamera.CamShake(0.7f, GetPosition().x, GetPosition().y, GetPosition().z);
- if(this == FindPlayerVehicle())
- FindPlayerPed()->m_fHealth = 0.0f; // kill player
- if(pDriver){
- CDarkel::RegisterKillByPlayer(pDriver, WEAPONTYPE_EXPLOSION);
- pDriver->SetDead();
- pDriver->FlagToDestroyWhenNextProcessed();
- }
+ KillPedsInVehicle();
bEngineOn = false;
bLightsOn = false;
ChangeLawEnforcerState(false);
- CExplosion::AddExplosion(this, culprit, EXPLOSION_CAR, GetPosition(), 0);
+ CExplosion::AddExplosion(this, culprit, EXPLOSION_BOAT, GetPosition(), 0);
+ CDarkel::RegisterCarBlownUpByPlayer(this);
if(m_aBoatNodes[BOAT_MOVING] == nil)
return;
@@ -695,6 +880,7 @@ CBoat::BlowUpCar(CEntity *culprit)
RpAtomicSetFrame(atomic, frame);
CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
obj->AttachToRwObject((RwObject*)atomic);
+ obj->bDontStream = true;
// init object
obj->m_fMass = 10.0f;
@@ -724,7 +910,7 @@ CBoat::BlowUpCar(CEntity *culprit)
dist.Normalise();
if(GetUp().z > 0.0f)
dist += GetUp();
- obj->GetMatrix().GetPosition() += GetUp();
+ obj->GetMatrix().GetPosition() += dist;
CWorld::Add(obj);
@@ -734,41 +920,200 @@ CBoat::BlowUpCar(CEntity *culprit)
RpAtomicSetFlags(atomic, 0);
}
-RwIm3DVertex KeepWaterOutVertices[4];
-RwImVertexIndex KeepWaterOutIndices[6];
-
void
-CBoat::Render()
+CBoat::PreRender(void)
{
CMatrix matrix;
+ CVector pos;
+ RpAtomic *atomic;
- if (m_aBoatNodes[BOAT_MOVING] != nil) {
- matrix.Attach(RwFrameGetMatrix(m_aBoatNodes[BOAT_MOVING]));
+ if(GetModelIndex() == MI_SKIMMER){
+ m_fMovingRotation += m_fMovingSpeed*CTimer::GetTimeStep();
+ if(m_fMovingRotation > TWOPI) m_fMovingRotation -= TWOPI;
+ int alpha = (1.0f - Min(2.0f*m_fMovingSpeed*8.0f/PI, 1.0f))*255.0f;
+ if(GetStatus() == STATUS_PLAYER || GetStatus() == STATUS_PLAYER_REMOTE || GetStatus() == STATUS_PLAYER_PLAYBACKFROMBUFFER){
+ if(m_aBoatNodes[BOAT_RUDDER]){
+ float sine = Sin(m_fSteerAngle);
+ matrix.Attach(RwFrameGetMatrix(m_aBoatNodes[BOAT_RUDDER]));
+ pos = matrix.GetPosition();
+ matrix.SetRotate(0.0f, 0.0f, -m_fSteerAngle);
+ matrix.Rotate(0.0f, DEGTORAD(22.0f)*sine, 0.0f);
+ matrix.Translate(pos);
+ matrix.UpdateRW();
+ }
+ if(m_aBoatNodes[BOAT_FLAP_LEFT]){
+ matrix.Attach(RwFrameGetMatrix(m_aBoatNodes[BOAT_FLAP_LEFT]));
+ pos = matrix.GetPosition();
+ matrix.SetRotateX(-m_fSteerAngle);
+ matrix.Translate(pos);
+ matrix.UpdateRW();
+ }
+ if(m_aBoatNodes[BOAT_FLAP_RIGHT]){
+ matrix.Attach(RwFrameGetMatrix(m_aBoatNodes[BOAT_FLAP_RIGHT]));
+ pos = matrix.GetPosition();
+ matrix.SetRotateX(m_fSteerAngle);
+ matrix.Translate(pos);
+ matrix.UpdateRW();
+ }
+ if(m_aBoatNodes[BOAT_REARFLAP_LEFT]){
+ matrix.Attach(RwFrameGetMatrix(m_aBoatNodes[BOAT_REARFLAP_LEFT]));
+ pos = matrix.GetPosition();
+ matrix.SetRotateX(-CPad::GetPad(0)->GetSteeringUpDown()/128.0f);
+ matrix.Translate(pos);
+ matrix.UpdateRW();
+ }
+ if(m_aBoatNodes[BOAT_REARFLAP_RIGHT]){
+ matrix.Attach(RwFrameGetMatrix(m_aBoatNodes[BOAT_REARFLAP_RIGHT]));
+ pos = matrix.GetPosition();
+ matrix.SetRotateX(-CPad::GetPad(0)->GetSteeringUpDown()/128.0f);
+ matrix.Translate(pos);
+ matrix.UpdateRW();
+ }
+ }
+ if(m_aBoatNodes[BOAT_MOVING]){
+ matrix.Attach(RwFrameGetMatrix(m_aBoatNodes[BOAT_MOVING]));
+ pos = matrix.GetPosition();
+ matrix.SetRotateY(m_fMovingRotation);
+ matrix.Translate(pos);
+ matrix.UpdateRW();
+
+ atomic = nil;
+ RwFrameForAllObjects(m_aBoatNodes[BOAT_MOVING], GetBoatAtomicObjectCB, &atomic);
+ if(atomic)
+ SetComponentAtomicAlpha(atomic, alpha);
+ }
+ if(m_aBoatNodes[BOAT_WINDSCREEN]){
+ matrix.Attach(RwFrameGetMatrix(m_aBoatNodes[BOAT_WINDSCREEN]));
+ pos = matrix.GetPosition();
+ matrix.SetRotateY(-m_fMovingRotation);
+ matrix.Translate(pos);
+ matrix.UpdateRW();
+
+ atomic = nil;
+ RwFrameForAllObjects(m_aBoatNodes[BOAT_WINDSCREEN], GetBoatAtomicObjectCB, &atomic);
+ if(atomic)
+ SetComponentAtomicAlpha(atomic, Max(150-alpha, 0));
+ }
+ //CShadows::StoreShadowForVehicle(this);
+ }else if(GetModelIndex() == MI_COASTG || GetModelIndex() == MI_DINGHY || GetModelIndex() == MI_RIO ||
+ GetModelIndex() == MI_SQUALO || GetModelIndex() == MI_MARQUIS){
+ if(m_aBoatNodes[BOAT_RUDDER]){
+ matrix.Attach(RwFrameGetMatrix(m_aBoatNodes[BOAT_RUDDER]));
+ pos = matrix.GetPosition();
+ matrix.SetRotateZ(-m_fSteerAngle);
+ matrix.Translate(pos);
+ matrix.UpdateRW();
+ }
+ if(m_aBoatNodes[BOAT_REARFLAP_LEFT]){
+ matrix.Attach(RwFrameGetMatrix(m_aBoatNodes[BOAT_REARFLAP_LEFT]));
+ pos = matrix.GetPosition();
+ matrix.SetRotateZ(-m_fSteerAngle);
+ matrix.Translate(pos);
+ matrix.UpdateRW();
+ }
+ if(m_aBoatNodes[BOAT_REARFLAP_RIGHT]){
+ matrix.Attach(RwFrameGetMatrix(m_aBoatNodes[BOAT_REARFLAP_RIGHT]));
+ pos = matrix.GetPosition();
+ matrix.SetRotateZ(-m_fSteerAngle);
+ matrix.Translate(pos);
+ matrix.UpdateRW();
+ }
+ }
- CVector pos = matrix.GetPosition();
- matrix.SetRotateZ(m_fMovingHiRotation);
+ if(GetModelIndex() == MI_RIO || GetModelIndex() == MI_MARQUIS){
+ float axes[3] = { 0.0f, 0.0f, 0.0f };
+ m_boom.Process(this);
+ axes[m_boom.m_nAxis] = m_boom.m_fAngle;
+ matrix.Attach(RwFrameGetMatrix(m_aBoatNodes[BOAT_FLAP_LEFT]));
+ pos = matrix.GetPosition();
+ matrix.SetRotate(axes[0], axes[1], axes[2]);
matrix.Translate(pos);
-
matrix.UpdateRW();
- if (CVehicle::bWheelsOnlyCheat) {
- RpAtomicRender((RpAtomic*)GetFirstObject(m_aBoatNodes[BOAT_MOVING]));
+ }
+
+ if(GetModelIndex() == MI_RIO){
+ // That little wind propeller
+ if(m_aBoatNodes[BOAT_FLAP_RIGHT]){
+ matrix.Attach(RwFrameGetMatrix(m_aBoatNodes[BOAT_FLAP_RIGHT]));
+ pos = matrix.GetPosition();
+
+ float flapHeading = matrix.GetForward().Heading();
+ float boatHeading = GetForward().Heading();
+ float rot = -DEGTORAD(45.0f) - (flapHeading + boatHeading);
+ // eh what?
+ rot = CGeneral::LimitRadianAngle(rot);
+ if(rot > HALFPI) rot = PI;
+ else if(rot < -HALFPI) rot = -PI;
+ rot = clamp(rot, -DEGTORAD(63.0f), DEGTORAD(63.0f));
+ m_fMovingSpeed += (0.008f * CWeather::Wind + 0.002f) * rot;
+ m_fMovingSpeed *= Pow(0.9985f, CTimer::GetTimeStep())/(500.0f*SQR(m_fMovingSpeed) + 1.0f);
+
+ matrix.SetRotateZ(flapHeading + m_fMovingSpeed*CTimer::GetTimeStep());
+ matrix.Translate(pos);
+ matrix.UpdateRW();
+ }
+ if(m_aBoatNodes[BOAT_MOVING]){
+ matrix.Attach(RwFrameGetMatrix(m_aBoatNodes[BOAT_MOVING]));
+ pos = matrix.GetPosition();
+ matrix.SetRotateY(m_fMovingRotation);
+ matrix.Translate(pos);
+ matrix.UpdateRW();
+
+ CVector wind = CVector(0.707f, 0.707f, 0.0f) * (CWeather::Wind + 0.15f)*0.4f;
+ m_fMovingRotation += (m_vecMoveSpeed + wind).Magnitude()*CTimer::GetTimeStep();
+ }
+ }else if(GetModelIndex() == MI_PREDATOR || GetModelIndex() == MI_REEFER){
+ if (m_aBoatNodes[BOAT_MOVING] != nil) {
+ matrix.Attach(RwFrameGetMatrix(m_aBoatNodes[BOAT_MOVING]));
+
+ CVector pos = matrix.GetPosition();
+ matrix.SetRotateZ(m_fMovingRotation);
+ matrix.Translate(pos);
+
+ matrix.UpdateRW();
+ if (CVehicle::bWheelsOnlyCheat) {
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aBoatNodes[BOAT_MOVING]));
+ }
}
+ m_fMovingRotation += 0.02f * CTimer::GetTimeStep();
}
- m_fMovingHiRotation += 0.05f;
+}
+
+RwIm3DVertex KeepWaterOutVertices[4];
+RwImVertexIndex KeepWaterOutIndices[6];
+
+void
+CBoat::Render()
+{
((CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()))->SetVehicleColour(m_currentColour1, m_currentColour2);
+ m_nSetPieceExtendedRangeTime = CTimer::GetTimeInMilliseconds() + 3000;
if (!CVehicle::bWheelsOnlyCheat)
CEntity::Render();
- RwIm3DVertexSetRGBA(&KeepWaterOutVertices[0], 255, 255, 255, 255);
+ if(GetModelIndex() == MI_SKIMMER)
+ return;
KeepWaterOutIndices[0] = 0;
- RwIm3DVertexSetRGBA(&KeepWaterOutVertices[1], 255, 255, 255, 255);
KeepWaterOutIndices[1] = 2;
- RwIm3DVertexSetRGBA(&KeepWaterOutVertices[2], 255, 255, 255, 255);
KeepWaterOutIndices[2] = 1;
- RwIm3DVertexSetRGBA(&KeepWaterOutVertices[3], 255, 255, 255, 255);
KeepWaterOutIndices[3] = 1;
KeepWaterOutIndices[4] = 2;
KeepWaterOutIndices[5] = 3;
+ RwIm3DVertexSetRGBA(&KeepWaterOutVertices[0], 255, 255, 255, 255);
+ RwIm3DVertexSetRGBA(&KeepWaterOutVertices[1], 255, 255, 255, 255);
+ RwIm3DVertexSetRGBA(&KeepWaterOutVertices[2], 255, 255, 255, 255);
+ RwIm3DVertexSetRGBA(&KeepWaterOutVertices[3], 255, 255, 255, 255);
switch (GetModelIndex()) {
+ case MI_RIO:
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[0], -1.3f, -1.016f, 0.51f);
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[1], 1.3f, -1.016f, 0.51f);
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[2], -1.3f, -2.832f, 0.51f);
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[3], 1.3f, -2.832f, 0.51f);
+ break;
+ case MI_SQUALO:
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[0], -1.222f, 2.004f, 0.846f);
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[1], 1.222f, 2.004f, 0.846f);
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[2], -1.24f, -1.367f, 0.846f);
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[3], 1.24f, -1.367f, 0.846f);
+ break;
case MI_SPEEDER:
RwIm3DVertexSetPos(&KeepWaterOutVertices[0], -1.15f, 3.61f, 1.03f);
RwIm3DVertexSetPos(&KeepWaterOutVertices[1], 1.15f, 3.61f, 1.03f);
@@ -782,12 +1127,37 @@ CBoat::Render()
RwIm3DVertexSetPos(&KeepWaterOutVertices[3], 1.66f, -4.48f, 0.83f);
break;
case MI_PREDATOR:
- default:
RwIm3DVertexSetPos(&KeepWaterOutVertices[0], -1.45f, 1.9f, 0.96f);
RwIm3DVertexSetPos(&KeepWaterOutVertices[1], 1.45f, 1.9f, 0.96f);
RwIm3DVertexSetPos(&KeepWaterOutVertices[2], -1.45f, -3.75f, 0.96f);
RwIm3DVertexSetPos(&KeepWaterOutVertices[3], 1.45f, -3.75f, 0.96f);
break;
+ case MI_TROPIC:
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[0], -1.886f, -2.347f, 0.787f);
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[1], 1.886f, -2.347f, 0.787f);
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[2], -1.886f, -4.67f, 0.842f);
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[3], 1.886f, -4.67f, 0.842f);
+ break;
+ case MI_COASTG:
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[0], -0.663f, 3.565f, 0.382f);
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[1], 0.663f, 3.565f, 0.382f);
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[2], -1.087f, 0.83f, 0.381f);
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[3], 1.087f, 0.83f, 0.381f);
+ break;
+ case MI_DINGHY:
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[0], -0.797f, 1.641f, 0.573f);
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[1], 0.797f, 1.641f, 0.573f);
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[2], -0.865f, -1.444f, 0.509f);
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[3], 0.865f, -1.444f, 0.509f);
+ break;
+ case MI_MARQUIS:
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[0], -1.246f, -1.373f, 0.787f);
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[1], 1.246f, -1.373f, 0.787f);
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[2], -1.023f, -5.322f, 0.787f);
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[3], 1.023f, -5.322f, 0.787f);
+ break;
+ default:
+ return;
}
KeepWaterOutVertices[0].u = 0.0f;
KeepWaterOutVertices[0].v = 0.0f;
@@ -806,6 +1176,28 @@ CBoat::Render()
RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, KeepWaterOutIndices, 6);
RwIm3DEnd();
}
+ bool drawAnotherRect = false;
+ if(GetModelIndex() == MI_COASTG){
+ drawAnotherRect = true;
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[0], -1.087f, 0.831f, 0.381f);
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[1], 1.087f, 0.831f, 0.381f);
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[2], -1.097f, -2.977f, 0.381f);
+ RwIm3DVertexSetPos(&KeepWaterOutVertices[3], 1.097f, -2.977f, 0.381f);
+ }
+ if(drawAnotherRect){
+ KeepWaterOutVertices[0].u = 0.0f;
+ KeepWaterOutVertices[0].v = 0.0f;
+ KeepWaterOutVertices[1].u = 1.0f;
+ KeepWaterOutVertices[1].v = 0.0f;
+ KeepWaterOutVertices[2].u = 0.0f;
+ KeepWaterOutVertices[2].v = 1.0f;
+ KeepWaterOutVertices[3].u = 1.0f;
+ KeepWaterOutVertices[3].v = 1.0f;
+ if (!CVehicle::bWheelsOnlyCheat && RwIm3DTransform(KeepWaterOutVertices, 4, GetMatrix().m_attachment, rwIM3D_VERTEXUV)) {
+ RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, KeepWaterOutIndices, 6);
+ RwIm3DEnd();
+ }
+ }
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
@@ -822,6 +1214,7 @@ CBoat::Teleport(CVector v)
CWorld::Add(this);
}
+//--MIAMI: unused
bool
CBoat::IsSectorAffectedByWake(CVector2D sector, float fSize, CBoat **apBoats)
{
@@ -853,6 +1246,7 @@ CBoat::IsSectorAffectedByWake(CVector2D sector, float fSize, CBoat **apBoats)
return numVerts != 0;
}
+//--MIAMI: unused
float
CBoat::IsVertexAffectedByWake(CVector vecVertex, CBoat *pBoat)
{
@@ -889,22 +1283,35 @@ CBoat::FillBoatList()
apFrameWakeGeneratingBoats[1] = nil;
apFrameWakeGeneratingBoats[2] = nil;
apFrameWakeGeneratingBoats[3] = nil;
-
+ CVector2D camPos = TheCamera.GetPosition();
+ CVector2D camFwd = TheCamera.GetForward();
+ float camDist = camFwd.Magnitude();
+ if(camDist > 0.0f)
+ camFwd /= camDist;
for (int i = CPools::GetVehiclePool()->GetSize() - 1; i >= 0; i--) {
CBoat *boat = (CBoat *)(CPools::GetVehiclePool()->GetSlot(i));
if (boat && boat->m_vehType == VEHICLE_TYPE_BOAT) {
- int16 nNumWakePoints = boat->m_nNumWakePoints;
- if (nNumWakePoints != 0) {
+ if (boat->m_nNumWakePoints != 0) {
+ CVector2D camToBoat = CVector2D(boat->GetPosition()) - camPos;
+ float distToCam = DotProduct2D(camFwd, camToBoat);
+ if(distToCam > 100.0f || distToCam < -15.0f)
+ continue;
+ float distSq = camToBoat.MagnitudeSqr();
+ if(distSq > SQR(70.0f))
+ continue;
if (frameId >= ARRAY_SIZE(apFrameWakeGeneratingBoats)) {
+ float nearest = 999999.88f;
int16 frameId2 = -1;
for (int16 j = 0; j < ARRAY_SIZE(apFrameWakeGeneratingBoats); j++) {
- if (apFrameWakeGeneratingBoats[j]->m_nNumWakePoints < nNumWakePoints) {
+ float tmpDistSq = (CVector2D(apFrameWakeGeneratingBoats[j]->GetPosition()) - camPos).MagnitudeSqr();
+ if (tmpDistSq < nearest) {
+ nearest = tmpDistSq;
frameId2 = j;
- nNumWakePoints = apFrameWakeGeneratingBoats[j]->m_nNumWakePoints;
}
}
- if (frameId2 != -1)
+ if (frameId2 != -1 &&
+ (distSq < nearest || boat->GetStatus() == STATUS_PLAYER))
apFrameWakeGeneratingBoats[frameId2] = boat;
} else {
apFrameWakeGeneratingBoats[frameId++] = boat;
@@ -935,33 +1342,28 @@ void
CBoat::AddWakePoint(CVector point)
{
int i;
- if (m_afWakePointLifeTime[0] > 0.0f) {
- if ((CVector2D(GetPosition()) - m_avec2dWakePoints[0]).MagnitudeSqr() < SQR(2.0f)) {
- if (GetStatus() == STATUS_PHYSICS) {
- if (VehicleCreatedBy == MISSION_VEHICLE) {
- if (m_nNumWakePoints >= 20)
- m_nNumWakePoints = 20;
- }
- else {
- if (m_nNumWakePoints >= 15)
- m_nNumWakePoints = 15;
- }
- }
- else {
- if (m_nNumWakePoints >= 31)
+ if(m_afWakePointLifeTime[0] > 0.0f){
+ if((CVector2D(GetPosition()) - m_avec2dWakePoints[0]).MagnitudeSqr() < SQR(2.0f)) {
+ if(GetStatus() == STATUS_PLAYER){
+ if(m_nNumWakePoints >= 31)
m_nNumWakePoints = 31;
+ }else if(VehicleCreatedBy == MISSION_VEHICLE){
+ if(m_nNumWakePoints >= 20)
+ m_nNumWakePoints = 20;
+ }else{
+ if(m_nNumWakePoints >= 15)
+ m_nNumWakePoints = 15;
}
- for (i = m_nNumWakePoints; i != 0; i--) {
- m_avec2dWakePoints[i] = m_avec2dWakePoints[i - 1];
- m_afWakePointLifeTime[i] = m_afWakePointLifeTime[i - 1];
+ for(i = m_nNumWakePoints; i != 0; i--){
+ m_avec2dWakePoints[i] = m_avec2dWakePoints[i-1];
+ m_afWakePointLifeTime[i] = m_afWakePointLifeTime[i-1];
}
m_avec2dWakePoints[0] = point;
m_afWakePointLifeTime[0] = 150.0f;
- if (m_nNumWakePoints < ARRAY_SIZE(m_afWakePointLifeTime))
+ if(m_nNumWakePoints < ARRAY_SIZE(m_afWakePointLifeTime))
m_nNumWakePoints++;
}
- }
- else {
+ }else{
m_avec2dWakePoints[0] = point;
m_afWakePointLifeTime[0] = 150.0f;
m_nNumWakePoints = 1;
@@ -972,7 +1374,7 @@ void
CBoat::DoDriveByShootings(void)
{
CAnimBlendAssociation *anim = nil;
- CPlayerInfo* playerInfo = ((CPlayerPed*)this)->GetPlayerInfoForThisPlayerPed();
+ CPlayerInfo* playerInfo = ((CPlayerPed*)pDriver)->GetPlayerInfoForThisPlayerPed();
if (playerInfo && !playerInfo->m_bDriveByAllowed)
return;
@@ -984,7 +1386,8 @@ CBoat::DoDriveByShootings(void)
bool lookingLeft = false;
bool lookingRight = false;
- if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN){
+ if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN ||
+ TheCamera.m_bObbeCinematicCarCamOn){
if(CPad::GetPad(0)->GetLookLeft())
lookingLeft = true;
if(CPad::GetPad(0)->GetLookRight())
diff --git a/src/vehicles/Boat.h b/src/vehicles/Boat.h
index c6f4b7ad..5f8cc8a8 100644
--- a/src/vehicles/Boat.h
+++ b/src/vehicles/Boat.h
@@ -1,6 +1,7 @@
#pragma once
#include "Vehicle.h"
+#include "Door.h"
enum eBoatNodes
{
@@ -10,33 +11,34 @@ enum eBoatNodes
BOAT_FLAP_LEFT,
BOAT_FLAP_RIGHT,
BOAT_REARFLAP_LEFT,
- BOAT_REARFLAP_RIGHT
+ BOAT_REARFLAP_RIGHT,
+ NUM_BOAT_NODES
};
class CBoat : public CVehicle
{
public:
- // 0x288
- float m_fPropellerZ;
- float m_fPropellerY;
- CVector m_waterMoveDrag;
- CVector m_waterTurnDrag;
- float m_fMovingHiRotation;
- int32 _unk0;
- RwFrame *m_aBoatNodes[4];
+ float m_fMovingRotation;
+ float m_fMovingSpeed;
+ int32 m_boat_unused1;
+ RwFrame *m_aBoatNodes[NUM_BOAT_NODES];
+ CDoor m_boom;
+ tBoatHandlingData *pBoatHandling;
uint8 bBoatInWater : 1;
uint8 bPropellerInWater : 1;
bool m_bIsAnchored;
float m_fOrientation;
- int32 _unk1;
+ uint32 m_nPoliceShoutTimer;
+ int32 m_boat_unused2;
float m_fDamage;
CEntity *m_pSetOnFireEntity;
- bool _unk2;
+ float m_skimmerThingTimer;
+ bool m_boat_unused3;
float m_fAccelerate;
float m_fBrake;
float m_fSteeringLeftRight;
uint8 m_nPadID;
- int32 _unk3;
+ int32 m_boat_unused4;
float m_fVolumeUnderWater;
CVector m_vecBuoyancePoint;
float m_fPrevVolumeUnderWater;
@@ -54,7 +56,7 @@ public:
virtual void SetModelIndex(uint32 id);
virtual void ProcessControl();
virtual void Teleport(CVector v);
- virtual void PreRender(void) {};
+ virtual void PreRender(void);
virtual void Render(void);
virtual void ProcessControlInputs(uint8);
virtual void GetComponentWorldPosition(int32 component, CVector &pos);
diff --git a/src/vehicles/CarGen.cpp b/src/vehicles/CarGen.cpp
index 2a048881..84a19b82 100644
--- a/src/vehicles/CarGen.cpp
+++ b/src/vehicles/CarGen.cpp
@@ -16,6 +16,7 @@
#include "VisibilityPlugins.h"
#include "World.h"
#include "Zones.h"
+#include "Occlusion.h"
uint8 CTheCarGenerators::ProcessCounter;
uint32 CTheCarGenerators::NumOfCarGenerators;
@@ -31,7 +32,7 @@ void CCarGenerator::SwitchOff()
void CCarGenerator::SwitchOn()
{
- m_nUsesRemaining = -1;
+ m_nUsesRemaining = 255;
m_nTimer = CalcNextGen();
++CTheCarGenerators::CurrentActiveCount;
}
@@ -140,8 +141,14 @@ void CCarGenerator::DoInternalProcessing()
}
CVisibilityPlugins::SetClumpAlpha(pVehicle->GetClump(), 0);
m_nVehicleHandle = CPools::GetVehiclePool()->GetIndex(pVehicle);
- if (m_nUsesRemaining < -1) /* I don't think this is a correct comparasion */
+ /* I don't think this is a correct comparasion */
+#ifdef FIX_BUGS
+ if (m_nUsesRemaining != 0)
--m_nUsesRemaining;
+#else
+ if (m_nUsesRemaining < -1)
+ --m_nUsesRemaining;
+#endif
m_nTimer = CalcNextGen();
if (m_nUsesRemaining == 0)
--CTheCarGenerators::CurrentActiveCount;
@@ -151,7 +158,7 @@ void CCarGenerator::Process()
{
if (m_nVehicleHandle == -1 &&
(CTheCarGenerators::GenerateEvenIfPlayerIsCloseCounter || CTimer::GetTimeInMilliseconds() >= m_nTimer) &&
- m_nUsesRemaining != 0 && CheckIfWithinRangeOfAnyPlayer())
+ m_nUsesRemaining != 0 && CheckIfWithinRangeOfAnyPlayers())
DoInternalProcessing();
if (m_nVehicleHandle == -1)
return;
@@ -203,14 +210,14 @@ bool CCarGenerator::CheckForBlockage(int32 mi)
return false;
}
-bool CCarGenerator::CheckIfWithinRangeOfAnyPlayer()
+bool CCarGenerator::CheckIfWithinRangeOfAnyPlayers()
{
CVector2D direction = FindPlayerCentreOfWorld(CWorld::PlayerInFocus) - m_vecPos;
float distance = direction.Magnitude();
float farclip = 110.0f * TheCamera.GenerationDistMultiplier;
float nearclip = farclip - 20.0f;
bool canBeRemoved = (m_nModelIndex > 0 && CModelInfo::IsBoatModel(m_nModelIndex) && 165.0f * TheCamera.GenerationDistMultiplier > distance &&
- TheCamera.IsSphereVisible(m_vecPos, 0.0f)); // TODO(MIAMI) COcclision::IsPositionOccluded(m_vecPos, 0.0f)
+ TheCamera.IsSphereVisible(m_vecPos, 0.0f) && COcclusion::IsPositionOccluded(m_vecPos, 0.0f));
if (distance >= farclip || canBeRemoved){
if (m_bIsBlocking)
m_bIsBlocking = false;
diff --git a/src/vehicles/CarGen.h b/src/vehicles/CarGen.h
index 684f93ee..fccbee96 100644
--- a/src/vehicles/CarGen.h
+++ b/src/vehicles/CarGen.h
@@ -30,7 +30,7 @@ public:
void Process();
void Setup(float x, float y, float z, float angle, int32 mi, int16 color1, int16 color2, uint8 force, uint8 alarm, uint8 lock, uint16 min_delay, uint16 max_delay);
bool CheckForBlockage(int32 mi);
- bool CheckIfWithinRangeOfAnyPlayer();
+ bool CheckIfWithinRangeOfAnyPlayers();
void SetUsesRemaining(uint16 uses) { m_nUsesRemaining = uses; }
};
diff --git a/src/vehicles/Cranes.cpp b/src/vehicles/Cranes.cpp
index c8fa1c22..83c727f5 100644
--- a/src/vehicles/Cranes.cpp
+++ b/src/vehicles/Cranes.cpp
@@ -460,7 +460,7 @@ bool CCrane::DoesCranePickUpThisCarType(uint32 mi)
return mi == MI_FIRETRUCK ||
mi == MI_AMBULAN ||
mi == MI_ENFORCER ||
- mi == MI_FBICAR ||
+ mi == MI_FBIRANCH ||
mi == MI_RHINO ||
mi == MI_BARRACKS ||
mi == MI_POLICE;
@@ -474,7 +474,7 @@ bool CCranes::DoesMilitaryCraneHaveThisOneAlready(uint32 mi)
case MI_FIRETRUCK: return (CarsCollectedMilitaryCrane & 1);
case MI_AMBULAN: return (CarsCollectedMilitaryCrane & 2);
case MI_ENFORCER: return (CarsCollectedMilitaryCrane & 4);
- case MI_FBICAR: return (CarsCollectedMilitaryCrane & 8);
+ case MI_FBIRANCH: return (CarsCollectedMilitaryCrane & 8);
case MI_RHINO: return (CarsCollectedMilitaryCrane & 0x10);
case MI_BARRACKS: return (CarsCollectedMilitaryCrane & 0x20);
case MI_POLICE: return (CarsCollectedMilitaryCrane & 0x40);
@@ -489,7 +489,7 @@ void CCranes::RegisterCarForMilitaryCrane(uint32 mi)
case MI_FIRETRUCK: CarsCollectedMilitaryCrane |= 1; break;
case MI_AMBULAN: CarsCollectedMilitaryCrane |= 2; break;
case MI_ENFORCER: CarsCollectedMilitaryCrane |= 4; break;
- case MI_FBICAR: CarsCollectedMilitaryCrane |= 8; break;
+ case MI_FBIRANCH: CarsCollectedMilitaryCrane |= 8; break;
case MI_RHINO: CarsCollectedMilitaryCrane |= 0x10; break;
case MI_BARRACKS: CarsCollectedMilitaryCrane |= 0x20; break;
case MI_POLICE: CarsCollectedMilitaryCrane |= 0x40; break;
diff --git a/src/vehicles/Floater.cpp b/src/vehicles/Floater.cpp
index 1ae1c5c3..92e3d80e 100644
--- a/src/vehicles/Floater.cpp
+++ b/src/vehicles/Floater.cpp
@@ -7,18 +7,40 @@
#include "Vehicle.h"
#include "Floater.h"
+//--MIAMI: done
+
cBuoyancy mod_Buoyancy;
-static float fVolMultiplier = 1.0f;
+float fVolMultiplier = 1.0f;
// amount of boat volume in bounding box
// 1.0-volume is the empty space in the bbox
-static float fBoatVolumeDistribution[9] = {
+float fBoatVolumeDistribution[9] = {
// rear
0.75f, 0.9f, 0.75f,
0.95f, 1.0f, 0.95f,
- 0.3f, 0.7f, 0.3f
+ 0.4f, 0.7f, 0.4f
// bow
};
+float fBoatVolumeDistributionCat[9] = {
+ 0.9f, 0.3f, 0.9f,
+ 1.0f, 0.5f, 1.0f,
+ 0.95f, 0.4f, 0.95f
+};
+float fBoatVolumeDistributionSail[9] = {
+ 0.55f, 0.95f, 0.55f,
+ 0.75f, 1.1f, 0.75f,
+ 0.3f, 0.8f, 0.3f
+};
+float fBoatVolumeDistributionDinghy[9] = {
+ 0.65f, 0.85f, 0.65f,
+ 0.85f, 1.1f, 0.85f,
+ 0.65f, 0.95f, 0.65f
+};
+float fBoatVolumeDistributionSpeed[9] = {
+ 0.7f, 0.9f, 0.7f,
+ 0.95f, 1.0f, 0.95f,
+ 0.6f, 0.7f, 0.6f
+};
bool
cBuoyancy::ProcessBuoyancy(CPhysical *phys, float buoyancy, CVector *point, CVector *impulse)
@@ -37,6 +59,76 @@ cBuoyancy::ProcessBuoyancy(CPhysical *phys, float buoyancy, CVector *point, CVec
return f != 0.0f;
}
+bool
+cBuoyancy::ProcessBuoyancyBoat(CVehicle *veh, float buoyancy, CVector *point, CVector *impulse, bool bNoTurnForce)
+{
+ m_numSteps = 2.0f;
+
+ if(!CWaterLevel::GetWaterLevel(veh->GetPosition(), &m_waterlevel, veh->bTouchingWater))
+ return false;
+ m_matrix = veh->GetMatrix();
+ PreCalcSetup(veh, buoyancy);
+
+
+ float x, y;
+ int ix, i;
+ tWaterLevel waterPosition;
+ CVector waterNormal;
+
+ // Floater is divided into 3x3 parts. Process and sum each of them
+ float volDiv = 1.0f/((m_dimMax.z - m_dimMin.z)*sq(m_numSteps+1.0f));
+ ix = 0;
+ for(x = m_dimMin.x; x <= m_dimMax.x; x += m_step.x){
+ i = ix;
+ for(y = m_dimMin.y; y <= m_dimMax.y; y += m_step.y){
+ CVector waterLevel(x, y, 0.0f);
+ FindWaterLevelNorm(m_positionZ, &waterLevel, &waterPosition, &waterNormal);
+ switch(veh->GetModelIndex()){
+ case MI_RIO:
+ fVolMultiplier = fBoatVolumeDistributionCat[i];
+ break;
+ case MI_SQUALO:
+ case MI_SPEEDER:
+ case MI_JETMAX:
+ fVolMultiplier = fBoatVolumeDistributionSpeed[i];
+ break;
+ case MI_COASTG:
+ case MI_DINGHY:
+ fVolMultiplier = fBoatVolumeDistributionDinghy[i];
+ break;
+ case MI_MARQUIS:
+ fVolMultiplier = fBoatVolumeDistributionSail[i];
+ break;
+ case MI_PREDATOR:
+ case MI_SKIMMER:
+ case MI_REEFER:
+ case MI_TROPIC:
+ default:
+ fVolMultiplier = fBoatVolumeDistribution[i];
+ break;
+ }
+ if(waterPosition != FLOATER_ABOVE_WATER){
+ float volume = SimpleSumBuoyancyData(waterLevel, waterPosition);
+ float upImpulse = volume * volDiv * buoyancy * CTimer::GetTimeStep();
+ CVector speed = veh->GetSpeed(Multiply3x3(veh->GetMatrix(), CVector(x, y, 0.0f)));
+ float damp = 1.0f - DotProduct(speed, waterNormal)*veh->pHandling->fSuspensionDampingLevel;
+ float finalImpulse = upImpulse*Max(damp, 0.0f);
+ impulse->z += finalImpulse;
+ if(!bNoTurnForce)
+ veh->ApplyTurnForce(finalImpulse*waterNormal, Multiply3x3(m_matrix, waterLevel));
+ }
+ i += 3;
+ }
+ ix++;
+ }
+
+ m_volumeUnderWater *= volDiv;
+
+ *point = Multiply3x3(m_matrix, m_impulsePoint);
+ return m_isBoat || m_haveVolume;
+
+}
+
void
cBuoyancy::PreCalcSetup(CPhysical *phys, float buoyancy)
{
@@ -48,17 +140,55 @@ cBuoyancy::PreCalcSetup(CPhysical *phys, float buoyancy)
m_dimMax = colModel->boundingBox.max;
if(m_isBoat){
- if(phys->GetModelIndex() == MI_PREDATOR){
+ switch(phys->GetModelIndex()){
+ case MI_PREDATOR:
+ default:
+ m_dimMax.y *= 1.05f;
+ m_dimMin.y *= 0.9f;
+ break;
+ case MI_SPEEDER:
+ m_dimMax.y *= 1.25f;
+ m_dimMin.y *= 0.83f;
+ break;
+ case MI_REEFER:
+ m_dimMin.y *= 0.9f;
+ break;
+ case MI_RIO:
+ m_dimMax.y *= 0.9f;
+ m_dimMin.y *= 0.9f;
+ m_dimMax.z += 0.25f;
+ m_dimMin.z -= 0.2f;
+ break;
+ case MI_SQUALO:
m_dimMax.y *= 0.9f;
m_dimMin.y *= 0.9f;
- }else if(phys->GetModelIndex() == MI_SPEEDER){
+ break;
+ case MI_TROPIC:
+ m_dimMax.y *= 1.3f;
+ m_dimMin.y *= 0.82f;
+ m_dimMin.z -= 0.2f;
+ break;
+ case MI_SKIMMER:
+ m_dimMin.y = -m_dimMax.y;
+ m_dimMax.y *= 1.2f;
+ break;
+ case MI_COASTG:
m_dimMax.y *= 1.1f;
m_dimMin.y *= 0.9f;
- }else if(phys->GetModelIndex() == MI_REEFER){
+ m_dimMin.z -= 0.3f;
+ break;
+ case MI_DINGHY:
+ m_dimMax.y *= 1.3f;
m_dimMin.y *= 0.9f;
- }else{
- m_dimMax.y *= 0.9f;
+ m_dimMin.z -= 0.2f;
+ break;
+ case MI_MARQUIS:
+ m_dimMax.y *= 1.3f;
m_dimMin.y *= 0.9f;
+ break;
+ case MI_JETMAX:
+ m_dimMin.y *= 0.9f;
+ break;
}
}
@@ -92,22 +222,17 @@ void
cBuoyancy::SimpleCalcBuoyancy(void)
{
float x, y;
- int ix, i;
tWaterLevel waterPosition;
// Floater is divided into 3x3 parts. Process and sum each of them
- ix = 0;
for(x = m_dimMin.x; x <= m_dimMax.x; x += m_step.x){
- i = ix;
for(y = m_dimMin.y; y <= m_dimMax.y; y += m_step.y){
CVector waterLevel(x, y, 0.0f);
FindWaterLevel(m_positionZ, &waterLevel, &waterPosition);
- fVolMultiplier = m_isBoat ? fBoatVolumeDistribution[i] : 1.0f;
+ fVolMultiplier = 1.0f;
if(waterPosition != FLOATER_ABOVE_WATER)
SimpleSumBuoyancyData(waterLevel, waterPosition);
- i += 3;
}
- ix++;
}
m_volumeUnderWater /= (m_dimMax.z - m_dimMin.z)*sq(m_numSteps+1.0f);
@@ -129,10 +254,6 @@ cBuoyancy::SimpleSumBuoyancyData(CVector &waterLevel, tWaterLevel waterPosition)
if(m_isBoat){
fThisVolume *= fVolMultiplier;
- if(fThisVolume < 0.5f)
- fThisVolume = 2.0f*sq(fThisVolume);
- if(fThisVolume < 1.0f)
- fThisVolume = sq(fThisVolume);
fThisVolume = sq(fThisVolume);
}
@@ -173,6 +294,26 @@ cBuoyancy::FindWaterLevel(const CVector &zpos, CVector *waterLevel, tWaterLevel
}
}
+// Same as above but also get normal
+void
+cBuoyancy::FindWaterLevelNorm(const CVector &zpos, CVector *waterLevel, tWaterLevel *waterPosition, CVector *normal)
+{
+ *waterPosition = FLOATER_IN_WATER;
+ CVector xWaterLevel = Multiply3x3(m_matrix, *waterLevel);
+ CWaterLevel::GetWaterLevel(xWaterLevel.x + m_position.x, xWaterLevel.y + m_position.y, m_position.z,
+ &waterLevel->z, true);
+ waterLevel->z -= xWaterLevel.z + zpos.z; // make local
+ if(waterLevel->z >= m_dimMin.z)
+ *normal = CWaterLevel::GetWaterNormal(xWaterLevel.x + m_position.x, xWaterLevel.y + m_position.y);
+ if(waterLevel->z > m_dimMax.z){
+ waterLevel->z = m_dimMax.z;
+ *waterPosition = FLOATER_UNDER_WATER;
+ }else if(waterLevel->z < m_dimMin.z){
+ waterLevel->z = m_dimMin.z;
+ *waterPosition = FLOATER_ABOVE_WATER;
+ }
+}
+
bool
cBuoyancy::CalcBuoyancyForce(CPhysical *phys, CVector *point, CVector *impulse)
{
diff --git a/src/vehicles/Floater.h b/src/vehicles/Floater.h
index 1cfb46fb..91ab70ae 100644
--- a/src/vehicles/Floater.h
+++ b/src/vehicles/Floater.h
@@ -36,10 +36,12 @@ public:
CVector m_impulsePoint;
bool ProcessBuoyancy(CPhysical *phys, float buoyancy, CVector *point, CVector *impulse);
+ bool ProcessBuoyancyBoat(CVehicle *phys, float buoyancy, CVector *point, CVector *impulse, bool bNoTurnForce);
void PreCalcSetup(CPhysical *phys, float buoyancy);
void SimpleCalcBuoyancy(void);
float SimpleSumBuoyancyData(CVector &waterLevel, tWaterLevel waterPosition);
void FindWaterLevel(const CVector &zpos, CVector *waterLevel, tWaterLevel *waterPosition);
+ void FindWaterLevelNorm(const CVector &zpos, CVector *waterLevel, tWaterLevel *waterPosition, CVector *normal);
bool CalcBuoyancyForce(CPhysical *phys, CVector *impulse, CVector *point);
};
extern cBuoyancy mod_Buoyancy;
diff --git a/src/vehicles/Heli.cpp b/src/vehicles/Heli.cpp
index 36681c15..46e51b09 100644
--- a/src/vehicles/Heli.cpp
+++ b/src/vehicles/Heli.cpp
@@ -14,20 +14,26 @@
#include "Shadows.h"
#include "Coronas.h"
#include "Explosion.h"
+#include "WindModifiers.h"
#include "Timecycle.h"
#include "TempColModels.h"
#include "World.h"
#include "WaterLevel.h"
+#include "Population.h"
#include "PlayerPed.h"
+#include "CopPed.h"
#include "Wanted.h"
#include "DMAudio.h"
#include "Object.h"
#include "HandlingMgr.h"
+#include "Ropes.h"
#include "Heli.h"
#ifdef FIX_BUGS
#include "Replay.h"
#endif
+//--MIAMI: done
+
enum
{
HELI_STATUS_HOVER,
@@ -40,7 +46,6 @@ enum
CHeli *CHeli::pHelis[NUM_HELIS];
int16 CHeli::NumRandomHelis;
uint32 CHeli::TestForNewRandomHelisTimer;
-int16 CHeli::NumScriptHelis; // unused
bool CHeli::CatalinaHeliOn;
bool CHeli::CatalinaHasBeenShotDown;
bool CHeli::ScriptHeliOn;
@@ -67,6 +72,9 @@ CHeli::CHeli(int32 id, uint8 CreatedBy)
m_nBulletDamage = 0;
m_fAngularSpeed = 0.0f;
m_fRotation = 0.0f;
+
+ m_numSwat = 4;
+
m_nSearchLightTimer = CTimer::GetTimeInMilliseconds();
for(i = 0; i < 6; i++){
m_aSearchLightHistoryX[i] = 0.0f;
@@ -82,6 +90,8 @@ CHeli::CHeli(int32 id, uint8 CreatedBy)
m_fTargetOffset = 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
m_nLastShotTime = 0;
}
@@ -120,6 +130,8 @@ CHeli::ProcessControl(void)
if(gbModelViewer)
return;
+ CWindModifiers::RegisterOne(GetPosition(), 1);
+
// Find target
CVector target(0.0f, 0.0f, 0.0f);
CVector2D vTargetDist;
@@ -266,7 +278,9 @@ CHeli::ProcessControl(void)
if(fTargetDist > targetHeight)
m_heliStatus = HELI_STATUS_CHASE_PLAYER;
}
- // fall through, BUG?
+ if(m_numSwat)
+ SendDownSwat();
+ break;
case HELI_STATUS_CHASE_PLAYER:{
float targetHeight;
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))
m_heliStatus = HELI_STATUS_HOVER;
}
+ break;
}
// Find xy speed
@@ -346,13 +361,6 @@ CHeli::ProcessControl(void)
if(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;
float speedDiff = speedDir.Magnitude();
if(speedDiff != 0.0f)
@@ -457,7 +465,7 @@ CHeli::ProcessControl(void)
else if (searchLightDist < 40.0f)
m_fSearchLightIntensity = 1.0f;
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))
m_nShootTimer = CTimer::GetTimeInMilliseconds();
@@ -524,28 +532,17 @@ CHeli::ProcessControl(void)
}
}
- // Drop Catalina's bombs
- if(m_heliType == HELI_TYPE_CATALINA && m_pathState > 8 && (CTimer::GetTimeInMilliseconds()>>9) != (CTimer::GetPreviousTimeInMilliseconds()>>9)){
- CVector bombPos = GetPosition() - 60.0f*m_vecMoveSpeed;
- if(sq(FindPlayerCoors().x-bombPos.x) + sq(FindPlayerCoors().y-bombPos.y) < sq(35.0f)){
- bool found;
- float groundZ = CWorld::FindGroundZFor3DCoord(bombPos.x, bombPos.y, bombPos.z, &found);
- float waterZ;
- if(!CWaterLevel::GetWaterLevelNoWaves(bombPos.x, bombPos.y, bombPos.z, &waterZ))
- waterZ = 0.0f;
- if(groundZ > waterZ){
- bombPos.z = groundZ + 2.0f;
- 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);
- }
- }
+ // Process ropes
+ for(i = 0; i < 4; i++){
+ if(m_aSwatState[i] == 0)
+ continue;
+
+ m_aSwatState[i]--;
+ CRopes::RegisterRope((uintptr)this + i, GetMatrix()*FindSwatPositionRelativeToHeli(i), false);
+ if(m_aSwatState[i] == 0){
+ CVector speed = Multiply3x3(GetMatrix(), 0.05f*FindSwatPositionRelativeToHeli(i));
+ speed.z = 0.0f;
+ CRopes::SetSpeedOfTopNode((uintptr)this + i, speed);
}
}
@@ -665,6 +662,7 @@ CHeli::SpawnFlyingComponent(int32 component)
RpAtomicSetFrame(atomic, frame);
CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
obj->AttachToRwObject((RwObject*)atomic);
+ obj->bDontStream = true;
// init object
obj->m_fMass = 10.0f;
@@ -710,6 +708,42 @@ CHeli::SpawnFlyingComponent(int32 component)
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_HELI_SWAT, pos);
+ swat->bUsesCollision = false;
+ swat->m_pRopeEntity = this;
+ RegisterReference(&swat->m_pRopeEntity);
+ m_numSwat--;
+ swat->m_nRopeID = (uintptr)this + m_numSwat;
+ m_aSwatState[m_numSwat] = 255;
+ CAnimManager::BlendAnimation(swat->GetClump(), ASSOCGRP_STD, ANIM_ABSEIL, 4.0f);
+ return true;
+ }
+ return false;
+}
void
@@ -719,7 +753,6 @@ CHeli::InitHelis(void)
NumRandomHelis = 0;
TestForNewRandomHelisTimer = 0;
- NumScriptHelis = 0;
CatalinaHeliOn = false;
ScriptHeliOn = false;
for(i = 0; i < NUM_HELIS; i++)
@@ -735,17 +768,20 @@ GenerateHeli(bool catalina)
CVector heliPos;
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)
heliPos = CVector(-224.0f, 201.0f, 83.0f);
else{
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.y += 250.0f*Cos(angle);
- if(heliPos.x < -2000.0f || heliPos.x > 2000.0f || heliPos.y < -2000.0f || heliPos.y > 2000.0f){
- // directly above player
+ if(heliPos.x < -2000.0f-400.0f || heliPos.x > 2000.0f-400.0f || heliPos.y < -2000.0f || heliPos.y > 2000.0f){
+ heliPos = FindPlayerCoors();
heliPos.x -= 250.0f*Sin(angle);
heliPos.y -= 250.0f*Cos(angle);
}
@@ -756,6 +792,7 @@ GenerateHeli(bool catalina)
heli->GetMatrix().SetRotateZOnly(DEGTORAD(270.0f)); // game actually uses 3.14 here
heli->SetStatus(STATUS_ABANDONED);
+ heli->bIsLocked = true;
int id = -1;
bool found = false;
@@ -784,6 +821,8 @@ CHeli::UpdateHelis(void)
CReplay::IsPlayingBack() ? 0 :
#endif
FindPlayerPed()->m_pWanted->NumOfHelisRequired();
+ if(CCullZones::PlayerNoRain() || CGame::IsInInterior())
+ numHelisRequired = 0;
if(CStreaming::HasModelLoaded(MI_CHOPPER) && CTimer::GetTimeInMilliseconds() > TestForNewRandomHelisTimer){
// Spawn a police heli
TestForNewRandomHelisTimer = CTimer::GetTimeInMilliseconds() + 15000;
@@ -832,7 +871,7 @@ CHeli::UpdateHelis(void)
TheCamera.CamShake(0.7f, pHelis[i]->GetPosition().x, pHelis[i]->GetPosition().y, pHelis[i]->GetPosition().z);
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[3] = CRGBA(0, 0, 0, 255);
colors[4] = CRGBA(66, 162, 252, 255);
@@ -852,7 +891,7 @@ CHeli::UpdateHelis(void)
int f = ++nFrameGen & 3;
CParticle::AddParticle(PARTICLE_HELI_DEBRIS, pos, dir,
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);
@@ -870,8 +909,7 @@ CHeli::UpdateHelis(void)
if(i == HELI_CATALINA)
CatalinaHasBeenShotDown = true;
- CStats::HelisDestroyed++;
- CStats::PeopleKilledByOthers += 2;
+ CStats::PeopleKilledByPlayer += 2;
CStats::PedsKilledOfThisType[PEDTYPE_COP] += 2;
CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 250;
pos = CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetPosition();
@@ -889,8 +927,8 @@ CHeli::UpdateHelis(void)
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();
- CExplosion::AddExplosion(nil, nil, EXPLOSION_HELI, pos, 0);
+ CVector pos = pHelis[i]->GetPosition() - 2.5f*pHelis[i]->GetForward();
+ CExplosion::AddExplosion(nil, nil, EXPLOSION_HELI2, pos, 0);
}else
pHelis[i]->m_fAngularSpeed *= 1.03f;
}
@@ -905,7 +943,7 @@ CHeli::UpdateHelis(void)
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)
for(i = 0; i < NUM_HELIS; i++)
if(pHelis[i] && pHelis[i]->m_heliStatus != HELI_STATUS_SHOT_DOWN)
@@ -950,7 +988,7 @@ CHeli::TestBulletCollision(CVector *line0, CVector *line1, CVector *bulletPos, i
float distToHeli = (pHelis[i]->GetPosition() - *line0).Magnitude();
CVector line = (*line1 - *line0);
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;
@@ -966,6 +1004,26 @@ CHeli::TestBulletCollision(CVector *line0, CVector *line1, CVector *bulletPos, i
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)
{
CatalinaHeliOn = true;
diff --git a/src/vehicles/Heli.h b/src/vehicles/Heli.h
index a8f604aa..1f372e42 100644
--- a/src/vehicles/Heli.h
+++ b/src/vehicles/Heli.h
@@ -21,7 +21,7 @@ enum
HELI_RANDOM0,
HELI_RANDOM1,
HELI_SCRIPT,
- HELI_CATALINA,
+ HELI_CATALINA, // TODO 2 in VC
NUM_HELIS
};
@@ -36,7 +36,6 @@ enum
class CHeli : public CVehicle
{
public:
- // 0x288
RwFrame *m_aHeliNodes[NUM_HELI_NODES];
int8 m_heliStatus;
float m_fSearchLightX;
@@ -49,6 +48,8 @@ public:
int8 m_nHeliId;
int8 m_heliType;
int8 m_pathState;
+ int8 m_numSwat;
+ uint8 m_aSwatState[4];
float m_aSearchLightHistoryX[6];
float m_aSearchLightHistoryY[6];
uint32 m_nSearchLightTimer;
@@ -64,7 +65,6 @@ public:
static CHeli *pHelis[NUM_HELIS];
static int16 NumRandomHelis;
static uint32 TestForNewRandomHelisTimer;
- static int16 NumScriptHelis; // unused
static bool CatalinaHeliOn;
static bool CatalinaHasBeenShotDown;
static bool ScriptHeliOn;
@@ -79,12 +79,15 @@ public:
void PreRenderAlways(void);
CObject *SpawnFlyingComponent(int32 component);
+ CVector FindSwatPositionRelativeToHeli(int n);
+ bool SendDownSwat(void);
static void InitHelis(void);
static void UpdateHelis(void);
static void SpecialHeliPreRender(void);
static bool TestRocketCollision(CVector *coors);
static bool TestBulletCollision(CVector *line0, CVector *line1, CVector *bulletPos, int32 damage);
+ static bool TestSniperCollision(CVector *line0, CVector *line1);
static void StartCatalinaFlyBy(void);
static void RemoveCatalinaHeli(void);
diff --git a/src/vehicles/Plane.cpp b/src/vehicles/Plane.cpp
index bc27ca32..ffe9ffbf 100644
--- a/src/vehicles/Plane.cpp
+++ b/src/vehicles/Plane.cpp
@@ -2,6 +2,7 @@
#include "main.h"
#include "General.h"
+#include "CutsceneMgr.h"
#include "ModelIndices.h"
#include "FileMgr.h"
#include "Streaming.h"
@@ -12,10 +13,14 @@
#include "Coronas.h"
#include "Particle.h"
#include "Explosion.h"
+#include "Fluff.h"
#include "World.h"
#include "HandlingMgr.h"
+#include "Heli.h"
#include "Plane.h"
+//--MIAMI: file done
+
CPlaneNode *pPathNodes;
CPlaneNode *pPath2Nodes;
CPlaneNode *pPath3Nodes;
@@ -39,12 +44,10 @@ CPlaneInterpolationLine aPlaneLineBits[6];
float PlanePathPosition[3];
float OldPlanePathPosition[3];
float PlanePathSpeed[3];
-float PlanePath2Position[3];
-float PlanePath3Position;
-float PlanePath4Position;
-float PlanePath2Speed[3];
-float PlanePath3Speed;
-float PlanePath4Speed;
+float PlanePath2Position[5];
+float PlanePath3Position[4];
+float PlanePath2Speed[5];
+float PlanePath3Speed[4];
enum
@@ -62,7 +65,6 @@ int32 DropOffCesnaMissionStatus;
int32 DropOffCesnaMissionStartTime;
CPlane *pDropOffCesna;
-
CPlane::CPlane(int32 id, uint8 CreatedBy)
: CVehicle(CreatedBy)
{
@@ -80,13 +82,15 @@ CPlane::CPlane(int32 id, uint8 CreatedBy)
m_bHasBeenHit = false;
m_bIsDrugRunCesna = false;
m_bIsDropOffCesna = false;
+ m_bTempPlane = false;
SetStatus(STATUS_PLANE);
bIsBIGBuilding = true;
- m_level = LEVEL_NONE;
+ m_level = LEVEL_GENERIC;
-#ifdef FIX_BUGS
- m_isFarAway = true;
+ m_isFarAway = false;
+#ifdef CPLANE_ROTORS
+ m_fRotorRotation = 0.0f;
#endif
}
@@ -99,6 +103,21 @@ void
CPlane::SetModelIndex(uint32 id)
{
CVehicle::SetModelIndex(id);
+#ifdef CPLANE_ROTORS
+ int i;
+ for(i = 0; i < NUM_PLANE_NODES; i++)
+ m_aPlaneNodes[i] = nil;
+ if(GetModelIndex() == MI_CHOPPER){
+ // This is surprisingly annoying...
+ RwFrame *heliNodes[NUM_HELI_NODES];
+ for(i = 0; i < NUM_HELI_NODES; i++)
+ heliNodes[i] = nil;
+ CClumpModelInfo::FillFrameArray(GetClump(), heliNodes);
+ m_aPlaneNodes[PLANE_TOPROTOR] = heliNodes[HELI_TOPROTOR];
+ m_aPlaneNodes[PLANE_BACKROTOR] = heliNodes[HELI_BACKROTOR];
+ }else
+ CClumpModelInfo::FillFrameArray(GetClump(), m_aPlaneNodes);
+#endif
}
void
@@ -123,6 +142,15 @@ CPlane::ProcessControl(void)
int i;
CVector pos;
+ if(CReplay::IsPlayingBack())
+ return;
+
+ if(GetModelIndex() == MI_AIRTRAIN){
+ if(GetPosition().z > 100.0f)
+ CPlaneTrails::RegisterPoint(GetPosition(), m_nPlaneId);
+ }else if(GetModelIndex() == MI_DEADDODO)
+ CPlaneBanners::RegisterPoint(GetPosition(), m_nPlaneId);
+
// Explosion
if(m_bHasBeenHit){
// BUG: since this is all based on frames, you can skip the explosion processing when you go into the menu
@@ -154,7 +182,7 @@ CPlane::ProcessControl(void)
int f = ++nFrameGen & 3;
CParticle::AddParticle(PARTICLE_HELI_DEBRIS, GetMatrix() * CVector(0.0f, 0.0f, 0.0f), dir,
nil, CGeneral::GetRandomNumberInRange(0.1f, 1.0f),
- colors[nFrameGen], rotSpeed, 0, f, 0);
+ colors[nFrameGen&7], rotSpeed, 0, f, 0);
}
}
if(frm >= 40 && frm <= 80 && frm & 1){
@@ -197,17 +225,18 @@ CPlane::ProcessControl(void)
colors[6] = CRGBA(0, 0, 0, 255);
colors[7] = CRGBA(252, 66, 66, 255);
+ CVector dir;
for(i = 0; i < 40; i++){
+ dir.x = CGeneral::GetRandomNumberInRange(-2.0f, 2.0f);
+ dir.y = CGeneral::GetRandomNumberInRange(-2.0f, 2.0f);
+ dir.z = CGeneral::GetRandomNumberInRange(0.0f, 2.0f);
int rotSpeed = CGeneral::GetRandomNumberInRange(30.0f, 20.0f);
if(CGeneral::GetRandomNumber() & 1)
rotSpeed = -rotSpeed;
int f = ++nFrameGen & 3;
- CParticle::AddParticle(PARTICLE_HELI_DEBRIS, GetMatrix() * CVector(0.0f, 0.0f, 0.0f),
- CVector(CGeneral::GetRandomNumberInRange(-2.0f, 2.0f),
- CGeneral::GetRandomNumberInRange(-2.0f, 2.0f),
- CGeneral::GetRandomNumberInRange(0.0f, 2.0f)),
+ CParticle::AddParticle(PARTICLE_HELI_DEBRIS, GetMatrix() * CVector(0.0f, 0.0f, 0.0f), dir,
nil, CGeneral::GetRandomNumberInRange(0.1f, 1.0f),
- colors[nFrameGen], rotSpeed, 0, f, 0);
+ colors[nFrameGen&7], rotSpeed, 0, f, 0);
}
}
if(frm >= 40 && frm <= 60 && frm & 1){
@@ -226,7 +255,7 @@ CPlane::ProcessControl(void)
}
if(frm == 30)
bRenderScorched = true;
- if(frm == 61){
+ if(frm == 62){
TheCamera.SetFadeColour(200, 200, 200);
TheCamera.Fade(0.0f, FADE_OUT);
TheCamera.ProcessFade();
@@ -363,7 +392,7 @@ CPlane::ProcessControl(void)
CVector posFront2 = (1.0f - f)*pPathNodes[curPathNodeFront2].p + f*pPathNodes[nextPathNodeFront2].p;
// Now set matrix
- GetMatrix().GetPosition() = (posRear + posFront) / 2.0f;
+ GetMatrix().SetTranslateOnly((posRear + posFront) / 2.0f);
GetMatrix().GetPosition().z += 4.3f;
CVector fwd = posFront - posRear;
fwd.Normalise();
@@ -382,13 +411,12 @@ CPlane::ProcessControl(void)
GetMatrix().GetRight() = right;
GetMatrix().GetUp() = up;
GetMatrix().GetForward() = fwd;
-
// Set speed
m_vecMoveSpeed = fwd*PlanePathSpeed[m_nPlaneId]/60.0f;
m_fSpeed = PlanePathSpeed[m_nPlaneId]/60.0f;
m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
- m_isFarAway = !((posFront - TheCamera.GetPosition()).Magnitude2D() < sq(300.0f));
+ m_isFarAway = !((posFront - TheCamera.GetPosition()).MagnitudeSqr2D() < sq(300.0f));
}else{
float planePathPosition;
float totalLengthOfFlightPath;
@@ -396,26 +424,12 @@ CPlane::ProcessControl(void)
float planePathSpeed;
int numPathNodes;
- if(m_bIsDrugRunCesna){
- planePathPosition = PlanePath3Position;
+ if(GetModelIndex() == MI_CHOPPER){
+ planePathPosition = PlanePath3Position[m_nPlaneId];
totalLengthOfFlightPath = TotalLengthOfFlightPath3;
pathNodes = pPath3Nodes;
- planePathSpeed = PlanePath3Speed;
+ planePathSpeed = PlanePath3Speed[m_nPlaneId];
numPathNodes = NumPath3Nodes;
- if(CesnaMissionStatus == CESNA_STATUS_LANDED){
- pDrugRunCesna = nil;
- FlagToDestroyWhenNextProcessed();
- }
- }else if(m_bIsDropOffCesna){
- planePathPosition = PlanePath4Position;
- totalLengthOfFlightPath = TotalLengthOfFlightPath4;
- pathNodes = pPath4Nodes;
- planePathSpeed = PlanePath4Speed;
- numPathNodes = NumPath4Nodes;
- if(DropOffCesnaMissionStatus == CESNA_STATUS_LANDED){
- pDropOffCesna = nil;
- FlagToDestroyWhenNextProcessed();
- }
}else{
planePathPosition = PlanePath2Position[m_nPlaneId];
totalLengthOfFlightPath = TotalLengthOfFlightPath2;
@@ -484,7 +498,7 @@ CPlane::ProcessControl(void)
f = (pathPositionFront - pathNodes[curPathNodeFront].t)/dist;
CVector posFront = (1.0f - f)*pathNodes[curPathNodeFront].p + f*pathNodes[nextPathNodeFront].p;
- // And for another point 60 units in front of the plane, used to calculate roll
+ // And for another point 30 units in front of the plane, used to calculate roll
float pathPositionFront2 = pathPositionFront + 30.0f;
if(pathPositionFront2 > totalLengthOfFlightPath)
pathPositionFront2 -= totalLengthOfFlightPath;
@@ -515,7 +529,7 @@ CPlane::ProcessControl(void)
CVector posFront2 = (1.0f - f)*pathNodes[curPathNodeFront2].p + f*pathNodes[nextPathNodeFront2].p;
// Now set matrix
- GetMatrix().GetPosition() = (posRear + posFront) / 2.0f;
+ GetMatrix().SetTranslateOnly((posRear + posFront) / 2.0f);
GetMatrix().GetPosition().z += 1.0f;
CVector fwd = posFront - posRear;
fwd.Normalise();
@@ -535,7 +549,7 @@ CPlane::ProcessControl(void)
m_fSpeed = planePathSpeed/60.0f;
m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
- m_isFarAway = !((posFront - TheCamera.GetPosition()).Magnitude2D() < sq(300.0f));
+ m_isFarAway = !((posFront - TheCamera.GetPosition()).MagnitudeSqr2D() < sq(300.0f));
}
}
@@ -634,12 +648,36 @@ CPlane::PreRender(void)
CCoronas::TYPE_NORMAL, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
}
+
+#ifdef CPLANE_ROTORS
+ CMatrix mat;
+ CVector pos;
+ m_fRotorRotation += 3.14f/6.5f;
+ if(m_fRotorRotation > 6.28f)
+ m_fRotorRotation -= 6.28f;
+
+ if(m_aPlaneNodes[PLANE_TOPROTOR]){
+ mat.Attach(RwFrameGetMatrix(m_aPlaneNodes[PLANE_TOPROTOR]));
+ pos = mat.GetPosition();
+ mat.SetRotateZ(m_fRotorRotation);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ }
+ if(m_aPlaneNodes[PLANE_BACKROTOR]){
+ mat.Attach(RwFrameGetMatrix(m_aPlaneNodes[PLANE_BACKROTOR]));
+ pos = mat.GetPosition();
+ mat.SetRotateX(m_fRotorRotation);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ }
+#endif
}
void
CPlane::Render(void)
{
- CEntity::Render();
+ if(!CCutsceneMgr::IsRunning())
+ CEntity::Render();
}
#define CRUISE_SPEED (50.0f)
@@ -657,11 +695,9 @@ CPlane::InitPlanes(void)
pPathNodes = LoadPath("data\\paths\\flight.dat", NumPathNodes, TotalLengthOfFlightPath, true);
// Figure out which nodes are on ground
- CColPoint colpoint;
- CEntity *entity;
for(i = 0; i < NumPathNodes; i++){
- if(CWorld::ProcessVerticalLine(pPathNodes[i].p, 1000.0f, colpoint, entity, true, false, false, false, true, false, nil)){
- pPathNodes[i].p.z = colpoint.point.z;
+ if(pPathNodes[i].p.z < 14.0f){
+ pPathNodes[i].p.z = 14.0f;
pPathNodes[i].bOnGround = true;
}else
pPathNodes[i].bOnGround = false;
@@ -688,7 +724,7 @@ CPlane::InitPlanes(void)
aPlaneLineBits[0].position = position;
aPlaneLineBits[0].speed = TAXI_SPEED;
aPlaneLineBits[0].acceleration = 0.0f;
- float dist = (TakeOffPoint-600.0f) - position;
+ float dist = (TakeOffPoint-500.0f) - position;
time += dist/TAXI_SPEED;
position += dist;
@@ -697,9 +733,9 @@ CPlane::InitPlanes(void)
aPlaneLineBits[1].time = time;
aPlaneLineBits[1].position = position;
aPlaneLineBits[1].speed = TAXI_SPEED;
- aPlaneLineBits[1].acceleration = 33.0f/32.0f;
- time += 600.0f/((CRUISE_SPEED+TAXI_SPEED)/2.0f);
- position += 600.0f;
+ aPlaneLineBits[1].acceleration = 618.75f/500.0f;
+ time += 500.0f/((CRUISE_SPEED+TAXI_SPEED)/2.0f);
+ position += 500.0f;
// Fly at cruise speed
aPlaneLineBits[2].type = 1;
@@ -716,9 +752,9 @@ CPlane::InitPlanes(void)
aPlaneLineBits[3].time = time;
aPlaneLineBits[3].position = position;
aPlaneLineBits[3].speed = CRUISE_SPEED;
- aPlaneLineBits[3].acceleration = -33.0f/32.0f;
- time += 600.0f/((CRUISE_SPEED+TAXI_SPEED)/2.0f);
- position += 600.0f;
+ aPlaneLineBits[3].acceleration = -618.75f/500.0f;
+ time += 500.0f/((CRUISE_SPEED+TAXI_SPEED)/2.0f);
+ position += 500.0f;
// Taxi
aPlaneLineBits[4].type = 1;
@@ -739,24 +775,17 @@ CPlane::InitPlanes(void)
TotalDurationOfFlightPath2 = TotalLengthOfFlightPath2/CRUISE_SPEED;
}
-/*
- // Mission Cesna
+ // Heli
if(pPath3Nodes == nil){
pPath3Nodes = LoadPath("data\\paths\\flight3.dat", NumPath3Nodes, TotalLengthOfFlightPath3, false);
TotalDurationOfFlightPath3 = TotalLengthOfFlightPath3/CRUISE_SPEED;
}
- // Mission Cesna
- if(pPath4Nodes == nil){
- pPath4Nodes = LoadPath("data\\paths\\flight4.dat", NumPath4Nodes, TotalLengthOfFlightPath4, false);
- TotalDurationOfFlightPath4 = TotalLengthOfFlightPath4/CRUISE_SPEED;
- }
-*/
-
CStreaming::LoadAllRequestedModels(false);
CStreaming::RequestModel(MI_AIRTRAIN, 0);
CStreaming::LoadAllRequestedModels(false);
+ // NB: 3 hardcoded also in CPlaneTrails
for(i = 0; i < 3; i++){
CPlane *plane = new CPlane(MI_AIRTRAIN, PERMANENT_VEHICLE);
plane->GetMatrix().SetTranslate(0.0f, 0.0f, 0.0f);
@@ -766,20 +795,6 @@ CPlane::InitPlanes(void)
plane->m_nCurPathNode = 0;
CWorld::Add(plane);
}
-
-
- CStreaming::RequestModel(MI_DEADDODO, 0);
- CStreaming::LoadAllRequestedModels(false);
-
- for(i = 0; i < 3; i++){
- CPlane *plane = new CPlane(MI_DEADDODO, PERMANENT_VEHICLE);
- plane->GetMatrix().SetTranslate(0.0f, 0.0f, 0.0f);
- plane->SetStatus(STATUS_ABANDONED);
- plane->bIsLocked = true;
- plane->m_nPlaneId = i;
- plane->m_nCurPathNode = 0;
- CWorld::Add(plane);
- }
}
void
@@ -811,7 +826,6 @@ CPlane::LoadPath(char const *filename, int32 &numNodes, float &totalLength, bool
CPlaneNode *nodes = new CPlaneNode[numNodes];
for(i = 0; i < numNodes; i++){
- *gString = '\0';
for(lp = 0; work_buff[bp] != '\n' && work_buff[bp] != '\0'; bp++, lp++)
gString[lp] = work_buff[bp];
bp++;
@@ -833,6 +847,10 @@ CPlane::LoadPath(char const *filename, int32 &numNodes, float &totalLength, bool
return nodes;
}
+int32 LastTimeInPlane, LastTimeNotInPlane;
+bool bCesnasActivated;
+bool bHelisActivated;
+
void
CPlane::UpdatePlanes(void)
{
@@ -875,25 +893,87 @@ CPlane::UpdatePlanes(void)
t = TotalDurationOfFlightPath2/0x80000;
PlanePath2Position[0] = CRUISE_SPEED * (time & 0x7FFFF)*t;
- PlanePath2Position[1] = CRUISE_SPEED * ((time + 0x80000/3) & 0x7FFFF)*t;
- PlanePath2Position[2] = CRUISE_SPEED * ((time + 0x80000/3*2) & 0x7FFFF)*t;
+ PlanePath2Position[1] = CRUISE_SPEED * ((time + 0x80000/5) & 0x7FFFF)*t;
+ PlanePath2Position[2] = CRUISE_SPEED * ((time + 0x80000/5*2) & 0x7FFFF)*t;
+ PlanePath2Position[3] = CRUISE_SPEED * ((time + 0x80000/5*3) & 0x7FFFF)*t;
+ PlanePath2Position[4] = CRUISE_SPEED * ((time + 0x80000/5*4) & 0x7FFFF)*t;
PlanePath2Speed[0] = CRUISE_SPEED*t;
PlanePath2Speed[1] = CRUISE_SPEED*t;
PlanePath2Speed[2] = CRUISE_SPEED*t;
+ PlanePath2Speed[3] = CRUISE_SPEED*t;
+ PlanePath2Speed[4] = CRUISE_SPEED*t;
+
+ t = TotalDurationOfFlightPath3/0x80000;
+ PlanePath3Position[0] = CRUISE_SPEED * (time & 0x7FFFF)*t;
+ PlanePath3Position[1] = CRUISE_SPEED * ((time + 0x80000/4) & 0x7FFFF)*t;
+ PlanePath3Position[2] = CRUISE_SPEED * ((time + 0x80000/4*2) & 0x7FFFF)*t;
+ PlanePath3Position[3] = CRUISE_SPEED * ((time + 0x80000/4*3) & 0x7FFFF)*t;
+ PlanePath3Speed[0] = CRUISE_SPEED*t;
+ PlanePath3Speed[1] = CRUISE_SPEED*t;
+ PlanePath3Speed[2] = CRUISE_SPEED*t;
+ PlanePath3Speed[3] = CRUISE_SPEED*t;
+
+ if(FindPlayerVehicle() && (FindPlayerVehicle()->GetVehicleAppearance() == VEHICLE_APPEARANCE_HELI ||
+ FindPlayerVehicle()->GetVehicleAppearance() == VEHICLE_APPEARANCE_PLANE))
+ LastTimeInPlane = CTimer::GetTimeInMilliseconds();
+ else
+ LastTimeNotInPlane = CTimer::GetTimeInMilliseconds();
+
+ if(CTimer::GetTimeInMilliseconds() - LastTimeNotInPlane > 10000){
+ if(!bCesnasActivated){
+ if(CStreaming::HasModelLoaded(MI_DEADDODO)){
+ for(i = 0; i < 5; i++){
+ CPlane *plane = new CPlane(MI_DEADDODO, PERMANENT_VEHICLE);
+ plane->GetMatrix().SetTranslate(0.0f, 0.0f, 0.0f);
+ plane->SetStatus(STATUS_ABANDONED);
+ plane->bIsLocked = true;
+ plane->m_nPlaneId = i;
+ plane->m_nCurPathNode = 0;
+ plane->m_bTempPlane = true;
+ CWorld::Add(plane);
+ }
+ bCesnasActivated = true;
+ }else
+ CStreaming::RequestModel(MI_DEADDODO, 0);
+ }
- if(CesnaMissionStatus == CESNA_STATUS_FLYING){
- PlanePath3Speed = CRUISE_SPEED*TotalDurationOfFlightPath3/0x20000;
- PlanePath3Position = PlanePath3Speed * ((time - CesnaMissionStartTime) & 0x1FFFF);
- if(time - CesnaMissionStartTime >= 128072)
- CesnaMissionStatus = CESNA_STATUS_LANDED;
- }
+ if(!bHelisActivated){
+ if(CStreaming::HasModelLoaded(MI_CHOPPER)){
+ for(i = 0; i < 4; i++){
+ CPlane *plane = new CPlane(MI_CHOPPER, PERMANENT_VEHICLE);
+ plane->GetMatrix().SetTranslate(0.0f, 0.0f, 0.0f);
+ plane->SetStatus(STATUS_ABANDONED);
+ plane->bIsLocked = true;
+ plane->m_nPlaneId = i;
+ plane->m_nCurPathNode = 0;
+ plane->m_bTempPlane = true;
+ CWorld::Add(plane);
+ }
+ bHelisActivated = true;
+ }else
+ CStreaming::RequestModel(MI_CHOPPER, 0);
+ }
+ }else if(CTimer::GetTimeInMilliseconds() - LastTimeInPlane > 10000)
+ RemoveTemporaryPlanes();
+}
- if(DropOffCesnaMissionStatus == CESNA_STATUS_FLYING){
- PlanePath4Speed = CRUISE_SPEED*TotalDurationOfFlightPath4/0x80000;
- PlanePath4Position = PlanePath4Speed * ((time - DropOffCesnaMissionStartTime) & 0x7FFFF);
- if(time - DropOffCesnaMissionStartTime >= 521288)
- DropOffCesnaMissionStatus = CESNA_STATUS_LANDED;
+void
+CPlane::RemoveTemporaryPlanes(void)
+{
+ int i;
+ if(!bHelisActivated && !bCesnasActivated)
+ return;
+
+ i = CPools::GetVehiclePool()->GetSize();
+ while(--i >= 0){
+ CPlane *plane = (CPlane*)CPools::GetVehiclePool()->GetSlot(i);
+ if(plane && plane->IsPlane() && plane->m_bTempPlane){
+ CWorld::Remove(plane);
+ delete plane;
+ }
}
+ bCesnasActivated = false;
+ bHelisActivated = false;
}
bool
@@ -921,6 +1001,7 @@ CPlane::TestRocketCollision(CVector *rocketPos)
return false;
}
+//--MIAMI: unused
// BUG: not in CPlane in the game
void
CPlane::CreateIncomingCesna(void)
@@ -944,6 +1025,7 @@ CPlane::CreateIncomingCesna(void)
printf("CPlane::CreateIncomingCesna(void)\n");
}
+//--MIAMI: unused
void
CPlane::CreateDropOffCesna(void)
{
@@ -966,8 +1048,21 @@ CPlane::CreateDropOffCesna(void)
printf("CPlane::CreateDropOffCesna(void)\n");
}
+//--MIAMI: all unused
const CVector CPlane::FindDrugPlaneCoordinates(void) { return pDrugRunCesna->GetPosition(); }
const CVector CPlane::FindDropOffCesnaCoordinates(void) { return pDropOffCesna->GetPosition(); }
bool CPlane::HasCesnaLanded(void) { return CesnaMissionStatus == CESNA_STATUS_LANDED; }
bool CPlane::HasCesnaBeenDestroyed(void) { return CesnaMissionStatus == CESNA_STATUS_DESTROYED; }
bool CPlane::HasDropOffCesnaBeenShotDown(void) { return DropOffCesnaMissionStatus == CESNA_STATUS_DESTROYED; }
+
+void
+CPlane::Load(void)
+{
+ RemoveTemporaryPlanes();
+}
+
+void
+CPlane::Save(void)
+{
+ RemoveTemporaryPlanes();
+}
diff --git a/src/vehicles/Plane.h b/src/vehicles/Plane.h
index e9456bcd..c8f02048 100644
--- a/src/vehicles/Plane.h
+++ b/src/vehicles/Plane.h
@@ -4,6 +4,11 @@
enum ePlaneNodes
{
+#ifdef CPLANE_ROTORS
+ // for heli
+ PLANE_TOPROTOR,
+ PLANE_BACKROTOR,
+#endif
PLANE_WHEEL_FRONT = 2,
PLANE_WHEEL_READ,
NUM_PLANE_NODES
@@ -29,7 +34,10 @@ struct CPlaneInterpolationLine
class CPlane : public CVehicle
{
public:
- // 0x288
+#ifdef CPLANE_ROTORS
+ RwFrame *m_aPlaneNodes[NUM_PLANE_NODES];
+ float m_fRotorRotation;
+#endif
int16 m_nPlaneId;
int16 m_isFarAway;
int16 m_nCurPathNode;
@@ -38,6 +46,7 @@ public:
bool m_bHasBeenHit;
bool m_bIsDrugRunCesna;
bool m_bIsDropOffCesna;
+ bool m_bTempPlane;
CPlane(int32 id, uint8 CreatedBy);
~CPlane(void);
@@ -53,6 +62,7 @@ public:
static void InitPlanes(void);
static void Shutdown(void);
static CPlaneNode *LoadPath(char const *filename, int32 &numNodes, float &totalLength, bool loop);
+ static void RemoveTemporaryPlanes(void);
static void UpdatePlanes(void);
static bool TestRocketCollision(CVector *rocketPos);
static void CreateIncomingCesna(void);
@@ -62,6 +72,8 @@ public:
static bool HasCesnaLanded(void);
static bool HasCesnaBeenDestroyed(void);
static bool HasDropOffCesnaBeenShotDown(void);
+ static void Load(void);
+ static void Save(void);
};
extern float LandingPoint;
diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp
index 360b843b..378a4c0a 100644
--- a/src/vehicles/Vehicle.cpp
+++ b/src/vehicles/Vehicle.cpp
@@ -232,7 +232,7 @@ CVehicle::SetupLighting(void)
}else{
CVector coors = GetPosition();
float lighting = CPointLights::GenerateLightsAffectingObject(&coors);
- if(!bHasBlip && lighting != 1.0f){
+ if(lighting != 1.0f){
SetAmbientAndDirectionalColours(lighting);
return true;
}
@@ -1512,7 +1512,7 @@ CVehicle::MakeNonDraggedPedsLeaveVehicle(CPed *ped1, CPed *ped2, CPlayerPed *&pl
for(i = 0; i < numPeds2; i++)
if(peds2[i]->IsFemale() || CGeneral::GetRandomTrueFalse()){
peds2[i]->m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 10000;
- peds2[i]->b156_8 = true;
+ peds2[i]->bHeldHostageInCar = true;
peds2[i]->bFleeAfterExitingCar = true;
}
}
@@ -1557,9 +1557,9 @@ CVehicle::IsLawEnforcementVehicle(void)
}
bool
-CVehicle::UsesSiren(uint32 id)
+CVehicle::UsesSiren(void)
{
- switch(id){
+ switch(GetModelIndex()){
case MI_FIRETRUCK:
case MI_AMBULAN:
case MI_FBICAR:
@@ -2239,7 +2239,7 @@ CVehicle::DoSunGlare(void)
int a2 = colmodel->triangles[i+1].a;
int b2 = colmodel->triangles[i+1].b;
int c2 = colmodel->triangles[i+1].c;
- CVector vert1 = colmodel->vertices[a1];
+ CVector vert1 = colmodel->vertices[a1].Get();
CVector vert4;
// Need an upward surface
if(vert1.z <= 0.0f)
@@ -2250,23 +2250,23 @@ CVehicle::DoSunGlare(void)
if(a2 != a1 && a2 != b1 && a2 != c1){
// a2 is not in tri1
numTri2Verts++;
- vert4 = colmodel->vertices[a2];
+ vert4 = colmodel->vertices[a2].Get();
}
if(b2 != a1 && b2 != b1 && b2 != c1){
// b2 is not in tri1
numTri2Verts++;
- vert4 = colmodel->vertices[b2];
+ vert4 = colmodel->vertices[b2].Get();
}
if(c2 != a1 && c2 != b1 && c2 != c1){
// c2 is not in tri1
numTri2Verts++;
- vert4 = colmodel->vertices[c2];
+ vert4 = colmodel->vertices[c2].Get();
}
// Need exactly one vertex from tri2 for a quad with tri1
if(numTri2Verts != 1)
continue;
- CVector mid = (vert1 + colmodel->vertices[b1] + colmodel->vertices[c1] + vert4)/4.0f;
+ CVector mid = (vert1 + colmodel->vertices[b1].Get() + colmodel->vertices[c1].Get() + vert4)/4.0f;
float dy = mid.y - vert1.y;
float dx = mid.x - vert1.x;
float dist = 1.4f * Min(Abs(dx), Abs(dy));
diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h
index b1e3d803..34106327 100644
--- a/src/vehicles/Vehicle.h
+++ b/src/vehicles/Vehicle.h
@@ -345,7 +345,7 @@ public:
int FindTyreNearestPoint(float x, float y);
bool IsLawEnforcementVehicle(void);
void ChangeLawEnforcerState(uint8 enable);
- bool UsesSiren(uint32 id);
+ bool UsesSiren(void);
bool IsVehicleNormal(void);
bool CarHasRoof(void);
bool IsUpsideDown(void);