summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/core/re3.cpp2
-rw-r--r--src/modelinfo/VehicleModelInfo.cpp10
-rw-r--r--src/render/Particle.h1
-rw-r--r--src/render/Weather.cpp2
-rw-r--r--src/rw/VisibilityPlugins.cpp8
-rw-r--r--src/rw/VisibilityPlugins.h1
-rw-r--r--src/vehicles/Automobile.cpp2
-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/Floater.cpp177
-rw-r--r--src/vehicles/Floater.h2
12 files changed, 882 insertions, 312 deletions
diff --git a/src/core/re3.cpp b/src/core/re3.cpp
index 6032fc4a..d49eff50 100644
--- a/src/core/re3.cpp
+++ b/src/core/re3.cpp
@@ -474,6 +474,8 @@ DebugMenuPopulate(void)
DebugMenuAddCmd("Spawn", "Spawn PCJ 600", [](){ SpawnCar(MI_PCJ600); });
DebugMenuAddCmd("Spawn", "Spawn Faggio", [](){ SpawnCar(MI_FAGGIO); });
DebugMenuAddCmd("Spawn", "Spawn Freeway", [](){ SpawnCar(MI_FREEWAY); });
+ DebugMenuAddCmd("Spawn", "Spawn Squalo", [](){ SpawnCar(MI_SQUALO); });
+ DebugMenuAddCmd("Spawn", "Spawn Skimmer", [](){ SpawnCar(MI_SKIMMER); });
DebugMenuAddVarBool8("Render", "Draw hud", &CHud::m_Wants_To_Draw_Hud, nil);
DebugMenuAddVarBool8("Render", "Backface Culling", &gBackfaceCulling, nil);
diff --git a/src/modelinfo/VehicleModelInfo.cpp b/src/modelinfo/VehicleModelInfo.cpp
index d1994c06..f80e908a 100644
--- a/src/modelinfo/VehicleModelInfo.cpp
+++ b/src/modelinfo/VehicleModelInfo.cpp
@@ -89,7 +89,17 @@ RwObjectNameIdAssocation boatIds[] = {
{ "boat_flap_right", BOAT_FLAP_RIGHT, 0 },
{ "boat_rearflap_left", BOAT_REARFLAP_LEFT, 0 },
{ "boat_rearflap_right", BOAT_REARFLAP_RIGHT, 0 },
+#ifdef FIX_BUGS
+ // let's just accept both
+ { "windscreen", BOAT_WINDSCREEN, VEHICLE_FLAG_WINDSCREEN | VEHICLE_FLAG_DRAWLAST },
{ "windscreen_hi_ok", BOAT_WINDSCREEN, VEHICLE_FLAG_WINDSCREEN | VEHICLE_FLAG_DRAWLAST },
+#else
+#ifdef GTA_PS2
+ { "windscreen", BOAT_WINDSCREEN, VEHICLE_FLAG_WINDSCREEN | VEHICLE_FLAG_DRAWLAST },
+#else
+ { "windscreen_hi_ok", BOAT_WINDSCREEN, VEHICLE_FLAG_WINDSCREEN | VEHICLE_FLAG_DRAWLAST },
+#endif
+#endif
{ "ped_frontseat", BOAT_POS_FRONTSEAT, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
{ nil, 0, 0 }
};
diff --git a/src/render/Particle.h b/src/render/Particle.h
index f2c3a459..9c496fe1 100644
--- a/src/render/Particle.h
+++ b/src/render/Particle.h
@@ -98,5 +98,6 @@ public:
};
extern bool clearWaterDrop;
+extern int32 numWaterDropOnScreen;
VALIDATE_SIZE(CParticle, 0x58);
diff --git a/src/render/Weather.cpp b/src/render/Weather.cpp
index 106e2f89..945e1f5e 100644
--- a/src/render/Weather.cpp
+++ b/src/render/Weather.cpp
@@ -279,7 +279,7 @@ void CWeather::Update(void)
}
Wind = InterpolationValue * Windiness[NewWeatherType] + (1.0f - InterpolationValue) * Windiness[OldWeatherType];
- WindClipped = Max(1.0f, Wind);
+ WindClipped = Min(1.0f, Wind);
if (CClock::GetHours() == 20)
TrafficLightBrightness = CClock::GetMinutes() / 60.0f;
diff --git a/src/rw/VisibilityPlugins.cpp b/src/rw/VisibilityPlugins.cpp
index cff1ff16..25dffb4e 100644
--- a/src/rw/VisibilityPlugins.cpp
+++ b/src/rw/VisibilityPlugins.cpp
@@ -626,6 +626,14 @@ CVisibilityPlugins::RenderPedCB(RpAtomic *atomic)
}
float
+CVisibilityPlugins::GetDistanceSquaredFromCamera(RwV3d *pos)
+{
+ RwV3d dist;
+ RwV3dSub(&dist, pos, ms_pCameraPosn);
+ return RwV3dDotProduct(&dist, &dist);
+}
+
+float
CVisibilityPlugins::GetDistanceSquaredFromCamera(RwFrame *frame)
{
RwMatrix *m;
diff --git a/src/rw/VisibilityPlugins.h b/src/rw/VisibilityPlugins.h
index 89583432..d426abec 100644
--- a/src/rw/VisibilityPlugins.h
+++ b/src/rw/VisibilityPlugins.h
@@ -83,6 +83,7 @@ public:
static bool VehicleVisibilityCB(RpClump *clump);
static bool VehicleVisibilityCB_BigVehicle(RpClump *clump);
+ static float GetDistanceSquaredFromCamera(RwV3d *pos);
static float GetDistanceSquaredFromCamera(RwFrame *frame);
static float GetDotProductWithCameraVector(RwMatrix *atomicMat, RwMatrix *clumpMat, uint32 flags);
diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp
index 925bc884..217b383f 100644
--- a/src/vehicles/Automobile.cpp
+++ b/src/vehicles/Automobile.cpp
@@ -3796,7 +3796,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 6f52c33f..e52027f9 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..786b5f4d 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_HELI, 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/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;