summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/core/Cam.cpp5
-rw-r--r--src/core/Camera.h1
-rw-r--r--src/core/Pad.cpp12
-rw-r--r--src/core/PlayerInfo.h1
-rw-r--r--src/core/Stats.cpp1
-rw-r--r--src/core/Stats.h1
-rw-r--r--src/core/config.h4
-rw-r--r--src/core/re3.cpp5
-rw-r--r--src/entities/Entity.cpp6
-rw-r--r--src/entities/Entity.h2
-rw-r--r--src/entities/Physical.cpp4
-rw-r--r--src/math/Matrix.h14
-rw-r--r--src/math/math.cpp6
-rw-r--r--src/peds/Ped.cpp3
-rw-r--r--src/render/Glass.h4
-rw-r--r--src/render/Renderer.cpp6
-rw-r--r--src/render/Skidmarks.cpp54
-rw-r--r--src/render/Skidmarks.h27
-rw-r--r--src/render/WindModifiers.cpp5
-rw-r--r--src/render/WindModifiers.h1
-rw-r--r--src/vehicles/Automobile.cpp2226
-rw-r--r--src/vehicles/Automobile.h32
-rw-r--r--src/vehicles/DamageManager.cpp30
-rw-r--r--src/vehicles/DamageManager.h2
-rw-r--r--src/vehicles/Vehicle.cpp77
-rw-r--r--src/vehicles/Vehicle.h9
-rw-r--r--src/weapons/Explosion.cpp2
-rw-r--r--src/weapons/Explosion.h3
-rw-r--r--src/weapons/Weapon.cpp12
-rw-r--r--src/weapons/Weapon.h1
30 files changed, 1886 insertions, 670 deletions
diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp
index 1c74598c..fe2c250f 100644
--- a/src/core/Cam.cpp
+++ b/src/core/Cam.cpp
@@ -3778,7 +3778,7 @@ CCam::Process_Debug(const CVector&, float, float, float)
if(FindPlayerVehicle())
FindPlayerVehicle()->Teleport(Source);
else
- CWorld::Players[CWorld::PlayerInFocus].m_pPed->SetPosition(Source);
+ CWorld::Players[CWorld::PlayerInFocus].m_pPed->SetPosition(Source);
}
// stay inside sectors
@@ -3845,8 +3845,7 @@ CCam::Process_Debug(const CVector&, float, float, float)
if(FindPlayerVehicle())
FindPlayerVehicle()->Teleport(Source);
else
- CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetPosition() = Source;
-
+ CWorld::Players[CWorld::PlayerInFocus].m_pPed->SetPosition(Source);
}
// stay inside sectors
diff --git a/src/core/Camera.h b/src/core/Camera.h
index 18144ef5..669ac740 100644
--- a/src/core/Camera.h
+++ b/src/core/Camera.h
@@ -382,6 +382,7 @@ public:
bool m_WideScreenOn;
bool m_1rstPersonRunCloseToAWall;
bool m_bHeadBob;
+ bool m_bVehicleSuspenHigh;
bool m_bFailedCullZoneTestPreviously;
bool m_FadeTargetIsSplashScreen;
diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp
index 89b3f053..d309d469 100644
--- a/src/core/Pad.cpp
+++ b/src/core/Pad.cpp
@@ -321,6 +321,12 @@ void RenderWaterLayersCheat(void)
CWaterLevel::m_nRenderWaterLayers = 0;
}
+void BackToTheFuture(void)
+{
+ CHud::SetHelpMessage(TheText.Get("CHEAT1"), true);
+ CVehicle::bHoverCheat = !CVehicle::bHoverCheat;
+}
+
//////////////////////////////////////////////////////////////////////////
@@ -1080,7 +1086,11 @@ void CPad::AddToPCCheatString(char c)
if (!_CHEATCMP("TAEHCSREYALRETAW"))
RenderWaterLayersCheat();
#endif
-
+
+ // SEAWAYS
+ if (!_CHEATCMP("SYAWAES"))
+ BackToTheFuture();
+
#undef _CHEATCMP
}
diff --git a/src/core/PlayerInfo.h b/src/core/PlayerInfo.h
index dfe6a53e..11f51ac0 100644
--- a/src/core/PlayerInfo.h
+++ b/src/core/PlayerInfo.h
@@ -49,6 +49,7 @@ public:
uint32 m_nTimeLastHealthLoss;
uint32 m_nTimeLastArmourLoss;
uint32 m_nTimeTankShotGun;
+ int32 m_nTimeNotFullyOnGround;
int32 m_nUpsideDownCounter;
int32 field_248;
int16 m_nTrafficMultiplier;
diff --git a/src/core/Stats.cpp b/src/core/Stats.cpp
index 34fc41d1..91f583bd 100644
--- a/src/core/Stats.cpp
+++ b/src/core/Stats.cpp
@@ -67,6 +67,7 @@ float CStats::AutoPaintingBudget;
int32 CStats::NoMoreHurricanes;
float CStats::FashionBudget;
int32 CStats::SafeHouseVisits;
+int32 CStats::TyresPopped;
void CStats::Init()
{
diff --git a/src/core/Stats.h b/src/core/Stats.h
index 485bdccf..33d4ef72 100644
--- a/src/core/Stats.h
+++ b/src/core/Stats.h
@@ -71,6 +71,7 @@ public:
static int32 NoMoreHurricanes;
static float FashionBudget;
static int32 SafeHouseVisits;
+ static int32 TyresPopped;
public:
static void Init(void);
diff --git a/src/core/config.h b/src/core/config.h
index 6744e888..dd68f296 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -41,7 +41,7 @@ enum Config {
NUMANIMBLOCKS = 35,
NUMANIMATIONS = 450,
- NUMTEMPOBJECTS = 30,
+ NUMTEMPOBJECTS = 40,
// Path data
NUM_PATHNODES = 9650,
@@ -208,7 +208,7 @@ enum Config {
#define RELOADABLES // some debug menu options to reload TXD files
#endif
-#define PC_WATER
+//#define PC_WATER
#define WATER_CHEATS
// Particle
diff --git a/src/core/re3.cpp b/src/core/re3.cpp
index 54077e6f..d02bd9b0 100644
--- a/src/core/re3.cpp
+++ b/src/core/re3.cpp
@@ -335,15 +335,18 @@ DebugMenuPopulate(void)
DebugMenuAddCmd("Spawn", "Spawn Stinger", [](){ SpawnCar(MI_STINGER); });
DebugMenuAddCmd("Spawn", "Spawn Infernus", [](){ SpawnCar(MI_INFERNUS); });
DebugMenuAddCmd("Spawn", "Spawn Cheetah", [](){ SpawnCar(MI_CHEETAH); });
+ DebugMenuAddCmd("Spawn", "Spawn Phoenix", [](){ SpawnCar(MI_PHEONIX); });
+ DebugMenuAddCmd("Spawn", "Spawn Banshee", [](){ SpawnCar(MI_BANSHEE); });
DebugMenuAddCmd("Spawn", "Spawn Esperanto", [](){ SpawnCar(MI_ESPERANT); });
DebugMenuAddCmd("Spawn", "Spawn Stallion", [](){ SpawnCar(MI_STALLION); });
+ DebugMenuAddCmd("Spawn", "Spawn Admiral", [](){ SpawnCar(MI_ADMIRAL); });
DebugMenuAddCmd("Spawn", "Spawn Washington", [](){ SpawnCar(MI_WASHING); });
DebugMenuAddCmd("Spawn", "Spawn Taxi", [](){ SpawnCar(MI_TAXI); });
DebugMenuAddCmd("Spawn", "Spawn Police", [](){ SpawnCar(MI_POLICE); });
DebugMenuAddCmd("Spawn", "Spawn Enforcer", [](){ SpawnCar(MI_ENFORCER); });
- DebugMenuAddCmd("Spawn", "Spawn Banshee", [](){ SpawnCar(MI_BANSHEE); });
DebugMenuAddCmd("Spawn", "Spawn Cuban", [](){ SpawnCar(MI_CUBAN); });
DebugMenuAddCmd("Spawn", "Spawn Voodoo", [](){ SpawnCar(MI_VOODOO); });
+ DebugMenuAddCmd("Spawn", "Spawn BF injection", [](){ SpawnCar(MI_BFINJECT); });
DebugMenuAddCmd("Spawn", "Spawn Maverick", [](){ SpawnCar(MI_MAVERICK); });
DebugMenuAddCmd("Spawn", "Spawn VCN Maverick", [](){ SpawnCar(MI_VCNMAV); });
DebugMenuAddCmd("Spawn", "Spawn Sparrow", [](){ SpawnCar(MI_SPARROW); });
diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp
index 68486a3c..41a2e2bd 100644
--- a/src/entities/Entity.cpp
+++ b/src/entities/Entity.cpp
@@ -81,7 +81,7 @@ CEntity::CEntity(void)
m_flagE2 = false;
bOffscreen = false;
bIsStaticWaitingForCollision = false;
- m_flagE10 = false;
+ bDontStream = false;
bUnderwater = false;
bHasPreRenderEffects = false;
@@ -1083,7 +1083,7 @@ CEntity::SaveEntityFlags(uint8*& buf)
if (m_flagE2) tmp |= BIT(9);
if (bOffscreen) tmp |= BIT(10);
if (bIsStaticWaitingForCollision) tmp |= BIT(11);
- if (m_flagE10) tmp |= BIT(12);
+ if (bDontStream) tmp |= BIT(12);
if (bUnderwater) tmp |= BIT(13);
if (bHasPreRenderEffects) tmp |= BIT(14);
@@ -1139,7 +1139,7 @@ CEntity::LoadEntityFlags(uint8*& buf)
m_flagE2 = !!(tmp & BIT(9));
bOffscreen = !!(tmp & BIT(10));
bIsStaticWaitingForCollision = !!(tmp & BIT(11));
- m_flagE10 = !!(tmp & BIT(12));
+ bDontStream = !!(tmp & BIT(12));
bUnderwater = !!(tmp & BIT(13));
bHasPreRenderEffects = !!(tmp & BIT(14));
}
diff --git a/src/entities/Entity.h b/src/entities/Entity.h
index e7d402d0..f506017a 100644
--- a/src/entities/Entity.h
+++ b/src/entities/Entity.h
@@ -87,7 +87,7 @@ public:
uint32 m_flagE2 : 1;
uint32 bOffscreen : 1; // offscreen flag. This can only be trusted when it is set to true
uint32 bIsStaticWaitingForCollision : 1; // this is used by script created entities - they are static until the collision is loaded below them
- uint32 m_flagE10 : 1; // probably bDontStream
+ uint32 bDontStream : 1; // tell the streaming not to stream me
uint32 bUnderwater : 1; // this object is underwater change drawing order
uint32 bHasPreRenderEffects : 1; // Object has a prerender effects attached to it
diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp
index 02feb5cb..f97194d0 100644
--- a/src/entities/Physical.cpp
+++ b/src/entities/Physical.cpp
@@ -478,7 +478,9 @@ CPhysical::ApplySpringCollisionAlt(float springConst, CVector &springDir, CVecto
if(DotProduct(springDir, forceDir) > 0.0f)
forceDir *= -1.0f;
float step = Min(CTimer::GetTimeStep(), 3.0f);
- float impulse = -GRAVITY*m_fMass*step * springConst * compression * bias*2.0f;
+ float impulse = GRAVITY*m_fMass*step * springConst * compression * bias*2.0f;
+ if(bIsHeavy)
+ impulse *= 0.75f;
ApplyMoveForce(forceDir*impulse);
ApplyTurnForce(forceDir*impulse, point);
}
diff --git a/src/math/Matrix.h b/src/math/Matrix.h
index 9979e701..46789c94 100644
--- a/src/math/Matrix.h
+++ b/src/math/Matrix.h
@@ -130,13 +130,18 @@ public:
{
float *pFloatMatrix = (float*)&m_matrix;
for (int i = 0; i < 3; i++)
-#ifdef FIX_BUGS // BUGFIX from VC
for (int j = 0; j < 3; j++)
-#else
- for (int j = 0; j < 4; j++)
-#endif
pFloatMatrix[i * 4 + j] *= scale;
}
+ void Scale(float sx, float sy, float sz)
+ {
+ float *pFloatMatrix = (float*)&m_matrix;
+ for (int i = 0; i < 3; i++){
+ pFloatMatrix[i * 4 + 0] *= sx;
+ pFloatMatrix[i * 4 + 1] *= sy;
+ pFloatMatrix[i * 4 + 2] *= sz;
+ }
+ }
void SetRotateXOnly(float angle){
@@ -224,6 +229,7 @@ public:
void SetRotate(float xAngle, float yAngle, float zAngle);
void Rotate(float x, float y, float z);
void RotateX(float x);
+ void RotateY(float y);
void RotateZ(float z);
void Reorthogonalise(void);
diff --git a/src/math/math.cpp b/src/math/math.cpp
index e11d048c..e8b459ae 100644
--- a/src/math/math.cpp
+++ b/src/math/math.cpp
@@ -47,6 +47,12 @@ CMatrix::RotateX(float x)
}
void
+CMatrix::RotateY(float y)
+{
+ Rotate(0.0f, y, 0.0f);
+}
+
+void
CMatrix::RotateZ(float z)
{
Rotate(0.0f, 0.0f, z);
diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp
index 406ac23f..e60d702b 100644
--- a/src/peds/Ped.cpp
+++ b/src/peds/Ped.cpp
@@ -16630,6 +16630,8 @@ CPed::ScanForThreats(void)
CPed *shooter = nil;
if ((fearFlags & PED_FLAG_GUN) && (shooter = CheckForGunShots()) && (m_nPedType != shooter->m_nPedType || m_nPedType == PEDTYPE_CIVMALE || m_nPedType == PEDTYPE_CIVFEMALE)) {
+//TODO(MIAMI): just a quick fix for heli weapons
+if(shooter->IsPed()){
if (!IsGangMember()) {
m_threatEntity = shooter;
m_threatEntity->RegisterReference((CEntity **) &m_threatEntity);
@@ -16641,6 +16643,7 @@ CPed::ScanForThreats(void)
m_threatEntity->RegisterReference((CEntity **) &m_threatEntity);
return CPedType::GetFlag(shooter->m_nPedType);
}
+}
}
CPed *deadPed = nil;
diff --git a/src/render/Glass.h b/src/render/Glass.h
index 51c5aae9..736e5205 100644
--- a/src/render/Glass.h
+++ b/src/render/Glass.h
@@ -1,6 +1,7 @@
#pragma once
class CEntity;
+class CVehicle;
class CFallingGlassPane : public CMatrix
{
@@ -49,4 +50,7 @@ public:
static void WindowRespondsToSoftCollision(CEntity *entity, float amount);
static void WasGlassHitByBullet(CEntity *entity, CVector point);
static void WindowRespondsToExplosion(CEntity *entity, CVector point);
+
+//TODO(MIAMI)
+ static void CarWindscreenShatters(CVehicle *vehicle, bool unk) {}
}; \ No newline at end of file
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index f149c6fb..f2f55b92 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -269,10 +269,8 @@ CRenderer::RenderBoats(void)
for(node = gSortedVehiclesAndPeds.tail.prev;
node != &gSortedVehiclesAndPeds.head;
node = node->prev){
- // only boats in this list
CVehicle *v = (CVehicle*)node->item.ent;
- if(v->IsBoat())
- RenderOneNonRoad(v);
+ RenderOneNonRoad(v);
}
}
@@ -394,7 +392,7 @@ CRenderer::SetupEntityVisibility(CEntity *ent)
}
return VIS_VISIBLE;
}
- if(ent->m_flagE10){
+ if(ent->bDontStream){
if(ent->m_rwObject == nil || !ent->bIsVisible)
return VIS_INVISIBLE;
if(!ent->GetIsOnScreen() || ent->IsEntityOccluded())
diff --git a/src/render/Skidmarks.cpp b/src/render/Skidmarks.cpp
index 961c38a6..efd88387 100644
--- a/src/render/Skidmarks.cpp
+++ b/src/render/Skidmarks.cpp
@@ -114,11 +114,12 @@ CSkidmarks::Render(void)
continue;
CRGBA color(0, 0, 0, 255);
- // TODO(MIAMI): we have a type field here actually (0-3)
- if(aSkidmarks[i].m_isBloody) // TODO: type 3
- color = CRGBA(132, 34, 11, 255);
- else if(aSkidmarks[i].m_isMuddy) // TODO: type 1
- color = CRGBA(90, 62, 9, 255);
+ switch(aSkidmarks[i].m_type){
+ case SKIDMARK_NORMAL: color = CRGBA(0, 0, 0, 255); break;
+ case SKIDMARK_MUDDY: color = CRGBA(90, 62, 9, 255); break;
+ case SKIDMARK_SANDY: color = CRGBA(108, 108, 96, 255); break;
+ case SKIDMARK_BLOODY: color = CRGBA(132, 34, 11, 255); break;
+ }
uint32 fade, alpha;
if(aSkidmarks[i].m_state == 1 || CTimer::GetTimeInMilliseconds() < aSkidmarks[i].m_fadeStart)
@@ -132,8 +133,12 @@ CSkidmarks::Render(void)
alpha = 0;
alpha = alpha*fade/256;
- CVector p1 = aSkidmarks[i].m_pos[j] + aSkidmarks[i].m_side[j];
- CVector p2 = aSkidmarks[i].m_pos[j] - aSkidmarks[i].m_side[j];
+ CVector p1 = aSkidmarks[i].m_pos[j];
+ p1.x += aSkidmarks[i].m_sideX[j];
+ p1.y += aSkidmarks[i].m_sideY[j];
+ CVector p2 = aSkidmarks[i].m_pos[j];
+ p2.x -= aSkidmarks[i].m_sideX[j];
+ p2.y -= aSkidmarks[i].m_sideY[j];
RwIm3DVertexSetRGBA(&SkidmarkVertices[j*2+0], color.red, color.green, color.blue, alpha);
RwIm3DVertexSetPos(&SkidmarkVertices[j*2+0], p1.x, p1.y, p1.z+0.1f);
RwIm3DVertexSetRGBA(&SkidmarkVertices[j*2+1], color.red, color.green, color.blue, alpha);
@@ -153,7 +158,20 @@ CSkidmarks::Render(void)
}
void
-CSkidmarks::RegisterOne(uintptr id, CVector pos, float fwdX, float fwdY, bool *isMuddy, bool *isBloody)
+CSkidmarks::RegisterOne(uintptr id, const CVector &pos, float fwdX, float fwdY, bool *isMuddy, bool *isBloody)
+{
+ eSkidmarkType type;
+ if(*isBloody)
+ type = SKIDMARK_BLOODY;
+ else if(*isMuddy)
+ type = SKIDMARK_MUDDY;
+ else
+ type = SKIDMARK_NORMAL;
+ RegisterOne(id, pos, fwdX, fwdY, type, isBloody);
+}
+
+void
+CSkidmarks::RegisterOne(uintptr id, const CVector &pos, float fwdX, float fwdY, eSkidmarkType type, bool *isBloody)
{
int i;
CVector2D fwd(fwdX, fwdY);
@@ -169,7 +187,7 @@ CSkidmarks::RegisterOne(uintptr id, CVector pos, float fwdX, float fwdY, bool *i
if(i < NUMSKIDMARKS){
// Continue this one
- if(aSkidmarks[i].m_isBloody != *isBloody){
+ if((aSkidmarks[i].m_type==SKIDMARK_BLOODY) != *isBloody){
// Blood-status changed, end this one
aSkidmarks[i].m_state = 2;
aSkidmarks[i].m_fadeStart = CTimer::GetTimeInMilliseconds() + 10000;
@@ -204,9 +222,12 @@ CSkidmarks::RegisterOne(uintptr id, CVector pos, float fwdX, float fwdY, bool *i
CVector2D right(dist.y, -dist.x);
float turn = DotProduct2D(fwd, right);
turn = Abs(turn) + 1.0f;
- aSkidmarks[i].m_side[aSkidmarks[i].m_last] = CVector(right.x, right.y, 0.0f) * turn * 0.125f;
- if(aSkidmarks[i].m_last == 1)
- aSkidmarks[i].m_side[0] = aSkidmarks[i].m_side[1];
+ aSkidmarks[i].m_sideX[aSkidmarks[i].m_last] = right.x * turn * 0.125f;
+ aSkidmarks[i].m_sideY[aSkidmarks[i].m_last] = right.y * turn * 0.125f;
+ if(aSkidmarks[i].m_last == 1){
+ aSkidmarks[i].m_sideX[0] = aSkidmarks[i].m_sideX[1];
+ aSkidmarks[i].m_sideY[0] = aSkidmarks[i].m_sideY[1];
+ }
if(aSkidmarks[i].m_last > 8)
*isBloody = false; // stop blood marks after 8
@@ -222,12 +243,15 @@ CSkidmarks::RegisterOne(uintptr id, CVector pos, float fwdX, float fwdY, bool *i
aSkidmarks[i].m_state = 1;
aSkidmarks[i].m_id = id;
aSkidmarks[i].m_pos[0] = pos;
- aSkidmarks[i].m_side[0] = CVector(0.0f, 0.0f, 0.0f);
+ aSkidmarks[i].m_sideX[0] = 0.0f;
+ aSkidmarks[i].m_sideY[0] = 0.0f;
aSkidmarks[i].m_wasUpdated = true;
aSkidmarks[i].m_last = 0;
aSkidmarks[i].m_lastUpdate = CTimer::GetTimeInMilliseconds() - 1000;
- aSkidmarks[i].m_isBloody = *isBloody;
- aSkidmarks[i].m_isMuddy = *isMuddy;
+ if(*isBloody)
+ aSkidmarks[i].m_type = SKIDMARK_BLOODY;
+ else
+ aSkidmarks[i].m_type = type;
}else
*isBloody = false; // stop blood marks if no space
}
diff --git a/src/render/Skidmarks.h b/src/render/Skidmarks.h
index 085b4c6d..28082f08 100644
--- a/src/render/Skidmarks.h
+++ b/src/render/Skidmarks.h
@@ -2,20 +2,28 @@
enum { SKIDMARK_LENGTH = 16 };
+enum eSkidmarkType
+{
+ SKIDMARK_NORMAL,
+ SKIDMARK_MUDDY,
+ SKIDMARK_SANDY,
+ SKIDMARK_BLOODY
+};
+
class CSkidmark
{
public:
- uint8 m_state;
- bool m_wasUpdated;
- bool m_isBloody;
- bool m_isMuddy;
+ CVector m_pos[SKIDMARK_LENGTH];
+ float m_sideX[SKIDMARK_LENGTH];
+ float m_sideY[SKIDMARK_LENGTH];
uintptr m_id;
- int16 m_last;
- uint32 m_lastUpdate;;
+ uint32 m_lastUpdate;
uint32 m_fadeStart;
uint32 m_fadeEnd;
- CVector m_pos[SKIDMARK_LENGTH];
- CVector m_side[SKIDMARK_LENGTH];
+ uint32 m_type;
+ int16 m_last;
+ uint8 m_state;
+ bool m_wasUpdated;
};
class CSkidmarks
@@ -28,5 +36,6 @@ public:
static void Clear(void);
static void Update(void);
static void Render(void);
- static void RegisterOne(uintptr id, CVector pos, float fwdX, float fwdY, bool *isMuddy, bool *isBloody);
+ static void RegisterOne(uintptr id, const CVector &pos, float fwdX, float fwdY, eSkidmarkType type, bool *isBloody);
+ static void RegisterOne(uintptr id, const CVector &pos, float fwdX, float fwdY, bool *isMuddy, bool *isBloody);
};
diff --git a/src/render/WindModifiers.cpp b/src/render/WindModifiers.cpp
index d7405c7a..49e7c96a 100644
--- a/src/render/WindModifiers.cpp
+++ b/src/render/WindModifiers.cpp
@@ -1,6 +1,11 @@
#include "common.h"
#include "WindModifiers.h"
+void
+CWindModifiers::RegisterOne(CVector pos, int32 unk)
+{
+}
+
int32
CWindModifiers::FindWindModifier(CVector pos, float *x, float *y)
{
diff --git a/src/render/WindModifiers.h b/src/render/WindModifiers.h
index b4024343..c42e185d 100644
--- a/src/render/WindModifiers.h
+++ b/src/render/WindModifiers.h
@@ -3,5 +3,6 @@
class CWindModifiers
{
public:
+ static void RegisterOne(CVector pos, int32 unk);
static int32 FindWindModifier(CVector pos, float *x, float *y);
};
diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp
index 9fa0df39..bb5a58ec 100644
--- a/src/vehicles/Automobile.cpp
+++ b/src/vehicles/Automobile.cpp
@@ -17,8 +17,10 @@
#include "Explosion.h"
#include "Particle.h"
#include "ParticleObject.h"
+#include "Glass.h"
#include "Antennas.h"
#include "Skidmarks.h"
+#include "WindModifiers.h"
#include "Shadows.h"
#include "PointLights.h"
#include "Coronas.h"
@@ -35,8 +37,10 @@
#include "Population.h"
#include "CarCtrl.h"
#include "CarAI.h"
+#include "Stats.h"
#include "Garages.h"
#include "PathFind.h"
+#include "Replay.h"
#include "AnimManager.h"
#include "RpAnimBlend.h"
#include "AnimBlendAssociation.h"
@@ -45,7 +49,9 @@
#include "Object.h"
#include "Automobile.h"
-bool bAllCarCheat; // unused
+//--MIAMI: file done except TODOs
+
+bool bAllCarCheat;
RwObject *GetCurrentAtomicObjectCB(RwObject *object, void *data);
@@ -67,20 +73,37 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(id);
m_fFireBlowUpTimer = 0.0f;
- field_4E0 = 0;
+ m_doingBurnout = 0;
bTaxiLight = m_sAllTaxiLights;
bFixedColour = false;
bBigWheels = false;
bWaterTight = false;
- bTankDetonateCars = true;
SetModelIndex(id);
+ // Already done in CVehicle...
+ switch(GetModelIndex()){
+ case MI_HUNTER:
+ case MI_ANGEL:
+ case MI_FREEWAY:
+ m_nRadioStation = V_ROCK;
+ break;
+ case MI_RCBARON:
+ case MI_RCBANDIT:
+ case MI_RCRAIDER:
+ case MI_RCGOBLIN:
+ case MI_TOPFUN:
+ case MI_CADDY:
+ case MI_BAGGAGE:
+ m_nRadioStation = RADIO_OFF;
+ break;
+ }
+
pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)mi->m_handlingId);
pFlyingHandling = mod_HandlingManager.GetFlyingPointer((eHandlingId)mi->m_handlingId);
- field_49C = 20.0f;
- field_4D8 = 0;
+ m_auto_unused1 = 20.0f;
+ m_auto_unused2 = 0;
mi->ChooseVehicleColour(m_currentColour1, m_currentColour2);
@@ -131,6 +154,8 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
m_fElasticity = 0.05f;
m_fBuoyancy = pHandling->fBuoyancy;
+ m_fOrientation = m_auto_unk4 = 0.0f;
+
m_nBusDoorTimerEnd = 0;
m_nBusDoorTimerStart = 0;
@@ -141,6 +166,9 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
m_fGasPedalAudio = 0.0f;
bNotDamagedUpsideDown = false;
bMoreResistantToDamage = false;
+ bTankDetonateCars = true;
+ bStuckInSand = false;
+ bHeliDestroyed = false;
m_fVelocityChangeForAudio = 0.0f;
m_hydraulicState = 0;
@@ -153,7 +181,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
m_aWheelRotation[i] = 0.0f;
m_aWheelSpeed[i] = 0.0f;
m_aWheelState[i] = WHEEL_STATE_NORMAL;
- m_aWheelSkidmarkMuddy[i] = false;
+ m_aWheelSkidmarkType[i] = SKIDMARK_NORMAL;
m_aWheelSkidmarkBloody[i] = false;
}
@@ -162,6 +190,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
m_nDriveWheelsOnGroundPrev = 0;
m_fHeightAboveRoad = 0.0f;
m_fTraction = 1.0f;
+ m_fTireTemperature = 1.0f;
CColModel *colModel = mi->GetColModel();
if(colModel->lines == nil){
@@ -176,10 +205,6 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
m_nNumPassengers = 0;
- m_bombType = CARBOMB_NONE;
- bDriverLastFrame = false;
- m_pBombRigger = nil;
-
if(m_nDoorLock == CARLOCK_UNLOCKED &&
(id == MI_POLICE || id == MI_ENFORCER || id == MI_RHINO))
m_nDoorLock = CARLOCK_LOCKED_INITIALLY;
@@ -187,6 +212,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
m_fCarGunLR = 0.0f;
m_fCarGunUD = 0.05f;
m_fPropellerRotation = 0.0f;
+ m_fHeliOrientation = -1.0f;
m_weaponDoorTimerLeft = 0.0f;
m_weaponDoorTimerRight = m_weaponDoorTimerLeft;
@@ -197,6 +223,9 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
CMatrix mat2(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LF]));
mat1.GetPosition() += CVector(mat2.GetPosition().x + 0.1f, 0.0f, mat2.GetPosition().z);
mat1.UpdateRW();
+ }else if(GetModelIndex() == MI_HUNTER){
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LB]), 0);
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RB]), 0);
}else if(IsRealHeli()){
RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]), 0);
RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]), 0);
@@ -208,7 +237,6 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
}
}
-
void
CAutomobile::SetModelIndex(uint32 id)
{
@@ -216,6 +244,11 @@ CAutomobile::SetModelIndex(uint32 id)
SetupModelNodes();
}
+#define SAND_SLOWDOWN (0.01f)
+float CAR_BALANCE_MULT = 0.3f;
+CVector vecSeaSparrowGunPos(-0.5f, 2.4f, -0.785f);
+CVector vecHunterGunPos(0.0f, 4.8f, -1.3f);
+CVector vecHunterRocketPos(2.5f, 1.0f, -0.5f);
CVector vecDAMAGE_ENGINE_POS_SMALL(-0.1f, -0.1f, 0.0f);
CVector vecDAMAGE_ENGINE_POS_BIG(-0.5f, -0.3f, 0.0f);
@@ -229,30 +262,41 @@ CAutomobile::ProcessControl(void)
colModel = &CWorld::Players[CWorld::PlayerInFocus].m_ColModel;
else
colModel = GetColModel();
+ bool drivingInSand = false;
bWarnedPeds = false;
+ m_doingBurnout = 0;
+ bStuckInSand = false;
+ bRestingOnPhysical = false;
+
+ bool carHasNitro = bAllTaxisHaveNitro && GetStatus() == STATUS_PLAYER && IsTaxi();
+
+ if(CReplay::IsPlayingBack())
+ return;
+
+ UpdatePassengerList();
+
+ // Heli wind
+ if(IsRealHeli())
+ if((GetStatus() == STATUS_PLAYER || GetStatus() == STATUS_PHYSICS) && m_aWheelSpeed[1] > 0.075f ||
+ GetStatus() == STATUS_SIMPLE)
+ CWindModifiers::RegisterOne(GetPosition(), 1);
// Improve grip of vehicles in certain cases
bool strongGrip1 = false;
bool strongGrip2 = false;
- if(FindPlayerVehicle() && this != FindPlayerVehicle()){
- switch(AutoPilot.m_nCarMission){
- case MISSION_RAMPLAYER_FARAWAY:
- case MISSION_RAMPLAYER_CLOSE:
- case MISSION_BLOCKPLAYER_FARAWAY:
- case MISSION_BLOCKPLAYER_CLOSE:
- if(FindPlayerSpeed().Magnitude() > 0.3f){
- strongGrip1 = true;
- if(FindPlayerSpeed().Magnitude() > 0.4f){
- if(m_vecMoveSpeed.Magnitude() < 0.3f)
- strongGrip2 = true;
- }else{
- if((GetPosition() - FindPlayerCoors()).Magnitude() > 50.0f)
- strongGrip2 = true;
- }
- }
- default: break;
+ if(FindPlayerVehicle() && this != FindPlayerVehicle() &&
+ (AutoPilot.m_nCarMission == MISSION_RAMPLAYER_FARAWAY || AutoPilot.m_nCarMission == MISSION_RAMPLAYER_CLOSE ||
+ AutoPilot.m_nCarMission == MISSION_BLOCKPLAYER_FARAWAY || AutoPilot.m_nCarMission == MISSION_BLOCKPLAYER_CLOSE)){
+ if(FindPlayerSpeed().Magnitude() > 0.3f){
+ strongGrip1 = true;
+ if(FindPlayerSpeed().Magnitude() > 0.4f &&
+ m_vecMoveSpeed.Magnitude() < 0.3f)
+ strongGrip2 = true;
+ else if((GetPosition() - FindPlayerCoors()).Magnitude() > 50.0f)
+ strongGrip2 = true;
}
- }
+ }else if(GetModelIndex() == MI_RCBANDIT && GetStatus() != STATUS_PLAYER_REMOTE)
+ strongGrip1 = true;
if(bIsBus)
ProcessAutoBusDoors();
@@ -261,9 +305,9 @@ CAutomobile::ProcessControl(void)
// Scan if this car sees the player committing any crimes
if(GetStatus() != STATUS_ABANDONED && GetStatus() != STATUS_WRECKED &&
- GetStatus() != STATUS_PLAYER && GetStatus() != STATUS_PLAYER_REMOTE && GetStatus() != STATUS_PLAYER_DISABLED){
+ GetStatus() != STATUS_PLAYER && GetStatus() != STATUS_PLAYER_REMOTE && GetStatus() != STATUS_PLAYER_DISABLED){
switch(GetModelIndex())
- case MI_FBICAR:
+ case MI_FBIRANCH:
case MI_POLICE:
case MI_ENFORCER:
case MI_SECURICA:
@@ -306,7 +350,18 @@ CAutomobile::ProcessControl(void)
else if(pHandling->Flags & HANDLING_NONPLAYER_STABILISER && GetStatus() == STATUS_PHYSICS)
m_vecCentreOfMass.z = pHandling->CentreOfMass.z - 0.2f*pHandling->Dimension.z;
else
- m_vecCentreOfMass.z = pHandling->CentreOfMass.z;
+ m_vecCentreOfMass = pHandling->CentreOfMass;
+
+ // Park car
+ if(bCanPark && !bParking && VehicleCreatedBy != MISSION_VEHICLE && AutoPilot.m_nCarMission == MISSION_CRUISE &&
+ ((CTimer::GetFrameCounter() + m_randomSeed)&0xF) == 0 && !IsTaxi()){
+ CVector parkPosition = GetPosition() + 3.0f*GetRight() + 10.0f*GetForward();
+ CEntity *ent = nil;
+ CColPoint colpoint;
+ if(!CWorld::ProcessLineOfSight(GetPosition(), parkPosition, colpoint, ent, true, true, true, false, false, false) ||
+ ent == this)
+ CCarAI::GetCarToParkAtCoors(this, &parkPosition);
+ }
// Process depending on status
@@ -318,12 +373,10 @@ CAutomobile::ProcessControl(void)
CRemote::TakeRemoteControlledCarFromPlayer();
}
- if(GetModelIndex() == MI_RCBANDIT){
- CVector pos = GetPosition();
+ if(GetModelIndex() == MI_RCBANDIT && !bDisableRemoteDetonationOnContact){
+ //CVector pos = GetPosition();
// FindPlayerCoors unused
- if(RcbanditCheckHitWheels() || bIsInWater || CPopulation::IsPointInSafeZone(&pos)){
- if(CPopulation::IsPointInSafeZone(&pos))
- CGarages::TriggerMessage("HM2_5", -1, 5000, -1);
+ if(RcbanditCheckHitWheels() || bIsInWater){
CRemote::TakeRemoteControlledCarFromPlayer();
BlowUpCar(FindPlayerPed());
}
@@ -334,7 +387,7 @@ CAutomobile::ProcessControl(void)
// fall through
case STATUS_PLAYER:
if(playerRemote ||
- pDriver && pDriver->GetPedState() != PED_EXIT_CAR && pDriver->GetPedState() != PED_DRAG_FROM_CAR){
+ pDriver && pDriver->GetPedState() != PED_EXIT_CAR && pDriver->GetPedState() != PED_DRAG_FROM_CAR && pDriver->GetPedState() != PED_ARRESTED){
// process control input if controlled by player
if(playerRemote || pDriver->m_nPedType == PEDTYPE_PLAYER1)
ProcessControlInputs(0);
@@ -343,7 +396,59 @@ CAutomobile::ProcessControl(void)
if(GetStatus() == STATUS_PLAYER && !CRecordDataForChase::IsRecording())
DoDriveByShootings();
+
+ // Tweak center on mass when driving on two wheels
+ int twoWheelTime = CWorld::Players[CWorld::PlayerInFocus].m_nTimeNotFullyOnGround;
+ if(twoWheelTime > 500 && !IsRealHeli() && !IsRealPlane()){
+ float tweak = Min(twoWheelTime-500, 1000)/500.0f;
+ if(GetUp().z > 0.0f){
+ // positive when on left wheels, negative on right wheels
+ if(GetRight().z <= 0.0f)
+ tweak *= -1.0f;
+ m_vecCentreOfMass.z = pHandling->CentreOfMass.z +
+ CPad::GetPad(0)->GetSteeringLeftRight()/128.0f *
+ CAR_BALANCE_MULT * tweak * colModel->boundingBox.max.z;
+ }
+ }else
+ m_vecCentreOfMass.z = pHandling->CentreOfMass.z;
+
+ if(bHoverCheat)
+ DoHoverSuspensionRatios();
+
+ if(m_aSuspensionSpringRatio[0] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[0].surfaceB) == ADHESIVE_SAND ||
+ m_aSuspensionSpringRatio[1] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[1].surfaceB) == ADHESIVE_SAND ||
+ m_aSuspensionSpringRatio[2] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[2].surfaceB) == ADHESIVE_SAND ||
+ m_aSuspensionSpringRatio[3] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[3].surfaceB) == ADHESIVE_SAND){
+ if(GetModelIndex() != MI_RCBANDIT && GetModelIndex() != MI_RHINO){
+ float slowdown;
+ CVector parallelSpeed = m_vecMoveSpeed - DotProduct(m_vecMoveSpeed, GetUp())*m_vecMoveSpeed;
+ float fSpeed = parallelSpeed.MagnitudeSqr();
+ if(fSpeed > 0.09f){
+ fSpeed = Sqrt(fSpeed);
+ parallelSpeed *= 0.3f / fSpeed;
+ slowdown = SAND_SLOWDOWN * Max(1.0f - 2.0f*fSpeed, 0.2f);
+ }else{
+ bStuckInSand = true;
+ slowdown = SAND_SLOWDOWN;
+ }
+ if(pHandling->Flags & HANDLING_GOOD_INSAND)
+ slowdown *= 0.5f;
+ if(CWeather::WetRoads > 0.2f)
+ slowdown *= (1.2f - CWeather::WetRoads);
+ ApplyMoveForce(parallelSpeed * -CTimer::GetTimeStep()*slowdown*m_fMass);
+ drivingInSand = true;
+ }
+ }
+ }else if(pDriver && pDriver->IsPlayer() &&
+ (pDriver->GetPedState() == PED_ARRESTED ||
+ pDriver->GetPedState() == PED_DRAG_FROM_CAR ||
+ (pDriver->GetPedState() == PED_EXIT_CAR || pDriver->m_objective == OBJECTIVE_LEAVE_VEHICLE) && !CanPedJumpOutCar())){
+ bIsHandbrakeOn = true;
+ m_fBrakePedal = 1.0f;
+ m_fGasPedal = 0.0f;
}
+ if(CPad::GetPad(0)->WeaponJustDown())
+ ActivateBomb();
break;
case STATUS_SIMPLE:
@@ -366,6 +471,7 @@ CAutomobile::ProcessControl(void)
PlayHornIfNecessary();
ReduceHornCounter();
bVehicleColProcessed = false;
+ bAudioChangingGear = false;
// that's all we do for simple vehicles
return;
@@ -373,15 +479,44 @@ CAutomobile::ProcessControl(void)
CCarAI::UpdateCarAI(this);
CCarCtrl::SteerAICarWithPhysics(this);
PlayHornIfNecessary();
+
+ if(bIsBeingCarJacked){
+ m_fGasPedal = 0.0f;
+ m_fBrakePedal = 1.0f;
+ bIsHandbrakeOn = true;
+ }
+
+ if(m_aSuspensionSpringRatio[0] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[0].surfaceB) == ADHESIVE_SAND ||
+ m_aSuspensionSpringRatio[1] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[1].surfaceB) == ADHESIVE_SAND ||
+ m_aSuspensionSpringRatio[2] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[2].surfaceB) == ADHESIVE_SAND ||
+ m_aSuspensionSpringRatio[3] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[3].surfaceB) == ADHESIVE_SAND){
+ if(GetModelIndex() != MI_RCBANDIT && GetModelIndex() != MI_SANDKING && GetModelIndex() != MI_BFINJECT){
+ bStuckInSand = true;
+ if(CWeather::WetRoads > 0.0f)
+ ApplyMoveForce(m_vecMoveSpeed * -CTimer::GetTimeStep()*SAND_SLOWDOWN*m_fMass * (1.0f-CWeather::WetRoads));
+ else
+ ApplyMoveForce(m_vecMoveSpeed * -CTimer::GetTimeStep()*SAND_SLOWDOWN*m_fMass);
+ }
+ }
break;
case STATUS_ABANDONED:
- m_fBrakePedal = 0.2f;
+ if(m_vecMoveSpeed.MagnitudeSqr() < 0.01f)
+ m_fBrakePedal = 0.2f;
+ else
+ m_fBrakePedal = 0.0f;
bIsHandbrakeOn = false;
m_fSteerAngle = 0.0f;
m_fGasPedal = 0.0f;
- m_nCarHornTimer = 0;
+ if(!IsAlarmOn())
+ m_nCarHornTimer = 0;
+
+ if(bIsBeingCarJacked){
+ m_fGasPedal = 0.0f;
+ m_fBrakePedal = 1.0f;
+ bIsHandbrakeOn = true;
+ }
break;
case STATUS_WRECKED:
@@ -390,26 +525,32 @@ CAutomobile::ProcessControl(void)
m_fSteerAngle = 0.0f;
m_fGasPedal = 0.0f;
- m_nCarHornTimer = 0;
+ if(!IsAlarmOn())
+ m_nCarHornTimer = 0;
break;
case STATUS_PLAYER_DISABLED:
- m_fBrakePedal = 1.0f;
- bIsHandbrakeOn = true;
+ if(m_vecMoveSpeed.MagnitudeSqr() < 0.01f ||
+ (pDriver && pDriver->IsPlayer() &&
+ (pDriver->GetPedState() == PED_ARRESTED ||
+ pDriver->GetPedState() == PED_DRAG_FROM_CAR ||
+ (pDriver->GetPedState() == PED_EXIT_CAR || pDriver->m_objective == OBJECTIVE_LEAVE_VEHICLE) && !CanPedJumpOutCar()))){
+ bIsHandbrakeOn = true;
+ m_fBrakePedal = 1.0f;
+ m_fGasPedal = 0.0f;
+ }else{
+ m_fBrakePedal = 0.0f;
+ bIsHandbrakeOn = false;
+ }
m_fSteerAngle = 0.0f;
m_fGasPedal = 0.0f;
- m_nCarHornTimer = 0;
+ if(!IsAlarmOn())
+ m_nCarHornTimer = 0;
break;
default: break;
}
- // what's going on here?
- if(GetPosition().z < -0.6f &&
- Abs(m_vecMoveSpeed.x) < 0.05f &&
- Abs(m_vecMoveSpeed.y) < 0.05f)
- m_vecTurnSpeed *= Pow(0.95f, CTimer::GetTimeStep());
-
// Skip physics if object is found to have been static recently
bool skipPhysics = false;
if(!bIsStuck && (GetStatus() == STATUS_ABANDONED || GetStatus() == STATUS_WRECKED)){
@@ -437,7 +578,8 @@ CAutomobile::ProcessControl(void)
if(m_vecMoveSpeedAvg.MagnitudeSqr() <= sq(moveSpeedLimit*CTimer::GetTimeStep()) &&
m_vecTurnSpeedAvg.MagnitudeSqr() <= sq(turnSpeedLimit*CTimer::GetTimeStep()) &&
- m_fDistanceTravelled < distanceLimit ||
+ m_fDistanceTravelled < distanceLimit &&
+ !(m_fDamageImpulse > 0.0f && m_pDamageEntity && m_pDamageEntity->IsPed()) ||
makeStatic){
m_nStaticFrames++;
@@ -453,15 +595,27 @@ CAutomobile::ProcessControl(void)
}
}else
m_nStaticFrames = 0;
+ if(IsRealHeli() && m_aWheelSpeed[1] > 0.0f){
+ skipPhysics = false;
+ m_nStaticFrames = 0;
+ }
}
// Postpone
for(i = 0; i < 4; i++)
- if(m_aGroundPhysical[i] && !CWorld::bForceProcessControl && m_aGroundPhysical[i]->bIsInSafePosition){
- bWasPostponed = true;
- return;
+ if(m_aGroundPhysical[i]){
+ bRestingOnPhysical = true;
+ if(!CWorld::bForceProcessControl && m_aGroundPhysical[i]->bIsInSafePosition){
+ bWasPostponed = true;
+ return;
+ }
}
+ if(bRestingOnPhysical){
+ skipPhysics = false;
+ m_nStaticFrames = 0;
+ }
+
VehicleDamage(0.0f, 0);
// special control
@@ -477,7 +631,7 @@ CAutomobile::ProcessControl(void)
HydraulicControl();
break;
default:
- if(CVehicle::bCheat3){
+ if(CVehicle::bCheat3 || carHasNitro){
// Make vehicle jump when horn is sounded
if(GetStatus() == STATUS_PLAYER && m_vecMoveSpeed.MagnitudeSqr() > sq(0.2f) &&
// BUG: game checks [0] four times, instead of all wheels
@@ -516,12 +670,17 @@ CAutomobile::ProcessControl(void)
1.2f*m_vecMoveSpeed, nil, 2.0f);
ApplyMoveForce(CVector(0.0f, 0.0f, 1.0f)*m_fMass*0.4f);
- ApplyTurnForce(GetUp()*m_fMass*0.035f, GetForward()*1.0f);
+ ApplyTurnForce(GetUp()*m_fTurnMass*0.01f, GetForward()*1.0f);
}
}
break;
}
+ if(GetStatus() == STATUS_PHYSICS || GetStatus() == STATUS_SIMPLE)
+ if(AutoPilot.m_nCarMission == MISSION_HELI_FLYTOCOORS ||
+ AutoPilot.m_nCarMission == MISSION_PLANE_FLYTOCOORS)
+ skipPhysics = true;
+
float brake;
if(skipPhysics){
bHasContacted = false;
@@ -531,11 +690,13 @@ CAutomobile::ProcessControl(void)
m_nCollisionRecords = 0;
bHasCollided = false;
bVehicleColProcessed = false;
+ bAudioChangingGear = false;
m_nDamagePieceType = 0;
m_fDamageImpulse = 0.0f;
m_pDamageEntity = nil;
m_vecTurnFriction = CVector(0.0f, 0.0f, 0.0f);
m_vecMoveFriction = CVector(0.0f, 0.0f, 0.0f);
+ m_fTireTemperature = 1.0f;
}else{
// This has to be done if ProcessEntityCollision wasn't called
@@ -572,7 +733,7 @@ CAutomobile::ProcessControl(void)
m_aSuspensionSpringRatio[i] = (m_aSuspensionSpringRatio[i]-wheelRadius)/(1.0f-wheelRadius);
}
- float fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward());
+ float fwdSpeed = Abs(DotProduct(m_vecMoveSpeed, GetForward()));
CVector contactPoints[4]; // relative to model
CVector contactSpeeds[4]; // speed at contact points
CVector springDirections[4]; // normalized, in model space
@@ -588,6 +749,14 @@ CAutomobile::ProcessControl(void)
if(m_aSuspensionSpringRatio[i] > 1.0f)
m_aSuspensionSpringRatio[i] = 1.0f;
}
+ }else if(CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[i].surfaceB) == ADHESIVE_SAND &&
+ GetModelIndex() != MI_RHINO){
+ fwdSpeed *= 0.7f;
+ float f = 1.0f - fwdSpeed/0.3f - 0.7f*CWeather::WetRoads;
+ f = Max(f, 0.4f);
+ m_aSuspensionSpringRatio[i] += f*(m_aSuspensionLineLength[i]-m_aSuspensionSpringLength[i])/m_aSuspensionSpringLength[i];
+ if(m_aSuspensionSpringRatio[i] > 1.0f)
+ m_aSuspensionSpringRatio[i] = 1.0f;
}
// get points and directions if spring is compressed
@@ -605,13 +774,20 @@ CAutomobile::ProcessControl(void)
if(i == 1 || i == 3) // rear
bias = 1.0f - bias;
- ApplySpringCollision(pHandling->fSuspensionForceLevel,
+ ApplySpringCollisionAlt(pHandling->fSuspensionForceLevel,
springDirections[i], contactPoints[i],
- m_aSuspensionSpringRatio[i], bias);
- m_aWheelSkidmarkMuddy[i] =
- m_aWheelColPoints[i].surfaceB == SURFACE_GRASS ||
- m_aWheelColPoints[i].surfaceB == SURFACE_MUD_DRY ||
- m_aWheelColPoints[i].surfaceB == SURFACE_SAND;
+ m_aSuspensionSpringRatio[i], bias, m_aWheelColPoints[i].normal);
+
+ m_aWheelSkidmarkUnk[i] = false;
+ if(m_aWheelColPoints[i].surfaceB == SURFACE_GRASS ||
+ m_aWheelColPoints[i].surfaceB == SURFACE_MUD_DRY)
+ m_aWheelSkidmarkType[i] = SKIDMARK_MUDDY;
+ else if(m_aWheelColPoints[i].surfaceB == SURFACE_SAND ||
+ m_aWheelColPoints[i].surfaceB == SURFACE_SAND_BEACH){
+ m_aWheelSkidmarkType[i] = SKIDMARK_SANDY;
+ m_aWheelSkidmarkUnk[i] = true;
+ }else
+ m_aWheelSkidmarkType[i] = SKIDMARK_NORMAL;
}else{
contactPoints[i] = Multiply3x3(GetMatrix(), colModel->lines[i].p1);
}
@@ -628,6 +804,8 @@ CAutomobile::ProcessControl(void)
m_aGroundPhysical[i] = nil;
#endif
}
+ if(m_aSuspensionSpringRatio[i] < 1.0f && m_aWheelColPoints[i].normal.z > 0.35f)
+ springDirections[i] = -m_aWheelColPoints[i].normal;
}
// dampen springs
@@ -654,16 +832,29 @@ CAutomobile::ProcessControl(void)
float acceleration = pHandling->Transmission.CalculateDriveAcceleration(m_fGasPedal, m_nCurrentGear, m_fChangeGearTime, fwdSpeed, gripCheat);
acceleration /= m_fForceMultiplier;
- // unused
- if(GetModelIndex() == MI_RCBARON || IsRealHeli())
+ if(IsRealHeli() || IsRealPlane())
acceleration = 0.0f;
+ if(bAudioChangingGear && m_fGasPedal > 0.4f && m_fBrakePedal < 0.1f && fwdSpeed > 0.15f &&
+ this == FindPlayerVehicle() && TheCamera.Cams[TheCamera.ActiveCam].Mode != CCam::MODE_1STPERSON){
+ if(GetStatus() == STATUS_PLAYER && pHandling->Flags & HANDLING_IS_BUS){
+ if(m_nBusDoorTimerEnd == 0)
+ m_nBusDoorTimerEnd = 1000;
+ else if(m_nBusDoorTimerEnd > (uint32)CTimer::GetTimeStepInMilliseconds())
+ m_nBusDoorTimerEnd -= CTimer::GetTimeStepInMilliseconds();
+ }
+
+ if(m_aSuspensionSpringRatio[0] < 1.0f || m_aSuspensionSpringRatio[1] < 1.0f ||
+ m_aSuspensionSpringRatio[2] < 1.0f || m_aSuspensionSpringRatio[3] < 1.0f)
+ ApplyTurnForce(-0.008*Min(m_fTurnMass, 2500.0f)*GetUp(), -1.0f*GetForward());
+ }
+
brake = m_fBrakePedal * pHandling->fBrakeDeceleration * CTimer::GetTimeStep();
- bool neutralHandling = !!(pHandling->Flags & HANDLING_NEUTRALHANDLING);
+ bool neutralHandling = GetStatus() != STATUS_PLAYER && GetStatus() != STATUS_PLAYER_REMOTE && (pHandling->Flags & HANDLING_NEUTRALHANDLING);
float brakeBiasFront = neutralHandling ? 1.0f : 2.0f*pHandling->fBrakeBias;
float brakeBiasRear = neutralHandling ? 1.0f : 2.0f*(1.0f-pHandling->fBrakeBias);
float tractionBiasFront = neutralHandling ? 1.0f : 2.0f*pHandling->fTractionBias;
- float tractionBiasRear = neutralHandling ? 1.0f : 2.0f*(1.0f-pHandling->fTractionBias);
+ float tractionBiasRear = neutralHandling ? 1.0f : 2.0f-tractionBiasFront;
// Count how many wheels are touching the ground
@@ -705,10 +896,7 @@ CAutomobile::ProcessControl(void)
if(CVehicle::bCheat3)
traction *= 4.0f;
- if(FindPlayerVehicle() && FindPlayerVehicle() == this){
- if(CPad::GetPad(0)->WeaponJustDown())
- ActivateBomb();
- }else if(strongGrip1 || CVehicle::bCheat3){
+ if(FindPlayerVehicle() != this && (strongGrip1 || CVehicle::bCheat3)){
traction *= 1.2f;
acceleration *= 1.4f;
if(strongGrip2 || CVehicle::bCheat3){
@@ -720,13 +908,16 @@ CAutomobile::ProcessControl(void)
static float fThrust;
static tWheelState WheelState[4];
- // Process front wheels on ground
+ bool rearWheelsFirst = !!(pHandling->Flags & HANDLING_REARWHEEL_1ST);
+ // Process front wheels on ground - first try
+
+ if(!rearWheelsFirst){
if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] > 0.0f || m_aWheelTimer[CARWHEEL_FRONT_RIGHT] > 0.0f){
float s = Sin(m_fSteerAngle);
float c = Cos(m_fSteerAngle);
- CVector wheelFwd = Multiply3x3(GetMatrix(), CVector(-s, c, 0.0f));
- CVector wheelRight = Multiply3x3(GetMatrix(), CVector(c, s, 0.0f));
+
+ CVector wheelFwd, wheelRight, tmp;
if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] > 0.0f){
if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier))
@@ -734,6 +925,15 @@ CAutomobile::ProcessControl(void)
else
fThrust = acceleration;
+ wheelFwd = GetForward();
+ wheelFwd -= DotProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_FRONT_LEFT].normal)*m_aWheelColPoints[CARWHEEL_FRONT_LEFT].normal;
+ wheelFwd.Normalise();
+ wheelRight = CrossProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_FRONT_LEFT].normal);
+ wheelRight.Normalise();
+ tmp = c*wheelFwd - s*wheelRight;
+ wheelRight = s*wheelFwd + c*wheelRight;
+ wheelFwd = tmp;
+
m_aWheelColPoints[CARWHEEL_FRONT_LEFT].surfaceA = SURFACE_WHEELBASE;
float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_FRONT_LEFT])*traction;
if(GetStatus() == STATUS_PLAYER)
@@ -768,6 +968,15 @@ CAutomobile::ProcessControl(void)
else
fThrust = acceleration;
+ wheelFwd = GetForward();
+ wheelFwd -= DotProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].normal)*m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].normal;
+ wheelFwd.Normalise();
+ wheelRight = CrossProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].normal);
+ wheelRight.Normalise();
+ tmp = c*wheelFwd - s*wheelRight;
+ wheelRight = s*wheelFwd + c*wheelRight;
+ wheelFwd = tmp;
+
m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].surfaceA = SURFACE_WHEELBASE;
float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_FRONT_RIGHT])*traction;
if(GetStatus() == STATUS_PLAYER)
@@ -799,33 +1008,36 @@ CAutomobile::ProcessControl(void)
// Process front wheels off ground
- if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] <= 0.0f){
- if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
- m_aWheelSpeed[CARWHEEL_FRONT_LEFT] *= 0.95f;
- else{
- if(acceleration > 0.0f){
- if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] < 2.0f)
- m_aWheelSpeed[CARWHEEL_FRONT_LEFT] -= 0.2f;
- }else{
- if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] > -2.0f)
- m_aWheelSpeed[CARWHEEL_FRONT_LEFT] += 0.1f;
+ if(!IsRealHeli()){
+ if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] <= 0.0f){
+ if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_LEFT] *= 0.95f;
+ else{
+ if(acceleration > 0.0f){
+ if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] < 2.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_LEFT] -= 0.2f;
+ }else{
+ if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] > -2.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_LEFT] += 0.1f;
+ }
}
+ m_aWheelRotation[CARWHEEL_FRONT_LEFT] += m_aWheelSpeed[CARWHEEL_FRONT_LEFT];
}
- m_aWheelRotation[CARWHEEL_FRONT_LEFT] += m_aWheelSpeed[CARWHEEL_FRONT_LEFT];
- }
- if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] <= 0.0f){
- if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
- m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] *= 0.95f;
- else{
- if(acceleration > 0.0f){
- if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] < 2.0f)
- m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] -= 0.2f;
- }else{
- if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] > -2.0f)
- m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] += 0.1f;
+ if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] <= 0.0f){
+ if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] *= 0.95f;
+ else{
+ if(acceleration > 0.0f){
+ if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] < 2.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] -= 0.2f;
+ }else{
+ if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] > -2.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] += 0.1f;
+ }
}
+ m_aWheelRotation[CARWHEEL_FRONT_RIGHT] += m_aWheelSpeed[CARWHEEL_FRONT_RIGHT];
}
- m_aWheelRotation[CARWHEEL_FRONT_RIGHT] += m_aWheelSpeed[CARWHEEL_FRONT_RIGHT];
+ }
}
// Process rear wheels
@@ -834,14 +1046,27 @@ CAutomobile::ProcessControl(void)
CVector wheelFwd = GetForward();
CVector wheelRight = GetRight();
+ float rearBrake = brake;
+ float rearTraction = traction;
+ if(bIsHandbrakeOn){
#ifdef FIX_BUGS
- // Not sure if this is needed, but brake usually has timestep as a factor
- if(bIsHandbrakeOn)
- brake = 20000.0f * CTimer::GetTimeStepFix();
+ // Not sure if this is needed, but brake usually has timestep as a factor
+ rearBrake = 20000.0f * CTimer::GetTimeStepFix();
#else
- if(bIsHandbrakeOn)
- brake = 20000.0f;
+ rearBrake = 20000.0f;
#endif
+ if(fwdSpeed > 0.1f && pHandling->Flags & HANDLING_HANDBRAKE_TYRE){
+ m_fTireTemperature += 0.005*CTimer::GetTimeStep();
+ if(m_fTireTemperature > 2.0f)
+ m_fTireTemperature = 2.0f;
+ }
+ }else if(m_doingBurnout && !mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier)){
+ rearBrake = 0.0f;
+ rearTraction = 0.0f;
+ ApplyTurnForce(contactPoints[CARWHEEL_REAR_LEFT], -0.001f*m_fTurnMass*m_fSteerAngle*GetRight());
+ }else if(m_fTireTemperature > 1.0f){
+ rearTraction *= m_fTireTemperature;
+ }
if(m_aWheelTimer[CARWHEEL_REAR_LEFT] > 0.0f){
if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier))
@@ -849,8 +1074,14 @@ CAutomobile::ProcessControl(void)
else
fThrust = acceleration;
+ wheelFwd = GetForward();
+ wheelFwd -= DotProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_REAR_LEFT].normal)*m_aWheelColPoints[CARWHEEL_REAR_LEFT].normal;
+ wheelFwd.Normalise();
+ wheelRight = CrossProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_REAR_LEFT].normal);
+ wheelRight.Normalise();
+
m_aWheelColPoints[CARWHEEL_REAR_LEFT].surfaceA = SURFACE_WHEELBASE;
- float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_REAR_LEFT])*traction;
+ float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_REAR_LEFT])*rearTraction;
if(GetStatus() == STATUS_PLAYER)
adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[CARWHEEL_REAR_LEFT].surfaceB);
WheelState[CARWHEEL_REAR_LEFT] = m_aWheelState[CARWHEEL_REAR_LEFT];
@@ -859,7 +1090,7 @@ CAutomobile::ProcessControl(void)
ProcessWheel(wheelFwd, wheelRight,
contactSpeeds[CARWHEEL_REAR_LEFT], contactPoints[CARWHEEL_REAR_LEFT],
m_nWheelsOnGround, fThrust,
- brake*brakeBiasRear,
+ rearBrake*brakeBiasRear,
adhesion*tractionBiasRear*Damage.m_fWheelDamageEffect,
CARWHEEL_REAR_LEFT,
&m_aWheelSpeed[CARWHEEL_REAR_LEFT],
@@ -869,7 +1100,7 @@ CAutomobile::ProcessControl(void)
ProcessWheel(wheelFwd, wheelRight,
contactSpeeds[CARWHEEL_REAR_LEFT], contactPoints[CARWHEEL_REAR_LEFT],
m_nWheelsOnGround, fThrust,
- brake*brakeBiasRear,
+ rearBrake*brakeBiasRear,
adhesion*tractionBiasRear,
CARWHEEL_REAR_LEFT,
&m_aWheelSpeed[CARWHEEL_REAR_LEFT],
@@ -877,14 +1108,26 @@ CAutomobile::ProcessControl(void)
WHEEL_STATUS_OK);
}
+#ifdef FIX_BUGS
+ // Shouldn't we reset these after the left wheel?
+ wheelFwd = GetForward();
+ wheelRight = GetRight();
+#endif
+
if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] > 0.0f){
if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier))
fThrust = 0.0f;
else
fThrust = acceleration;
+ wheelFwd = GetForward();
+ wheelFwd -= DotProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_REAR_RIGHT].normal)*m_aWheelColPoints[CARWHEEL_REAR_RIGHT].normal;
+ wheelFwd.Normalise();
+ wheelRight = CrossProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_REAR_RIGHT].normal);
+ wheelRight.Normalise();
+
m_aWheelColPoints[CARWHEEL_REAR_RIGHT].surfaceA = SURFACE_WHEELBASE;
- float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_REAR_RIGHT])*traction;
+ float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_REAR_RIGHT])*rearTraction;
if(GetStatus() == STATUS_PLAYER)
adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[CARWHEEL_REAR_RIGHT].surfaceB);
WheelState[CARWHEEL_REAR_RIGHT] = m_aWheelState[CARWHEEL_REAR_RIGHT];
@@ -893,7 +1136,7 @@ CAutomobile::ProcessControl(void)
ProcessWheel(wheelFwd, wheelRight,
contactSpeeds[CARWHEEL_REAR_RIGHT], contactPoints[CARWHEEL_REAR_RIGHT],
m_nWheelsOnGround, fThrust,
- brake*brakeBiasRear,
+ rearBrake*brakeBiasRear,
adhesion*tractionBiasRear*Damage.m_fWheelDamageEffect,
CARWHEEL_REAR_RIGHT,
&m_aWheelSpeed[CARWHEEL_REAR_RIGHT],
@@ -903,7 +1146,7 @@ CAutomobile::ProcessControl(void)
ProcessWheel(wheelFwd, wheelRight,
contactSpeeds[CARWHEEL_REAR_RIGHT], contactPoints[CARWHEEL_REAR_RIGHT],
m_nWheelsOnGround, fThrust,
- brake*brakeBiasRear,
+ rearBrake*brakeBiasRear,
adhesion*tractionBiasRear,
CARWHEEL_REAR_RIGHT,
&m_aWheelSpeed[CARWHEEL_REAR_RIGHT],
@@ -912,58 +1155,203 @@ CAutomobile::ProcessControl(void)
}
}
+ if(m_doingBurnout && !mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) &&
+ (m_aWheelState[CARWHEEL_REAR_LEFT] == WHEEL_STATE_SPINNING || m_aWheelState[CARWHEEL_REAR_RIGHT])){
+ m_fTireTemperature += 0.001f*CTimer::GetTimeStep();
+ if(m_fTireTemperature > 3.0f)
+ m_fTireTemperature = 3.0f;
+ }else if(m_fTireTemperature > 1.0f){
+ m_fTireTemperature = (m_fTireTemperature - 1.0f)*Pow(0.995f, CTimer::GetTimeStep()) + 1.0f;
+ }
+
// Process rear wheels off ground
- if(m_aWheelTimer[CARWHEEL_REAR_LEFT] <= 0.0f){
- if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
- m_aWheelSpeed[CARWHEEL_REAR_LEFT] *= 0.95f;
- else{
- if(acceleration > 0.0f){
- if(m_aWheelSpeed[CARWHEEL_REAR_LEFT] < 2.0f)
- m_aWheelSpeed[CARWHEEL_REAR_LEFT] -= 0.2f;
- }else{
- if(m_aWheelSpeed[CARWHEEL_REAR_LEFT] > -2.0f)
- m_aWheelSpeed[CARWHEEL_REAR_LEFT] += 0.1f;
+ if(!IsRealHeli()){
+ if(m_aWheelTimer[CARWHEEL_REAR_LEFT] <= 0.0f){
+ if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
+ m_aWheelSpeed[CARWHEEL_REAR_LEFT] *= 0.95f;
+ else{
+ if(acceleration > 0.0f){
+ if(m_aWheelSpeed[CARWHEEL_REAR_LEFT] < 2.0f)
+ m_aWheelSpeed[CARWHEEL_REAR_LEFT] -= 0.2f;
+ }else{
+ if(m_aWheelSpeed[CARWHEEL_REAR_LEFT] > -2.0f)
+ m_aWheelSpeed[CARWHEEL_REAR_LEFT] += 0.1f;
+ }
}
+ m_aWheelRotation[CARWHEEL_REAR_LEFT] += m_aWheelSpeed[CARWHEEL_REAR_LEFT];
}
- m_aWheelRotation[CARWHEEL_REAR_LEFT] += m_aWheelSpeed[CARWHEEL_REAR_LEFT];
- }
- if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] <= 0.0f){
- if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
- m_aWheelSpeed[CARWHEEL_REAR_RIGHT] *= 0.95f;
- else{
- if(acceleration > 0.0f){
- if(m_aWheelSpeed[CARWHEEL_REAR_RIGHT] < 2.0f)
- m_aWheelSpeed[CARWHEEL_REAR_RIGHT] -= 0.2f;
- }else{
- if(m_aWheelSpeed[CARWHEEL_REAR_RIGHT] > -2.0f)
- m_aWheelSpeed[CARWHEEL_REAR_RIGHT] += 0.1f;
+ if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] <= 0.0f){
+ if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
+ m_aWheelSpeed[CARWHEEL_REAR_RIGHT] *= 0.95f;
+ else{
+ if(acceleration > 0.0f){
+ if(m_aWheelSpeed[CARWHEEL_REAR_RIGHT] < 2.0f)
+ m_aWheelSpeed[CARWHEEL_REAR_RIGHT] -= 0.2f;
+ }else{
+ if(m_aWheelSpeed[CARWHEEL_REAR_RIGHT] > -2.0f)
+ m_aWheelSpeed[CARWHEEL_REAR_RIGHT] += 0.1f;
+ }
+ }
+ m_aWheelRotation[CARWHEEL_REAR_RIGHT] += m_aWheelSpeed[CARWHEEL_REAR_RIGHT];
+ }
+ }
+
+ // Process front wheels on ground - second try
+
+ if(rearWheelsFirst){
+ if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] > 0.0f || m_aWheelTimer[CARWHEEL_FRONT_RIGHT] > 0.0f){
+ float s = Sin(m_fSteerAngle);
+ float c = Cos(m_fSteerAngle);
+
+ CVector wheelFwd, wheelRight, tmp;
+
+ if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] > 0.0f){
+ if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier))
+ fThrust = 0.0f;
+ else
+ fThrust = acceleration;
+
+ wheelFwd = GetForward();
+ wheelFwd -= DotProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_FRONT_LEFT].normal)*m_aWheelColPoints[CARWHEEL_FRONT_LEFT].normal;
+ wheelFwd.Normalise();
+ wheelRight = CrossProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_FRONT_LEFT].normal);
+ wheelRight.Normalise();
+ tmp = c*wheelFwd - s*wheelRight;
+ wheelRight = s*wheelFwd + c*wheelRight;
+ wheelFwd = tmp;
+
+ m_aWheelColPoints[CARWHEEL_FRONT_LEFT].surfaceA = SURFACE_WHEELBASE;
+ float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_FRONT_LEFT])*traction;
+ if(GetStatus() == STATUS_PLAYER)
+ adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[CARWHEEL_FRONT_LEFT].surfaceB);
+ WheelState[CARWHEEL_FRONT_LEFT] = m_aWheelState[CARWHEEL_FRONT_LEFT];
+
+ if(Damage.GetWheelStatus(VEHWHEEL_FRONT_LEFT) == WHEEL_STATUS_BURST)
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[CARWHEEL_FRONT_LEFT], contactPoints[CARWHEEL_FRONT_LEFT],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBiasFront,
+ adhesion*tractionBiasFront*Damage.m_fWheelDamageEffect,
+ CARWHEEL_FRONT_LEFT,
+ &m_aWheelSpeed[CARWHEEL_FRONT_LEFT],
+ &WheelState[CARWHEEL_FRONT_LEFT],
+ WHEEL_STATUS_BURST);
+ else
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[CARWHEEL_FRONT_LEFT], contactPoints[CARWHEEL_FRONT_LEFT],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBiasFront,
+ adhesion*tractionBiasFront,
+ CARWHEEL_FRONT_LEFT,
+ &m_aWheelSpeed[CARWHEEL_FRONT_LEFT],
+ &WheelState[CARWHEEL_FRONT_LEFT],
+ WHEEL_STATUS_OK);
+ }
+
+ if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] > 0.0f){
+ if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier))
+ fThrust = 0.0f;
+ else
+ fThrust = acceleration;
+
+ wheelFwd = GetForward();
+ wheelFwd -= DotProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].normal)*m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].normal;
+ wheelFwd.Normalise();
+ wheelRight = CrossProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].normal);
+ wheelRight.Normalise();
+ tmp = c*wheelFwd - s*wheelRight;
+ wheelRight = s*wheelFwd + c*wheelRight;
+ wheelFwd = tmp;
+
+ m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].surfaceA = SURFACE_WHEELBASE;
+ float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_FRONT_RIGHT])*traction;
+ if(GetStatus() == STATUS_PLAYER)
+ adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].surfaceB);
+ WheelState[CARWHEEL_FRONT_RIGHT] = m_aWheelState[CARWHEEL_FRONT_RIGHT];
+
+ if(Damage.GetWheelStatus(VEHWHEEL_FRONT_RIGHT) == WHEEL_STATUS_BURST)
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[CARWHEEL_FRONT_RIGHT], contactPoints[CARWHEEL_FRONT_RIGHT],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBiasFront,
+ adhesion*tractionBiasFront*Damage.m_fWheelDamageEffect,
+ CARWHEEL_FRONT_RIGHT,
+ &m_aWheelSpeed[CARWHEEL_FRONT_RIGHT],
+ &WheelState[CARWHEEL_FRONT_RIGHT],
+ WHEEL_STATUS_BURST);
+ else
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[CARWHEEL_FRONT_RIGHT], contactPoints[CARWHEEL_FRONT_RIGHT],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBiasFront,
+ adhesion*tractionBiasFront,
+ CARWHEEL_FRONT_RIGHT,
+ &m_aWheelSpeed[CARWHEEL_FRONT_RIGHT],
+ &WheelState[CARWHEEL_FRONT_RIGHT],
+ WHEEL_STATUS_OK);
+ }
+ }
+
+ // Process front wheels off ground
+
+ if(!IsRealHeli()){
+ if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] <= 0.0f){
+ if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_LEFT] *= 0.95f;
+ else{
+ if(acceleration > 0.0f){
+ if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] < 2.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_LEFT] -= 0.2f;
+ }else{
+ if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] > -2.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_LEFT] += 0.1f;
+ }
}
+ m_aWheelRotation[CARWHEEL_FRONT_LEFT] += m_aWheelSpeed[CARWHEEL_FRONT_LEFT];
}
- m_aWheelRotation[CARWHEEL_REAR_RIGHT] += m_aWheelSpeed[CARWHEEL_REAR_RIGHT];
+ if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] <= 0.0f){
+ if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] *= 0.95f;
+ else{
+ if(acceleration > 0.0f){
+ if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] < 2.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] -= 0.2f;
+ }else{
+ if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] > -2.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] += 0.1f;
+ }
+ }
+ m_aWheelRotation[CARWHEEL_FRONT_RIGHT] += m_aWheelSpeed[CARWHEEL_FRONT_RIGHT];
+ }
+ }
}
for(i = 0; i < 4; i++){
float wheelPos = colModel->lines[i].p0.z;
if(m_aSuspensionSpringRatio[i] > 0.0f)
wheelPos -= m_aSuspensionSpringRatio[i]*m_aSuspensionSpringLength[i];
- m_aWheelPosition[i] += (wheelPos - m_aWheelPosition[i])*0.75f;
+ if(GetModelIndex() == MI_VOODOO && bUsingSpecialColModel)
+ m_aWheelPosition[i] = wheelPos;
+ else
+ m_aWheelPosition[i] += (wheelPos - m_aWheelPosition[i])*0.75f;
}
for(i = 0; i < 4; i++)
m_aWheelState[i] = WheelState[i];
+ if(m_fGasPedal < 0.0f){
+ if(m_aWheelState[CARWHEEL_REAR_LEFT] == WHEEL_STATE_SPINNING)
+ m_aWheelState[CARWHEEL_REAR_LEFT] = WHEEL_STATE_NORMAL;
+ if(m_aWheelState[CARWHEEL_REAR_RIGHT] == WHEEL_STATE_SPINNING)
+ m_aWheelState[CARWHEEL_REAR_RIGHT] = WHEEL_STATE_NORMAL;
+ }
// Process horn
if(GetStatus() != STATUS_PLAYER){
- ReduceHornCounter();
+ if(!IsAlarmOn())
+ ReduceHornCounter();
}else{
- if(GetModelIndex() == MI_MRWHOOP){
- if(Pads[0].bHornHistory[Pads[0].iCurrHornHistory] &&
- !Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % 5]){
- m_bSirenOrAlarm = !m_bSirenOrAlarm;
- printf("m_bSirenOrAlarm toggled to %d\n", m_bSirenOrAlarm);
- }
- }else if(UsesSiren(GetModelIndex())){
+ if(UsesSiren(GetModelIndex())){
if(Pads[0].bHornHistory[Pads[0].iCurrHornHistory]){
if(Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % 5] &&
Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+3) % 5])
@@ -976,44 +1364,126 @@ CAutomobile::ProcessControl(void)
m_bSirenOrAlarm = !m_bSirenOrAlarm;
}else
m_nCarHornTimer = 0;
- }else if(GetModelIndex() != MI_VOODOO && !CVehicle::bCheat3){
- if(Pads[0].GetHorn())
- m_nCarHornTimer = 1;
- else
- m_nCarHornTimer = 0;
+ }else if(GetModelIndex() != MI_VOODOO && !CVehicle::bCheat3 && !carHasNitro){
+ if(!IsAlarmOn()){
+ if(Pads[0].GetHorn())
+ m_nCarHornTimer = 1;
+ else
+ m_nCarHornTimer = 0;
+ }
}
}
// Flying
+ bool foo = false;
if(GetStatus() != STATUS_PLAYER && GetStatus() != STATUS_PLAYER_REMOTE && GetStatus() != STATUS_PHYSICS){
- if(GetModelIndex() == MI_RCRAIDER || GetModelIndex() == MI_SPARROW)
- m_aWheelSpeed[0] = Max(m_aWheelSpeed[0]-0.0005f, 0.0f);
+ if(IsRealHeli()){
+ bEngineOn = false;
+ m_aWheelSpeed[1] = Max(m_aWheelSpeed[1]-0.0005f, 0.0f);
+ if(GetModelIndex() != MI_RCRAIDER && GetModelIndex() != MI_RCGOBLIN)
+ if(m_aWheelSpeed[1] < 0.154f && m_aWheelSpeed[1] > 0.0044f)
+ foo = true;
+ }
}else if((GetModelIndex() == MI_DODO || CVehicle::bAllDodosCheat) &&
m_vecMoveSpeed.Magnitude() > 0.0f && CTimer::GetTimeStep() > 0.0f){
#ifdef ALT_DODO_CHEAT
if (bAltDodoCheat)
- FlyingControl(FLIGHT_MODEL_SEAPLANE);
+ FlyingControl(FLIGHT_MODEL_PLANE);
else
#endif
+ if(GetModelIndex() == MI_DODO)
FlyingControl(FLIGHT_MODEL_DODO);
+ else
+ FlyingControl(FLIGHT_MODEL_PLANE);
}else if(GetModelIndex() == MI_RCBARON){
FlyingControl(FLIGHT_MODEL_RCPLANE);
}else if(IsRealHeli() || bAllCarCheat){
-#ifdef ALLCARSHELI_CHEAT
- if (bAllCarCheat)
- FlyingControl(FLIGHT_MODEL_HELI);
- else
-#endif
- {
- // if (CPad::GetPad(0)->GetCircleJustDown())
- // m_aWheelSpeed[0] = Max(m_aWheelSpeed[0] - 0.03f, 0.0f);
- // if (m_aWheelSpeed[0] < 0.22f)
- // m_aWheelSpeed[0] += 0.0001f;
- // if (m_aWheelSpeed[0] > 0.15f)
+ // Speed up rotor
+ if(m_aWheelSpeed[1] < 0.22f && !bIsInWater){
+ if(GetModelIndex() == MI_RCRAIDER || GetModelIndex() == MI_RCGOBLIN)
+ m_aWheelSpeed[1] += 0.003f;
+ else
+ m_aWheelSpeed[1] += 0.001f;
+ }
+
+ // Fly
+ if(m_aWheelSpeed[1] > 0.15f){
+ if(GetModelIndex() == MI_RCRAIDER || GetModelIndex() == MI_RCGOBLIN)
+ FlyingControl(FLIGHT_MODEL_RCHELI);
+ else if(m_nWheelsOnGround < 4 && !(GetModelIndex() == MI_SEASPAR && bTouchingWater) ||
+ CPad::GetPad(0)->GetAccelerate() != 0 || CPad::GetPad(0)->GetCarGunUpDown() > 1.0f ||
+ Abs(m_vecMoveSpeed.x) > 0.02f ||
+ Abs(m_vecMoveSpeed.y) > 0.02f ||
+ Abs(m_vecMoveSpeed.z) > 0.02f)
FlyingControl(FLIGHT_MODEL_HELI);
}
+
+ // Blade collision
+ if(m_aWheelSpeed[1] > 0.015f && m_aCarNodes[CAR_BONNET]){
+ CMatrix mat;
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BONNET]));
+ if(GetModelIndex() == MI_RCRAIDER || GetModelIndex() == MI_RCGOBLIN)
+ DoBladeCollision(mat.GetPosition(), GetMatrix(), ROTOR_TOP, 0.72f, 0.9f);
+ else if(GetModelIndex() == MI_SPARROW || GetModelIndex() == MI_SEASPAR)
+ DoBladeCollision(mat.GetPosition(), GetMatrix(), ROTOR_TOP, 5.15f, 0.8f);
+ else if(GetModelIndex() == MI_HUNTER)
+ DoBladeCollision(mat.GetPosition(), GetMatrix(), ROTOR_TOP, 6.15f, 0.5f);
+ else
+ DoBladeCollision(mat.GetPosition(), GetMatrix(), ROTOR_TOP, 6.15f, 1.0f);
+ }
+
+ // Heli weapons
+ if(GetModelIndex() == MI_HUNTER && GetStatus() == STATUS_PLAYER){
+ // Hunter rockets
+ if(CPad::GetPad(0)->CarGunJustDown() && CTimer::GetTimeInMilliseconds() > m_nGunFiringTime+350){
+ CWeapon gun(WEAPONTYPE_ROCKETLAUNCHER, 100);
+ CVector source = vecHunterRocketPos;
+ source = GetMatrix()*source + Max(DotProduct(m_vecMoveSpeed, GetForward()), 0.0f)*GetForward()*CTimer::GetTimeStep();
+ gun.FireProjectile(this, &source, 0.0f);
+
+ source = vecHunterRocketPos;
+ source.x = -source.x;
+ source = GetMatrix()*source + Max(DotProduct(m_vecMoveSpeed, GetForward()), 0.0f)*GetForward()*CTimer::GetTimeStep();
+ gun.FireProjectile(this, &source, 0.0f);
+
+ CStats::RoundsFiredByPlayer++;
+//TODO(MIAMI):
+// DMAudio.PlayOneShot(m_audioEntityId, 55, 0.0f);
+ m_nGunFiringTime = CTimer::GetTimeInMilliseconds();
+ // Hunter gun
+ }else if(CPad::GetPad(0)->GetHandBrake() && CTimer::GetTimeInMilliseconds() > m_nGunFiringTime+60){
+ CWeapon gun(WEAPONTYPE_HELICANNON, 5000);
+ CVector source = vecHunterGunPos;
+ source = GetMatrix()*source + m_vecMoveSpeed*CTimer::GetTimeStep();
+ gun.FireInstantHit(this, &source);
+ gun.AddGunshell(this, source, CVector2D(0.0f, 0.1f), 0.025f);
+ CStats::RoundsFiredByPlayer++;
+//TODO(MIAMI):
+// DMAudio.PlayOneShot(m_audioEntityId, 55, 0.0f);
+ m_nGunFiringTime = CTimer::GetTimeInMilliseconds();
+ }
+ }else if(GetModelIndex() == MI_SEASPAR && GetStatus() == STATUS_PLAYER){
+ // Sea sparrow gun
+ if(CPad::GetPad(0)->GetHandBrake() && CTimer::GetTimeInMilliseconds() > m_nGunFiringTime+40){
+ CWeapon gun(WEAPONTYPE_M4, 5000);
+ CVector source = vecSeaSparrowGunPos;
+ source = GetMatrix()*source + m_vecMoveSpeed*CTimer::GetTimeStep();
+ gun.FireInstantHit(this, &source);
+ gun.AddGunshell(this, source, CVector2D(0.0f, 0.1f), 0.025f);
+ CStats::RoundsFiredByPlayer++;
+//TODO(MIAMI):
+// DMAudio.PlayOneShot(m_audioEntityId, 55, 0.0f);
+ m_nGunFiringTime = CTimer::GetTimeInMilliseconds();
+ }
+ }
+
+ if(GetModelIndex() != MI_RCRAIDER && GetModelIndex() != MI_RCGOBLIN)
+ if(m_aWheelSpeed[1] < 0.154f && m_aWheelSpeed[1] > 0.0044f)
+ foo = true;
}
+
+//TODO(MIAMI): propeller stuff
}
@@ -1054,7 +1524,7 @@ CAutomobile::ProcessControl(void)
CParticle::AddParticle(PARTICLE_CARFLAME, damagePos,
CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(0.01125f, 0.09f)),
- nil, 0.9f);
+ nil, 0.63f);
CVector coors = damagePos;
coors.x += CGeneral::GetRandomNumberInRange(-0.5625f, 0.5625f),
@@ -1089,9 +1559,11 @@ CAutomobile::ProcessControl(void)
float suspShake = 0.0f;
float surfShake = 0.0f;
+ float speedsq = m_vecMoveSpeed.MagnitudeSqr();
for(i = 0; i < 4; i++){
float suspChange = m_aSuspensionSpringRatioPrev[i] - m_aSuspensionSpringRatio[i];
- if(suspChange > 0.3f){
+ if(suspChange > 0.3f && !drivingInSand && speedsq > 0.04f){
+//TODO(MIAMI): depends on wheel status
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_JUMP, suspChange);
if(suspChange > suspShake)
suspShake = suspChange;
@@ -1101,7 +1573,7 @@ CAutomobile::ProcessControl(void)
if(surf == SURFACE_GRAVEL || surf == SURFACE_WATER || surf == SURFACE_HEDGE){
if(surfShake < 0.2f)
surfShake = 0.3f;
- }else if(surf == SURFACE_MUD_DRY || surf == SURFACE_SAND){
+ }else if(surf == SURFACE_MUD_DRY){
if(surfShake < 0.1f)
surfShake = 0.2f;
}else if(surf == SURFACE_GRASS){
@@ -1109,13 +1581,17 @@ CAutomobile::ProcessControl(void)
surfShake = 0.1f;
}
+ if(this == FindPlayerVehicle())
+// BUG: this only observes one of the wheels
+ TheCamera.m_bVehicleSuspenHigh = suspChange > 0.05f;
+
m_aSuspensionSpringRatioPrev[i] = m_aSuspensionSpringRatio[i];
m_aSuspensionSpringRatio[i] = 1.0f;
}
// Shake pad
- if((suspShake > 0.0f || surfShake > 0.0f) && GetStatus() == STATUS_PLAYER){
+ if(!drivingInSand && (suspShake > 0.0f || surfShake > 0.0f) && GetStatus() == STATUS_PLAYER){
float speed = m_vecMoveSpeed.MagnitudeSqr();
if(speed > sq(0.1f)){
speed = Sqrt(speed);
@@ -1123,15 +1599,16 @@ CAutomobile::ProcessControl(void)
uint8 freq = Min(200.0f*suspShake*speed*2000.0f/m_fMass + 100.0f, 250.0f);
CPad::GetPad(0)->StartShake(20000.0f*CTimer::GetTimeStep()/freq, freq);
}else{
- uint8 freq = Min(200.0f*surfShake*speed*2000.0f/m_fMass + 40.0f, 145.0f);
+ uint8 freq = Min(200.0f*surfShake*speed*2000.0f/m_fMass + 40.0f, 150.0f);
CPad::GetPad(0)->StartShake(5000.0f*CTimer::GetTimeStep()/freq, freq);
}
}
}
bVehicleColProcessed = false;
+ bAudioChangingGear = false;
- if(!bWarnedPeds)
+ if(!bWarnedPeds && GetVehicleAppearance() != VEHICLE_APPEARANCE_HELI && GetVehicleAppearance() != VEHICLE_APPEARANCE_PLANE)
CCarCtrl::ScanForPedDanger(this);
@@ -1139,20 +1616,20 @@ CAutomobile::ProcessControl(void)
// TODO: make the numbers defines
float heading;
- if(GetPosition().x > 1900.0f){
+ if(GetPosition().x > 1950.0f-400.0f){
if(m_vecMoveSpeed.x > 0.0f)
m_vecMoveSpeed.x *= -1.0f;
heading = GetForward().Heading();
if(heading > 0.0f) // going west
SetHeading(-heading);
- }else if(GetPosition().x < -1900.0f){
+ }else if(GetPosition().x < -1950.0f-400.0f){
if(m_vecMoveSpeed.x < 0.0f)
m_vecMoveSpeed.x *= -1.0f;
heading = GetForward().Heading();
if(heading < 0.0f) // going east
SetHeading(-heading);
}
- if(GetPosition().y > 1900.0f){
+ if(GetPosition().y > 1950.0f){
if(m_vecMoveSpeed.y > 0.0f)
m_vecMoveSpeed.y *= -1.0f;
heading = GetForward().Heading();
@@ -1160,7 +1637,7 @@ CAutomobile::ProcessControl(void)
SetHeading(PI-heading);
else if(heading > -HALFPI && heading < 0.0f)
SetHeading(-PI-heading);
- }else if(GetPosition().y < -1900.0f){
+ }else if(GetPosition().y < -1950.0f){
if(m_vecMoveSpeed.y < 0.0f)
m_vecMoveSpeed.y *= -1.0f;
heading = GetForward().Heading();
@@ -1179,11 +1656,31 @@ CAutomobile::ProcessControl(void)
(m_fGasPedal == 0.0f && brake == 0.0f || GetStatus() == STATUS_WRECKED)){
if(Abs(m_vecMoveSpeed.x) < 0.005f &&
Abs(m_vecMoveSpeed.y) < 0.005f &&
- Abs(m_vecMoveSpeed.z) < 0.005f){
+ Abs(m_vecMoveSpeed.z) < 0.005f &&
+ !(m_fDamageImpulse > 0.0f && m_pDamageEntity == FindPlayerPed()) &&
+ (m_aSuspensionSpringRatioPrev[0] < 1.0f && m_aSuspensionSpringRatioPrev[1] < 1.0f &&
+ m_aSuspensionSpringRatioPrev[2] < 1.0f && m_aSuspensionSpringRatioPrev[3] < 1.0f)){
m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
m_vecTurnSpeed.z = 0.0f;
}
}
+
+ if(IsRealHeli() && bHeliDestroyed && !bRenderScorched){
+ ApplyMoveForce(0.0f, 0.0f, -2.0f*CTimer::GetTimeStep());
+ m_vecTurnSpeed.z += -0.002f*CTimer::GetTimeStep();
+ m_vecTurnSpeed.x += -0.0002f*CTimer::GetTimeStep();
+
+ RwRGBA col = { 84, 84, 84, 255 };
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE, GetMatrix()*CVector(0.0f, 0.0f, -10.0f),
+ CVector(0.0f, 0.0f, 0.0f), nil, 0.7f, col, 0, 0, 0, 3000);
+
+ if(CWorld::TestSphereAgainstWorld(GetPosition(), 10.0f, this, true, false, false, false, false, false) ||
+ GetPosition().z < 6.0f)
+ if(!bRenderScorched){ // we already know this is true...
+ CExplosion::AddExplosion(this, nil, EXPLOSION_CAR, GetPosition(), 0);
+ bRenderScorched = true;
+ }
+ }
}
void
@@ -1207,6 +1704,17 @@ CAutomobile::PreRender(void)
int i, j, n;
CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+ if(GetModelIndex() == MI_RHINO && m_aCarNodes[CAR_BONNET]){
+ // Rotate Rhino turret
+ CMatrix m;
+ CVector p;
+ m.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BONNET]));
+ p = m.GetPosition();
+ m.SetRotateZ(m_fCarGunLR);
+ m.Translate(p);
+ m.UpdateRW();
+ }
+
if(GetModelIndex() == MI_RCBANDIT){
CVector pos = GetMatrix() * CVector(0.218f, -0.444f, 0.391f);
CAntennas::RegisterOne((uintptr)this, GetUp(), pos, 1.0f);
@@ -1217,7 +1725,7 @@ CAutomobile::PreRender(void)
// Wheel particles
- if(GetModelIndex() == MI_DODO){
+ if(GetModelIndex() == MI_DODO || GetVehicleAppearance() != VEHICLE_APPEARANCE_CAR){
; // nothing
}else if(GetModelIndex() == MI_RCBANDIT){
for(i = 0; i < 4; i++){
@@ -1265,13 +1773,14 @@ CAutomobile::PreRender(void)
int drawParticles = Abs(fwdSpeed) < 90.0f;
if(GetStatus() == STATUS_SIMPLE || GetStatus() == STATUS_PHYSICS ||
- GetStatus() == STATUS_PLAYER || GetStatus() == STATUS_PLAYER_PLAYBACKFROMBUFFER){
+ GetStatus() == STATUS_PLAYER || GetStatus() == STATUS_PLAYER_PLAYBACKFROMBUFFER){
bool rearSkidding = false;
if(m_aWheelState[CARWHEEL_REAR_LEFT] == WHEEL_STATE_SKIDDING ||
m_aWheelState[CARWHEEL_REAR_RIGHT] == WHEEL_STATE_SKIDDING)
rearSkidding = true;
for(i = 0; i < 4; i++){
+ if(m_aSuspensionSpringRatioPrev[i] < 1.0f && m_aWheelColPoints[i].surfaceB != SURFACE_WATER)
switch(m_aWheelState[i]){
case WHEEL_STATE_SPINNING:
if(AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles)){
@@ -1291,46 +1800,79 @@ CAutomobile::PreRender(void)
if(m_aWheelTimer[i] > 0.0f)
CSkidmarks::RegisterOne((uintptr)this + i, m_aWheelColPoints[i].point,
GetForward().x, GetForward().y,
- &m_aWheelSkidmarkMuddy[i], &m_aWheelSkidmarkBloody[i]);
+ m_aWheelSkidmarkType[i], &m_aWheelSkidmarkBloody[i]);
break;
case WHEEL_STATE_SKIDDING:
if(i == CARWHEEL_REAR_LEFT || i == CARWHEEL_REAR_RIGHT || rearSkidding){
// same as below
- AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles);
+ if(Abs(fwdSpeed) > 5.0f){
+ AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles);
- CParticle::AddParticle(PARTICLE_RUBBER_SMOKE,
- m_aWheelColPoints[i].point + CVector(0.0f, 0.0f, 0.25f),
- CVector(0.0f, 0.0f, 0.0f));
+ CParticle::AddParticle(PARTICLE_RUBBER_SMOKE,
+ m_aWheelColPoints[i].point + CVector(0.0f, 0.0f, 0.25f),
+ CVector(0.0f, 0.0f, 0.0f));
+ }
if(m_aWheelTimer[i] > 0.0f)
CSkidmarks::RegisterOne((uintptr)this + i, m_aWheelColPoints[i].point,
GetForward().x, GetForward().y,
- &m_aWheelSkidmarkMuddy[i], &m_aWheelSkidmarkBloody[i]);
+ m_aWheelSkidmarkType[i], &m_aWheelSkidmarkBloody[i]);
}
break;
case WHEEL_STATE_FIXED:
- AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles);
+ if(Abs(fwdSpeed) > 5.0f){
+ AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles);
- CParticle::AddParticle(PARTICLE_RUBBER_SMOKE,
- m_aWheelColPoints[i].point + CVector(0.0f, 0.0f, 0.25f),
- CVector(0.0f, 0.0f, 0.0f));
+ CParticle::AddParticle(PARTICLE_RUBBER_SMOKE,
+ m_aWheelColPoints[i].point + CVector(0.0f, 0.0f, 0.25f),
+ CVector(0.0f, 0.0f, 0.0f));
+ }
if(m_aWheelTimer[i] > 0.0f)
CSkidmarks::RegisterOne((uintptr)this + i, m_aWheelColPoints[i].point,
GetForward().x, GetForward().y,
- &m_aWheelSkidmarkMuddy[i], &m_aWheelSkidmarkBloody[i]);
+ m_aWheelSkidmarkType[i], &m_aWheelSkidmarkBloody[i]);
break;
default:
if(Abs(fwdSpeed) > 0.5f)
AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles);
- if(m_aWheelSkidmarkBloody[i] && m_aWheelTimer[i] > 0.0f)
+ if((m_aWheelSkidmarkBloody[i] || m_aWheelSkidmarkUnk[i]) && m_aWheelTimer[i] > 0.0f)
CSkidmarks::RegisterOne((uintptr)this + i, m_aWheelColPoints[i].point,
GetForward().x, GetForward().y,
- &m_aWheelSkidmarkMuddy[i], &m_aWheelSkidmarkBloody[i]);
+ m_aWheelSkidmarkType[i], &m_aWheelSkidmarkBloody[i]);
+ }
+
+ // Sparks for friction of burst wheels
+ if(Damage.GetWheelStatus(i) == WHEEL_STATUS_BURST && m_aSuspensionSpringRatioPrev[i] < 1.0f){
+ static float speedSq;
+ speedSq = m_vecMoveSpeed.MagnitudeSqr();
+ if(speedSq > 0.01f &&
+ m_aWheelColPoints[i].surfaceB != SURFACE_GRASS &&
+ m_aWheelColPoints[i].surfaceB != SURFACE_MUD_DRY &&
+ m_aWheelColPoints[i].surfaceB != SURFACE_SAND &&
+ m_aWheelColPoints[i].surfaceB != SURFACE_SAND_BEACH &&
+ m_aWheelColPoints[i].surfaceB != SURFACE_WATER){
+ CVector normalSpeed = m_aWheelColPoints[i].normal * DotProduct(m_aWheelColPoints[i].normal, m_vecMoveSpeed);
+ CVector frictionSpeed = m_vecMoveSpeed - normalSpeed;
+ if(i == CARWHEEL_FRONT_LEFT || i == CARWHEEL_REAR_LEFT)
+ frictionSpeed -= 0.05f*GetRight();
+ else
+ frictionSpeed += 0.05f*GetRight();
+ CVector unusedRight = 0.15f*GetRight();
+ CVector sparkDir = 0.25f*frictionSpeed;
+ CParticle::AddParticle(PARTICLE_SPARK_SMALL, m_aWheelColPoints[i].point, sparkDir);
+
+ if(speedSq > 0.04f)
+ CParticle::AddParticle(PARTICLE_SPARK_SMALL, m_aWheelColPoints[i].point, sparkDir);
+ if(speedSq > 0.16f){
+ CParticle::AddParticle(PARTICLE_SPARK_SMALL, m_aWheelColPoints[i].point, sparkDir);
+ CParticle::AddParticle(PARTICLE_SPARK_SMALL, m_aWheelColPoints[i].point, sparkDir);
+ }
+ }
}
}
}
@@ -1353,7 +1895,7 @@ CAutomobile::PreRender(void)
CSkidmarks::RegisterOne((uintptr)this + CARWHEEL_REAR_LEFT,
m_aWheelColPoints[CARWHEEL_REAR_LEFT].point + offset,
GetForward().x, GetForward().y,
- &m_aWheelSkidmarkMuddy[CARWHEEL_REAR_LEFT], &m_aWheelSkidmarkBloody[CARWHEEL_REAR_LEFT]);
+ m_aWheelSkidmarkType[CARWHEEL_REAR_LEFT], &m_aWheelSkidmarkBloody[CARWHEEL_REAR_LEFT]);
break;
default: break;
}
@@ -1371,7 +1913,7 @@ CAutomobile::PreRender(void)
CSkidmarks::RegisterOne((uintptr)this + CARWHEEL_REAR_RIGHT,
m_aWheelColPoints[CARWHEEL_REAR_RIGHT].point + offset,
GetForward().x, GetForward().y,
- &m_aWheelSkidmarkMuddy[CARWHEEL_REAR_RIGHT], &m_aWheelSkidmarkBloody[CARWHEEL_REAR_RIGHT]);
+ m_aWheelSkidmarkType[CARWHEEL_REAR_RIGHT], &m_aWheelSkidmarkBloody[CARWHEEL_REAR_RIGHT]);
break;
default: break;
}
@@ -1397,7 +1939,7 @@ CAutomobile::PreRender(void)
n = 6.0f*CWeather::Rain;
for(j = 0; j <= n; j++)
CParticle::AddParticle(PARTICLE_RAIN_SPLASHUP,
- c + CVector(CGeneral::GetRandomNumberInRange(-.04f, 0.4f), CGeneral::GetRandomNumberInRange(-.04f, 0.4f), 0.0f),
+ c + CVector(CGeneral::GetRandomNumberInRange(-0.4f, 0.4f), CGeneral::GetRandomNumberInRange(-0.4f, 0.4f), 0.0f),
CVector(0.0f, 0.0f, 0.0f),
nil, 0.0f, 0, 0, CGeneral::GetRandomNumber() & 1);
}
@@ -1406,21 +1948,22 @@ CAutomobile::PreRender(void)
AddDamagedVehicleParticles();
// Exhaust smoke
- if(bEngineOn && fwdSpeed < 90.0f){
+ if(bEngineOn && !(pHandling->Flags & HANDLING_NO_EXHAUST) && fwdSpeed < 130.0f){
CVector exhaustPos = mi->m_positions[CAR_POS_EXHAUST];
- CVector pos1, pos2, dir;
+ CVector pos1, pos2, dir1, dir2;
if(exhaustPos != CVector(0.0f, 0.0f, 0.0f)){
- dir.z = 0.0f;
+ dir1.z = 0.0f;
+ dir2.z = 0.0f;
if(fwdSpeed < 10.0f){
CVector steerFwd(-Sin(m_fSteerAngle), Cos(m_fSteerAngle), 0.0f);
steerFwd = Multiply3x3(GetMatrix(), steerFwd);
float r = CGeneral::GetRandomNumberInRange(-0.06f, -0.03f);
- dir.x = steerFwd.x * r;
- dir.y = steerFwd.y * r;
+ dir1.x = steerFwd.x * r;
+ dir1.y = steerFwd.y * r;
}else{
- dir.x = m_vecMoveSpeed.x;
- dir.y = m_vecMoveSpeed.y;
+ dir1.x = m_vecMoveSpeed.x;
+ dir1.y = m_vecMoveSpeed.y;
}
bool dblExhaust = false;
@@ -1430,17 +1973,62 @@ CAutomobile::PreRender(void)
pos2 = exhaustPos;
pos2.x = -pos2.x;
pos2 = GetMatrix() * pos2;
+ dir2 = dir1;
}
- n = 4.0f*m_fGasPedal;
- if(dblExhaust)
- for(i = 0; i <= n; i++){
- CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos1, dir);
- CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos2, dir);
+ static float fumesLimit = 2.0f;
+ if(CGeneral::GetRandomNumberInRange(1.0f, 3.0f)*(m_fGasPedal+1.1f) > fumesLimit)
+ for(i = 0; i < 4;){
+ CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos1, dir1);
+ if(pHandling->Flags & HANDLING_DBL_EXHAUST)
+ CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos2, dir2);
+
+ static float extraFumesLimit = 0.5f;
+ if(m_fGasPedal > extraFumesLimit && m_nCurrentGear < 3){
+ if(CGeneral::GetRandomNumber() & 1)
+ CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos1, dir1);
+ else if(pHandling->Flags & HANDLING_DBL_EXHAUST)
+ CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos2, dir2);
+ }
+
+ // Fire on Cuban hermes
+ if(GetModelIndex() == MI_CUBAN && i == 1 && m_fGasPedal > 0.9f){
+ if(m_nCurrentGear == 1 || m_nCurrentGear == 3 && (CTimer::GetTimeInMilliseconds()%1500) > 750){
+ if(CGeneral::GetRandomNumber() & 1){
+ CParticle::AddParticle(PARTICLE_FIREBALL, pos1, dir1, nil, 0.05f, 0, 0, 2, 200);
+ CParticle::AddParticle(PARTICLE_FIREBALL, pos1, dir1, nil, 0.05f, 0, 0, 2, 200);
+ }else{
+ CParticle::AddParticle(PARTICLE_FIREBALL, pos2, dir2, nil, 0.05f, 0, 0, 2, 200);
+ CParticle::AddParticle(PARTICLE_FIREBALL, pos2, dir2, nil, 0.05f, 0, 0, 2, 200);
+ }
+ }
+ }
+
+ if(GetStatus() == STATUS_PLAYER && (CTimer::GetFrameCounter()&3) == 0 &&
+ CWeather::Rain == 0.0f && i == 0){
+ CVector camDist = GetPosition() - TheCamera.GetPosition();
+ if(DotProduct(GetForward(), camDist) > 0.0f ||
+ TheCamera.GetLookDirection() == LOOKING_LEFT ||
+ TheCamera.GetLookDirection() == LOOKING_RIGHT){
+ CParticle::AddParticle(PARTICLE_HEATHAZE, pos1, CVector(0.0f, 0.0f, 0.0f));
+ if(pHandling->Flags & HANDLING_DBL_EXHAUST)
+ CParticle::AddParticle(PARTICLE_HEATHAZE, pos2, CVector(0.0f, 0.0f, 0.0f));
+
+ CParticle::AddParticle(PARTICLE_HEATHAZE, pos1, CVector(0.0f, 0.0f, 0.0f));
+ if(pHandling->Flags & HANDLING_DBL_EXHAUST)
+ CParticle::AddParticle(PARTICLE_HEATHAZE, pos2, CVector(0.0f, 0.0f, 0.0f));
+ }
+ }
+
+ if(GetModelIndex() == MI_CUBAN && i < 1){
+ i = 1;
+ pos1 = GetMatrix() * CVector(1.134f, -1.276f, -0.56f);
+ pos2 = GetMatrix() * CVector(-1.134f, -1.276f, -0.56f);
+ dir1 += 0.05f*GetRight();
+ dir2 -= 0.05f*GetRight();
+ }else
+ i = 99;
}
- else
- for(i = 0; i <= n; i++)
- CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos1, dir);
}
}
@@ -1512,8 +2100,8 @@ CAutomobile::PreRender(void)
float angle = (CTimer::GetTimeInMilliseconds() & 0x3FF)*TWOPI/0x3FF;
float s = 8.0f*Sin(angle);
float c = 8.0f*Cos(angle);
- CShadows::StoreCarLightShadow(this, (uintptr)this + 21, gpShadowHeadLightsTex,
- &pos, c, s, s, -c, r, g, b, 8.0f);
+ //CShadows::StoreCarLightShadow(this, (uintptr)this + 21, gpShadowHeadLightsTex,
+ // &pos, c, s, s, -c, r, g, b, 8.0f);
CPointLights::AddLight(CPointLights::LIGHT_POINT,
pos + GetUp()*2.0f, CVector(0.0f, 0.0f, 0.0f), 12.0f,
@@ -1551,17 +2139,26 @@ CAutomobile::PreRender(void)
}
break;
- case MI_FBICAR:
+ case MI_FBIRANCH:
+ case MI_VICECHEE:
if(m_bSirenOrAlarm){
CVector pos = GetMatrix() * CVector(0.4f, 0.6f, 0.3f);
if(CTimer::GetTimeInMilliseconds() & 0x100 &&
DotProduct(GetForward(), GetPosition() - TheCamera.GetPosition()) < 0.0f)
- CCoronas::RegisterCorona((uintptr)this + 21,
- 0, 0, 255, 255,
- pos, 0.4f, 50.0f,
- CCoronas::TYPE_STAR,
- CCoronas::FLARE_NONE,
- CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+ if(GetModelIndex() == MI_VICECHEE)
+ CCoronas::RegisterCorona((uintptr)this + 21,
+ 255, 70, 70, 255,
+ pos, 0.4f, 50.0f,
+ CCoronas::TYPE_STAR,
+ CCoronas::FLARE_NONE,
+ CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+ else
+ CCoronas::RegisterCorona((uintptr)this + 21,
+ 0, 0, 255, 255,
+ pos, 0.4f, 50.0f,
+ CCoronas::TYPE_STAR,
+ CCoronas::FLARE_NONE,
+ CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
else
CCoronas::UpdateCoronaCoors((uintptr)this + 21, pos, 50.0f, 0.0f);
}
@@ -1586,11 +2183,10 @@ CAutomobile::PreRender(void)
break;
}
- if(GetModelIndex() == MI_RCBANDIT || GetModelIndex() == MI_DODO ||
- GetModelIndex() == MI_RHINO) {
- CShadows::StoreShadowForCar(this);
- return;
- }
+ if(GetModelIndex() != MI_RCBANDIT && GetModelIndex() != MI_DODO &&
+ GetModelIndex() != MI_RHINO && GetModelIndex() != MI_RCBARON &&
+ GetVehicleAppearance() != VEHICLE_APPEARANCE_HELI) {
+ // Process lights
// Turn lights on/off
bool shouldLightsBeOn =
@@ -1628,7 +2224,6 @@ CAutomobile::PreRender(void)
lookVector = CVector(1.0f, 0.0f, 0.0f);
// 1.0 if directly behind car, -1.0 if in front
- // BUG on PC: Abs of DotProduct is taken
float behindness = DotProduct(lookVector, GetForward());
behindness = clamp(behindness, -1.0f, 1.0f); // shouldn't be necessary
// 0.0 if behind car, PI if in front
@@ -1643,7 +2238,8 @@ CAutomobile::PreRender(void)
lightL -= GetRight()*2.0f*headLightPos.x;
// Headlight coronas
- if(behindness < 0.0f){
+ if(DotProduct(lightR-TheCamera.GetPosition(), GetForward()) < 0.0f &&
+ (TheCamera.Cams[TheCamera.ActiveCam].Mode != CCam::MODE_1STPERSON || this != FindPlayerVehicle())){
// In front of car
float intensity = -0.5f*behindness + 0.3f;
float size = 1.0f - behindness;
@@ -1733,7 +2329,7 @@ CAutomobile::PreRender(void)
lightL -= GetRight()*2.0f*tailLightPos.x;
// Taillight coronas
- if(behindness > 0.0f){
+ if(DotProduct(lightR-TheCamera.GetPosition(), GetForward()) > 0.0f){
// Behind car
float intensity = 0.4f*behindness + 0.4f;
float size = (behindness + 1.0f)/2.0f;
@@ -1807,7 +2403,7 @@ CAutomobile::PreRender(void)
if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK ||
Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK)
CShadows::StoreCarLightShadow(this, (uintptr)this + 22, gpShadowHeadLightsTex, &pos,
- 7.0f*fwd.x, 7.0f*fwd.y, 7.0f*fwd.y, -7.0f*fwd.x, 45, 45, 45, 7.0f);
+ 7.0f*fwd.x, 7.0f*fwd.y, 5.5f*fwd.y, -5.5f*fwd.x, 45, 45, 45, 7.0f);
f = (tailLightPos.y - 2.5f) - (headLightPos.y + 6.0f);
pos += CVector(f*fwd.x, f*fwd.y, 0.0f);
@@ -1837,14 +2433,9 @@ CAutomobile::PreRender(void)
CPointLights::FOG_NONE, false);
}
}
- }else{
+ }else if(GetStatus() != STATUS_ABANDONED && GetStatus() != STATUS_WRECKED){
// Lights off
- if(GetStatus() == STATUS_ABANDONED || GetStatus() == STATUS_WRECKED) {
- CShadows::StoreShadowForCar(this);
- return;
- }
-
CVector lightPos = mi->m_positions[CAR_POS_TAILLIGHTS];
CVector lightR = GetMatrix() * lightPos;
CVector lightL = lightR;
@@ -1901,29 +2492,42 @@ CAutomobile::PreRender(void)
CCoronas::UpdateCoronaCoors((uintptr)this + 3, lightR, 50.0f*TheCamera.LODDistMultiplier, 0.0f);
}
}
+ // end of lights
+ }
+//TODO(MIAMI): StoreShadowForVehicle once we have it
CShadows::StoreShadowForCar(this);
DoSunGlare();
-}
-void
-CAutomobile::Render(void)
-{
- int i;
+ // Heli dust
+ if(IsRealHeli() && m_aWheelSpeed[1] > 0.1125f && GetPosition().z < 30.0f){
+ bool foundGround = false;
+ float waterZ = -1000.0f;
+ float groundZ = CWorld::FindGroundZFor3DCoord(GetPosition().x, GetPosition().y, GetPosition().z, &foundGround);
+ if(!CWaterLevel::GetWaterLevel(GetPosition(), &waterZ, false))
+ waterZ = 0.0f;
+ groundZ = Max(groundZ, waterZ);
+ float rnd = (m_aWheelSpeed[1]-0.1125f)*((int)Max(16.0f-4.0f*CTimer::GetTimeStep(),2.0f))*400.0f/43.0f;
+ float radius = 10.0f;
+ if(GetModelIndex() == MI_RCGOBLIN || GetModelIndex() == MI_RCRAIDER)
+ radius = 3.0f;
+ if(GetPosition().z - groundZ < radius)
+ HeliDustGenerate(this, radius-(GetPosition().z - groundZ), groundZ, ceilf(rnd));
+ }
+
CMatrix mat;
CVector pos;
- CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
- if(GetModelIndex() == MI_RHINO && m_aCarNodes[CAR_BONNET]){
- // Rotate Rhino turret
- CMatrix m;
- CVector p;
- m.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BONNET]));
- p = m.GetPosition();
- m.SetRotateZ(m_fCarGunLR);
- m.Translate(p);
- m.UpdateRW();
+ bool onlyFrontWheels = false;
+ if(IsRealHeli()){
+ // top rotor
+ m_aWheelRotation[1] += m_aWheelSpeed[1]*CTimer::GetTimeStep();
+ if(m_aWheelRotation[1] > TWOPI) m_aWheelRotation[1] -= TWOPI;
+ // rear rotor
+ m_aWheelRotation[3] += m_aWheelSpeed[1]*CTimer::GetTimeStep();
+ if(m_aWheelRotation[3] > TWOPI) m_aWheelRotation[3] -= TWOPI;
+ onlyFrontWheels = true;
}
CVector contactPoints[4]; // relative to model
@@ -1931,7 +2535,7 @@ CAutomobile::Render(void)
CVector frontWheelFwd = Multiply3x3(GetMatrix(), CVector(-Sin(m_fSteerAngle), Cos(m_fSteerAngle), 0.0f));
CVector rearWheelFwd = GetForward();
for(i = 0; i < 4; i++){
- if (m_aWheelTimer[i] > 0.0f) {
+ if (m_aWheelTimer[i] > 0.0f && (!onlyFrontWheels || i == CARWHEEL_FRONT_LEFT || i == CARWHEEL_FRONT_RIGHT)) {
contactPoints[i] = m_aWheelColPoints[i].point - GetPosition();
contactSpeeds[i] = GetSpeed(contactPoints[i]);
if (i == CARWHEEL_FRONT_LEFT || i == CARWHEEL_FRONT_RIGHT)
@@ -1942,75 +2546,146 @@ CAutomobile::Render(void)
}
}
+ RwRGBA hoverParticleCol = { 255, 255, 255, 32 };
+
// Rear right wheel
mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RB]));
- pos.x = mat.GetPosition().x;
- pos.y = mat.GetPosition().y;
+ pos = mat.GetPosition();
pos.z = m_aWheelPosition[CARWHEEL_REAR_RIGHT];
if(Damage.GetWheelStatus(CARWHEEL_REAR_RIGHT) == WHEEL_STATUS_BURST)
mat.SetRotate(m_aWheelRotation[CARWHEEL_REAR_RIGHT], 0.0f, 0.3f*Sin(m_aWheelRotation[CARWHEEL_REAR_RIGHT]));
else
mat.SetRotateX(m_aWheelRotation[CARWHEEL_REAR_RIGHT]);
- mat.Scale(mi->m_wheelScale);
+ if(GetStatus() == STATUS_PLAYER){
+ if(bHoverCheat && m_aSuspensionSpringRatioPrev[CARWHEEL_REAR_RIGHT] < 1.0f &&
+ m_aWheelColPoints[CARWHEEL_REAR_RIGHT].surfaceB == SURFACE_WATER){
+ // hovering on water
+ mat.RotateY(-HALFPI);
+ if((CTimer::GetFrameCounter()+CARWHEEL_REAR_RIGHT) & 1){
+ CParticle::AddParticle(PARTICLE_STEAM_NY_SLOWMOTION, m_aWheelColPoints[CARWHEEL_REAR_RIGHT].point,
+ 0.5f*m_vecMoveSpeed+0.1f*GetRight(), nil, 0.4f, hoverParticleCol);
+ }else{
+ CParticle::AddParticle(PARTICLE_CAR_SPLASH, m_aWheelColPoints[CARWHEEL_REAR_RIGHT].point,
+ 0.3f*m_vecMoveSpeed+0.15f*GetRight()+CVector(0.0f, 0.0f, 0.1f), nil, 0.15f, hoverParticleCol,
+ CGeneral::GetRandomNumberInRange(0.0f, 90.0f),
+ CGeneral::GetRandomNumberInRange(0.0f, 10.0f), 1);
+ }
+ }else{
+ // tilt wheel depending oh how much it presses on ground
+ float groundOffset = pos.z + m_fHeightAboveRoad - 0.5f*mi->m_wheelScale;
+ if(GetModelIndex() == MI_VOODOO)
+ groundOffset *= 0.6f;
+ mat.RotateY(Asin(clamp(-groundOffset, -1.0f, 1.0f)));
+ }
+ }
+ if(pHandling->Flags & HANDLING_FAT_REARW)
+ mat.Scale(1.15f*mi->m_wheelScale, mi->m_wheelScale, mi->m_wheelScale);
+ else
+ mat.Scale(mi->m_wheelScale);
mat.Translate(pos);
mat.UpdateRW();
- if(CVehicle::bWheelsOnlyCheat)
- RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RB]));
// Rear left wheel
mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LB]));
- pos.x = mat.GetPosition().x;
- pos.y = mat.GetPosition().y;
+ pos = mat.GetPosition();
pos.z = m_aWheelPosition[CARWHEEL_REAR_LEFT];
if(Damage.GetWheelStatus(CARWHEEL_REAR_LEFT) == WHEEL_STATUS_BURST)
- mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI+0.3f*Sin(-m_aWheelRotation[CARWHEEL_REAR_LEFT]));
+ mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI+0.3f*Sin(m_aWheelRotation[CARWHEEL_REAR_LEFT]));
else
mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI);
- mat.Scale(mi->m_wheelScale);
+ if(GetStatus() == STATUS_PLAYER){
+ if(bHoverCheat && m_aSuspensionSpringRatioPrev[CARWHEEL_REAR_LEFT] < 1.0f &&
+ m_aWheelColPoints[CARWHEEL_REAR_LEFT].surfaceB == SURFACE_WATER){
+ // hovering on water
+ mat.RotateY(HALFPI);
+ if((CTimer::GetFrameCounter()+CARWHEEL_REAR_LEFT) & 1){
+ CParticle::AddParticle(PARTICLE_STEAM_NY_SLOWMOTION, m_aWheelColPoints[CARWHEEL_REAR_LEFT].point,
+ 0.5f*m_vecMoveSpeed-0.1f*GetRight(), nil, 0.4f, hoverParticleCol);
+ }else{
+ CParticle::AddParticle(PARTICLE_CAR_SPLASH, m_aWheelColPoints[CARWHEEL_REAR_LEFT].point,
+ 0.3f*m_vecMoveSpeed-0.15f*GetRight()+CVector(0.0f, 0.0f, 0.1f), nil, 0.15f, hoverParticleCol,
+ CGeneral::GetRandomNumberInRange(0.0f, 90.0f),
+ CGeneral::GetRandomNumberInRange(0.0f, 10.0f), 1);
+ }
+ }else{
+ // tilt wheel depending oh how much it presses on ground
+ float groundOffset = pos.z + m_fHeightAboveRoad - 0.5f*mi->m_wheelScale;
+ if(GetModelIndex() == MI_VOODOO)
+ groundOffset *= 0.6f;
+ mat.RotateY(Asin(clamp(groundOffset, -1.0f, 1.0f)));
+ }
+ }
+ if(pHandling->Flags & HANDLING_FAT_REARW)
+ mat.Scale(1.15f*mi->m_wheelScale, mi->m_wheelScale, mi->m_wheelScale);
+ else
+ mat.Scale(mi->m_wheelScale);
mat.Translate(pos);
mat.UpdateRW();
- if(CVehicle::bWheelsOnlyCheat)
- RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LB]));
// Mid right wheel
if(m_aCarNodes[CAR_WHEEL_RM]){
mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RM]));
- pos.x = mat.GetPosition().x;
- pos.y = mat.GetPosition().y;
+ pos = mat.GetPosition();
pos.z = m_aWheelPosition[CARWHEEL_REAR_RIGHT];
if(Damage.GetWheelStatus(CARWHEEL_REAR_RIGHT) == WHEEL_STATUS_BURST)
mat.SetRotate(m_aWheelRotation[CARWHEEL_REAR_RIGHT], 0.0f, 0.3f*Sin(m_aWheelRotation[CARWHEEL_REAR_RIGHT]));
else
mat.SetRotateX(m_aWheelRotation[CARWHEEL_REAR_RIGHT]);
- mat.Scale(mi->m_wheelScale);
+ if(GetStatus() == STATUS_PLAYER){
+ if(bHoverCheat && m_aSuspensionSpringRatioPrev[CARWHEEL_REAR_RIGHT] < 1.0f &&
+ m_aWheelColPoints[CARWHEEL_REAR_RIGHT].surfaceB == SURFACE_WATER){
+ // hovering on water
+ mat.RotateY(-HALFPI);
+ }else{
+ // tilt wheel depending oh how much it presses on ground
+ float groundOffset = pos.z + m_fHeightAboveRoad - 0.5f*mi->m_wheelScale;
+ if(GetModelIndex() == MI_VOODOO)
+ groundOffset *= 0.6f;
+ mat.RotateY(Asin(clamp(-groundOffset, -1.0f, 1.0f)));
+ }
+ }
+ if(pHandling->Flags & HANDLING_FAT_REARW)
+ mat.Scale(1.15f*mi->m_wheelScale, mi->m_wheelScale, mi->m_wheelScale);
+ else
+ mat.Scale(mi->m_wheelScale);
mat.Translate(pos);
mat.UpdateRW();
- if(CVehicle::bWheelsOnlyCheat)
- RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RM]));
}
// Mid left wheel
if(m_aCarNodes[CAR_WHEEL_LM]){
mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LM]));
- pos.x = mat.GetPosition().x;
- pos.y = mat.GetPosition().y;
+ pos = mat.GetPosition();
pos.z = m_aWheelPosition[CARWHEEL_REAR_LEFT];
if(Damage.GetWheelStatus(CARWHEEL_REAR_LEFT) == WHEEL_STATUS_BURST)
- mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI+0.3f*Sin(-m_aWheelRotation[CARWHEEL_REAR_LEFT]));
+ mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI+0.3f*Sin(m_aWheelRotation[CARWHEEL_REAR_LEFT]));
else
mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI);
- mat.Scale(mi->m_wheelScale);
+ if(GetStatus() == STATUS_PLAYER){
+ if(bHoverCheat && m_aSuspensionSpringRatioPrev[CARWHEEL_REAR_LEFT] < 1.0f &&
+ m_aWheelColPoints[CARWHEEL_REAR_LEFT].surfaceB == SURFACE_WATER){
+ // hovering on water
+ mat.RotateY(HALFPI);
+ }else{
+ // tilt wheel depending oh how much it presses on ground
+ float groundOffset = pos.z + m_fHeightAboveRoad - 0.5f*mi->m_wheelScale;
+ if(GetModelIndex() == MI_VOODOO)
+ groundOffset *= 0.6f;
+ mat.RotateY(Asin(clamp(groundOffset, -1.0f, 1.0f)));
+ }
+ }
+ if(pHandling->Flags & HANDLING_FAT_REARW)
+ mat.Scale(1.15f*mi->m_wheelScale, mi->m_wheelScale, mi->m_wheelScale);
+ else
+ mat.Scale(mi->m_wheelScale);
mat.Translate(pos);
mat.UpdateRW();
- if(CVehicle::bWheelsOnlyCheat)
- RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LM]));
}
if(GetModelIndex() == MI_DODO){
// Front wheel
mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF]));
- pos.x = mat.GetPosition().x;
- pos.y = mat.GetPosition().y;
+ pos = mat.GetPosition();
pos.z = m_aWheelPosition[CARWHEEL_FRONT_RIGHT];
if(Damage.GetWheelStatus(CARWHEEL_FRONT_RIGHT) == WHEEL_STATUS_BURST)
mat.SetRotate(m_aWheelRotation[CARWHEEL_FRONT_RIGHT], 0.0f, m_fSteerAngle+0.3f*Sin(m_aWheelRotation[CARWHEEL_FRONT_RIGHT]));
@@ -2019,8 +2694,6 @@ CAutomobile::Render(void)
mat.Scale(mi->m_wheelScale);
mat.Translate(pos);
mat.UpdateRW();
- if(CVehicle::bWheelsOnlyCheat)
- RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]));
// Rotate propeller
if(m_aCarNodes[CAR_WINDSCREEN]){
@@ -2050,59 +2723,130 @@ CAutomobile::Render(void)
}else if(GetModelIndex() == MI_RHINO){
// Front right wheel
mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF]));
- pos.x = mat.GetPosition().x;
- pos.y = mat.GetPosition().y;
+ pos = mat.GetPosition();
pos.z = m_aWheelPosition[CARWHEEL_FRONT_RIGHT];
// no damaged wheels or steering
mat.SetRotate(m_aWheelRotation[CARWHEEL_FRONT_RIGHT], 0.0f, 0.0f);
mat.Scale(mi->m_wheelScale);
mat.Translate(pos);
mat.UpdateRW();
- if(CVehicle::bWheelsOnlyCheat)
- RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]));
// Front left wheel
mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LF]));
- pos.x = mat.GetPosition().x;
- pos.y = mat.GetPosition().y;
+ pos = mat.GetPosition();
pos.z = m_aWheelPosition[CARWHEEL_FRONT_LEFT];
// no damaged wheels or steering
mat.SetRotate(-m_aWheelRotation[CARWHEEL_FRONT_LEFT], 0.0f, PI);
mat.Scale(mi->m_wheelScale);
mat.Translate(pos);
mat.UpdateRW();
- if(CVehicle::bWheelsOnlyCheat)
- RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]));
+ }else if(IsRealHeli()){
+ // Top rotor
+ if(m_aCarNodes[CAR_BONNET]){
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BONNET]));
+ pos = mat.GetPosition();
+ mat.SetRotateZ(m_aWheelRotation[1]);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ }
+ // Blurred top rotor
+ if(m_aCarNodes[CAR_WINDSCREEN]){
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WINDSCREEN]));
+ pos = mat.GetPosition();
+ mat.SetRotateZ(-m_aWheelRotation[1]);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ }
+ // Rear rotor
+ if(m_aCarNodes[CAR_BOOT]){
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BOOT]));
+ pos = mat.GetPosition();
+ mat.SetRotateX(m_aWheelRotation[3]);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ }
+ // Blurred rear rotor
+ if(m_aCarNodes[CAR_BUMP_REAR]){
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BUMP_REAR]));
+ pos = mat.GetPosition();
+ mat.SetRotateX(-m_aWheelRotation[3]);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ }
}else{
// Front right wheel
mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF]));
- pos.x = mat.GetPosition().x;
- pos.y = mat.GetPosition().y;
+ pos = mat.GetPosition();
pos.z = m_aWheelPosition[CARWHEEL_FRONT_RIGHT];
if(Damage.GetWheelStatus(CARWHEEL_FRONT_RIGHT) == WHEEL_STATUS_BURST)
mat.SetRotate(m_aWheelRotation[CARWHEEL_FRONT_RIGHT], 0.0f, m_fSteerAngle+0.3f*Sin(m_aWheelRotation[CARWHEEL_FRONT_RIGHT]));
else
mat.SetRotate(m_aWheelRotation[CARWHEEL_FRONT_RIGHT], 0.0f, m_fSteerAngle);
- mat.Scale(mi->m_wheelScale);
+ if(GetStatus() == STATUS_PLAYER){
+ if(bHoverCheat && m_aSuspensionSpringRatioPrev[CARWHEEL_FRONT_RIGHT] < 1.0f &&
+ m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].surfaceB == SURFACE_WATER){
+ // hovering on water
+ mat.RotateY(-HALFPI);
+ if((CTimer::GetFrameCounter()+CARWHEEL_FRONT_RIGHT) & 1){
+ CParticle::AddParticle(PARTICLE_STEAM_NY_SLOWMOTION, m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].point,
+ 0.5f*m_vecMoveSpeed+0.1f*GetRight(), nil, 0.4f, hoverParticleCol);
+ }else{
+ CParticle::AddParticle(PARTICLE_CAR_SPLASH, m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].point,
+ 0.3f*m_vecMoveSpeed+0.15f*GetRight()+CVector(0.0f, 0.0f, 0.1f), nil, 0.15f, hoverParticleCol,
+ CGeneral::GetRandomNumberInRange(0.0f, 90.0f),
+ CGeneral::GetRandomNumberInRange(0.0f, 10.0f), 1);
+ }
+ }else{
+ // tilt wheel depending oh how much it presses on ground
+ float groundOffset = pos.z + m_fHeightAboveRoad - 0.5f*mi->m_wheelScale;
+ if(GetModelIndex() == MI_VOODOO)
+ groundOffset *= 0.6f;
+ mat.RotateY(Asin(clamp(-groundOffset, -1.0f, 1.0f)));
+ }
+ }
+ if(pHandling->Flags & HANDLING_NARROW_FRONTW)
+ mat.Scale(0.7f*mi->m_wheelScale, mi->m_wheelScale, mi->m_wheelScale);
+ else
+ mat.Scale(mi->m_wheelScale);
mat.Translate(pos);
mat.UpdateRW();
- if(CVehicle::bWheelsOnlyCheat)
- RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]));
// Front left wheel
mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LF]));
- pos.x = mat.GetPosition().x;
- pos.y = mat.GetPosition().y;
+ pos = mat.GetPosition();
pos.z = m_aWheelPosition[CARWHEEL_FRONT_LEFT];
if(Damage.GetWheelStatus(CARWHEEL_FRONT_LEFT) == WHEEL_STATUS_BURST)
- mat.SetRotate(-m_aWheelRotation[CARWHEEL_FRONT_LEFT], 0.0f, PI+m_fSteerAngle+0.3f*Sin(-m_aWheelRotation[CARWHEEL_FRONT_LEFT]));
+ mat.SetRotate(-m_aWheelRotation[CARWHEEL_FRONT_LEFT], 0.0f, PI+m_fSteerAngle+0.3f*Sin(m_aWheelRotation[CARWHEEL_FRONT_LEFT]));
else
mat.SetRotate(-m_aWheelRotation[CARWHEEL_FRONT_LEFT], 0.0f, PI+m_fSteerAngle);
- mat.Scale(mi->m_wheelScale);
+ if(GetStatus() == STATUS_PLAYER){
+ if(bHoverCheat && m_aSuspensionSpringRatioPrev[CARWHEEL_FRONT_LEFT] < 1.0f &&
+ m_aWheelColPoints[CARWHEEL_FRONT_LEFT].surfaceB == SURFACE_WATER){
+ // hovering on water
+ mat.RotateY(HALFPI);
+ if((CTimer::GetFrameCounter()+CARWHEEL_FRONT_LEFT) & 1){
+ CParticle::AddParticle(PARTICLE_STEAM_NY_SLOWMOTION, m_aWheelColPoints[CARWHEEL_FRONT_LEFT].point,
+ 0.5f*m_vecMoveSpeed-0.1f*GetRight(), nil, 0.4f, hoverParticleCol);
+ }else{
+ CParticle::AddParticle(PARTICLE_CAR_SPLASH, m_aWheelColPoints[CARWHEEL_FRONT_LEFT].point,
+ 0.3f*m_vecMoveSpeed-0.15f*GetRight()+CVector(0.0f, 0.0f, 0.1f), nil, 0.15f, hoverParticleCol,
+ CGeneral::GetRandomNumberInRange(0.0f, 90.0f),
+ CGeneral::GetRandomNumberInRange(0.0f, 10.0f), 1);
+ }
+ }else{
+ // tilt wheel depending oh how much it presses on ground
+ float groundOffset = pos.z + m_fHeightAboveRoad - 0.5f*mi->m_wheelScale;
+ if(GetModelIndex() == MI_VOODOO)
+ groundOffset *= 0.6f;
+ mat.RotateY(Asin(clamp(groundOffset, -1.0f, 1.0f)));
+ }
+ }
+ if(pHandling->Flags & HANDLING_NARROW_FRONTW)
+ mat.Scale(0.7f*mi->m_wheelScale, mi->m_wheelScale, mi->m_wheelScale);
+ else
+ mat.Scale(mi->m_wheelScale);
mat.Translate(pos);
mat.UpdateRW();
- if(CVehicle::bWheelsOnlyCheat)
- RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]));
ProcessSwingingDoor(CAR_DOOR_LF, DOOR_FRONT_LEFT);
ProcessSwingingDoor(CAR_DOOR_RF, DOOR_FRONT_RIGHT);
@@ -2110,11 +2854,104 @@ CAutomobile::Render(void)
ProcessSwingingDoor(CAR_DOOR_RR, DOOR_REAR_RIGHT);
ProcessSwingingDoor(CAR_BONNET, DOOR_BONNET);
ProcessSwingingDoor(CAR_BOOT, DOOR_BOOT);
+ }
+
+ if((GetModelIndex() == MI_PHEONIX || GetModelIndex() == MI_BFINJECT) &&
+ GetStatus() == STATUS_PLAYER && m_aCarNodes[CAR_WING_LR]){
+ float rotation = 0.0f;
+
+ if(GetModelIndex() == MI_BFINJECT)
+ if(m_fPropellerRotation > TWOPI) m_fPropellerRotation -= TWOPI;
+
+ if(Abs(m_fGasPedal) > 0.0f){
+ if(GetModelIndex() == MI_BFINJECT){
+ m_fPropellerRotation += 0.2f*CTimer::GetTimeStep();
+ rotation = m_fPropellerRotation;
+ }else{
+ if(m_fPropellerRotation < 1.3f){
+ m_fPropellerRotation = Min(m_fPropellerRotation+0.1f*CTimer::GetTimeStep(), 1.3f);
+ rotation = m_fPropellerRotation;
+ }else{
+ float wave = Sin((CTimer::GetTimeInMilliseconds()%10000)/70.0f);
+ rotation = m_fPropellerRotation + 0.13*wave;
+ }
+ }
+ }else{
+ if(GetModelIndex() == MI_BFINJECT){
+ m_fPropellerRotation += 0.1f*CTimer::GetTimeStep();
+ rotation = m_fPropellerRotation;
+ }else{
+ if(m_fPropellerRotation > 0.0f){
+ m_fPropellerRotation = Max(m_fPropellerRotation-0.05f*CTimer::GetTimeStep(), 0.0f);
+ rotation = m_fPropellerRotation;
+ }
+ }
+ }
+
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WING_LR]));
+ pos = mat.GetPosition();
+ if(GetModelIndex() == MI_BFINJECT)
+ mat.SetRotateY(rotation);
+ else
+ mat.SetRotateX(rotation);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ }
+}
+
+void
+CAutomobile::Render(void)
+{
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+
+ mi->SetVehicleColour(m_currentColour1, m_currentColour2);
+
+ if(IsRealHeli()){
+ RpAtomic *atomic = nil;
+ int rotorAlpha = (1.5f - Min(1.7f*Max(m_aWheelSpeed[1],0.0f)/0.22f, 1.5f))*255.0f;
+ rotorAlpha = Min(rotorAlpha, 255);
+ int blurAlpha = Max(1.5f*m_aWheelSpeed[1]/0.22f - 0.4f, 0.0f)*150.0f;
+ blurAlpha = Min(blurAlpha, 150);
- mi->SetVehicleColour(m_currentColour1, m_currentColour2);
+ // Top rotor
+ if(m_aCarNodes[CAR_BONNET]){
+ RwFrameForAllObjects(m_aCarNodes[CAR_BONNET], GetCurrentAtomicObjectCB, &atomic);
+ if(atomic)
+ SetComponentAtomicAlpha(atomic, rotorAlpha);
+ }
+ atomic = nil;
+ // Rear rotor
+ if(m_aCarNodes[CAR_BOOT]){
+ RwFrameForAllObjects(m_aCarNodes[CAR_BOOT], GetCurrentAtomicObjectCB, &atomic);
+ if(atomic)
+ SetComponentAtomicAlpha(atomic, rotorAlpha);
+ }
+ atomic = nil;
+ // Blurred top rotor
+ if(m_aCarNodes[CAR_WINDSCREEN]){
+ RwFrameForAllObjects(m_aCarNodes[CAR_WINDSCREEN], GetCurrentAtomicObjectCB, &atomic);
+ if(atomic)
+ SetComponentAtomicAlpha(atomic, blurAlpha);
+ }
+ atomic = nil;
+ // Blurred rear rotor
+ if(m_aCarNodes[CAR_BUMP_REAR]){
+ RwFrameForAllObjects(m_aCarNodes[CAR_BUMP_REAR], GetCurrentAtomicObjectCB, &atomic);
+ if(atomic)
+ SetComponentAtomicAlpha(atomic, blurAlpha);
+ }
}
- if(!CVehicle::bWheelsOnlyCheat)
+ if(CVehicle::bWheelsOnlyCheat){
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RB]));
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LB]));
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]));
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]));
+ if(m_aCarNodes[CAR_WHEEL_RM])
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RM]));
+ if(m_aCarNodes[CAR_WHEEL_LM])
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LM]));
+ }else
CEntity::Render();
}
@@ -2137,6 +2974,10 @@ CAutomobile::ProcessEntityCollision(CEntity *ent, CColPoint *colpoints)
for(i = 0; i < 4; i++)
prevRatios[i] = m_aSuspensionSpringRatio[i];
+ if(m_bIsVehicleBeingShifted || bSkipLineCol || ent->IsPed() ||
+ GetModelIndex() == MI_DODO && ent->IsVehicle())
+ colModel->numLines = 0;
+
int numCollisions = CCollision::ProcessColModels(GetMatrix(), *colModel,
ent->GetMatrix(), *ent->GetColModel(),
colpoints,
@@ -2145,12 +2986,7 @@ CAutomobile::ProcessEntityCollision(CEntity *ent, CColPoint *colpoints)
// m_aSuspensionSpringRatio are now set to the point where the tyre touches ground.
// In ProcessControl these will be re-normalized to ignore the tyre radius.
- if(m_bIsVehicleBeingShifted || bSkipLineCol ||
- GetModelIndex() == MI_DODO && (ent->IsPed() || ent->IsVehicle())){
- // don't do line collision
- for(i = 0; i < 4; i++)
- m_aSuspensionSpringRatio[i] = prevRatios[i];
- }else{
+ if(colModel->numLines){
for(i = 0; i < 4; i++)
if(m_aSuspensionSpringRatio[i] < 1.0f && m_aSuspensionSpringRatio[i] < prevRatios[i]){
numWheelCollisions++;
@@ -2162,32 +2998,14 @@ CAutomobile::ProcessEntityCollision(CEntity *ent, CColPoint *colpoints)
m_aGroundPhysical[i] = phys;
phys->RegisterReference((CEntity**)&m_aGroundPhysical[i]);
m_aGroundOffset[i] = m_aWheelColPoints[i].point - phys->GetPosition();
-
-#if 0
- if(phys->GetModelIndex() == MI_BODYCAST && GetStatus() == STATUS_PLAYER){
- // damage body cast
- float speed = m_vecMoveSpeed.MagnitudeSqr();
- if(speed > 0.1f){
- CObject::nBodyCastHealth -= 0.1f*m_fMass*speed;
- DMAudio.PlayOneShot(m_audioEntityId, SOUND_PED_BODYCAST_HIT, 0.0f);
- }
-
- // move body cast
- if(phys->IsStatic()){
- phys->bIsStatic = false;
- phys->m_nStaticFrames = 0;
- phys->ApplyMoveForce(m_vecMoveSpeed / Sqrt(speed));
- phys->AddToMovingList();
- }
- }
-#endif
}
m_nSurfaceTouched = m_aWheelColPoints[i].surfaceB;
if(ent->IsBuilding())
m_pCurGroundEntity = ent;
}
- }
+ }else
+ colModel->numLines = 4;
if(numCollisions > 0 || numWheelCollisions > 0){
AddCollisionRecord(ent);
@@ -2213,10 +3031,12 @@ CAutomobile::ProcessControlInputs(uint8 pad)
{
float speed = DotProduct(m_vecMoveSpeed, GetForward());
- if(CPad::GetPad(pad)->GetExitVehicle())
- bIsHandbrakeOn = true;
- else
+ if(!CPad::GetPad(pad)->GetExitVehicle() ||
+ pDriver && pDriver->m_pVehicleAnim && (pDriver->m_pVehicleAnim->animId == ANIM_CAR_ROLLOUT_LHS ||
+ pDriver->m_pVehicleAnim->animId == ANIM_CAR_ROLLOUT_LHS2))
bIsHandbrakeOn = !!CPad::GetPad(pad)->GetHandBrake();
+ else
+ bIsHandbrakeOn = true;
// Steer left/right
if(CCamera::m_bUseMouse3rdPerson && !CVehicle::m_bDisableMouseSteering){
@@ -2244,8 +3064,14 @@ CAutomobile::ProcessControlInputs(uint8 pad)
acceleration *= 0.3f;
if(Abs(speed) < 0.01f){
// standing still, go into direction we want
- m_fGasPedal = acceleration;
- m_fBrakePedal = 0.0f;
+ if(CPad::GetPad(pad)->GetAccelerate() > 150.0f && CPad::GetPad(pad)->GetBrake() > 150.0f){
+ m_fGasPedal = CPad::GetPad(pad)->GetAccelerate()/255.0f;
+ m_fBrakePedal = CPad::GetPad(pad)->GetBrake()/255.0f;
+ m_doingBurnout = 1;
+ }else{
+ m_fGasPedal = acceleration;
+ m_fBrakePedal = 0.0f;
+ }
}else{
#if 1
// simpler than the code below
@@ -2475,7 +3301,7 @@ CAutomobile::TankControl(void)
float f = i/15.0f;
CParticle::AddParticle(PARTICLE_GUNSMOKE2, point1,
shotDir*CGeneral::GetRandomNumberInRange(0.3f, 1.0f)*f,
- nil, CGeneral::GetRandomNumberInRange(0.5f, 1.0f)*f, black);
+ nil, CGeneral::GetRandomNumberInRange(0.5f, 1.5f)*f, black);
}
// And some gun flashes near the gun
@@ -2493,20 +3319,11 @@ CAutomobile::TankControl(void)
flashPos += 0.1f*shotDir;
CParticle::AddParticle(PARTICLE_GUNFLASH, flashPos, nullDir, nil, 0.15f, black, 0, 0, 0, lifeSpan);
}
-
- // Actually update turret node
- if(m_aCarNodes[CAR_WINDSCREEN]){
- CMatrix mat;
- CVector pos;
-
- mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WINDSCREEN]));
- pos = mat.GetPosition();
- mat.SetRotateZ(m_fCarGunLR);
- mat.Translate(pos);
- mat.UpdateRW();
- }
}
+#define HYDRAULIC_UPPER_EXT (-0.16f)
+#define HYDRAULIC_LOWER_EXT (0.16f)
+
void
CAutomobile::HydraulicControl(void)
{
@@ -2569,8 +3386,8 @@ CAutomobile::HydraulicControl(void)
m_hydraulicState = 20;
else{
m_hydraulicState = 0;
- normalUpperLimit += -0.12f;
- normalSpringLength = normalUpperLimit - (normalLowerLimit+0.14f);
+ normalUpperLimit += HYDRAULIC_UPPER_EXT;
+ normalSpringLength = normalUpperLimit - (normalLowerLimit+HYDRAULIC_LOWER_EXT);
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
}
@@ -2603,7 +3420,7 @@ CAutomobile::HydraulicControl(void)
float radius = Max(specialColModel->boundingBox.min.Magnitude(), specialColModel->boundingBox.max.Magnitude());
if(specialColModel->boundingSphere.radius < radius)
specialColModel->boundingSphere.radius = radius;
-
+ return;
}
if(playerInfo->m_WBState != WBSTATE_PLAYING)
@@ -2642,8 +3459,8 @@ CAutomobile::HydraulicControl(void)
if(m_hydraulicState < 100){
if(m_hydraulicState == 0){
- normalUpperLimit += -0.12f;
- normalLowerLimit += 0.14f;
+ normalUpperLimit += HYDRAULIC_UPPER_EXT;
+ normalLowerLimit += HYDRAULIC_LOWER_EXT;
normalSpringLength = normalUpperLimit - normalLowerLimit;
}
@@ -2688,7 +3505,6 @@ CAutomobile::HydraulicControl(void)
}
setPrevRatio = true;
- m_aWheelPosition[i] -= 0.05f;
}
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
}
@@ -2708,8 +3524,8 @@ CAutomobile::HydraulicControl(void)
// Lowered, move wheels up
if(m_hydraulicState == 0){
- normalUpperLimit += -0.12f;
- normalLowerLimit += 0.14f;
+ normalUpperLimit += HYDRAULIC_UPPER_EXT;
+ normalLowerLimit += HYDRAULIC_LOWER_EXT;
normalSpringLength = normalUpperLimit - normalLowerLimit;
}
@@ -2719,7 +3535,6 @@ CAutomobile::HydraulicControl(void)
if(suspChange[i] > 1.0f)
suspChange[i] = 1.0f;
- float oldZ = specialColModel->lines[i].p1.z;
float upperLimit = suspChange[i]*(extendedUpperLimit-normalUpperLimit) + normalUpperLimit;
float springLength = suspChange[i]*(extendedSpringLength-normalSpringLength) + normalSpringLength;
float lineLength = springLength + wheelRadius;
@@ -2739,19 +3554,15 @@ CAutomobile::HydraulicControl(void)
m_aSuspensionSpringRatio[i] = (specialColModel->lines[i].p0.z - wheelPositions[i])/m_aSuspensionLineLength[i];
if(m_aSuspensionSpringRatio[i] > 1.0f)
m_aSuspensionSpringRatio[i] = 1.0f;
- m_aWheelPosition[i] -= (oldZ - specialColModel->lines[i].p1.z)*0.3f;
}
}
}else{
- if(m_hydraulicState < 104){
+ if(m_hydraulicState < 104)
m_hydraulicState++;
- for(i = 0; i < 4; i++)
- m_aWheelPosition[i] -= 0.1f;
- }
if(m_fVelocityChangeForAudio < 0.1f){
- normalUpperLimit += -0.12f;
- normalLowerLimit += 0.14f;
+ normalUpperLimit += HYDRAULIC_UPPER_EXT;
+ normalLowerLimit += HYDRAULIC_LOWER_EXT;
normalSpringLength = normalUpperLimit - normalLowerLimit;
}
@@ -2813,18 +3624,45 @@ CAutomobile::ProcessBuoyancy(void)
CVector impulse, point;
if(mod_Buoyancy.ProcessBuoyancy(this, m_fBuoyancy, &point, &impulse)){
- bTouchingWater = true;
- ApplyMoveForce(impulse);
- ApplyTurnForce(impulse, point);
-
- CVector initialSpeed = m_vecMoveSpeed;
float timeStep = Max(CTimer::GetTimeStep(), 0.01f);
float impulseRatio = impulse.z / (GRAVITY * m_fMass * timeStep);
float waterResistance = Pow(1.0f - 0.05f*impulseRatio, CTimer::GetTimeStep());
m_vecMoveSpeed *= waterResistance;
m_vecTurnSpeed *= waterResistance;
- if(impulseRatio > 0.5f){
+ bool heliHitWaterHard = false;
+ if(IsRealHeli() && m_aWheelSpeed[1] > 0.15f){
+ if(GetModelIndex() == MI_SEASPAR){
+ if(impulseRatio > 3.0f){
+ m_aWheelSpeed[1] = 0.0f;
+ heliHitWaterHard = true;
+ }
+ }else{
+ float strength = 1.0f/Max(8.0f*impulseRatio, 1.0f);
+ ApplyMoveForce(-2.0f*impulse/strength);
+ ApplyTurnForce(-impulse/strength, point);
+ if(impulseRatio > 0.9f){
+ m_aWheelSpeed[1] = 0.0f;
+ heliHitWaterHard = true;
+ }else
+ return;
+ }
+ }
+
+ bTouchingWater = true;
+ ApplyMoveForce(impulse);
+ ApplyTurnForce(impulse, point);
+ CVector initialSpeed = m_vecMoveSpeed;
+
+ if(m_modelIndex == MI_SEASPAR && impulseRatio < 3.0f && (GetUp().z > -0.5f || impulseRatio < 0.6f) ||
+ CVehicle::bHoverCheat && GetStatus() == STATUS_PLAYER && GetUp().z > 0.1f){
+ bIsInWater = false;
+ bIsDrowning = false;
+ }else if(heliHitWaterHard || impulseRatio > 1.0f ||
+ impulseRatio > 0.6f && (m_aSuspensionSpringRatio[0] == 1.0f ||
+ m_aSuspensionSpringRatio[1] == 1.0f ||
+ m_aSuspensionSpringRatio[2] == 1.0f ||
+ m_aSuspensionSpringRatio[3] == 1.0f)){
bIsInWater = true;
bIsDrowning = true;
if(m_vecMoveSpeed.z < -0.1f)
@@ -2841,8 +3679,7 @@ CAutomobile::ProcessBuoyancy(void)
if(pPassengers[i]->IsPlayer() || !bWaterTight)
pPassengers[i]->InflictDamage(nil, WEAPONTYPE_DROWNING, CTimer::GetTimeStep(), PEDPIECE_TORSO, 0);
}
- }
- else {
+ }else{
bIsInWater = false;
bIsDrowning = false;
}
@@ -2850,49 +3687,33 @@ CAutomobile::ProcessBuoyancy(void)
static uint32 nGenerateRaindrops = 0;
static uint32 nGenerateWaterCircles = 0;
- if(initialSpeed.z < -0.3f && impulse.z > 0.3f){
-#if defined(PC_PARTICLE) || defined (PS2_ALTERNATIVE_CARSPLASH)
+ if(initialSpeed.z < -0.1f && impulse.z > 0.3f || heliHitWaterHard){
RwRGBA color;
- color.red = (0.5f * CTimeCycle::GetDirectionalRed() + CTimeCycle::GetAmbientRed())*0.45f*255;
- color.green = (0.5f * CTimeCycle::GetDirectionalGreen() + CTimeCycle::GetAmbientGreen())*0.45f*255;
- color.blue = (0.5f * CTimeCycle::GetDirectionalBlue() + CTimeCycle::GetAmbientBlue())*0.45f*255;
+ color.red = (0.5f * CTimeCycle::GetDirectionalRed() + CTimeCycle::GetAmbientRed_Obj())*0.45f*255;
+ color.green = (0.5f * CTimeCycle::GetDirectionalGreen() + CTimeCycle::GetAmbientGreen_Obj())*0.45f*255;
+ color.blue = (0.5f * CTimeCycle::GetDirectionalBlue() + CTimeCycle::GetAmbientBlue_Obj())*0.45f*255;
color.alpha = CGeneral::GetRandomNumberInRange(0, 32) + 128;
+ CVector target = CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(0.15f, 0.45f));
CParticleObject::AddObject(POBJECT_CAR_WATER_SPLASH, GetPosition(),
- CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(0.15f, 0.3f)),
- 0.0f, 75, color, true);
-#else
- CVector pos = (initialSpeed * 2.0f) + (GetPosition() + point);
-
- for ( int32 i = 0; i < 360; i += 4 )
- {
- float fSin = Sin(float(i));
- float fCos = Cos(float(i));
-
- CVector dir(fSin*0.01f, fCos*0.01f, CGeneral::GetRandomNumberInRange(0.25f, 0.45f));
-
- CParticle::AddParticle(PARTICLE_CAR_SPLASH,
- pos + CVector(fSin*4.5f, fCos*4.5f, 0.0f),
- dir, NULL, 0.0f, CRGBA(225, 225, 255, 180));
-
- for ( int32 j = 0; j < 3; j++ )
- {
- float fMul = 1.5f * float(j + 1);
-
- CParticle::AddParticle(PARTICLE_CAR_SPLASH,
- pos + CVector(fSin * fMul, fCos * fMul, 0.0f),
- dir, NULL, 0.0f, CRGBA(225, 225, 255, 180));
- }
- }
-#endif
+ target, 0.0f, 75, color, true);
nGenerateRaindrops = CTimer::GetTimeInMilliseconds() + 300;
nGenerateWaterCircles = CTimer::GetTimeInMilliseconds() + 60;
+
+ if(heliHitWaterHard){
+ CVector right = CrossProduct(GetForward(), CVector(0.0f, 0.0f, 1.0f));
+ CParticleObject::AddObject(POBJECT_CAR_WATER_SPLASH, GetPosition() + right,
+ target, 0.0f, 75, color, true);
+ CParticleObject::AddObject(POBJECT_CAR_WATER_SPLASH, GetPosition() - right,
+ target, 0.0f, 75, color, true);
+ }
+
if(m_vecMoveSpeed.z < -0.2f)
m_vecMoveSpeed.z = -0.2f;
DMAudio.PlayOneShot(m_audioEntityId, SOUND_WATER_FALL, 0.0f);
}
- if(nGenerateWaterCircles > 0 && nGenerateWaterCircles < CTimer::GetTimeInMilliseconds()){
+ if(nGenerateWaterCircles > 0 && nGenerateWaterCircles <= CTimer::GetTimeInMilliseconds()){
CVector pos = GetPosition();
float waterLevel = 0.0f;
if(CWaterLevel::GetWaterLevel(pos.x, pos.y, pos.z, &waterLevel, false))
@@ -2912,7 +3733,7 @@ CAutomobile::ProcessBuoyancy(void)
}
}
- if(nGenerateRaindrops > 0 && nGenerateRaindrops < CTimer::GetTimeInMilliseconds()){
+ if(nGenerateRaindrops > 0 && nGenerateRaindrops <= CTimer::GetTimeInMilliseconds()){
CVector pos = GetPosition();
float waterLevel = 0.0f;
if(CWaterLevel::GetWaterLevel(pos.x, pos.y, pos.z, &waterLevel, false))
@@ -2938,13 +3759,7 @@ CAutomobile::ProcessBuoyancy(void)
CVector pos = m_aWheelColPoints[i].point + 0.3f*GetUp() - GetPosition();
CVector vSpeed = GetSpeed(pos);
vSpeed.z = 0.0f;
-#ifdef GTA_PS2_STUFF
- // ps2 puddle physics
- CVector moveForce = CTimer::GetTimeStep() * (m_fMass * (vSpeed * -0.003f));
- ApplyMoveForce(moveForce.x, moveForce.y, moveForce.z);
-#endif
float fSpeed = vSpeed.MagnitudeSqr();
-#ifdef PC_PARTICLE
if(fSpeed > sq(0.05f)){
fSpeed = Sqrt(fSpeed);
@@ -2964,35 +3779,6 @@ CAutomobile::ProcessBuoyancy(void)
if((CTimer::GetFrameCounter() & 0xF) == 0)
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_SPLASH, 2000.0f*fSpeed);
}
-#else
- if ( ( (CTimer::GetFrameCounter() + i) & 3 ) == 0 )
- {
- if(fSpeed > sq(0.05f))
- {
- fSpeed = Sqrt(fSpeed);
- CRGBA color(155, 185, 155, 255);
- float boxY = GetColModel()->boundingBox.max.y;
- CVector right = 0.5f * GetRight();
-
- if ( i == 2 )
- {
- CParticle::AddParticle(PARTICLE_PED_SPLASH,
- GetPosition() + (boxY * GetForward()) + right,
- 0.75f*m_vecMoveSpeed, NULL, 0.0f, color);
-
- }
- else if ( i == 0 )
- {
- CParticle::AddParticle(PARTICLE_PED_SPLASH,
- GetPosition() + (boxY * GetForward()) - right,
- 0.75f*m_vecMoveSpeed, NULL, 0.0f, color);
- }
-
- if((CTimer::GetFrameCounter() & 0xF) == 0)
- DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_SPLASH, 2000.0f*fSpeed);
- }
- }
-#endif
}
}
}
@@ -3014,7 +3800,8 @@ CAutomobile::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())
@@ -3077,6 +3864,44 @@ CAutomobile::DoDriveByShootings(void)
}
}
+void
+CAutomobile::DoHoverSuspensionRatios(void)
+{
+ int i;
+
+ if(GetUp().z < 0.1f)
+ return;
+
+ CColModel *colmodel = GetColModel();
+ for(i = 0; i < 4; i++){
+ float z, waterZ;
+ CVector upper = GetMatrix() * colmodel->lines[i].p0;
+ CVector lower = GetMatrix() * colmodel->lines[i].p1;
+ if(m_aSuspensionSpringRatio[i] < 1.0f)
+ z = m_aWheelColPoints[i].point.z;
+ else
+ z = -100.0f;
+ // see if touching water
+ if(CWaterLevel::GetWaterLevel(lower, &waterZ, false) &&
+ waterZ > z && lower.z-1.0f < waterZ){
+ // compress spring
+ if(lower.z < waterZ){
+ if(upper.z < waterZ)
+ m_aSuspensionSpringRatio[i] = 0.0f;
+ else
+ m_aSuspensionSpringRatio[i] = (upper.z - waterZ)/(upper.z - lower.z);
+ }else
+ m_aSuspensionSpringRatio[i] = 0.99999f;
+
+ m_aWheelColPoints[i].point.x = (lower.x - upper.x)*m_aSuspensionSpringRatio[i] + upper.x;
+ m_aWheelColPoints[i].point.y = (lower.y - upper.y)*m_aSuspensionSpringRatio[i] + upper.y;
+ m_aWheelColPoints[i].point.z = waterZ;
+ m_aWheelColPoints[i].normal = CVector(0.01f, 0.0f, 1.0f);
+ m_aWheelColPoints[i].surfaceB = SURFACE_WATER;
+ }
+ }
+}
+
int32
CAutomobile::RcbanditCheckHitWheels(void)
{
@@ -3116,7 +3941,8 @@ CAutomobile::RcbanditCheck1CarWheels(CPtrList &list)
for(node = list.first; node; node = node->next){
car = (CAutomobile*)node->item;
- if(this != car && car->IsCar() && car->m_scanCode != CWorld::GetCurrentScanCode()){
+ if(this != car && car->IsCar() && car->GetModelIndex() != MI_RCBANDIT &&
+ car->m_scanCode != CWorld::GetCurrentScanCode()){
car->m_scanCode = CWorld::GetCurrentScanCode();
if(Abs(this->GetPosition().x - car->GetPosition().x) < 10.0f &&
@@ -3190,8 +4016,7 @@ void
CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece)
{
int i;
- float damageMultiplier = 0.2f;
- bool doubleMoney = false;
+ float damageMultiplier = 0.333f;
if(impulse == 0.0f){
impulse = m_fDamageImpulse;
@@ -3199,22 +4024,33 @@ CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece)
damageMultiplier = 1.0f;
}
+ if(GetStatus() == STATUS_PLAYER && CStats::GetPercentageProgress() >= 100.0f)
+ impulse *= 0.5f;
+
CVector pos(0.0f, 0.0f, 0.0f);
if(!bCanBeDamaged)
return;
+ if(m_pDamageEntity && m_pDamageEntity->IsPed() && ((CPed*)m_pDamageEntity)->bIsStanding){
+ float speed = ((CPed*)m_pDamageEntity)->m_vecAnimMoveDelta.y * DotProduct(GetForward(), m_vecDamageNormal);
+ if(speed < 0.0f)
+ impulse = Max(impulse + ((CPed*)m_pDamageEntity)->m_fMass * speed, 0.0f);
+ }
+
// damage flipped over car
if(GetUp().z < 0.0f && this != FindPlayerVehicle()){
if(bNotDamagedUpsideDown || GetStatus() == STATUS_PLAYER_REMOTE || bIsInWater)
return;
- m_fHealth -= 4.0f*CTimer::GetTimeStep();
+ if(GetStatus() != STATUS_WRECKED)
+ m_fHealth = Max(m_fHealth - 4.0f*CTimer::GetTimeStep(), 0.0f);
}
- if(impulse > 25.0f && GetStatus() != STATUS_WRECKED){
+ float minImpulse = GetModelIndex() == MI_RCRAIDER || GetModelIndex() == MI_RCGOBLIN ? 1.0f : 25.0f;
+ if(impulse > minImpulse && GetStatus() != STATUS_WRECKED){
if(bIsLawEnforcer &&
FindPlayerVehicle() && FindPlayerVehicle() == m_pDamageEntity &&
- GetStatus() != STATUS_ABANDONED &&
+ GetStatus() != STATUS_ABANDONED &&
FindPlayerVehicle()->m_vecMoveSpeed.Magnitude() >= m_vecMoveSpeed.Magnitude() &&
FindPlayerVehicle()->m_vecMoveSpeed.Magnitude() > 0.1f)
FindPlayerPed()->SetWantedLevelNoDrop(1);
@@ -3224,12 +4060,17 @@ CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece)
CPad::GetPad(0)->StartShake(40000/freq, freq);
}
- if(bOnlyDamagedByPlayer){
+ if(GetStatus() != STATUS_PLAYER && bOnlyDamagedByPlayer){
if(m_pDamageEntity != FindPlayerPed() &&
m_pDamageEntity != FindPlayerVehicle())
return;
}
+ if(m_pDamageEntity && m_pDamageEntity->IsVehicle()){
+ m_nLastWeaponDamage = WEAPONTYPE_RAMMEDBYCAR;
+ m_pLastDamageEntity = m_pDamageEntity;
+ }
+
if(bCollisionProof)
return;
@@ -3249,108 +4090,81 @@ CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece)
switch(damagedPiece){
case CAR_PIECE_BUMP_FRONT:
GetComponentWorldPosition(CAR_BUMP_FRONT, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if(Damage.ApplyDamage(COMPONENT_BUMPER_FRONT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_BUMPER_FRONT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetBumperDamage(CAR_BUMP_FRONT, VEHBUMPER_FRONT);
- doubleMoney = true;
- }
if(m_aCarNodes[CAR_BONNET] && Damage.GetPanelStatus(VEHBUMPER_FRONT) == PANEL_STATUS_MISSING){
case CAR_PIECE_BONNET:
GetComponentWorldPosition(CAR_BONNET, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if(Damage.ApplyDamage(COMPONENT_DOOR_BONNET, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(GetModelIndex() != MI_DODO)
+ if(Damage.ApplyDamage(COMPONENT_DOOR_BONNET, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetDoorDamage(CAR_BONNET, DOOR_BONNET);
- doubleMoney = true;
- }
}
break;
case CAR_PIECE_BUMP_REAR:
GetComponentWorldPosition(CAR_BUMP_REAR, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if(Damage.ApplyDamage(COMPONENT_BUMPER_FRONT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_BUMPER_REAR, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetBumperDamage(CAR_BUMP_REAR, VEHBUMPER_REAR);
- doubleMoney = true;
- }
if(m_aCarNodes[CAR_BOOT] && Damage.GetPanelStatus(VEHBUMPER_REAR) == PANEL_STATUS_MISSING){
case CAR_PIECE_BOOT:
GetComponentWorldPosition(CAR_BOOT, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if(Damage.ApplyDamage(COMPONENT_DOOR_BOOT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_DOOR_BOOT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetDoorDamage(CAR_BOOT, DOOR_BOOT);
- doubleMoney = true;
- }
}
break;
case CAR_PIECE_DOOR_LF:
GetComponentWorldPosition(CAR_DOOR_LF, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if((m_nDoorLock == CARLOCK_NOT_USED || m_nDoorLock == CARLOCK_UNLOCKED) &&
- Damage.ApplyDamage(COMPONENT_DOOR_FRONT_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_DOOR_FRONT_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetDoorDamage(CAR_DOOR_LF, DOOR_FRONT_LEFT);
- doubleMoney = true;
- }
break;
case CAR_PIECE_DOOR_RF:
GetComponentWorldPosition(CAR_DOOR_RF, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if((m_nDoorLock == CARLOCK_NOT_USED || m_nDoorLock == CARLOCK_UNLOCKED) &&
- Damage.ApplyDamage(COMPONENT_DOOR_FRONT_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_DOOR_FRONT_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetDoorDamage(CAR_DOOR_RF, DOOR_FRONT_RIGHT);
- doubleMoney = true;
- }
break;
case CAR_PIECE_DOOR_LR:
GetComponentWorldPosition(CAR_DOOR_LR, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if((m_nDoorLock == CARLOCK_NOT_USED || m_nDoorLock == CARLOCK_UNLOCKED) &&
- Damage.ApplyDamage(COMPONENT_DOOR_REAR_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_DOOR_REAR_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetDoorDamage(CAR_DOOR_LR, DOOR_REAR_LEFT);
- doubleMoney = true;
- }
break;
case CAR_PIECE_DOOR_RR:
GetComponentWorldPosition(CAR_DOOR_RR, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if((m_nDoorLock == CARLOCK_NOT_USED || m_nDoorLock == CARLOCK_UNLOCKED) &&
- Damage.ApplyDamage(COMPONENT_DOOR_REAR_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_DOOR_REAR_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetDoorDamage(CAR_DOOR_RR, DOOR_REAR_RIGHT);
- doubleMoney = true;
- }
break;
case CAR_PIECE_WING_LF:
GetComponentWorldPosition(CAR_WING_LF, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if(Damage.ApplyDamage(COMPONENT_PANEL_FRONT_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_PANEL_FRONT_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetPanelDamage(CAR_WING_LF, VEHPANEL_FRONT_LEFT);
- doubleMoney = true;
- }
break;
case CAR_PIECE_WING_RF:
GetComponentWorldPosition(CAR_WING_RF, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if(Damage.ApplyDamage(COMPONENT_PANEL_FRONT_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_PANEL_FRONT_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetPanelDamage(CAR_WING_RF, VEHPANEL_FRONT_RIGHT);
- doubleMoney = true;
- }
break;
case CAR_PIECE_WING_LR:
GetComponentWorldPosition(CAR_WING_LR, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if(Damage.ApplyDamage(COMPONENT_PANEL_REAR_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_PANEL_REAR_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetPanelDamage(CAR_WING_LR, VEHPANEL_REAR_LEFT);
- doubleMoney = true;
- }
break;
case CAR_PIECE_WING_RR:
GetComponentWorldPosition(CAR_WING_RR, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if(Damage.ApplyDamage(COMPONENT_PANEL_REAR_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_PANEL_REAR_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetPanelDamage(CAR_WING_RR, VEHPANEL_REAR_RIGHT);
- doubleMoney = true;
- }
break;
case CAR_PIECE_WHEEL_LF:
@@ -3364,37 +4178,43 @@ CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece)
uint8 oldStatus = Damage.GetPanelStatus(VEHPANEL_WINDSCREEN);
SetPanelDamage(CAR_WINDSCREEN, VEHPANEL_WINDSCREEN);
if(oldStatus != Damage.GetPanelStatus(VEHPANEL_WINDSCREEN)){
- DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_WINDSHIELD_CRACK, 0.0f);
- doubleMoney = true;
+ // DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_WINDSHIELD_CRACK, 0.0f);
}
}
break;
}
-
- if(m_pDamageEntity && m_pDamageEntity == FindPlayerVehicle() && impulse > 10.0f){
- int money = (doubleMoney ? 2 : 1) * impulse*pHandling->nMonetaryValue/1000000.0f;
- money = Min(money, 40);
- if(money > 2){
- sprintf(gString, "$%d", money);
- CWorld::Players[CWorld::PlayerInFocus].m_nMoney += money;
- }
- }
}
- float damage = (impulse-25.0f)*pHandling->fCollisionDamageMultiplier*0.6f*damageMultiplier;
+ float damage = (impulse-minImpulse)*pHandling->fCollisionDamageMultiplier*0.6f*damageMultiplier;
if(GetModelIndex() == MI_SECURICA && m_pDamageEntity && m_pDamageEntity->GetStatus() == STATUS_PLAYER)
damage *= 7.0f;
+ if(GetModelIndex() == MI_RCGOBLIN || GetModelIndex() == MI_RCRAIDER)
+ damage *= 30.0f;
+
if(damage > 0.0f){
+ if(damage > 5.0f &&
+ pDriver &&
+ m_pDamageEntity && m_pDamageEntity->IsVehicle() &&
+ (this != FindPlayerVehicle() || ((CVehicle*)m_pDamageEntity)->VehicleCreatedBy == MISSION_VEHICLE) &&
+ ((CVehicle*)m_pDamageEntity)->pDriver){
+// TODO(MIAMI)
+// if(GetVehicleAppearance() == VEHICLE_APPEARANCE_CAR)
+// pDriver->Say(145);
+// else
+// pDriver->Say(144);
+ }
+
int oldHealth = m_fHealth;
- if(this == FindPlayerVehicle()){
+ if(this == FindPlayerVehicle())
m_fHealth -= bTakeLessDamage ? damage/6.0f : damage/2.0f;
- }else{
- if(damage > 35.0f && pDriver)
- pDriver->Say(SOUND_PED_CAR_COLLISION);
- m_fHealth -= bTakeLessDamage ? damage/12.0f : damage/4.0f;
- }
+ else if(bTakeLessDamage)
+ m_fHealth -= damage/12.0f;
+ else if(m_pDamageEntity && m_pDamageEntity == FindPlayerVehicle())
+ m_fHealth -= damage/1.5f;
+ else
+ m_fHealth -= damage/4.0f;
if(m_fHealth <= 0.0f && oldHealth > 0)
m_fHealth = 1.0f;
}
@@ -3469,15 +4289,16 @@ CAutomobile::dmgDrawCarCollidingParticles(const CVector &pos, float amount)
void
CAutomobile::AddDamagedVehicleParticles(void)
{
+ int i, n;
+
if(this == FindPlayerVehicle() && TheCamera.GetLookingForwardFirstPerson())
return;
-
- uint8 engineStatus = Damage.GetEngineStatus();
- if(engineStatus < ENGINE_STATUS_STEAM1)
+ if(this != FindPlayerVehicle() && (CTimer::GetFrameCounter() + m_randomSeed) & 1)
+ return;
+ if(m_fHealth >= 650.0f)
return;
- float fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward()) * 180.0f;
- CVector direction = 0.5f*m_vecMoveSpeed;
+ CVector direction = 0.85f*m_vecMoveSpeed;
CVector damagePos = ((CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()))->m_positions[CAR_POS_HEADLIGHTS];
switch(Damage.GetDoorStatus(DOOR_BONNET)){
@@ -3495,26 +4316,72 @@ CAutomobile::AddDamagedVehicleParticles(void)
if(GetModelIndex() == MI_BFINJECT)
damagePos = CVector(0.3f, -1.5f, -0.1f);
-
+ else if(GetModelIndex() == MI_CADDY)
+ damagePos = CVector(0.6f, -1.0f, -0.25f);
+ else if(IsRealHeli()){
+ damagePos.x = 0.4f*GetColModel()->boundingBox.max.x;
+ damagePos.y = 0.2f*GetColModel()->boundingBox.min.y;
+ damagePos.z = 0.3f*GetColModel()->boundingBox.max.z;
+ }else
+ damagePos.z += 0.4f*(GetColModel()->boundingBox.max.z-damagePos.z) * DotProduct(GetForward(), m_vecMoveSpeed);
damagePos = GetMatrix()*damagePos;
damagePos.z += 0.15f;
- if(engineStatus < ENGINE_STATUS_STEAM2){
- if(fwdSpeed < 90.0f){
- direction.z += 0.05f;
- CParticle::AddParticle(PARTICLE_ENGINE_STEAM, damagePos, direction, nil, 0.1f);
- }
- }else if(engineStatus < ENGINE_STATUS_SMOKE){
- if(fwdSpeed < 90.0f)
- CParticle::AddParticle(PARTICLE_ENGINE_STEAM, damagePos, direction, nil, 0.0f);
- }else if(engineStatus < ENGINE_STATUS_ON_FIRE){
- if(fwdSpeed < 90.0f){
- CParticle::AddParticle(PARTICLE_ENGINE_STEAM, damagePos, direction, nil, 0.0f);
- CParticle::AddParticle(PARTICLE_ENGINE_SMOKE, damagePos, 0.3f*direction, nil, 0.0f);
- }
- }else if(m_fHealth > 250.0f){
- if(fwdSpeed < 90.0f)
- CParticle::AddParticle(PARTICLE_ENGINE_SMOKE2, damagePos, 0.2f*direction, nil, 0.0f);
+ bool electric = pHandling->Transmission.nEngineType == 'E';
+
+ if(electric && m_fHealth < 320.0f && m_fHealth > 1.0f){
+ direction = 0.85f*m_vecMoveSpeed;
+ direction += GetRight() * CGeneral::GetRandomNumberInRange(0.0f, 0.04f) * (1.0f - 2.0f*m_vecMoveSpeed.Magnitude());
+ direction.z += 0.001f;
+ n = (CGeneral::GetRandomNumber() & 7) + 2;
+ for(i = 0; i < n; i++)
+ CParticle::AddParticle(PARTICLE_SPARK_SMALL, damagePos, direction);
+ if(((CTimer::GetFrameCounter() + m_randomSeed) & 7) == 0)
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE2, damagePos, 0.8f*m_vecMoveSpeed, nil, 0.1f, 0, 0, 0, 1000);
+ }else if(electric && m_fHealth < 460.0f){
+ direction = 0.85f*m_vecMoveSpeed;
+ direction += GetRight() * CGeneral::GetRandomNumberInRange(0.0f, 0.04f) * (1.0f - 2.0f*m_vecMoveSpeed.Magnitude());
+ direction.z += 0.001f;
+ n = (CGeneral::GetRandomNumber() & 3) + 2;
+ for(i = 0; i < n; i++)
+ CParticle::AddParticle(PARTICLE_SPARK_SMALL, damagePos, direction);
+ if(((CTimer::GetFrameCounter() + m_randomSeed) & 0xF) == 0)
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE, damagePos, 0.8f*m_vecMoveSpeed, nil, 0.1f, 0, 0, 0, 1000);
+ }else if(m_fHealth < 250.0f){
+ // nothing
+ }else if(m_fHealth < 320.0f){
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE2, damagePos, 0.8f*direction);
+ }else if(m_fHealth < 390.0f){
+ CParticle::AddParticle(PARTICLE_ENGINE_STEAM, damagePos, 0.75f*direction);
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE, damagePos, 0.85f*direction);
+ }else if(m_fHealth < 460.0f){
+ int rnd = CTimer::GetFrameCounter() + m_randomSeed;
+ if(rnd < 10 ||
+ rnd < 70 && rnd > 25 ||
+ rnd < 160 && rnd > 100 ||
+ rnd < 200 && rnd > 175 ||
+ rnd > 235)
+ return;
+ direction.z += 0.05f*Max(1.0f - 1.6f*m_vecMoveSpeed.Magnitude(), 0.0f);
+ if(electric){
+ // BUG. we had that case already
+ direction = 0.85f*m_vecMoveSpeed;
+ direction += GetRight() * CGeneral::GetRandomNumberInRange(0.0f, 0.04f) * (1.0f - 2.0f*m_vecMoveSpeed.Magnitude());
+ direction.z += 0.001f;
+ n = (CGeneral::GetRandomNumber() & 2) + 2;
+ for(i = 0; i < n; i++)
+ CParticle::AddParticle(PARTICLE_SPARK_SMALL, damagePos, direction);
+ if(((CTimer::GetFrameCounter() + m_randomSeed) & 0xF) == 0)
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE, damagePos, 0.8f*m_vecMoveSpeed, nil, 0.1f, 0, 0, 0, 1000);
+ }else{
+ if(TheCamera.GetLookDirection() != LOOKING_FORWARD)
+ CParticle::AddParticle(PARTICLE_ENGINE_STEAM, damagePos, 0.75f*direction);
+ else if(((CTimer::GetFrameCounter() + m_randomSeed) & 1) == 0)
+ CParticle::AddParticle(PARTICLE_ENGINE_STEAM, damagePos, 0.85f*m_vecMoveSpeed);
+ }
+ }else if(((CTimer::GetFrameCounter() + m_randomSeed) & 3) == 0 ||
+ ((CTimer::GetFrameCounter() + m_randomSeed) & 3) == 2){
+ CParticle::AddParticle(PARTICLE_ENGINE_STEAM, damagePos, 0.9f*direction);
}
}
@@ -3524,11 +4391,13 @@ CAutomobile::AddWheelDirtAndWater(CColPoint *colpoint, uint32 belowEffectSpeed)
int i;
CVector dir;
static RwRGBA grassCol = { 8, 24, 8, 255 };
- static RwRGBA dirtCol = { 64, 64, 64, 255 };
- static RwRGBA dirttrackCol = { 64, 32, 16, 255 };
+ static RwRGBA gravelCol = { 64, 64, 64, 255 };
+ static RwRGBA mudCol = { 64, 32, 16, 255 };
+ static RwRGBA sandCol = { 170, 165, 140, 255 };
static RwRGBA waterCol = { 48, 48, 64, 0 };
- if(!belowEffectSpeed)
+ if(!belowEffectSpeed &&
+ colpoint->surfaceB != SURFACE_SAND && colpoint->surfaceB != SURFACE_SAND_BEACH)
return 0;
switch(colpoint->surfaceB){
@@ -3547,7 +4416,7 @@ CAutomobile::AddWheelDirtAndWater(CColPoint *colpoint, uint32 belowEffectSpeed)
for(i = 0; i < 4; i++){
dir.z = CGeneral::GetRandomNumberInRange(0.03f, 0.06f);
CParticle::AddParticle(PARTICLE_WHEEL_DIRT, colpoint->point, dir, nil,
- CGeneral::GetRandomNumberInRange(0.02f, 0.06f), dirtCol);
+ CGeneral::GetRandomNumberInRange(0.05f, 0.09f), gravelCol);
}
return 1;
case SURFACE_MUD_DRY:
@@ -3556,7 +4425,20 @@ CAutomobile::AddWheelDirtAndWater(CColPoint *colpoint, uint32 belowEffectSpeed)
for(i = 0; i < 4; i++){
dir.z = CGeneral::GetRandomNumberInRange(0.03f, 0.06f);
CParticle::AddParticle(PARTICLE_WHEEL_DIRT, colpoint->point, dir, nil,
- CGeneral::GetRandomNumberInRange(0.02f, 0.06f), dirttrackCol);
+ CGeneral::GetRandomNumberInRange(0.02f, 0.06f), mudCol);
+ }
+ return 0;
+ case SURFACE_SAND:
+ case SURFACE_SAND_BEACH:
+ if(CTimer::GetFrameCounter() & 2 ||
+ CGeneral::GetRandomNumberInRange(CWeather::WetRoads, 1.01f) > 0.5f)
+ return 0;
+ dir.x = 0.5f*m_vecMoveSpeed.x;
+ dir.y = 0.5f*m_vecMoveSpeed.y;
+ for(i = 0; i < 1; i++){
+ dir.z = CGeneral::GetRandomNumberInRange(0.02f, 0.055f);
+ CParticle::AddParticle(PARTICLE_SAND, colpoint->point, dir, nil,
+ 2.0f*m_vecMoveSpeed.Magnitude(), sandCol);
}
return 0;
default:
@@ -3573,11 +4455,7 @@ CAutomobile::AddWheelDirtAndWater(CColPoint *colpoint, uint32 belowEffectSpeed)
PARTICLE_WATERSPRAY,
#endif
colpoint->point + CVector(0.0f, 0.0f, 0.25f+0.25f),
-#ifdef PC_PARTICLE
- CVector(0.0f, 0.0f, 1.0f),
-#else
CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(0.005f, 0.04f)),
-#endif
nil,
CGeneral::GetRandomNumberInRange(0.1f, 0.5f), waterCol);
return 0;
@@ -3693,6 +4571,7 @@ inline void ProcessDoorOpenCloseAnimation(CAutomobile *car, uint32 component, eD
car->OpenDoor(component, door, 0.0f);
}
}
+
void
CAutomobile::ProcessOpenDoor(uint32 component, uint32 anim, float time)
{
@@ -3713,13 +4592,13 @@ CAutomobile::ProcessOpenDoor(uint32 component, uint32 anim, float time)
case ANIM_CAR_QJACK:
case ANIM_CAR_OPEN_LHS:
case ANIM_CAR_OPEN_RHS:
- ProcessDoorOpenAnimation(this, component, door, time, 0.66f, 0.8f);
+ ProcessDoorOpenAnimation(this, component, door, time, 0.41f, 0.89f);
break;
case ANIM_CAR_CLOSEDOOR_LHS:
case ANIM_CAR_CLOSEDOOR_LOW_LHS:
case ANIM_CAR_CLOSEDOOR_RHS:
case ANIM_CAR_CLOSEDOOR_LOW_RHS:
- ProcessDoorCloseAnimation(this, component, door, time, 0.2f, 0.63f);
+ ProcessDoorCloseAnimation(this, component, door, time, 0.2f, 0.45f);
break;
case ANIM_CAR_ROLLDOOR:
case ANIM_CAR_ROLLDOOR_LOW:
@@ -3798,6 +4677,41 @@ CAutomobile::IsDoorMissing(eDoors door)
return Damage.GetDoorStatus(door) == DOOR_STATUS_MISSING;
}
+bool
+CAutomobile::IsDoorReady(uint32 door)
+{
+ switch(door){
+ case CAR_DOOR_RF: return IsDoorReady(DOOR_FRONT_RIGHT);
+ case CAR_DOOR_RR: return IsDoorReady(DOOR_REAR_RIGHT);
+ case CAR_DOOR_LF: return IsDoorReady(DOOR_FRONT_LEFT);
+ case CAR_DOOR_LR: return IsDoorReady(DOOR_REAR_LEFT);
+ default:
+ return false;
+ }
+}
+
+bool
+CAutomobile::IsDoorMissing(uint32 door)
+{
+ switch(door){
+ case CAR_DOOR_RF: return IsDoorMissing(DOOR_FRONT_RIGHT);
+ case CAR_DOOR_RR: return IsDoorMissing(DOOR_REAR_RIGHT);
+ case CAR_DOOR_LF: return IsDoorMissing(DOOR_FRONT_LEFT);
+ case CAR_DOOR_LR: return IsDoorMissing(DOOR_REAR_LEFT);
+ default:
+ return false;
+ }
+}
+
+bool
+CAutomobile::IsOpenTopCar(void)
+{
+ return GetModelIndex() == MI_STINGER ||
+ // component 0 is assumed to be a roof
+ GetModelIndex() == MI_COMET && m_aExtras[0] != 0 && m_aExtras[1] != 0 ||
+ GetModelIndex() == MI_STALLION && m_aExtras[0] != 0 && m_aExtras[1] != 0;
+}
+
void
CAutomobile::RemoveRefsToVehicle(CEntity *ent)
{
@@ -3810,12 +4724,17 @@ CAutomobile::RemoveRefsToVehicle(CEntity *ent)
void
CAutomobile::BlowUpCar(CEntity *culprit)
{
- int i;
RpAtomic *atomic;
if(!bCanBeDamaged)
return;
+ if(culprit == FindPlayerPed() || culprit == FindPlayerVehicle()){
+ CWorld::Players[CWorld::PlayerInFocus].m_nHavocLevel += 20;
+ CWorld::Players[CWorld::PlayerInFocus].m_fMediaAttention += 10.0f;
+ CStats::PropertyDestroyed += CGeneral::GetRandomNumber()%6000 + 4000;
+ }
+
// explosion pushes vehicle up
m_vecMoveSpeed.z += 0.13f;
SetStatus(STATUS_WRECKED);
@@ -3845,27 +4764,7 @@ CAutomobile::BlowUpCar(CEntity *culprit)
TheCamera.CamShake(0.7f, GetPosition().x, GetPosition().y, GetPosition().z);
- // kill driver and passengers
- if(pDriver){
- CDarkel::RegisterKillByPlayer(pDriver, WEAPONTYPE_EXPLOSION);
- if(pDriver->GetPedState() == PED_DRIVING){
- pDriver->SetDead();
- if(!pDriver->IsPlayer())
- pDriver->FlagToDestroyWhenNextProcessed();
- }else
- pDriver->SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f);
- }
- for(i = 0; i < m_nNumMaxPassengers; i++){
- if(pPassengers[i]){
- CDarkel::RegisterKillByPlayer(pPassengers[i], WEAPONTYPE_EXPLOSION);
- if(pPassengers[i]->GetPedState() == PED_DRIVING){
- pPassengers[i]->SetDead();
- if(!pPassengers[i]->IsPlayer())
- pPassengers[i]->FlagToDestroyWhenNextProcessed();
- }else
- pPassengers[i]->SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f);
- }
- }
+ KillPedsInVehicle();
bEngineOn = false;
bLightsOn = false;
@@ -3895,6 +4794,10 @@ CAutomobile::SetUpWheelColModel(CColModel *colModel)
CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
CColModel *vehColModel = mi->GetColModel();
+ if(GetVehicleAppearance() == VEHICLE_APPEARANCE_HELI ||
+ GetVehicleAppearance() == VEHICLE_APPEARANCE_PLANE)
+ return false;
+
colModel->boundingSphere = vehColModel->boundingSphere;
colModel->boundingBox = vehColModel->boundingBox;
@@ -3923,16 +4826,23 @@ CAutomobile::SetUpWheelColModel(CColModel *colModel)
void
CAutomobile::BurstTyre(uint8 wheel, bool applyForces)
{
+ if(GetModelIndex() == MI_RHINO || bTyresDontBurst)
+ return;
+
switch(wheel){
case CAR_PIECE_WHEEL_LF: wheel = VEHWHEEL_FRONT_LEFT; break;
case CAR_PIECE_WHEEL_LR: wheel = VEHWHEEL_REAR_LEFT; break;
case CAR_PIECE_WHEEL_RF: wheel = VEHWHEEL_FRONT_RIGHT; break;
case CAR_PIECE_WHEEL_RR: wheel = VEHWHEEL_REAR_RIGHT; break;
+ default: assert(0 && "invalid wheel");
}
int status = Damage.GetWheelStatus(wheel);
if(status == WHEEL_STATUS_OK){
Damage.SetWheelStatus(wheel, WHEEL_STATUS_BURST);
+ CStats::TyresPopped++;
+// TODO(MIAMI)
+// DMAudio.PlayOneShot(m_audioEntityId, SOUND_15, 0.0f);
if(GetStatus() == STATUS_SIMPLE){
SetStatus(STATUS_PHYSICS);
@@ -4019,13 +4929,7 @@ CAutomobile::PlayCarHorn(void)
{
int r;
- if (m_nAlarmState && m_nAlarmState != -1)
- return;
-
- if (GetStatus() == STATUS_WRECKED)
- return;
-
- if(m_nCarHornTimer != 0)
+ if (IsAlarmOn() || m_nCarHornTimer != 0)
return;
if (m_nCarHornDelay) {
@@ -4056,7 +4960,6 @@ CAutomobile::PlayHornIfNecessary(void)
PlayCarHorn();
}
-
void
CAutomobile::ResetSuspension(void)
{
@@ -4099,8 +5002,8 @@ CAutomobile::SetupSuspensionLines(void)
}
// Compress spring somewhat to get normal height on road
- m_fHeightAboveRoad = -(colModel->lines[0].p0.z + (colModel->lines[0].p1.z - colModel->lines[0].p0.z)*
- (1.0f - 1.0f/(8.0f*pHandling->fSuspensionForceLevel)));
+ m_fHeightAboveRoad = m_aSuspensionSpringLength[0]*(1.0f - 1.0f/(4.0f*pHandling->fSuspensionForceLevel))
+ - colModel->lines[0].p0.z + mi->m_wheelScale*0.5f;
for(i = 0; i < 4; i++)
m_aWheelPosition[i] = mi->m_wheelScale*0.5f - m_fHeightAboveRoad;
@@ -4139,8 +5042,11 @@ CAutomobile::BlowUpCarsInPath(void)
if(m_aCollisionRecords[i] &&
m_aCollisionRecords[i]->IsVehicle() &&
m_aCollisionRecords[i]->GetModelIndex() != MI_RHINO &&
- !m_aCollisionRecords[i]->bRenderScorched)
+ !m_aCollisionRecords[i]->bRenderScorched){
+ if(this == FindPlayerVehicle())
+ CEventList::RegisterEvent(EVENT_EXPLOSION, EVENT_ENTITY_VEHICLE, this, FindPlayerPed(), 2000);
((CVehicle*)m_aCollisionRecords[i])->BlowUpCar(this);
+ }
}
bool
@@ -4242,6 +5148,27 @@ CAutomobile::ProcessSwingingDoor(int32 component, eDoors door)
mat.SetRotate(axes[0], axes[1], axes[2]);
mat.Translate(pos);
mat.UpdateRW();
+
+ // make wind rip off bonnet
+ if(door == DOOR_BONNET && Doors[door].m_nDoorState == DOORST_OPEN &&
+ DotProduct(m_vecMoveSpeed, GetForward()) > 0.4f){
+#ifdef FIX_BUGS
+ CObject *comp = SpawnFlyingComponent(CAR_BONNET, COMPGROUP_BONNET);
+#else
+ CObject *comp = SpawnFlyingComponent(CAR_BONNET, COMPGROUP_DOOR);
+#endif
+ // make both doors invisible on car
+ SetComponentVisibility(m_aCarNodes[CAR_BONNET], ATOMIC_FLAG_NONE);
+ Damage.SetDoorStatus(DOOR_BONNET, DOOR_STATUS_MISSING);
+
+ if(comp){
+ if(CGeneral::GetRandomNumber() & 1)
+ comp->m_vecMoveSpeed = 0.4f*m_vecMoveSpeed + 0.1f*GetRight() + 0.5f*GetUp();
+ else
+ comp->m_vecMoveSpeed = 0.4f*m_vecMoveSpeed - 0.1f*GetRight() + 0.5f*GetUp();
+ comp->ApplyTurnForce(10.0f*GetUp(), GetForward());
+ }
+ }
}
void
@@ -4268,6 +5195,19 @@ CAutomobile::Fix(void)
mat.UpdateRW();
}
}
+
+ for(component = 0; component < 4; component++)
+ Damage.SetWheelStatus(component, WHEEL_STATUS_OK);
+
+ if(GetModelIndex() == MI_HUNTER){
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LB]), 0);
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RB]), 0);
+ }else if(IsRealHeli()){
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]), 0);
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]), 0);
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LB]), 0);
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RB]), 0);
+ }
}
void
@@ -4309,8 +5249,6 @@ GetCurrentAtomicObjectCB(RwObject *object, void *data)
return object;
}
-static CColPoint aTempPedColPts[MAX_COLLISION_POINTS];
-
CObject*
CAutomobile::SpawnFlyingComponent(int32 component, uint32 type)
{
@@ -4343,6 +5281,7 @@ CAutomobile::SpawnFlyingComponent(int32 component, uint32 type)
case COMPGROUP_DOOR:
obj->SetModelIndexNoCreate(MI_CAR_DOOR);
obj->SetCenterOfMass(0.0f, -0.5f, 0.0f);
+ obj->bDrawLast = true;
break;
case COMPGROUP_BONNET:
obj->SetModelIndexNoCreate(MI_CAR_BONNET);
@@ -4369,6 +5308,7 @@ CAutomobile::SpawnFlyingComponent(int32 component, uint32 type)
RpAtomicSetFrame(atomic, frame);
CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
obj->AttachToRwObject((RwObject*)atomic);
+ obj->bDontStream = true;
// init object
obj->m_fMass = 10.0f;
@@ -4415,7 +5355,7 @@ CAutomobile::SpawnFlyingComponent(int32 component, uint32 type)
dist += GetUp();
if(GetUp().z > 0.0f){
// simulate fast upward movement if going fast
- float speed = CVector2D(m_vecMoveSpeed).MagnitudeSqr();
+ float speed = CVector2D(m_vecMoveSpeed).Magnitude();
obj->GetMatrix().Translate(GetUp()*speed);
}
}
@@ -4427,9 +5367,16 @@ CAutomobile::SpawnFlyingComponent(int32 component, uint32 type)
obj->m_fAirResistance = 0.99f;
}
+ if(GetStatus() == STATUS_WRECKED && IsVisible() && DotProduct(dist, TheCamera.GetPosition() - GetPosition()) > -0.5f){
+ dist = TheCamera.GetPosition() - GetPosition();
+ dist.Normalise();
+ dist.z += 0.3f;
+ ApplyMoveForce(5.0f*dist);
+ }
+
if(CCollision::ProcessColModels(obj->GetMatrix(), *obj->GetColModel(),
this->GetMatrix(), *this->GetColModel(),
- aTempPedColPts, nil, nil) > 0)
+ CWorld::m_aTempColPts, nil, nil) > 0)
obj->m_pCollidingEntity = this;
if(bRenderScorched)
@@ -4447,8 +5394,11 @@ CAutomobile::RemoveBonnetInPedCollision(void)
if(Damage.GetDoorStatus(DOOR_BONNET) == DOOR_STATUS_SWINGING &&
Doors[DOOR_BONNET].RetAngleWhenOpen()*0.4f < Doors[DOOR_BONNET].m_fAngle){
- // BUG? why not COMPGROUP_BONNET?
+#ifdef FIX_BUGS
+ obj = SpawnFlyingComponent(CAR_BONNET, COMPGROUP_BONNET);
+#else
obj = SpawnFlyingComponent(CAR_BONNET, COMPGROUP_DOOR);
+#endif
// make both doors invisible on car
SetComponentVisibility(m_aCarNodes[CAR_BONNET], ATOMIC_FLAG_NONE);
Damage.SetDoorStatus(DOOR_BONNET, DOOR_STATUS_MISSING);
@@ -4464,11 +5414,15 @@ CAutomobile::SetPanelDamage(int32 component, ePanels panel, bool noFlyingCompone
if(m_aCarNodes[component] == nil)
return;
if(status == PANEL_STATUS_SMASHED1){
+// TODO(MIAMI)
+// DMAudio.PlayOneShot(m_audioEntityId, SOUND_12, 0.0f);
// show damaged part
SetComponentVisibility(m_aCarNodes[component], ATOMIC_FLAG_DAM);
}else if(status == PANEL_STATUS_MISSING){
if(!noFlyingComponents)
SpawnFlyingComponent(component, COMPGROUP_PANEL);
+ else
+ CGlass::CarWindscreenShatters(this, false);
// hide both
SetComponentVisibility(m_aCarNodes[component], ATOMIC_FLAG_NONE);
}
@@ -4504,18 +5458,26 @@ CAutomobile::SetDoorDamage(int32 component, eDoors door, bool noFlyingComponents
return;
}
+ if(!CanDoorsBeDamaged() && status > DOOR_STATUS_SMASHED && door != DOOR_BONNET && door != DOOR_BOOT){
+ Damage.SetDoorStatus(door, DOOR_STATUS_SMASHED);
+ status = DOOR_STATUS_SMASHED;
+ }
+
if(door == DOOR_BOOT && status == DOOR_STATUS_SWINGING && pHandling->Flags & HANDLING_NOSWING_BOOT){
Damage.SetDoorStatus(DOOR_BOOT, DOOR_STATUS_MISSING);
status = DOOR_STATUS_MISSING;
}
- if(status == DOOR_STATUS_SMASHED){
+ switch(status){
+ case DOOR_STATUS_SMASHED:
// show damaged part
SetComponentVisibility(m_aCarNodes[component], ATOMIC_FLAG_DAM);
- }else if(status == DOOR_STATUS_SWINGING){
+ break;
+ case DOOR_STATUS_SWINGING:
// turn off angle cull for swinging doors
RwFrameForAllObjects(m_aCarNodes[component], CVehicleModelInfo::SetAtomicFlagCB, (void*)ATOMIC_FLAG_NOCULL);
- }else if(status == DOOR_STATUS_MISSING){
+ break;
+ case DOOR_STATUS_MISSING:
if(!noFlyingComponents){
if(door == DOOR_BONNET)
SpawnFlyingComponent(component, COMPGROUP_BONNET);
@@ -4526,6 +5488,7 @@ CAutomobile::SetDoorDamage(int32 component, eDoors door, bool noFlyingComponents
}
// hide both
SetComponentVisibility(m_aCarNodes[component], ATOMIC_FLAG_NONE);
+ break;
}
}
@@ -4605,7 +5568,112 @@ CAutomobile::TellHeliToGoToCoors(float x, float y, float z, uint8 speed)
AutoPilot.m_vecDestinationCoors.z = z;
AutoPilot.m_nCruiseSpeed = speed;
SetStatus(STATUS_PHYSICS);
- //TODO(MIAMI)
+
+ if(m_fOrientation == 0.0f){
+ m_fOrientation = CGeneral::GetATanOfXY(GetForward().x, GetForward().y) + TWOPI;
+ while(m_fOrientation > TWOPI) m_fOrientation -= TWOPI;
+ }
+}
+
+void
+CAutomobile::TellPlaneToGoToCoors(float x, float y, float z, uint8 speed)
+{
+ AutoPilot.m_nCarMission = MISSION_HELI_FLYTOCOORS;
+ AutoPilot.m_vecDestinationCoors.x = x;
+ AutoPilot.m_vecDestinationCoors.y = y;
+ AutoPilot.m_vecDestinationCoors.z = z;
+ AutoPilot.m_nCruiseSpeed = speed;
+ SetStatus(STATUS_PHYSICS);
+
+ if(m_fOrientation == 0.0f)
+ m_fOrientation = CGeneral::GetATanOfXY(GetForward().x, GetForward().y);
+}
+
+void
+CAutomobile::PopBoot(void)
+{
+ switch(Damage.GetDoorStatus(DOOR_BOOT)){
+ case DOOR_STATUS_OK:
+ case DOOR_STATUS_SMASHED:
+ Doors[DOOR_BOOT].m_fAngle = Doors[DOOR_BOOT].m_fMinAngle;
+ CMatrix mat(RwFrameGetMatrix(m_aCarNodes[DOOR_BOOT]));
+ CVector pos = mat.GetPosition();
+ float axes[3] = { 0.0f, 0.0f, 0.0f };
+ axes[Doors[DOOR_BOOT].m_nAxis] = Doors[DOOR_BOOT].m_fAngle;
+ mat.SetRotate(axes[0], axes[1], axes[2]);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ }
+}
+
+void
+CAutomobile::PopBootUsingPhysics(void)
+{
+ switch(Damage.GetDoorStatus(DOOR_BOOT))
+ case DOOR_STATUS_OK:
+ case DOOR_STATUS_SMASHED:
+ Damage.SetDoorStatus(DOOR_BOOT, DOOR_STATUS_SWINGING);
+ Doors[DOOR_BOOT].m_fAngle = -2.0f;
+}
+
+void
+CAutomobile::CloseAllDoors(void)
+{
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+ if(!IsDoorMissing(DOOR_FRONT_LEFT))
+ OpenDoor(CAR_DOOR_LF, DOOR_FRONT_LEFT, 0.0f);
+ if(mi->m_numDoors > 1){
+ if(!IsDoorMissing(DOOR_FRONT_RIGHT))
+ OpenDoor(CAR_DOOR_RF, DOOR_FRONT_RIGHT, 0.0f);
+ if(mi->m_numDoors > 2){
+ if(!IsDoorMissing(DOOR_REAR_LEFT))
+ OpenDoor(CAR_DOOR_LR, DOOR_REAR_LEFT, 0.0f);
+ if(!IsDoorMissing(DOOR_REAR_RIGHT))
+ OpenDoor(CAR_DOOR_RR, DOOR_REAR_RIGHT, 0.0f);
+ }
+ }
+}
+
+void
+CAutomobile::KnockPedOutCar(eWeaponType weapon, uint16 door, CPed *ped)
+{
+ AnimationId anim = ANIM_KO_SHOT_FRONT1;
+ if(ped == nil)
+ return;
+
+ ped->m_vehEnterType = door;
+ ped->SetPedState(PED_IDLE);
+ CAnimManager::BlendAnimation(ped->GetClump(), ped->m_animGroup, ANIM_IDLE_STANCE, 100.0f);
+ CPed::PedSetOutCarCB(nil, ped);
+ ped->SetMoveState(PEDMOVE_STILL);
+ if(GetUp().z < 0.0f)
+ ped->SetHeading(CGeneral::LimitRadianAngle(GetForward().Heading() + PI));
+ else
+ ped->SetHeading(GetForward().Heading());
+
+ switch(weapon){
+ case WEAPONTYPE_UNARMED:
+ case WEAPONTYPE_UNIDENTIFIED:
+ ped->m_vecMoveSpeed = m_vecMoveSpeed;
+ ped->m_pCollidingEntity = this;
+ anim = NUM_STD_ANIMS;
+ break;
+
+ case WEAPONTYPE_BASEBALLBAT:
+ case WEAPONTYPE_RAMMEDBYCAR:
+ case WEAPONTYPE_FALL:
+ ped->m_vecMoveSpeed = m_vecMoveSpeed;
+ anim = ANIM_KD_LEFT;
+ ApplyMoveForce(4.0f*GetUp() + 8.0f*GetRight());
+ break;
+ }
+
+ if(weapon != WEAPONTYPE_UNARMED){
+ ped->SetFall(1000, anim, 0);
+ ped->bIsStanding = false;
+ ped->m_headingRate = 0.0f;
+ }
+ ped->m_pMyVehicle = nil;
}
#ifdef COMPATIBLE_SAVES
diff --git a/src/vehicles/Automobile.h b/src/vehicles/Automobile.h
index 883177aa..9d24d237 100644
--- a/src/vehicles/Automobile.h
+++ b/src/vehicles/Automobile.h
@@ -3,6 +3,7 @@
#include "Vehicle.h"
#include "DamageManager.h"
#include "Door.h"
+#include "Skidmarks.h"
class CObject;
@@ -69,7 +70,6 @@ enum {
class CAutomobile : public CVehicle
{
public:
- // 0x288
CDamageManager Damage;
CDoor Doors[6];
RwFrame *m_aCarNodes[NUM_CAR_NODES];
@@ -77,23 +77,24 @@ public:
float m_aSuspensionSpringRatio[4];
float m_aSuspensionSpringRatioPrev[4];
float m_aWheelTimer[4]; // set to 4.0 when wheel is touching ground, then decremented
- float field_49C;
- bool m_aWheelSkidmarkMuddy[4];
+ float m_auto_unused1;
+ eSkidmarkType m_aWheelSkidmarkType[4];
bool m_aWheelSkidmarkBloody[4];
+ bool m_aWheelSkidmarkUnk[4];
float m_aWheelRotation[4];
float m_aWheelPosition[4];
float m_aWheelSpeed[4];
- float m_fRotorSpeed;
- uint8 field_4D8;
+ uint8 m_auto_unused2;
uint8 bTaxiLight : 1;
- //uint8 bHadDriver : 1; // for bombs
uint8 bFixedColour : 1;
uint8 bBigWheels : 1;
uint8 bWaterTight : 1; // no damage for non-player peds
uint8 bNotDamagedUpsideDown : 1;
uint8 bMoreResistantToDamage : 1;
uint8 bTankDetonateCars : 1;
- int16 field_4E0;
+ uint8 bStuckInSand : 1;
+ uint8 bHeliDestroyed : 1;
+ int16 m_doingBurnout;
uint16 m_hydraulicState;
uint32 m_nBusDoorTimerEnd;
uint32 m_nBusDoorTimerStart;
@@ -101,6 +102,9 @@ public:
float m_aSuspensionLineLength[4];
float m_fHeightAboveRoad;
float m_fTraction;
+ float m_fTireTemperature;
+ float m_fOrientation; // for heli and plane go-to
+ float m_auto_unk4; // related to the above
float m_fVelocityChangeForAudio;
float m_randomValues[6]; // used for what?
float m_fFireBlowUpTimer;
@@ -111,6 +115,7 @@ public:
float m_weaponDoorTimerRight;
float m_fCarGunLR;
float m_fCarGunUD;
+ float m_fHeliOrientation;
float m_fPropellerRotation;
uint8 stuff4[4];
uint8 m_nWheelsOnGround;
@@ -144,6 +149,9 @@ public:
bool IsDoorFullyOpen(eDoors door);
bool IsDoorClosed(eDoors door);
bool IsDoorMissing(eDoors door);
+ bool IsDoorReady(uint32 door);
+ bool IsDoorMissing(uint32 door);
+ bool IsOpenTopCar(void);
void RemoveRefsToVehicle(CEntity *ent);
void BlowUpCar(CEntity *ent);
bool SetUpWheelColModel(CColModel *colModel);
@@ -158,6 +166,7 @@ public:
void VehicleDamage(float impulse, uint16 damagedPiece);
void ProcessBuoyancy(void);
void DoDriveByShootings(void);
+ void DoHoverSuspensionRatios(void);
int32 RcbanditCheckHitWheels(void);
int32 RcbanditCheck1CarWheels(CPtrList &list);
void PlaceOnRoadProperly(void);
@@ -181,6 +190,9 @@ public:
void SetDoorDamage(int32 component, eDoors door, bool noFlyingComponents = false);
void TellHeliToGoToCoors(float x, float y, float z, uint8 speed);
+ void TellPlaneToGoToCoors(float x, float y, float z, uint8 speed);
+ void SetHeliOrientation(float orient) { m_fHeliOrientation = orient; }
+ void ClearHeliOrientation(void) { m_fHeliOrientation = -1.0f; }
void Fix(void);
void SetComponentVisibility(RwFrame *frame, uint32 flags);
@@ -190,6 +202,12 @@ public:
void HideAllComps(void);
void ShowAllComps(void);
void ReduceHornCounter(void);
+
+ void PopBoot(void);
+ void PopBootUsingPhysics(void);
+ void CloseAllDoors(void);
+ void KnockPedOutCar(eWeaponType weapon, uint16 door, CPed *ped);
+
#ifdef COMPATIBLE_SAVES
virtual void Save(uint8*& buf);
virtual void Load(uint8*& buf);
diff --git a/src/vehicles/DamageManager.cpp b/src/vehicles/DamageManager.cpp
index 6b59ccda..e4c28c95 100644
--- a/src/vehicles/DamageManager.cpp
+++ b/src/vehicles/DamageManager.cpp
@@ -10,14 +10,20 @@ float G_aComponentDamage[] = { 2.5f, 1.25f, 3.2f, 1.4f, 2.5f, 2.8f, 0.5f };
CDamageManager::CDamageManager(void)
{
ResetDamageStatus();
- m_fWheelDamageEffect = 0.75f;
- field_24 = 1;
+ m_fWheelDamageEffect = 0.5f;
+ field_18 = 1;
}
void
CDamageManager::ResetDamageStatus(void)
{
- memset(this, 0, sizeof(*this));
+ int i;
+ m_fWheelDamageEffect = 0.0f;
+ m_engineStatus = 0;
+ for(i = 0; i < ARRAY_SIZE(m_wheelStatus); i++) m_wheelStatus[i] = 0;
+ for(i = 0; i < ARRAY_SIZE(m_doorStatus); i++) m_doorStatus[i] = 0;
+ m_lightStatus = 0;
+ m_panelStatus = 0;
}
void
@@ -28,12 +34,8 @@ CDamageManager::FuckCarCompletely(void)
m_wheelStatus[0] = WHEEL_STATUS_MISSING;
// wheels 1-3 not reset?
- m_doorStatus[0] = DOOR_STATUS_MISSING;
- m_doorStatus[1] = DOOR_STATUS_MISSING;
- m_doorStatus[2] = DOOR_STATUS_MISSING;
- m_doorStatus[3] = DOOR_STATUS_MISSING;
- m_doorStatus[4] = DOOR_STATUS_MISSING;
- m_doorStatus[5] = DOOR_STATUS_MISSING;
+ for(i = 0; i < ARRAY_SIZE(m_doorStatus); i++)
+ m_doorStatus[i] = DOOR_STATUS_MISSING;
for(i = 0; i < 3; i++){
#ifdef FIX_BUGS
@@ -59,6 +61,8 @@ CDamageManager::ApplyDamage(tComponent component, float damage, float unused)
GetComponentGroup(component, &group, &subComp);
damage *= G_aComponentDamage[group];
+ if(component == COMPONENT_PANEL_WINDSCREEN)
+ damage *= 0.6f;
if(damage > 150.0f){
switch(group){
case COMPGROUP_WHEEL:
@@ -222,10 +226,6 @@ CDamageManager::GetEngineStatus(void)
bool
CDamageManager::ProgressEngineDamage(void)
{
- int status = GetEngineStatus();
- int newstatus = status + 32 + (CGeneral::GetRandomNumber() & 0x1F);
- if(status < ENGINE_STATUS_ON_FIRE && newstatus > ENGINE_STATUS_ON_FIRE-1)
- newstatus = ENGINE_STATUS_ON_FIRE-1;
- SetEngineStatus(newstatus);
- return true;
+ // gone in VC
+ return false;
}
diff --git a/src/vehicles/DamageManager.h b/src/vehicles/DamageManager.h
index bf0c59a1..312006e3 100644
--- a/src/vehicles/DamageManager.h
+++ b/src/vehicles/DamageManager.h
@@ -86,7 +86,7 @@ public:
uint8 m_doorStatus[6];
uint32 m_lightStatus;
uint32 m_panelStatus;
- uint32 field_24;
+ uint8 field_18;
CDamageManager(void);
diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp
index 7e4ff2fe..88f15ffd 100644
--- a/src/vehicles/Vehicle.cpp
+++ b/src/vehicles/Vehicle.cpp
@@ -41,6 +41,8 @@ bool CVehicle::bCheat5;
#ifdef ALT_DODO_CHEAT
bool CVehicle::bAltDodoCheat;
#endif
+bool CVehicle::bHoverCheat;
+bool CVehicle::bAllTaxisHaveNitro;
bool CVehicle::m_bDisableMouseSteering = true;
bool CVehicle::bDisableRemoteDetonation;
bool CVehicle::bDisableRemoteDetonationOnContact;
@@ -125,7 +127,7 @@ CVehicle::CVehicle(uint8 CreatedBy)
bCreatedAsPoliceVehicle = false;
bRestingOnPhysical = false;
bParking = false;
- bCanPark = CGeneral::GetRandomNumberInRange(0.0f, 1.0f) < 0.0f; // BUG? this makes no sense
+ bCanPark = CGeneral::GetRandomNumberInRange(0.0f, 1.0f) < 0.0f; // never true. probably doesn't work very well
bIsVan = false;
bIsBus = false;
bIsBig = false;
@@ -344,7 +346,7 @@ CVehicle::FlyingControl(eFlightModel flightModel)
// thrust
float fForwSpeed = DotProduct(GetMoveSpeed(), GetForward());
- CVector vecWidthForward = GetColModel()->boundingBox.min.y * GetForward();
+ CVector vecTail = GetColModel()->boundingBox.min.y * GetForward();
float fThrust = (CPad::GetPad(0)->GetAccelerate() - CPad::GetPad(0)->GetBrake()) / 255.0f;
float fThrustAccel;
if(fForwSpeed > 0.0f || fThrust > 0.0f)
@@ -362,9 +364,9 @@ CVehicle::FlyingControl(eFlightModel flightModel)
float fSideSlipAccel = pFlyingHandling->fSideSlip * fSideSpeed * Abs(fSideSpeed);
ApplyMoveForce(m_fMass * GetRight() * fSideSlipAccel * CTimer::GetTimeStep());
- float fYaw = -DotProduct(GetSpeed(vecWidthForward), GetRight());
+ float fYaw = -DotProduct(GetSpeed(vecTail), GetRight());
float fYawAccel = pFlyingHandling->fYawStab * fYaw * Abs(fYaw) + pFlyingHandling->fYaw * fSteerLR * fForwSpeed;
- ApplyTurnForce(fYawAccel * GetRight() * m_fTurnMass * CTimer::GetTimeStep(), vecWidthForward);
+ ApplyTurnForce(fYawAccel * GetRight() * m_fTurnMass * CTimer::GetTimeStep(), vecTail);
float fRollAccel;
if (flightModel == FLIGHT_MODEL_RCPLANE) {
@@ -384,9 +386,9 @@ CVehicle::FlyingControl(eFlightModel flightModel)
ApplyTurnForce(fStabiliseSpeed * m_fTurnMass * GetRight(), GetUp()); // no CTimer::GetTimeStep(), is it right?
// up/down
- float fTail = -DotProduct(GetSpeed(vecWidthForward), GetUp());
+ float fTail = -DotProduct(GetSpeed(vecTail), GetUp());
float fPitchAccel = pFlyingHandling->fPitchStab * fTail * Abs(fTail) + pFlyingHandling->fPitch * fSteerUD * fForwSpeed;
- ApplyTurnForce(fPitchAccel * m_fTurnMass * GetUp() * CTimer::GetTimeStep(), vecWidthForward);
+ ApplyTurnForce(fPitchAccel * m_fTurnMass * GetUp() * CTimer::GetTimeStep(), vecTail);
float fLift = -DotProduct(GetMoveSpeed(), GetUp()) / Max(0.01f, GetMoveSpeed().Magnitude());
float fLiftAccel = (pFlyingHandling->fAttackLift * fLift + pFlyingHandling->fFormLift) * fForwSpeed * fForwSpeed;
@@ -554,7 +556,7 @@ CVehicle::DoBladeCollision(CVector pos, CMatrix &matrix, int16 rotorType, float
rotorColModel.numSpheres = 1;
pos = matrix * pos;
- bool hadCollision;
+ bool hadCollision = false;
int minX = CWorld::GetSectorIndexX(pos.x - radius);
if(minX <= 0) minX = 0;
@@ -655,7 +657,7 @@ CVehicle::BladeColSectorList(CPtrList &list, CColModel &rotorColModel, CMatrix &
if(entity->IsPed())
entityCol = ((CPedModelInfo*)CModelInfo::GetModelInfo(entity->GetModelIndex()))->AnimatePedColModelSkinned(entity->GetClump());
else
- entityCol = CModelInfo::GetModelInfo(entity->GetModelIndex())->GetColModel();
+ entityCol = entity->GetColModel();
if(entityCol)
numCollisions = CCollision::ProcessColModels(matrix, rotorColModel, entity->GetMatrix(), *entityCol,
CWorld::m_aTempColPts, nil, nil);
@@ -690,10 +692,12 @@ CVehicle::BladeColSectorList(CPtrList &list, CColModel &rotorColModel, CMatrix &
CVector localColpos = colpos - center;
float axisDir = DotProduct(axis, localColpos);
float colDir = DotProduct(CWorld::m_aTempColPts[i].normal, localColpos);
+
if(2.0f*ROTOR_SEMI_THICKNESS < Abs(axisDir) &&
ROTOR_DISGUARD_MULT*Abs(colDir) < Abs(axisDir))
continue;
+ hadCollision = true;
colpos -= axisDir*axis; // get rid of axis component
CVector tangentSpeed = CrossProduct(turnSpeed, colpos - center);
@@ -707,19 +711,18 @@ CVehicle::BladeColSectorList(CPtrList &list, CColModel &rotorColModel, CMatrix &
// Apply Collision
if(IsCar()){
CAutomobile *heli = (CAutomobile*)this;
- if(heli->m_fRotorSpeed > 0.15f){
+ if(heli->m_aWheelSpeed[1] > 0.15f){
ApplyCollision(CWorld::m_aTempColPts[i], impulse);
ApplyTurnForce(m_fTurnMass*ROTOR_COL_TURNMULT*tangentSpeed, colpos - center);
- heli->m_fRotorSpeed = 0.15f;
- }else if(heli->m_fRotorSpeed < 0.075f && heli->m_fRotorSpeed > 0.0f)
- heli->m_fRotorSpeed *= -1.0f;
+ heli->m_aWheelSpeed[1] = 0.15f;
+ }else if(heli->m_aWheelSpeed[1] < 0.075f && heli->m_aWheelSpeed[1] > 0.0f)
+ heli->m_aWheelSpeed[1] *= -1.0f;
}
float damageImpulse = damageMult * Max(impulse, ROTOR_DEFAULT_DAMAGE*m_fMass/3000.0f);
if(damageImpulse > m_fDamageImpulse)
SetDamagedPieceRecord(0, damageImpulse, entity, CWorld::m_aTempColPts[i].normal);
- hadCollision = true;
}
if(hadCollision && !entity->IsPed())
@@ -1395,7 +1398,7 @@ CVehicle::ShufflePassengersToMakeSpace(void)
return false;
if (pPassengers[1] &&
!(m_nGettingInFlags & CAR_DOOR_FLAG_LR) &&
- IsRoomForPedToLeaveCar(COMPONENT_DOOR_REAR_LEFT, nil)) {
+ IsRoomForPedToLeaveCar(CAR_DOOR_LR, nil)) {
if (!pPassengers[2] && !(m_nGettingInFlags & CAR_DOOR_FLAG_RR)) {
pPassengers[2] = pPassengers[1];
pPassengers[1] = nil;
@@ -1412,7 +1415,7 @@ CVehicle::ShufflePassengersToMakeSpace(void)
}
if (pPassengers[2] &&
!(m_nGettingInFlags & CAR_DOOR_FLAG_RR) &&
- IsRoomForPedToLeaveCar(COMPONENT_DOOR_REAR_RIGHT, nil)) {
+ IsRoomForPedToLeaveCar(CAR_DOOR_RR, nil)) {
if (!pPassengers[1] && !(m_nGettingInFlags & CAR_DOOR_FLAG_LR)) {
pPassengers[1] = pPassengers[2];
pPassengers[2] = nil;
@@ -1429,7 +1432,7 @@ CVehicle::ShufflePassengersToMakeSpace(void)
}
if (pPassengers[0] &&
!(m_nGettingInFlags & CAR_DOOR_FLAG_RF) &&
- IsRoomForPedToLeaveCar(COMPONENT_DOOR_FRONT_RIGHT, nil)) {
+ IsRoomForPedToLeaveCar(CAR_DOOR_RF, nil)) {
if (!pPassengers[1] && !(m_nGettingInFlags & CAR_DOOR_FLAG_LR)) {
pPassengers[1] = pPassengers[0];
pPassengers[0] = nil;
@@ -1581,9 +1584,8 @@ CVehicle::CarHasRoof(void)
{
if((pHandling->Flags & HANDLING_HAS_NO_ROOF) == 0)
return true;
- if(m_aExtras[0] && m_aExtras[1])
- return false;
- return true;
+ // component 0 is assumed to be a roof
+ return m_aExtras[0] == 0 || m_aExtras[1] == 0;
}
bool
@@ -1713,6 +1715,15 @@ CVehicle::CanPedExitCar(bool jumpExit)
}
bool
+CVehicle::CanPedJumpOutCar(void)
+{
+ if(GetUp().z < 0.3f)
+ return false;
+ float speed = m_vecMoveSpeed.MagnitudeSqr();
+ return speed < 0.1f || speed > 0.5f ? false : true;
+}
+
+bool
CVehicle::CanPedJumpOffBike(void)
{
if(pPassengers[0])
@@ -1977,7 +1988,7 @@ CVehicle::ProcessCarAlarm(void)
{
uint32 step;
- if(m_nAlarmState == 0 || m_nAlarmState == -1)
+ if(!IsAlarmOn())
return;
step = CTimer::GetTimeStepInMilliseconds();
@@ -2268,6 +2279,32 @@ CVehicle::DoSunGlare(void)
}
void
+CVehicle::KillPedsInVehicle(void)
+{
+ int i;
+ if(pDriver){
+ CDarkel::RegisterKillByPlayer(pDriver, WEAPONTYPE_EXPLOSION);
+ if(pDriver->GetPedState() == PED_DRIVING){
+ pDriver->SetDead();
+ if(!pDriver->IsPlayer())
+ pDriver->FlagToDestroyWhenNextProcessed();
+ }else
+ pDriver->SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f);
+ }
+ for(i = 0; i < m_nNumMaxPassengers; i++){
+ if(pPassengers[i]){
+ CDarkel::RegisterKillByPlayer(pPassengers[i], WEAPONTYPE_EXPLOSION);
+ if(pPassengers[i]->GetPedState() == PED_DRIVING){
+ pPassengers[i]->SetDead();
+ if(!pPassengers[i]->IsPlayer())
+ pPassengers[i]->FlagToDestroyWhenNextProcessed();
+ }else
+ pPassengers[i]->SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f);
+ }
+ }
+}
+
+void
DestroyVehicleAndDriverAndPassengers(CVehicle* pVehicle)
{
if (pVehicle->pDriver) {
diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h
index 083a8a15..87ee928c 100644
--- a/src/vehicles/Vehicle.h
+++ b/src/vehicles/Vehicle.h
@@ -276,7 +276,7 @@ public:
virtual void BlowUpCar(CEntity *ent) {}
virtual bool SetUpWheelColModel(CColModel *colModel) { return false; }
virtual void BurstTyre(uint8 tyre, bool applyForces) {}
- virtual bool IsRoomForPedToLeaveCar(uint32 component, CVector *forcedDoorPos) { return false;}
+ virtual bool IsRoomForPedToLeaveCar(uint32 component, CVector *forcedDoorPos) { return false; }
virtual bool IsClearToDriveAway(void);
virtual float GetHeightAboveRoad(void);
virtual void PlayCarHorn(void) {}
@@ -317,6 +317,7 @@ public:
bool CanDoorsBeDamaged(void);
bool CanPedEnterCar(void);
bool CanPedExitCar(bool jumpExit);
+ bool CanPedJumpOutCar(void);
bool CanPedJumpOffBike(void);
// do these two actually return something?
CPed *SetUpDriver(void);
@@ -340,6 +341,7 @@ public:
void FireFixedMachineGuns(void);
void ActivateBomb(void);
void ActivateBombWhenEntered(void);
+ void KillPedsInVehicle(void);
void SetComponentAtomicAlpha(RpAtomic *atomic, int32 alpha);
void UpdateClumpAlpha(void);
@@ -347,11 +349,12 @@ public:
static void HeliDustGenerate(CEntity *heli, float radius, float ground, int rnd);
void DoSunGlare(void);
- bool IsAlarmOn(void) { return m_nAlarmState != 0 && m_nAlarmState != -1; }
+ bool IsAlarmOn(void) { return m_nAlarmState != 0 && m_nAlarmState != -1 && GetStatus() != STATUS_WRECKED; }
CVehicleModelInfo* GetModelInfo() { return (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()); }
bool IsTaxi(void) { return GetModelIndex() == MI_TAXI || GetModelIndex() == MI_CABBIE || GetModelIndex() == MI_ZEBRA || GetModelIndex() == MI_KAUFMAN; }
bool IsLimo(void) { return GetModelIndex() == MI_STRETCH || GetModelIndex() == MI_LOVEFIST; }
bool IsRealHeli(void) { return !!(pHandling->Flags & HANDLING_IS_HELI); }
+ bool IsRealPlane(void) { return !!(pHandling->Flags & HANDLING_IS_PLANE); }
static bool bWheelsOnlyCheat;
static bool bAllDodosCheat;
@@ -361,6 +364,8 @@ public:
#ifdef ALT_DODO_CHEAT
static bool bAltDodoCheat;
#endif
+ static bool bHoverCheat;
+ static bool bAllTaxisHaveNitro;
static bool m_bDisableMouseSteering;
static bool bDisableRemoteDetonation;
static bool bDisableRemoteDetonationOnContact;
diff --git a/src/weapons/Explosion.cpp b/src/weapons/Explosion.cpp
index d0a68279..f4ad346d 100644
--- a/src/weapons/Explosion.cpp
+++ b/src/weapons/Explosion.cpp
@@ -86,7 +86,7 @@ CExplosion::GetExplosionPosition(uint8 id)
}
bool
-CExplosion::AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type, const CVector &pos, uint32 lifetime)
+CExplosion::AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type, const CVector &pos, uint32 lifetime, bool unk)
{
CVector pPosn;
CVector posGround;
diff --git a/src/weapons/Explosion.h b/src/weapons/Explosion.h
index bf54328c..c8539cca 100644
--- a/src/weapons/Explosion.h
+++ b/src/weapons/Explosion.h
@@ -40,7 +40,8 @@ public:
static void ResetExplosionActiveCounter(uint8 id);
static uint8 GetExplosionType(uint8 id);
static CVector *GetExplosionPosition(uint8 id);
- static bool AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type, const CVector &pos, uint32 lifetime);
+// TODO(MIAMI): that new parameter
+ static bool AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type, const CVector &pos, uint32 lifetime, bool unk = true);
static void Update();
static bool TestForExplosionInArea(eExplosionType type, float x1, float x2, float y1, float y2, float z1, float z2);
static void RemoveAllExplosionsInArea(CVector pos, float radius);
diff --git a/src/weapons/Weapon.cpp b/src/weapons/Weapon.cpp
index 0ac37e31..b2ac2ad2 100644
--- a/src/weapons/Weapon.cpp
+++ b/src/weapons/Weapon.cpp
@@ -113,6 +113,18 @@ CWeapon::UpdateWeapons(void)
CBulletInfo::Update();
}
+//--MIAMI: done
+CWeapon::CWeapon(eWeaponType type, int32 ammo)
+{
+ m_eWeaponType = type;
+ m_eWeaponState = WEAPONSTATE_READY;
+ m_nAmmoTotal = Min(ammo, 99999);
+ m_nAmmoInClip = 0;
+ Reload();
+ m_nTimer = 0;
+ m_bAddRotOffset = false;
+}
+
// --MIAMI: Done
void
CWeapon::Initialise(eWeaponType type, int32 ammo)
diff --git a/src/weapons/Weapon.h b/src/weapons/Weapon.h
index b4ed93c3..8680fdcf 100644
--- a/src/weapons/Weapon.h
+++ b/src/weapons/Weapon.h
@@ -25,6 +25,7 @@ public:
CWeapon() {
m_bAddRotOffset = false;
}
+ CWeapon(eWeaponType type, int32 ammo);
CWeaponInfo *GetInfo();