summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/animation/AnimBlendAssociation.cpp4
-rw-r--r--src/animation/AnimBlendHierarchy.cpp2
-rw-r--r--src/audio/AudioManager.cpp1329
-rw-r--r--src/audio/AudioManager.h66
-rw-r--r--src/audio/DMAudio.h3
-rw-r--r--src/control/PathFind.cpp10
-rw-r--r--src/control/Population.h3
-rw-r--r--src/control/Replay.cpp38
-rw-r--r--src/control/Script.cpp6
-rw-r--r--src/core/Camera.cpp10
-rw-r--r--src/core/Camera.h2
-rw-r--r--src/core/CdStream.cpp4
-rw-r--r--src/core/Collision.cpp8
-rw-r--r--src/core/EventList.cpp2
-rw-r--r--src/core/Explosion.cpp24
-rw-r--r--src/core/Explosion.h9
-rw-r--r--src/core/Frontend.cpp2
-rw-r--r--src/core/Game.cpp2
-rw-r--r--src/core/Instance.h1
-rw-r--r--src/core/Pad.cpp4
-rw-r--r--src/core/Placeable.cpp2
-rw-r--r--src/core/Streaming.cpp42
-rw-r--r--src/core/Wanted.cpp2
-rw-r--r--src/core/common.h9
-rw-r--r--src/core/main.cpp2
-rw-r--r--src/core/re3.cpp26
-rw-r--r--src/core/re3.cpp.autosave483
-rw-r--r--src/entities/Physical.cpp40
-rw-r--r--src/peds/Ped.cpp12
-rw-r--r--src/peds/Ped.h9
-rw-r--r--src/peds/PedPlacement.cpp4
-rw-r--r--src/peds/PlayerPed.cpp8
-rw-r--r--src/peds/PlayerPed.cpp.autosave110
-rw-r--r--src/render/Clouds.cpp8
-rw-r--r--src/render/Coronas.cpp20
-rw-r--r--src/render/Lights.cpp28
-rw-r--r--src/render/ParticleMgr.cpp2
-rw-r--r--src/render/PointLights.cpp2
-rw-r--r--src/render/Shadows.cpp28
-rw-r--r--src/render/Timecycle.cpp6
-rw-r--r--src/render/WaterLevel.cpp12
-rw-r--r--src/vehicles/Automobile.cpp46
-rw-r--r--src/vehicles/Automobile.cpp.autosave4560
-rw-r--r--src/vehicles/Boat.cpp2
-rw-r--r--src/vehicles/Heli.cpp8
-rw-r--r--src/vehicles/Heli.cpp.autosave1055
-rw-r--r--src/vehicles/Plane.cpp8
-rw-r--r--src/vehicles/Plane.cpp.autosave985
-rw-r--r--src/vehicles/Vehicle.cpp8
49 files changed, 8804 insertions, 252 deletions
diff --git a/src/animation/AnimBlendAssociation.cpp b/src/animation/AnimBlendAssociation.cpp
index d94fe2c1..7273c846 100644
--- a/src/animation/AnimBlendAssociation.cpp
+++ b/src/animation/AnimBlendAssociation.cpp
@@ -185,7 +185,7 @@ CAnimBlendAssociation::UpdateBlend(float timeDelta)
if(blendAmount <= 0.0f && blendDelta < 0.0f){
// We're faded out and are not fading in
blendAmount = 0.0f;
- blendDelta = max(0.0, blendDelta);
+ blendDelta = Max(0.0, blendDelta);
if(flags & ASSOC_DELETEFADEDOUT){
if(callbackType == CB_FINISH || callbackType == CB_DELETE)
callback(this, callbackArg);
@@ -197,7 +197,7 @@ CAnimBlendAssociation::UpdateBlend(float timeDelta)
if(blendAmount > 1.0f){
// Maximally faded in, clamp values
blendAmount = 1.0f;
- blendDelta = min(0.0, blendDelta);
+ blendDelta = Min(0.0, blendDelta);
}
return true;
diff --git a/src/animation/AnimBlendHierarchy.cpp b/src/animation/AnimBlendHierarchy.cpp
index e4bcdc69..e594e5d8 100644
--- a/src/animation/AnimBlendHierarchy.cpp
+++ b/src/animation/AnimBlendHierarchy.cpp
@@ -36,7 +36,7 @@ CAnimBlendHierarchy::CalcTotalTime(void)
float seqTime = 0.0f;
for(j = 0; j < sequences[i].numFrames; j++)
seqTime += sequences[i].GetKeyFrame(j)->deltaTime;
- totalTime = max(totalTime, seqTime);
+ totalTime = Max(totalTime, seqTime);
}
totalLength = totalTime;
}
diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp
index e586366d..76bfb793 100644
--- a/src/audio/AudioManager.cpp
+++ b/src/audio/AudioManager.cpp
@@ -6,6 +6,7 @@
#include "Automobile.h"
#include "Camera.h"
#include "DMAudio.h"
+#include "Explosion.h"
#include "Garages.h"
#include "ModelIndices.h"
#include "MusicManager.h"
@@ -16,6 +17,7 @@
#include "Pools.h"
#include "sampman.h"
#include "Stats.h"
+#include "SurfaceTable.h"
#include "Vehicle.h"
#include "Plane.h"
#include "World.h"
@@ -96,10 +98,54 @@ enum eVehicleModel {
CAR159,
};
-void *cAudioScriptObject::operator new(size_t sz) { return CPools::GetAudioScriptObjectPool()->New(); }
-void *cAudioScriptObject::operator new(size_t sz, int handle) { return CPools::GetAudioScriptObjectPool()->New(handle); }
-void cAudioScriptObject::operator delete(void *p, size_t sz) { CPools::GetAudioScriptObjectPool()->Delete((cAudioScriptObject*)p); }
-void cAudioScriptObject::operator delete(void *p, int handle) { CPools::GetAudioScriptObjectPool()->Delete((cAudioScriptObject*)p); }
+void
+cPedComments::Add(tPedComment *com)
+{
+ uint8 index;
+
+ if(nrOfCommentsInBank[activeBank] >= 20u) {
+ index = field_1120[activeBank][19];
+ if(m_asPedComments[activeBank][index].m_bVolume > com->m_bVolume) return;
+ } else {
+ index = nrOfCommentsInBank[activeBank]++;
+ }
+ m_asPedComments[activeBank][index] = *com;
+
+ uint32 i = 0;
+ if(index != 0) {
+ for(i = 0; i < index; i++) {
+ if(m_asPedComments[activeBank][field_1120[activeBank][i]].m_bVolume <
+ m_asPedComments[activeBank][index].m_bVolume) {
+ memmove(&field_1120[activeBank][i + 1], &field_1120[activeBank][i],
+ 19 - i);
+ break;
+ }
+ }
+ }
+
+ field_1120[activeBank][i] = index;
+}
+
+void *
+cAudioScriptObject::operator new(size_t sz)
+{
+ return CPools::GetAudioScriptObjectPool()->New();
+}
+void *
+cAudioScriptObject::operator new(size_t sz, int handle)
+{
+ return CPools::GetAudioScriptObjectPool()->New(handle);
+}
+void
+cAudioScriptObject::operator delete(void *p, size_t sz)
+{
+ CPools::GetAudioScriptObjectPool()->Delete((cAudioScriptObject *)p);
+}
+void
+cAudioScriptObject::operator delete(void *p, int handle)
+{
+ CPools::GetAudioScriptObjectPool()->Delete((cAudioScriptObject *)p);
+}
cAudioManager &AudioManager = *(cAudioManager *)0x880FC0;
@@ -407,9 +453,9 @@ cAudioManager::ComputeDopplerEffectedFrequency(uint32 oldFreq, float position1,
float speedOfSource = (dist / field_19195) * speedMultiplier;
if(speedOfSound > fabsf(speedOfSource)) {
if(speedOfSource < 0.0f) {
- speedOfSource = max(speedOfSource, -1.5f);
+ speedOfSource = Max(speedOfSource, -1.5f);
} else {
- speedOfSource = min(speedOfSource, 1.5f);
+ speedOfSource = Min(speedOfSource, 1.5f);
}
newFreq = (oldFreq * speedOfSound) / (speedOfSource + speedOfSound);
}
@@ -830,7 +876,7 @@ cAudioManager::SetupJumboFlySound(uint8 emittingVol)
SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
m_sQueueSample.m_fSoundIntensity = 440.0f;
m_sQueueSample.field_56 = 0;
- m_sQueueSample.field_48 = 4.0;
+ m_sQueueSample.field_48 = 4.0f;
m_sQueueSample.m_bReverbFlag = 1;
m_sQueueSample.field_76 = 5;
m_sQueueSample.m_nLoopEnd =
@@ -861,8 +907,8 @@ cAudioManager::SetupJumboRumbleSound(uint8 emittingVol)
SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
m_sQueueSample.m_nLoopEnd =
SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
- m_sQueueSample.field_48 = 4.0;
- m_sQueueSample.m_fSoundIntensity = 240.0;
+ m_sQueueSample.field_48 = 4.0f;
+ m_sQueueSample.m_fSoundIntensity = 240.0f;
m_sQueueSample.field_56 = 0;
m_sQueueSample.field_76 = 12;
m_sQueueSample.m_bOffset = 0;
@@ -3729,7 +3775,6 @@ cAudioManager::ProcessAirBrakes(cVehicleParams *params)
void
cAudioManager::ProcessAirportScriptObject(uint8 sound)
{
-
float dist;
float distSquared;
float maxDist;
@@ -4002,68 +4047,68 @@ cAudioManager::ProcessEntity(int32 id)
case AUDIOTYPE_PHYSICAL:
if(!m_bUserPause) {
m_sQueueSample.m_bReverbFlag = 1;
- cAudioManager::ProcessPhysical(id);
+ ProcessPhysical(id);
}
break;
case AUDIOTYPE_EXPLOSION:
if(!m_bUserPause) {
m_sQueueSample.m_bReverbFlag = 1;
- cAudioManager::ProcessExplosions(id);
+ ProcessExplosions(id);
}
break;
case AUDIOTYPE_FIRE:
if(!m_bUserPause) {
m_sQueueSample.m_bReverbFlag = 1;
- cAudioManager::ProcessFires(id);
+ ProcessFires(id);
}
break;
case AUDIOTYPE_WEATHER:
if(!m_bUserPause) {
m_sQueueSample.m_bReverbFlag = 1;
- cAudioManager::ProcessWeather(id);
+ ProcessWeather(id);
}
break;
case AUDIOTYPE_CRANE:
if(!m_bUserPause) {
m_sQueueSample.m_bReverbFlag = 1;
- cAudioManager::ProcessCrane();
+ ProcessCrane();
}
break;
case AUDIOTYPE_SCRIPTOBJECT:
if(!m_bUserPause) {
m_sQueueSample.m_bReverbFlag = 1;
- cAudioManager::ProcessScriptObject(id);
+ ProcessScriptObject(id);
}
break;
case AUDIOTYPE_BRIDGE:
if(!m_bUserPause) {
m_sQueueSample.m_bReverbFlag = 1;
- cAudioManager::ProcessBridge();
+ ProcessBridge();
}
break;
case AUDIOTYPE_FRONTEND:
m_sQueueSample.m_bReverbFlag = 0;
- cAudioManager::ProcessFrontEnd();
+ ProcessFrontEnd();
break;
case AUDIOTYPE_PROJECTILE:
if(!m_bUserPause) {
m_sQueueSample.m_bReverbFlag = 1;
- cAudioManager::ProcessProjectiles();
+ ProcessProjectiles();
}
break;
case AUDIOTYPE_GARAGE:
- if(!m_bUserPause) cAudioManager::ProcessGarages();
+ if(!m_bUserPause) ProcessGarages();
break;
case AUDIOTYPE_FIREHYDRANT:
if(!m_bUserPause) {
m_sQueueSample.m_bReverbFlag = 1;
- cAudioManager::ProcessFireHydrant();
+ ProcessFireHydrant();
}
break;
case AUDIOTYPE_WATERCANNON:
if(!m_bUserPause) {
m_sQueueSample.m_bReverbFlag = 1;
- cAudioManager::ProcessWaterCannon(id);
+ ProcessWaterCannon(id);
}
break;
default: return;
@@ -4071,11 +4116,88 @@ cAudioManager::ProcessEntity(int32 id)
}
}
-WRAPPER
void
cAudioManager::ProcessExplosions(int32 explosion)
{
- EAXJMP(0x575AC0);
+ uint8 type;
+ CVector *pos;
+ float maxDist;
+ float distSquared;
+
+ for(uint8 i = 0; i < 48u; i++) {
+ if(CExplosion::GetExplosionActiveCounter(i) == 1) {
+ CExplosion::ResetExplosionActiveCounter(i);
+ type = CExplosion::GetExplosionType(i);
+ switch(type) {
+ case EXPLOSION_GRENADE:
+ case EXPLOSION_ROCKET:
+ case EXPLOSION_BARREL:
+ case EXPLOSION_TANK_GRENADE:
+ maxDist = 160000.f;
+ m_sQueueSample.m_fSoundIntensity = 400.0f;
+ m_sQueueSample.m_nSampleIndex =
+ AUDIO_SAMPLE_WEAPON_GRENADE_EXPLOSION;
+ m_sQueueSample.m_nFrequency = RandomDisplacement(2000u) + 38000;
+ m_sQueueSample.field_16 = 0;
+ m_sQueueSample.m_bBankIndex = 0;
+ break;
+ case EXPLOSION_MOLOTOV:
+ maxDist = 40000.f;
+ m_sQueueSample.m_fSoundIntensity = 200.0f;
+ m_sQueueSample.m_nSampleIndex =
+ AUDIO_SAMPLE_WEAPON_MOLOTOV_EXPLOSION;
+ m_sQueueSample.m_nFrequency = RandomDisplacement(1000u) + 19000;
+ m_sQueueSample.field_16 = 0;
+ m_sQueueSample.m_bBankIndex = 0;
+ break;
+ case EXPLOSION_MINE:
+ case EXPLOSION_HELI_BOMB:
+ maxDist = 90000.f;
+ m_sQueueSample.m_fSoundIntensity = 300.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_WEAPON_ROCKET_SHOT;
+ m_sQueueSample.m_nFrequency = RandomDisplacement(1000u) + 12347;
+ m_sQueueSample.field_16 = 0;
+ m_sQueueSample.m_bBankIndex = 0;
+ break;
+ default:
+ maxDist = 160000.f;
+ m_sQueueSample.m_fSoundIntensity = 400.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_EXPLOSION_CAR;
+ m_sQueueSample.m_nFrequency = RandomDisplacement(2000u) + 38000;
+ if(type == EXPLOSION_HELI)
+ m_sQueueSample.m_nFrequency =
+ 8 * m_sQueueSample.m_nFrequency / 10u;
+ m_sQueueSample.field_16 = 0;
+ m_sQueueSample.m_bBankIndex = 0;
+ break;
+ }
+ pos = CExplosion::GetExplosionPosition(i);
+ m_sQueueSample.m_vecPos.x = pos->x;
+ m_sQueueSample.m_vecPos.y = pos->y;
+ m_sQueueSample.m_vecPos.z = pos->z;
+ distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
+ if(distSquared < maxDist) {
+ m_sQueueSample.m_fDistance = Sqrt(distSquared);
+ m_sQueueSample.m_bVolume =
+ ComputeVolume(maxVolume, m_sQueueSample.m_fSoundIntensity,
+ m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.field_4 = i;
+ m_sQueueSample.field_48 = 2.0f;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.field_56 = 1;
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bEmittingVolume = maxVolume;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 1;
+ AddSampleToRequestedQueue();
+ }
+ }
+ }
+ }
}
void
@@ -5220,11 +5342,1001 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
}
}
-WRAPPER
void
-cAudioManager::ProcessPed(CPhysical *)
+cAudioManager::ProcessOneShotScriptObject(uint8 sound)
+{
+ CPlayerPed *playerPed;
+ uint8 emittingVolume;
+ float maxDist;
+ float distSquared;
+
+ cPedParams male;
+ cPedParams female;
+
+ static uint8 iSound = 0;
+
+ switch(sound) {
+ case SCRIPT_SOUND_INJURED_PED_MALE_OUCH_S:
+ case SCRIPT_SOUND_INJURED_PED_MALE_OUCH_L:
+ male.m_pPed = nil;
+ male.m_bDistanceCalculated = 0;
+ male.m_fDistance = GetDistanceSquared(&m_sQueueSample.m_vecPos);
+ cAudioManager::SetupPedComments(&male, SOUND_INJURED_PED_MALE_OUCH);
+ return;
+ case SCRIPT_SOUND_INJURED_PED_FEMALE_OUCH_S:
+ case SCRIPT_SOUND_INJURED_PED_FEMALE_OUCH_L:
+ female.m_pPed = nil;
+ female.m_bDistanceCalculated = 0;
+ female.m_fDistance = GetDistanceSquared(&m_sQueueSample.m_vecPos);
+ cAudioManager::SetupPedComments(&female, SOUND_INJURED_PED_FEMALE);
+ return;
+ case SCRIPT_SOUND_GATE_START_CLUNK:
+ case SCRIPT_SOUND_GATE_STOP_CLUNK:
+ maxDist = 1600.f;
+ m_sQueueSample.m_fSoundIntensity = 40.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_COLLISION_GATE;
+ m_sQueueSample.m_bBankIndex = 0;
+ if(sound == SCRIPT_SOUND_GATE_START_CLUNK)
+ m_sQueueSample.m_nFrequency = 10600;
+ else
+ m_sQueueSample.m_nFrequency = 9000;
+ m_sQueueSample.field_16 = 1;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_bRequireReflection = 1;
+ emittingVolume = RandomDisplacement(10u) + 50;
+ break;
+ case SCRIPT_SOUND_BULLET_HIT_GROUND_1:
+ case SCRIPT_SOUND_BULLET_HIT_GROUND_2:
+ case SCRIPT_SOUND_BULLET_HIT_GROUND_3:
+ maxDist = 2500.f;
+ m_sQueueSample.m_fSoundIntensity = 50.0f;
+ m_sQueueSample.m_nSampleIndex =
+ m_anRandomTable[iSound % 5] % 3u + AUDIO_SAMPLE_BULLET_HIT_GROUND_1;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
+ m_sQueueSample.field_16 = 9;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_bIsDistant = 0;
+ emittingVolume = m_anRandomTable[2] % 20 + 90;
+ break;
+ case SCRIPT_SOUND_110:
+ case SCRIPT_SOUND_111:
+ if(cSampleManager.IsSampleBankLoaded(0) != 1) return;
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_389;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_389);
+ m_sQueueSample.field_16 = 0;
+ m_sQueueSample.field_48 = 2.0f;
+ m_sQueueSample.m_bIsDistant = 0;
+ break;
+ case SCRIPT_SOUND_PAYPHONE_RINGING:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PAYPHONE_RINGING;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 80;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PAYPHONE_RINGING);
+ m_sQueueSample.field_16 = 1;
+ m_sQueueSample.field_48 = 2.0f;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_bRequireReflection = 0;
+ break;
+ case SCRIPT_SOUND_GLASS_BREAK_L:
+ maxDist = 3600.f;
+ m_sQueueSample.m_fSoundIntensity = 60.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_GLASS_GENERIC_BREAK;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 70;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_GLASS_GENERIC_BREAK);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_bIsDistant = 0;
+ break;
+ case SCRIPT_SOUND_GLASS_BREAK_S:
+ maxDist = 3600.f;
+ m_sQueueSample.m_fSoundIntensity = 60.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_GLASS_GENERIC_BREAK;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 60;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_GLASS_GENERIC_BREAK);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_bIsDistant = 0;
+ break;
+ case SCRIPT_SOUND_GLASS_CRACK:
+ maxDist = 3600.f;
+ m_sQueueSample.m_fSoundIntensity = 60.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_GLASS_WINDSHIELD_CRACK;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 70;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_GLASS_WINDSHIELD_CRACK);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_bRequireReflection = 1;
+ break;
+ case SCRIPT_SOUND_GLASS_LIGHT_BREAK:
+ maxDist = 3025.f;
+ m_sQueueSample.m_fSoundIntensity = 55.0f;
+ m_sQueueSample.m_nSampleIndex =
+ (m_anRandomTable[4] & 3) + AUDIO_SAMPLE_GLASS_LIGHT_BREAK_1;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_nFrequency = RandomDisplacement(2000u) + 19000;
+ m_sQueueSample.field_16 = 9;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_bIsDistant = 0;
+ emittingVolume = RandomDisplacement(11u) + 25;
+ break;
+ case SCRIPT_SOUND_BOX_DESTROYED_1:
+ maxDist = 3600.f;
+ m_sQueueSample.m_fSoundIntensity = 60.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_BOX_DESTROYED_1;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_nFrequency = RandomDisplacement(1500u) + 18600;
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_bRequireReflection = 1;
+ emittingVolume = m_anRandomTable[2] % 20 + 80;
+ break;
+ case SCRIPT_SOUND_BOX_DESTROYED_2:
+ maxDist = 3600.f;
+ m_sQueueSample.m_fSoundIntensity = 60.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_BOX_DESTROYED_2;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_nFrequency = RandomDisplacement(1500u) + 18600;
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_bRequireReflection = 1;
+ emittingVolume = m_anRandomTable[2] % 20 + 80;
+ break;
+ case SCRIPT_SOUND_METAL_COLLISION:
+ maxDist = 3600.f;
+ m_sQueueSample.m_fSoundIntensity = 60.0f;
+ m_sQueueSample.m_nSampleIndex =
+ m_anRandomTable[3] % 5u + AUDIO_SAMPLE_COLLISION_METAL;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency >> 4);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_bRequireReflection = 1;
+ emittingVolume = m_anRandomTable[2] % 30 + 70;
+ break;
+ case SCRIPT_SOUND_TIRE_COLLISION:
+ maxDist = 3600.f;
+ m_sQueueSample.m_fSoundIntensity = 60.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_COLLISION_RUBBER;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency >> 4);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_bRequireReflection = 1;
+ emittingVolume = m_anRandomTable[2] % 30 + 60;
+ break;
+ case SCRIPT_SOUND_GUNSHELL_DROP:
+ playerPed = FindPlayerPed();
+ if(playerPed) {
+ switch(playerPed->m_nSurfaceTouched) {
+ case SURFACE_GRASS:
+ case SURFACE_DIRT:
+ case SURFACE_DIRTTRACK:
+ case SURFACE_SCAFFOLD:
+ case SURFACE_FLESH:
+ case SURFACE_SAND:
+ case SURFACE_TIRE:
+ case SURFACE_HEDGE:
+ m_sQueueSample.m_nSampleIndex =
+ AUDIO_SAMPLE_BULLET_GUNSHELL_SOFT_DROP;
+ m_sQueueSample.m_nFrequency = RandomDisplacement(500u) + 11000;
+ m_sQueueSample.field_16 = 18;
+ maxDist = 400.f;
+ m_sQueueSample.m_fSoundIntensity = 20.0f;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_bIsDistant = 0;
+ emittingVolume = m_anRandomTable[2] % 20 + 30;
+ distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
+ if(distSquared < maxDist) {
+ m_sQueueSample.m_fDistance = Sqrt(distSquared);
+ m_sQueueSample.m_bVolume = ComputeVolume(
+ emittingVolume, m_sQueueSample.m_fSoundIntensity,
+ m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.field_4 = iSound++;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.field_56 = 1;
+ m_sQueueSample.m_bEmittingVolume = emittingVolume;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ m_sQueueSample.m_bReverbFlag = 1;
+ AddSampleToRequestedQueue();
+ }
+ }
+ return;
+ case SURFACE_PUDDLE: return;
+ default: break;
+ }
+ }
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_BULLET_GUNSHELL_HARD_DROP;
+ m_sQueueSample.m_nFrequency = RandomDisplacement(750u) + 18000;
+ m_sQueueSample.field_16 = 15;
+ maxDist = 400.f;
+ m_sQueueSample.m_fSoundIntensity = 20.0f;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_bIsDistant = 0;
+ emittingVolume = m_anRandomTable[2] % 20 + 30;
+ break;
+ case SCRIPT_SOUND_GUNSHELL_DROP_SOFT:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_BULLET_GUNSHELL_SOFT_DROP;
+ m_sQueueSample.m_nFrequency = RandomDisplacement(500u) + 11000;
+ m_sQueueSample.field_16 = 18;
+ maxDist = 400.f;
+ m_sQueueSample.m_fSoundIntensity = 20.0f;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_bIsDistant = 0;
+ emittingVolume = m_anRandomTable[2] % 20 + 30;
+ break;
+ default: return;
+ }
+
+ distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
+ if(distSquared < maxDist) {
+ m_sQueueSample.m_fDistance = Sqrt(distSquared);
+ m_sQueueSample.m_bVolume = ComputeVolume(
+ emittingVolume, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.field_4 = iSound++;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.field_56 = 1;
+ m_sQueueSample.m_bEmittingVolume = emittingVolume;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ m_sQueueSample.m_bReverbFlag = 1;
+ AddSampleToRequestedQueue();
+ }
+ }
+}
+
+void
+cAudioManager::ProcessPed(CPhysical *ped)
{
- EAXJMP(0x56F450);
+ cPedParams params;
+
+ params.m_pPed = 0;
+ params.m_bDistanceCalculated = 0;
+ params.m_fDistance = 0.0f;
+
+ m_sQueueSample.m_vecPos = ped->GetPosition();
+
+ params.m_bDistanceCalculated = 0;
+ params.m_pPed = (CPed *)ped;
+ params.m_fDistance = GetDistanceSquared(&m_sQueueSample.m_vecPos);
+ if(ped->m_modelIndex == MI_FATMALE02) ProcessPedHeadphones(&params);
+ ProcessPedOneShots(&params);
+}
+
+void
+cAudioManager::ProcessPedHeadphones(cPedParams *params)
+{
+ CPed *ped;
+ CVehicle *veh;
+ uint8 emittingVol;
+
+ if(params->m_fDistance < 49.f) {
+ ped = params->m_pPed;
+ if(!(ped->m_ped_flagA20) || ped->m_bodyPartBleeding != 2) {
+ CalculateDistance((bool *)params, params->m_fDistance);
+ if(ped->bInVehicle && ped->m_nPedState == PED_DRIVING) {
+ emittingVol = 10;
+ veh = ped->m_pMyVehicle;
+ if(veh && veh->m_type == 0) {
+ for(int32 i = 2; i < 6; i++) {
+ if(!veh->IsDoorClosed((eDoors)i) ||
+ veh->IsDoorMissing((eDoors)i)) {
+ emittingVol = 42;
+ break;
+ }
+ }
+ }
+ } else {
+ emittingVol = 42;
+ }
+
+ m_sQueueSample.m_bVolume =
+ ComputeVolume(emittingVol, 7.f, m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.field_4 = 64;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PED_HEADPHONES;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_16 = 5;
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ AUDIO_SAMPLE_PED_HEADPHONES);
+ m_sQueueSample.m_nLoopCount = 0;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_nLoopStart =
+ cSampleManager.GetSampleLoopStartOffset(
+ m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nLoopEnd = cSampleManager.GetSampleLoopEndOffset(
+ m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.field_48 = 4.0f;
+ m_sQueueSample.m_fSoundIntensity = 7.0f;
+ m_sQueueSample.field_56 = 0;
+ m_sQueueSample.field_76 = 5;
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ }
+ return;
+ }
+ }
+}
+
+void
+cAudioManager::ProcessPedOneShots(cPedParams *params)
+{
+ uint8 emittingVol;
+ int32 sampleIndex;
+
+ CPed *ped = params->m_pPed;
+
+ char processed;
+ int16 sound;
+ char noReflection;
+ CWeapon *weapon;
+ uint16 i;
+ float maxDist;
+
+ static uint8 iSound = 21;
+
+ i = 0;
+ weapon = nil;
+ while(i < m_asAudioEntities[m_sQueueSample.m_nEntityIndex].field_24) {
+ noReflection = 0;
+ processed = 0;
+ m_sQueueSample.m_bRequireReflection = 0;
+ sound = m_asAudioEntities[0].m_awAudioEvent[i + 20 * m_sQueueSample.m_nEntityIndex];
+ switch(sound) {
+ case SOUND_STEP_START:
+ case SOUND_STEP_END:
+ if(!params->m_pPed->bIsLooking) {
+ emittingVol = m_anRandomTable[3] % 15u + 45;
+ if(FindPlayerPed() !=
+ m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_pEntity)
+ emittingVol >>= 1;
+ maxDist = 400.f;
+ switch(params->m_pPed->m_nSurfaceTouched) {
+ case SURFACE_GRASS:
+ sampleIndex =
+ m_anRandomTable[1] % 5u + AUDIO_SAMPLE_PED_FALL_GRASS_1;
+ break;
+ case SURFACE_DIRT:
+ case SURFACE_DIRTTRACK:
+ sampleIndex =
+ m_anRandomTable[4] % 5u + AUDIO_SAMPLE_PED_FALL_DIRT_1;
+ break;
+ case SURFACE_METAL6:
+ case SURFACE_METAL_DOOR:
+ case SURFACE_BILLBOARD:
+ case SURFACE_STEEL:
+ case SURFACE_METAL_POLE:
+ case SURFACE_STREET_LIGHT:
+ case SURFACE_METAL14:
+ case SURFACE_METAL15:
+ case SURFACE_METAL_FENCE:
+ case SURFACE_METAL27:
+ case SURFACE_METAL28:
+ sampleIndex =
+ m_anRandomTable[0] % 5u + AUDIO_SAMPLE_PED_FALL_METAL_1;
+ break;
+ case SURFACE_SAND:
+ sampleIndex =
+ (m_anRandomTable[4] & 3) + AUDIO_SAMPLE_PED_FALL_SAND_1;
+ break;
+ case SURFACE_PUDDLE:
+ sampleIndex = (m_anRandomTable[3] & 3) +
+ AUDIO_SAMPLE_PED_FALL_IN_WATER_1;
+ break;
+ case SURFACE_WOOD:
+ case SURFACE_WOOD_BOX:
+ case SURFACE_WOOD_PLANK:
+ sampleIndex =
+ m_anRandomTable[2] % 5u + AUDIO_SAMPLE_PED_FALL_WOOD_1;
+ break;
+ case SURFACE_HEDGE:
+ sampleIndex =
+ m_anRandomTable[2] % 5u + AUDIO_SAMPLE_COLLISION_HEDGE;
+ break;
+ default:
+ sampleIndex = m_anRandomTable[2] % 5u +
+ AUDIO_SAMPLE_PED_FALL_PAVEMENT_1;
+ break;
+ }
+ m_sQueueSample.m_nSampleIndex = sampleIndex;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.field_4 =
+ m_asAudioEntities[0]
+ .m_awAudioEvent[i + 20 * m_sQueueSample.m_nEntityIndex] -
+ 28;
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nFrequency +=
+ RandomDisplacement(m_sQueueSample.m_nFrequency / 17u);
+ switch(params->m_pPed->m_nMoveState) {
+ case 2:
+ emittingVol >>= 2;
+ m_sQueueSample.m_nFrequency =
+ 9 * m_sQueueSample.m_nFrequency / 10u;
+ break;
+ case 3:
+ emittingVol >>= 1;
+ m_sQueueSample.m_nFrequency =
+ 11 * m_sQueueSample.m_nFrequency / 10u;
+ break;
+ case 4:
+ m_sQueueSample.m_nFrequency =
+ 12 * m_sQueueSample.m_nFrequency / 10u;
+ break;
+ default: break;
+ }
+ m_sQueueSample.field_16 = 5;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_fSoundIntensity = 20.0f;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_56 = 1;
+ m_sQueueSample.m_bRequireReflection = 1;
+ goto LABEL_84;
+ }
+ break;
+ case SOUND_FALL_LAND:
+ case SOUND_FALL_COLLAPSE:
+ if(!ped->bIsLooking) {
+ maxDist = 900.f;
+ emittingVol = m_anRandomTable[3] % 20 + 80;
+ if(ped->m_nSurfaceTouched == SURFACE_PUDDLE) {
+ m_sQueueSample.m_nSampleIndex =
+ (m_anRandomTable[3] & 3) +
+ AUDIO_SAMPLE_PED_FALL_IN_WATER_1;
+ } else if(sound == SOUND_FALL_LAND) {
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PED_FALL_LAND;
+ } else {
+ m_sQueueSample.m_nSampleIndex =
+ AUDIO_SAMPLE_PED_FALL_COLLAPSE;
+ }
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.field_4 = 1;
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nFrequency +=
+ RandomDisplacement(m_sQueueSample.m_nFrequency / 17u);
+ m_sQueueSample.field_16 = 2;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_56 = 1;
+ m_sQueueSample.m_bRequireReflection = 1;
+ goto LABEL_84;
+ }
+ break;
+ case SOUND_21:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PED_HIT_1;
+ m_sQueueSample.m_nFrequency = 18000;
+ goto LABEL_81;
+ case SOUND_22:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PED_HIT_1;
+ m_sQueueSample.m_nFrequency = 16500;
+ goto LABEL_81;
+ case SOUND_23:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PED_HIT_1;
+ goto LABEL_80;
+ case SOUND_24:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PED_HIT_2;
+ m_sQueueSample.m_nFrequency = 18000;
+ goto LABEL_81;
+ case SOUND_25:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PED_HIT_2;
+ m_sQueueSample.m_nFrequency = 16500;
+ goto LABEL_81;
+ case SOUND_26:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PED_HIT_2;
+ goto LABEL_80;
+ case SOUND_WEAPON_PUNCH_ATTACK:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PED_HIT_3;
+ m_sQueueSample.m_nFrequency = 18000;
+ goto LABEL_81;
+ case SOUND_28:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PED_HIT_3;
+ m_sQueueSample.m_nFrequency = 16500;
+ goto LABEL_81;
+ case SOUND_29:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PED_HIT_3;
+ goto LABEL_80;
+ case SOUND_2A:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PED_HIT_4;
+ m_sQueueSample.m_nFrequency = 18000;
+ goto LABEL_81;
+ case SOUND_2B:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PED_HIT_4;
+ m_sQueueSample.m_nFrequency = 16500;
+ goto LABEL_81;
+ case SOUND_2C:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PED_HIT_4;
+ LABEL_80:
+ m_sQueueSample.m_nFrequency = 20000;
+ LABEL_81:
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.field_4 = iSound;
+ processed = 1;
+ ++iSound;
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ maxDist = 900.f;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.m_nLoopStart = 0;
+ emittingVol = m_anRandomTable[3] % 26 + 100;
+ m_sQueueSample.m_nLoopEnd = -1;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_56 = 1;
+ m_sQueueSample.m_bRequireReflection = 1;
+ goto LABEL_84;
+ case SOUND_WEAPON_BAT_ATTACK:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PED_HIT_BY_BAT;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.field_4 = iSound++;
+ processed = 1;
+ m_sQueueSample.m_nFrequency = RandomDisplacement(2000u) + 22000;
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ maxDist = 900.f;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ emittingVol = m_anRandomTable[2] % 20 + 100;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_56 = 1;
+ if(m_bDynamicAcousticModelingStatus)
+ m_sQueueSample.m_bRequireReflection = 1;
+ else
+ noReflection = 1;
+ goto LABEL_84;
+ case SOUND_WEAPON_SHOT_FIRED:
+ weapon = &ped->m_weapons[ped->m_currentWeapon];
+ switch(weapon->m_eWeaponType) {
+ case WEAPONTYPE_COLT45:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_WEAPON_PISTOL_SHOT;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.field_4 = iSound++;
+ processed = 1;
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ AUDIO_SAMPLE_WEAPON_PISTOL_SHOT);
+ m_sQueueSample.m_nFrequency +=
+ RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_fSoundIntensity = 50.0f;
+ maxDist = 2500.f;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ emittingVol = m_anRandomTable[1] % 10 + 90;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_56 = 1;
+ if(m_bDynamicAcousticModelingStatus)
+ m_sQueueSample.m_bRequireReflection = 1;
+ else
+ noReflection = 1;
+ goto LABEL_84;
+ case WEAPONTYPE_UZI:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_WEAPON_UZI_SHOT;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.field_4 = iSound++;
+ processed = 1;
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ AUDIO_SAMPLE_WEAPON_UZI_SHOT);
+ m_sQueueSample.m_nFrequency +=
+ RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ maxDist = 6400.f;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.m_nLoopStart = 0;
+ emittingVol = m_anRandomTable[3] % 15 + 70;
+ m_sQueueSample.m_nLoopEnd = -1;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_56 = 1;
+ goto LABEL_84;
+ case WEAPONTYPE_SHOTGUN:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_WEAPON_SHOTGUN_SHOT;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.field_4 = iSound++;
+ processed = 1;
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ AUDIO_SAMPLE_WEAPON_SHOTGUN_SHOT);
+ m_sQueueSample.m_nFrequency +=
+ RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_fSoundIntensity = 60.0f;
+ maxDist = 3600.f;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ emittingVol = m_anRandomTable[2] % 10 + 100;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_56 = 1;
+ if(m_bDynamicAcousticModelingStatus)
+ m_sQueueSample.m_bRequireReflection = 1;
+ else
+ noReflection = 1;
+ goto LABEL_84;
+ case WEAPONTYPE_AK47:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_WEAPON_CHAINGUN_SHOT;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.field_4 = iSound++;
+ processed = 1;
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ AUDIO_SAMPLE_WEAPON_CHAINGUN_SHOT);
+ m_sQueueSample.m_nFrequency +=
+ RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ maxDist = 6400.f;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.m_nLoopStart = 0;
+ emittingVol = m_anRandomTable[1] % 15 + 70;
+ m_sQueueSample.m_nLoopEnd = -1;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_56 = 1;
+ goto LABEL_84;
+ case WEAPONTYPE_M16:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_WEAPON_M16_SHOT;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.field_4 = iSound++;
+ processed = 1;
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ AUDIO_SAMPLE_WEAPON_M16_SHOT);
+ m_sQueueSample.m_nFrequency +=
+ RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ maxDist = 6400.f;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.m_nLoopStart = 0;
+ emittingVol = m_anRandomTable[4] % 15 + 70;
+ m_sQueueSample.m_nLoopEnd = -1;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_56 = 1;
+ goto LABEL_84;
+ case WEAPONTYPE_SNIPERRIFLE:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_WEAPON_SNIPER_SHOT;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.field_4 = iSound++;
+ processed = 1;
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ AUDIO_SAMPLE_WEAPON_SNIPER_SHOT);
+ m_sQueueSample.m_nFrequency +=
+ RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_fSoundIntensity = 60.0f;
+ maxDist = 3600.f;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ emittingVol = m_anRandomTable[4] % 10 + 110;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_56 = 1;
+ if(m_bDynamicAcousticModelingStatus)
+ m_sQueueSample.m_bRequireReflection = 1;
+ else
+ noReflection = 1;
+ goto LABEL_84;
+ case WEAPONTYPE_ROCKETLAUNCHER:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_WEAPON_ROCKET_SHOT;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.field_4 = iSound++;
+ processed = 1;
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ AUDIO_SAMPLE_WEAPON_ROCKET_SHOT);
+ m_sQueueSample.m_nFrequency +=
+ RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
+ m_sQueueSample.field_16 = 1;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_fSoundIntensity = 90.0f;
+ maxDist = 8100.f;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ emittingVol = m_anRandomTable[0] % 20 + 80;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_56 = 1;
+ if(m_bDynamicAcousticModelingStatus)
+ m_sQueueSample.m_bRequireReflection = 1;
+ else
+ noReflection = 1;
+ goto LABEL_84;
+ case WEAPONTYPE_FLAMETHROWER:
+ m_sQueueSample.m_nSampleIndex =
+ AUDIO_SAMPLE_WEAPON_FLAMETHROWER_SHOT;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.field_4 = 9;
+ emittingVol = 90;
+ m_sQueueSample.m_nFrequency =
+ (10 * m_sQueueSample.m_nEntityIndex & 2047) +
+ cSampleManager.GetSampleBaseFrequency(
+ AUDIO_SAMPLE_WEAPON_FLAMETHROWER_SHOT);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 4.0f;
+ m_sQueueSample.m_fSoundIntensity = 60.0f;
+ maxDist = 3600.f;
+ m_sQueueSample.m_nLoopCount = 0;
+ m_sQueueSample.m_nLoopStart =
+ cSampleManager.GetSampleLoopStartOffset(
+ m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nLoopEnd = cSampleManager.GetSampleLoopEndOffset(
+ m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_bEmittingVolume = 90;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_56 = 0;
+ m_sQueueSample.field_76 = 6;
+ if(m_bDynamicAcousticModelingStatus)
+ m_sQueueSample.m_bRequireReflection = 1;
+ else
+ noReflection = 1;
+ goto LABEL_84;
+ default: goto LABEL_100;
+ }
+
+ break;
+ case SOUND_WEAPON_RELOAD:
+ weapon = &ped->m_weapons[ped->m_currentWeapon];
+ switch(weapon->m_eWeaponType) {
+ case WEAPONTYPE_COLT45:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_WEAPON_PISTOL_RELOAD;
+ emittingVol = 75;
+ m_sQueueSample.field_4 = iSound++;
+ processed = 1;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(
+ AUDIO_SAMPLE_WEAPON_PISTOL_RELOAD) +
+ RandomDisplacement(300u);
+ goto LABEL_63;
+ case WEAPONTYPE_UZI:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_WEAPON_UZI_RELOAD;
+ emittingVol = 75;
+ m_sQueueSample.field_4 = iSound++;
+ processed = 1;
+ m_sQueueSample.m_nFrequency = 39243;
+ goto LABEL_63;
+ case WEAPONTYPE_SHOTGUN:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_WEAPON_CHAINGUN_RELOAD;
+ emittingVol = 75;
+ m_sQueueSample.field_4 = iSound++;
+ processed = 1;
+ m_sQueueSample.m_nFrequency = 30290;
+ goto LABEL_63;
+ case WEAPONTYPE_AK47:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_WEAPON_CHAINGUN_RELOAD;
+ emittingVol = 75;
+ m_sQueueSample.field_4 = iSound++;
+ processed = 1;
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ AUDIO_SAMPLE_WEAPON_CHAINGUN_RELOAD);
+ goto LABEL_62;
+ case WEAPONTYPE_M16:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_WEAPON_UZI_RELOAD;
+ emittingVol = 75;
+ m_sQueueSample.field_4 = iSound++;
+ processed = 1;
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ AUDIO_SAMPLE_WEAPON_UZI_RELOAD);
+ goto LABEL_62;
+ case WEAPONTYPE_SNIPERRIFLE:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_WEAPON_SNIPER_RELOAD;
+ emittingVol = 75;
+ m_sQueueSample.field_4 = iSound++;
+ processed = 1;
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ AUDIO_SAMPLE_WEAPON_SNIPER_RELOAD);
+ goto LABEL_62;
+ case WEAPONTYPE_ROCKETLAUNCHER:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_WEAPON_ROCKET_RELOAD;
+ emittingVol = 75;
+ m_sQueueSample.field_4 = iSound++;
+ processed = 1;
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ AUDIO_SAMPLE_WEAPON_ROCKET_RELOAD);
+ LABEL_62:
+ LABEL_63:
+ m_sQueueSample.m_nFrequency += RandomDisplacement(300u);
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.field_16 = 5;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ maxDist = 900.f;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ m_sQueueSample.m_bEmittingVolume = 75;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_56 = 1;
+ m_sQueueSample.m_bRequireReflection = 1;
+ goto LABEL_84;
+ default: goto LABEL_100;
+ }
+
+ break;
+ case SOUND_WEAPON_AK47_BULLET_ECHO:
+ case SOUND_WEAPON_UZI_BULLET_ECHO:
+ case SOUND_WEAPON_M16_BULLET_ECHO:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_75;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.field_4 = iSound++;
+ processed = 1;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_75);
+ m_sQueueSample.m_nFrequency +=
+ RandomDisplacement(m_sQueueSample.m_nFrequency >> 4);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ maxDist = 6400.f;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ emittingVol = m_anRandomTable[4] % 10 + 40;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_56 = 1;
+ if(m_bDynamicAcousticModelingStatus)
+ m_sQueueSample.m_bRequireReflection = 1;
+ else
+ noReflection = 1;
+ goto LABEL_84;
+ case SOUND_WEAPON_FLAMETHROWER_FIRE:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_WEAPON_FLAMETHROWER_FIRE;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.field_4 = iSound++;
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ AUDIO_SAMPLE_WEAPON_FLAMETHROWER_FIRE);
+ m_sQueueSample.m_nFrequency +=
+ RandomDisplacement(m_sQueueSample.m_nFrequency >> 4);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 4.0f;
+ m_sQueueSample.m_fSoundIntensity = 60.0f;
+ maxDist = 3600.f;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ emittingVol = 70;
+ m_sQueueSample.m_bEmittingVolume = 70;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_56 = 1;
+ goto LABEL_84;
+ case SOUND_WEAPON_HIT_PED:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_BULLET_HIT_PED;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.field_4 = iSound++;
+ processed = 1;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_BULLET_HIT_PED);
+ m_sQueueSample.m_nFrequency +=
+ RandomDisplacement(m_sQueueSample.m_nFrequency >> 3);
+ m_sQueueSample.field_16 = 7;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ maxDist = 900.f;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.m_nLoopStart = 0;
+ emittingVol = m_anRandomTable[0] % 20 + 90;
+ m_sQueueSample.m_nLoopEnd = -1;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_56 = 1;
+ goto LABEL_84;
+ case SOUND_SPLASH:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_COLLISION_WATER;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.field_4 = iSound++;
+ processed = 1;
+ m_sQueueSample.m_nFrequency = RandomDisplacement(1400u) + 20000;
+ m_sQueueSample.field_16 = 1;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_fSoundIntensity = 40.0f;
+ maxDist = 1600.f;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.m_nLoopStart = 0;
+ emittingVol = m_anRandomTable[2] % 30 + 70;
+ m_sQueueSample.m_nLoopEnd = -1;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_56 = 1;
+ m_sQueueSample.m_bRequireReflection = 1;
+ LABEL_84:
+ if(processed && iSound > 60u) iSound = 21;
+ if(params->m_fDistance < maxDist) {
+ CalculateDistance((bool *)params, params->m_fDistance);
+ m_sQueueSample.m_bVolume =
+ ComputeVolume(emittingVol, m_sQueueSample.m_fSoundIntensity,
+ m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ if(noReflection) {
+ if(0.2f * m_sQueueSample.m_fSoundIntensity >
+ m_sQueueSample.m_fDistance) {
+ noReflection = 0;
+ } else {
+ m_sQueueSample.m_bIsDistant = 1;
+ m_sQueueSample.m_bOffset = 0;
+ }
+ }
+ m_sQueueSample.m_bReverbFlag = 1;
+ AddSampleToRequestedQueue();
+ if(noReflection) {
+ m_sQueueSample.m_bOffset = 127;
+ ++m_sQueueSample.m_nSampleIndex;
+ if(m_asAudioEntities[0].m_awAudioEvent
+ [i +
+ 20 * m_sQueueSample.m_nEntityIndex] !=
+ 47 ||
+ weapon->m_eWeaponType !=
+ WEAPONTYPE_FLAMETHROWER) {
+ m_sQueueSample.field_4 = iSound++;
+ if(iSound > 60u) iSound = 21;
+ } else {
+ ++m_sQueueSample.field_4;
+ }
+ AddSampleToRequestedQueue();
+ }
+ }
+ }
+ break;
+ default: SetupPedComments(params, sound); break;
+ }
+ LABEL_100:
+ ++i;
+ }
}
void
@@ -5396,8 +6508,8 @@ cAudioManager::ProcessSawMillScriptObject(uint8 sound)
distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
if(distSquared < maxDist) {
m_sQueueSample.m_fDistance = sqrt(distSquared);
- m_sQueueSample.m_bVolume = cAudioManager::ComputeVolume(
- 30u, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+ m_sQueueSample.m_bVolume = ComputeVolume(30u, m_sQueueSample.m_fSoundIntensity,
+ m_sQueueSample.m_fDistance);
if(m_sQueueSample.m_bVolume) {
m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_SAWMILL_1;
m_sQueueSample.m_bBankIndex = 0;
@@ -5420,7 +6532,7 @@ cAudioManager::ProcessSawMillScriptObject(uint8 sound)
}
time = CTimer::GetTimeInMilliseconds();
if(time > audioLogicTimers[1]) {
- m_sQueueSample.m_bVolume = cAudioManager::ComputeVolume(
+ m_sQueueSample.m_bVolume = ComputeVolume(
70u, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
if(m_sQueueSample.m_bVolume) {
m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_SAWMILL_2;
@@ -5444,11 +6556,19 @@ cAudioManager::ProcessSawMillScriptObject(uint8 sound)
}
}
-WRAPPER
void
cAudioManager::ProcessScriptObject(int32 id)
{
- EAXJMP(0x576070);
+ cAudioScriptObject *entity = (cAudioScriptObject *)m_asAudioEntities[id].m_pEntity;
+ if(entity) {
+ m_sQueueSample.m_vecPos.x = entity->m_vecPos.x;
+ m_sQueueSample.m_vecPos.y = entity->m_vecPos.y;
+ m_sQueueSample.m_vecPos.z = entity->m_vecPos.z;
+ if(m_asAudioEntities[id].field_24 == 1)
+ ProcessOneShotScriptObject(m_asAudioEntities[id].m_awAudioEvent[0]);
+ else
+ ProcessLoopingScriptObject(entity->m_wSound);
+ }
}
void
@@ -5490,7 +6610,7 @@ cAudioManager::ProcessShopScriptObject(uint8 sound)
SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
m_sQueueSample.m_bReverbFlag = 1;
m_sQueueSample.m_bRequireReflection = 0;
- cAudioManager::AddSampleToRequestedQueue();
+ AddSampleToRequestedQueue();
}
time = CTimer::GetTimeInMilliseconds();
if(time > audioLogicTimers[2]) {
@@ -5579,7 +6699,7 @@ cAudioManager::ProcessWorkShopScriptObject(uint8 sound)
case SCRIPT_SOUND_WORK_SHOP_LOOP_S:
case SCRIPT_SOUND_WORK_SHOP_LOOP_L:
maxDist = 400.f;
- m_sQueueSample.m_fSoundIntensity = 20.0;
+ m_sQueueSample.m_fSoundIntensity = 20.0f;
break;
default: break;
}
@@ -5598,7 +6718,7 @@ cAudioManager::ProcessWorkShopScriptObject(uint8 sound)
m_sQueueSample.m_nLoopCount = 0;
m_sQueueSample.field_56 = 0;
m_sQueueSample.field_16 = 5;
- m_sQueueSample.field_48 = 2.0;
+ m_sQueueSample.field_48 = 2.0f;
m_sQueueSample.m_bEmittingVolume = 30;
m_sQueueSample.m_nLoopStart =
SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
@@ -5611,6 +6731,136 @@ cAudioManager::ProcessWorkShopScriptObject(uint8 sound)
}
}
+void
+cAudioManager::SetupPedComments(cPedParams *params, uint32 sound)
+{
+ CPed *ped = params->m_pPed;
+ uint8 emittingVol;
+ float maxDist;
+ float soundIntensity;
+ tPedComment pedComment;
+
+ if(ped) {
+ switch(sound) {
+ case SOUND_AMMUNATION_WELCOME_1:
+ pedComment.m_nSampleIndex = AUDIO_SAMPLE_AMMUNATION_WELCOME_1;
+ break;
+ case SOUND_AMMUNATION_WELCOME_2:
+ pedComment.m_nSampleIndex = AUDIO_SAMPLE_AMMUNATION_WELCOME_2;
+ break;
+ case SOUND_AMMUNATION_WELCOME_3:
+ pedComment.m_nSampleIndex = AUDIO_SAMPLE_AMMUNATION_WELCOME_3;
+ break;
+ default:
+ pedComment.m_nSampleIndex = GetPedCommentSfx(ped, sound);
+ if(pedComment.m_nSampleIndex == NO_SAMPLE) return;
+ break;
+ }
+
+ maxDist = 2500.f;
+ soundIntensity = 50.f;
+
+ if(params->m_fDistance < maxDist) {
+ CalculateDistance((bool *)params, params->m_fDistance);
+ if(sound != SOUND_PAGER) {
+ switch(sound) {
+ case SOUND_AMMUNATION_WELCOME_1:
+ case SOUND_AMMUNATION_WELCOME_2:
+ case SOUND_AMMUNATION_WELCOME_3: emittingVol = maxVolume; break;
+ default:
+ if(CWorld::GetIsLineOfSightClear(
+ TheCamera.GetGameCamPosition(),
+ m_sQueueSample.m_vecPos, 1, 0, 0, 0, 0, 0, 0)) {
+ emittingVol = maxVolume;
+ } else {
+ emittingVol = 31;
+ }
+ break;
+ }
+ m_sQueueSample.m_bVolume = ComputeVolume(
+ emittingVol, soundIntensity, m_sQueueSample.m_fDistance);
+ pedComment.field_25 = 10;
+ if(m_sQueueSample.m_bVolume) {
+ pedComment.field_4 = m_sQueueSample.m_nEntityIndex;
+ pedComment.m_vecPos.x = m_sQueueSample.m_vecPos.x;
+ pedComment.m_vecPos.y = m_sQueueSample.m_vecPos.y;
+ pedComment.m_vecPos.z = m_sQueueSample.m_vecPos.z;
+ pedComment.m_fDistance = m_sQueueSample.m_fDistance;
+ pedComment.m_bVolume = m_sQueueSample.m_bVolume;
+ m_sPedComments.Add(&pedComment);
+ }
+ }
+ }
+ } else {
+ switch(sound) {
+ case SOUND_PED_HELI_PLAYER_FOUND:
+ maxDist = 160000.f;
+ soundIntensity = 400.f;
+ pedComment.m_nSampleIndex =
+ m_anRandomTable[m_sQueueSample.m_nEntityIndex & 3] % 29u +
+ AUDIO_SAMPLE_POLICE_HELI_FOUND_PLAYER_1;
+ break;
+ case SOUND_PED_BODYCAST_HIT:
+ if(CTimer::GetTimeInMilliseconds() <= audioLogicTimers[8]) return;
+ maxDist = 2500.f;
+ soundIntensity = 50.f;
+ audioLogicTimers[8] = CTimer::GetTimeInMilliseconds() + 500;
+ pedComment.m_nSampleIndex =
+ (m_anRandomTable[m_sQueueSample.m_nEntityIndex & 3] & 3) +
+ AUDIO_SAMPLE_PED_BODYCAST_HIT_1;
+ break;
+ case SOUND_INJURED_PED_MALE_OUCH:
+ case SOUND_8A:
+ maxDist = 2500.f;
+ soundIntensity = 50.f;
+ pedComment.m_nSampleIndex =
+ m_anRandomTable[m_sQueueSample.m_nEntityIndex & 3] % 15u +
+ AUDIO_SAMPLE_INJURED_PED_MALE_OUCH_1;
+ break;
+ case SOUND_INJURED_PED_FEMALE:
+ maxDist = 2500.f;
+ soundIntensity = 50.f;
+ pedComment.m_nSampleIndex =
+ m_anRandomTable[m_sQueueSample.m_nEntityIndex & 3] % 11u +
+ AUDIO_SAMPLE_INJURED_PED_FEMALE_OUCH_1;
+ break;
+ default: return;
+ }
+
+ if(params->m_fDistance < maxDist) {
+ CalculateDistance((bool *)params, params->m_fDistance);
+ if(sound != SOUND_PAGER) {
+ switch(sound) {
+ case SOUND_AMMUNATION_WELCOME_1:
+ case SOUND_AMMUNATION_WELCOME_2:
+ case SOUND_AMMUNATION_WELCOME_3: emittingVol = maxVolume; break;
+ default:
+ if(CWorld::GetIsLineOfSightClear(
+ TheCamera.GetGameCamPosition(),
+ m_sQueueSample.m_vecPos, 1, 0, 0, 0, 0, 0, 0)) {
+ emittingVol = maxVolume;
+ } else {
+ emittingVol = 31;
+ }
+ break;
+ }
+ m_sQueueSample.m_bVolume = ComputeVolume(
+ emittingVol, soundIntensity, m_sQueueSample.m_fDistance);
+ pedComment.field_25 = 10;
+ if(m_sQueueSample.m_bVolume) {
+ pedComment.field_4 = m_sQueueSample.m_nEntityIndex;
+ pedComment.m_vecPos.x = m_sQueueSample.m_vecPos.x;
+ pedComment.m_vecPos.y = m_sQueueSample.m_vecPos.y;
+ pedComment.m_vecPos.z = m_sQueueSample.m_vecPos.z;
+ pedComment.m_fDistance = m_sQueueSample.m_fDistance;
+ pedComment.m_bVolume = m_sQueueSample.m_bVolume;
+ m_sPedComments.Add(&pedComment);
+ }
+ }
+ }
+ }
+}
+
WRAPPER void
cAudioManager::Service()
{
@@ -5663,6 +6913,8 @@ WRAPPER void cAudioManager::PreloadMissionAudio(char *)
}
STARTPATCHES
+InjectHook(0x5755C0, &cPedComments::Add, PATCH_JUMP);
+
InjectHook(0x57B210, &cAudioManager::AddDetailsToRequestedOrderList, PATCH_JUMP);
InjectHook(0x56AD30, &cAudioManager::AddPlayerCarSample, PATCH_JUMP);
InjectHook(0x57B300, &cAudioManager::AddReflectionsToRequestedQueue, PATCH_JUMP);
@@ -5842,6 +7094,7 @@ InjectHook(0x579170, &cAudioManager::ProcessBridgeWarning, PATCH_JUMP);
InjectHook(0x577CA0, &cAudioManager::ProcessCinemaScriptObject, PATCH_JUMP);
InjectHook(0x577E50, &cAudioManager::ProcessDocksScriptObject, PATCH_JUMP);
InjectHook(0x569870, &cAudioManager::ProcessEntity, PATCH_JUMP);
+InjectHook(0x575AC0, &cAudioManager::ProcessExplosions, PATCH_JUMP);
InjectHook(0x578FD0, &cAudioManager::ProcessFireHydrant, PATCH_JUMP);
InjectHook(0x5785E0, &cAudioManager::ProcessFrontEnd, PATCH_JUMP);
InjectHook(0x577FE0, &cAudioManager::ProcessHomeScriptObject, PATCH_JUMP);
@@ -5854,10 +7107,16 @@ InjectHook(0x56EC00, &cAudioManager::ProcessJumboTakeOff, PATCH_JUMP);
InjectHook(0x56EA10, &cAudioManager::ProcessJumboTaxi, PATCH_JUMP);
InjectHook(0x5777E0, &cAudioManager::ProcessLaunderetteScriptObject, PATCH_JUMP);
InjectHook(0x576770, &cAudioManager::ProcessLoopingScriptObject, PATCH_JUMP);
+InjectHook(0x5760C0, &cAudioManager::ProcessOneShotScriptObject, PATCH_JUMP);
+InjectHook(0x56F450, &cAudioManager::ProcessPed, PATCH_JUMP);
+InjectHook(0x56F4D0, &cAudioManager::ProcessPedHeadphones, PATCH_JUMP);
+InjectHook(0x56F650, &cAudioManager::ProcessPedOneShots, PATCH_JUMP);
InjectHook(0x5699C0, &cAudioManager::ProcessPhysical, PATCH_JUMP);
InjectHook(0x577280, &cAudioManager::ProcessPornCinema, PATCH_JUMP);
InjectHook(0x577630, &cAudioManager::ProcessSawMillScriptObject, PATCH_JUMP);
+InjectHook(0x576070, &cAudioManager::ProcessScriptObject, PATCH_JUMP);
InjectHook(0x577970, &cAudioManager::ProcessShopScriptObject, PATCH_JUMP);
InjectHook(0x5697D0, &cAudioManager::ProcessSpecial, PATCH_JUMP);
InjectHook(0x577530, &cAudioManager::ProcessWorkShopScriptObject, PATCH_JUMP);
+InjectHook(0x570690, &cAudioManager::SetupPedComments, PATCH_JUMP);
ENDPATCHES
diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h
index 0d4a6f30..5b74cc16 100644
--- a/src/audio/AudioManager.h
+++ b/src/audio/AudioManager.h
@@ -51,7 +51,7 @@ public:
uint8 field_91;
};
-static_assert(sizeof(tActiveSample) == 0x5c, "tActiveSample: error");
+static_assert(sizeof(tActiveSample) == 92, "tActiveSample: error");
enum eAudioType : int32 {
AUDIOTYPE_PHYSICAL = 0,
@@ -83,11 +83,11 @@ public:
int16 m_awAudioEvent[4];
uint8 gap_18[2];
float m_afVolume[4];
- uint8 field_24;
+ uint8 field_24; // is looping
uint8 field_25[3];
};
-static_assert(sizeof(tAudioEntity) == 0x28, "tAudioEntity: error");
+static_assert(sizeof(tAudioEntity) == 40, "tAudioEntity: error");
class tPedComment
{
@@ -101,19 +101,21 @@ public:
uint8 gap_26[2];
};
-static_assert(sizeof(tPedComment) == 0x1c, "tPedComment: error");
+static_assert(sizeof(tPedComment) == 28, "tPedComment: error");
class cPedComments
{
public:
- tPedComment m_asPedComments[40];
- uint8 field_1120[40];
- uint8 field_1160[2];
- uint8 field_1162;
+ tPedComment m_asPedComments[2][20];
+ uint8 field_1120[2][20];
+ uint8 nrOfCommentsInBank[2];
+ uint8 activeBank;
uint8 gap_1163[1];
+
+ void Add(tPedComment *com); // test
};
-static_assert(sizeof(cPedComments) == 0x48c, "cPedComments: error");
+static_assert(sizeof(cPedComments) == 1164, "cPedComments: error");
class CEntity;
@@ -133,7 +135,7 @@ public:
int32 m_nBaseVolume;
};
-static_assert(sizeof(cAudioCollision) == 0x28, "cAudioCollision: error");
+static_assert(sizeof(cAudioCollision) == 40, "cAudioCollision: error");
class cAudioCollisionManager
{
@@ -146,7 +148,7 @@ public:
cAudioCollision m_sQueue;
};
-static_assert(sizeof(cAudioCollisionManager) == 0x354, "cAudioCollisionManager: error");
+static_assert(sizeof(cAudioCollisionManager) == 852, "cAudioCollisionManager: error");
class cMissionAudio
{
@@ -166,12 +168,13 @@ public:
uint8 field_31;
};
-static_assert(sizeof(cMissionAudio) == 0x20, "cMissionAudio: error");
+static_assert(sizeof(cMissionAudio) == 32, "cMissionAudio: error");
class cVehicleParams;
class CPlane;
class CVehicle;
class CPed;
+class cPedParams;
class cAudioScriptObject {
public:
@@ -182,11 +185,11 @@ public:
static void *operator new(size_t);
static void *operator new(size_t, int);
- static void operator delete(void*, size_t);
- static void operator delete(void*, int);
+ static void operator delete(void *, size_t);
+ static void operator delete(void *, int);
};
-static_assert(sizeof(cAudioScriptObject) == 0x14, "cAudioScriptObject: error");
+static_assert(sizeof(cAudioScriptObject) == 20, "cAudioScriptObject: error");
enum
{
@@ -334,7 +337,7 @@ public:
bool MissionScriptAudioUsesPoliceChannel(int32 soundMission);
- char* Get3DProviderName(uint8 id);
+ char *Get3DProviderName(uint8 id);
bool SetupJumboFlySound(uint8 emittingVol); /// ok
bool SetupJumboRumbleSound(uint8 emittingVol); /// ok
@@ -474,7 +477,7 @@ public:
void ProcessDocksScriptObject(uint8 sound); /// ok
// bool ProcessEngineDamage(void *); //todo requires CVehicle
void ProcessEntity(int32 sound); /// ok
- void ProcessExplosions(int32 explosion); // todo requires CExplosion
+ void ProcessExplosions(int32 explosion); // test
void ProcessFireHydrant(); /// ok
void ProcessFires(int32 entity); // todo requires gFireManager
void ProcessFrontEnd(); /// ok
@@ -492,12 +495,12 @@ public:
void ProcessLoopingScriptObject(uint8 sound); /// ok
// void ProcessMissionAudio();
// void ProcessModelVehicle(void *);
- // void ProcessOneShotScriptObject(uint8 sound);
- void ProcessPed(CPhysical *p); // todo
- // void ProcessPedHeadphones(void *);
- // void ProcessPedOneShots(void *);
- void ProcessPhysical(int32 id); /// ok
- void ProcessPlane(void *); // todo
+ void ProcessOneShotScriptObject(uint8 sound); // test
+ void ProcessPed(CPhysical *ped); // test
+ void ProcessPedHeadphones(cPedParams *params); // test
+ void ProcessPedOneShots(cPedParams *params); // test, remove goto
+ void ProcessPhysical(int32 id); /// ok
+ void ProcessPlane(void *); // todo
// void ProcessPlayersVehicleEngine(void *, void *);
void ProcessPoliceCellBeatingScriptObject(uint8 sound); // todo
void ProcessPornCinema(uint8 sound); /// ok
@@ -506,7 +509,7 @@ public:
// void ProcessReverb();
// bool ProcessReverseGear(void *);
void ProcessSawMillScriptObject(uint8 sound); /// ok
- void ProcessScriptObject(int32 id); // todo
+ void ProcessScriptObject(int32 id); // test
void ProcessShopScriptObject(uint8 sound); /// ok
void ProcessSpecial(); /// ok
// bool ProcessTrainNoise(void *);
@@ -523,19 +526,10 @@ public:
void ProcessWeather(int32 id); // todo
// bool ProcessWetRoadNoise(void *);
void ProcessWorkShopScriptObject(uint8 sound); /// ok
-
-
- void PlayOneShot(int, unsigned short, float);
- void SetEffectsFadeVol(unsigned char);
- void SetMusicFadeVol(unsigned char);
- int8 SetCurrent3DProvider(unsigned char);
- void ReportCrime(eCrimeType, CVector const &);
- void PlaySuspectLastSeen(float, float, float);
- void ReportCollision(CEntity *, CEntity *, unsigned char, unsigned char, float, float);
- void ResetTimers(unsigned int);
- void PreloadMissionAudio(char *);
+
+ void SetupPedComments(cPedParams *params, uint32 sound); // todo hook
};
-static_assert(sizeof(cAudioManager) == 0x4B14, "cAudioManager: error");
+static_assert(sizeof(cAudioManager) == 19220, "cAudioManager: error");
extern cAudioManager &AudioManager;
diff --git a/src/audio/DMAudio.h b/src/audio/DMAudio.h
index 318b9947..0932e581 100644
--- a/src/audio/DMAudio.h
+++ b/src/audio/DMAudio.h
@@ -1,4 +1,7 @@
#pragma once
+
+#include "Wanted.h"
+
enum eSound : int16
{
SOUND_CAR_DOOR_CLOSE_BONNET = 0,
diff --git a/src/control/PathFind.cpp b/src/control/PathFind.cpp
index e9b33395..87ce4476 100644
--- a/src/control/PathFind.cpp
+++ b/src/control/PathFind.cpp
@@ -207,8 +207,8 @@ CPathFind::PreparePathData(void)
numExtern++;
if(InfoForTileCars[k].numLeftLanes + InfoForTileCars[k].numRightLanes > numLanes)
numLanes = InfoForTileCars[k].numLeftLanes + InfoForTileCars[k].numRightLanes;
- maxX = max(maxX, Abs(InfoForTileCars[k].x));
- maxY = max(maxY, Abs(InfoForTileCars[k].y));
+ maxX = Max(maxX, Abs(InfoForTileCars[k].x));
+ maxY = Max(maxY, Abs(InfoForTileCars[k].y));
}else if(InfoForTileCars[k].type == NodeTypeIntern)
numIntern++;
}
@@ -392,7 +392,7 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor
if(Abs(dx) < nearestDist){
dy = tempnodes[k].pos.y - CoorsXFormed.y;
if(Abs(dy) < nearestDist){
- nearestDist = max(Abs(dx), Abs(dy));
+ nearestDist = Max(Abs(dx), Abs(dy));
nearestId = k;
}
}
@@ -501,13 +501,13 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor
// Find i inside path segment
iseg = 0;
- for(j = max(oldNumPathNodes, i-12); j < i; j++)
+ for(j = Max(oldNumPathNodes, i-12); j < i; j++)
if(m_pathNodes[j].objectIndex == m_pathNodes[i].objectIndex)
iseg++;
istart = 12*m_mapObjects[m_pathNodes[i].objectIndex]->m_modelIndex;
// Add links to other internal nodes
- for(j = max(oldNumPathNodes, i-12); j < min(m_numPathNodes, i+12); j++){
+ for(j = Max(oldNumPathNodes, i-12); j < Min(m_numPathNodes, i+12); j++){
if(m_pathNodes[i].objectIndex != m_pathNodes[j].objectIndex || i == j)
continue;
// N.B.: in every path segment, the externals have to be at the end
diff --git a/src/control/Population.h b/src/control/Population.h
index 7e4b40d8..3582ccef 100644
--- a/src/control/Population.h
+++ b/src/control/Population.h
@@ -1,8 +1,9 @@
#pragma once
+#include "Game.h"
+
class CPed;
class CVehicle;
-enum eLevelName;
struct PedGroup
{
diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp
index 12636d32..207845b9 100644
--- a/src/control/Replay.cpp
+++ b/src/control/Replay.cpp
@@ -366,8 +366,8 @@ void CReplay::StorePedAnimation(CPed *ped, CStoredAnimationState *state)
CAnimBlendAssociation* main = RpAnimBlendClumpGetMainAssociation((RpClump*)ped->m_rwObject, &second, &blend_amount);
if (main){
state->animId = main->animId;
- state->time = 255.0f / 4.0f * max(0.0f, min(4.0f, main->currentTime));
- state->speed = 255.0f / 3.0f * max(0.0f, min(3.0f, main->speed));
+ state->time = 255.0f / 4.0f * Max(0.0f, Min(4.0f, main->currentTime));
+ state->speed = 255.0f / 3.0f * Max(0.0f, Min(3.0f, main->speed));
}else{
state->animId = 3;
state->time = 0;
@@ -375,9 +375,9 @@ void CReplay::StorePedAnimation(CPed *ped, CStoredAnimationState *state)
}
if (second) {
state->secAnimId = second->animId;
- state->secTime = 255.0f / 4.0f * max(0.0f, min(4.0f, second->currentTime));
- state->secSpeed = 255.0f / 3.0f * max(0.0f, min(3.0f, second->speed));
- state->blendAmount = 255.0f / 2.0f * max(0.0f, min(2.0f, blend_amount));
+ state->secTime = 255.0f / 4.0f * Max(0.0f, Min(4.0f, second->currentTime));
+ state->secSpeed = 255.0f / 3.0f * Max(0.0f, Min(3.0f, second->speed));
+ state->blendAmount = 255.0f / 2.0f * Max(0.0f, Min(2.0f, blend_amount));
}else{
state->secAnimId = 0;
state->secTime = 0;
@@ -387,9 +387,9 @@ void CReplay::StorePedAnimation(CPed *ped, CStoredAnimationState *state)
CAnimBlendAssociation* partial = RpAnimBlendClumpGetMainPartialAssociation((RpClump*)ped->m_rwObject);
if (partial) {
state->partAnimId = partial->animId;
- state->partAnimTime = 255.0f / 4.0f * max(0.0f, min(4.0f, partial->currentTime));
- state->partAnimSpeed = 255.0f / 3.0f * max(0.0f, min(3.0f, partial->speed));
- state->partBlendAmount = 255.0f / 2.0f * max(0.0f, min(2.0f, partial->blendAmount));
+ state->partAnimTime = 255.0f / 4.0f * Max(0.0f, Min(4.0f, partial->currentTime));
+ state->partAnimSpeed = 255.0f / 3.0f * Max(0.0f, Min(3.0f, partial->speed));
+ state->partBlendAmount = 255.0f / 2.0f * Max(0.0f, Min(2.0f, partial->blendAmount));
}else{
state->partAnimId = 0;
state->partAnimTime = 0;
@@ -408,9 +408,9 @@ void CReplay::StoreDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState
CAnimBlendAssociation* assoc = RpAnimBlendClumpGetMainAssociation_N((RpClump*)ped->m_rwObject, i);
if (assoc){
state->aAnimId[i] = assoc->animId;
- state->aCurTime[i] = 255.0f / 4.0f * max(0.0f, min(4.0f, assoc->currentTime));
- state->aSpeed[i] = 255.0f / 3.0f * max(0.0f, min(3.0f, assoc->speed));
- state->aBlendAmount[i] = 255.0f / 2.0f * max(0.0f, min(2.0f, assoc->blendAmount));
+ state->aCurTime[i] = 255.0f / 4.0f * Max(0.0f, Min(4.0f, assoc->currentTime));
+ state->aSpeed[i] = 255.0f / 3.0f * Max(0.0f, Min(3.0f, assoc->speed));
+ state->aBlendAmount[i] = 255.0f / 2.0f * Max(0.0f, Min(2.0f, assoc->blendAmount));
state->aFlags[i] = assoc->flags;
if (assoc->callbackType == CAnimBlendAssociation::CB_FINISH || assoc->callbackType == CAnimBlendAssociation::CB_DELETE) {
state->aFunctionCallbackID[i] = FindCBFunctionID(assoc->callback);
@@ -431,9 +431,9 @@ void CReplay::StoreDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState
CAnimBlendAssociation* assoc = RpAnimBlendClumpGetMainPartialAssociation_N((RpClump*)ped->m_rwObject, i);
if (assoc) {
state->aAnimId2[i] = assoc->animId;
- state->aCurTime2[i] = 255.0f / 4.0f * max(0.0f, min(4.0f, assoc->currentTime));
- state->aSpeed2[i] = 255.0f / 3.0f * max(0.0f, min(3.0f, assoc->speed));
- state->aBlendAmount2[i] = 255.0f / 2.0f * max(0.0f, min(2.0f, assoc->blendAmount));
+ state->aCurTime2[i] = 255.0f / 4.0f * Max(0.0f, Min(4.0f, assoc->currentTime));
+ state->aSpeed2[i] = 255.0f / 3.0f * Max(0.0f, Min(3.0f, assoc->speed));
+ state->aBlendAmount2[i] = 255.0f / 2.0f * Max(0.0f, Min(2.0f, assoc->blendAmount));
state->aFlags2[i] = assoc->flags;
if (assoc->callbackType == CAnimBlendAssociation::CB_FINISH || assoc->callbackType == CAnimBlendAssociation::CB_DELETE) {
state->aFunctionCallbackID2[i] = FindCBFunctionID(assoc->callback);
@@ -625,9 +625,9 @@ void CReplay::StoreCarUpdate(CVehicle *vehicle, int id)
vp->health = vehicle->m_fHealth / 4.0f; /* Not anticipated that health can be > 1000. */
vp->acceleration = vehicle->m_fGasPedal * 100.0f;
vp->panels = vehicle->IsCar() ? ((CAutomobile*)vehicle)->Damage.m_panelStatus : 0;
- vp->velocityX = 8000.0f * max(-4.0f, min(4.0f, vehicle->GetMoveSpeed().x)); /* 8000!? */
- vp->velocityY = 8000.0f * max(-4.0f, min(4.0f, vehicle->GetMoveSpeed().y));
- vp->velocityZ = 8000.0f * max(-4.0f, min(4.0f, vehicle->GetMoveSpeed().z));
+ vp->velocityX = 8000.0f * Max(-4.0f, Min(4.0f, vehicle->GetMoveSpeed().x)); /* 8000!? */
+ vp->velocityY = 8000.0f * Max(-4.0f, Min(4.0f, vehicle->GetMoveSpeed().y));
+ vp->velocityZ = 8000.0f * Max(-4.0f, Min(4.0f, vehicle->GetMoveSpeed().z));
vp->mi = vehicle->GetModelIndex();
vp->primary_color = vehicle->m_currentColour1;
vp->secondary_color = vehicle->m_currentColour2;
@@ -1501,9 +1501,9 @@ void CReplay::ProcessLookAroundCam(void)
--FramesActiveLookAroundCam;
fBetaAngleLookAroundCam += x_moved;
if (CPad::NewMouseControllerState.LMB && CPad::NewMouseControllerState.RMB)
- fDistanceLookAroundCam = max(3.0f, min(15.0f, fDistanceLookAroundCam + 2.0f * y_moved));
+ fDistanceLookAroundCam = Max(3.0f, Min(15.0f, fDistanceLookAroundCam + 2.0f * y_moved));
else
- fAlphaAngleLookAroundCam = max(0.1f, min(1.5f, fAlphaAngleLookAroundCam + y_moved));
+ fAlphaAngleLookAroundCam = Max(0.1f, Min(1.5f, fAlphaAngleLookAroundCam + y_moved));
CVector camera_pt(
fDistanceLookAroundCam * Sin(fBetaAngleLookAroundCam) * Cos(fAlphaAngleLookAroundCam),
fDistanceLookAroundCam * Cos(fBetaAngleLookAroundCam) * Cos(fAlphaAngleLookAroundCam),
diff --git a/src/control/Script.cpp b/src/control/Script.cpp
index c81cd050..7e87fc6e 100644
--- a/src/control/Script.cpp
+++ b/src/control/Script.cpp
@@ -1987,7 +1987,7 @@ int8 CRunningScript::ProcessCommandsFrom100To199(int32 command)
car->AutoPilot.m_nCarMission = MISSION_GOTOCOORDS;
car->m_status = STATUS_PHYSICS;
car->bEngineOn = true;
- car->AutoPilot.m_nCruiseSpeed = max(car->AutoPilot.m_nCruiseSpeed, 6);
+ car->AutoPilot.m_nCruiseSpeed = Max(car->AutoPilot.m_nCruiseSpeed, 6);
car->AutoPilot.m_nTimeToStartMission = CTimer::GetTimeInMilliseconds();
return 0;
}
@@ -1999,7 +1999,7 @@ int8 CRunningScript::ProcessCommandsFrom100To199(int32 command)
CCarCtrl::JoinCarWithRoadSystem(car);
car->AutoPilot.m_nCarMission = MISSION_CRUISE;
car->bEngineOn = true;
- car->AutoPilot.m_nCruiseSpeed = max(car->AutoPilot.m_nCruiseSpeed, 6);
+ car->AutoPilot.m_nCruiseSpeed = Max(car->AutoPilot.m_nCruiseSpeed, 6);
car->AutoPilot.m_nTimeToStartMission = CTimer::GetTimeInMilliseconds();
return 0;
}
@@ -2083,7 +2083,7 @@ int8 CRunningScript::ProcessCommandsFrom100To199(int32 command)
CollectParameters(&m_nIp, 2);
CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
assert(car);
- car->AutoPilot.m_nCruiseSpeed = min(*(float*)&ScriptParams[1], 60.0f * car->pHandling->Transmission.fUnkMaxVelocity);
+ car->AutoPilot.m_nCruiseSpeed = Min(*(float*)&ScriptParams[1], 60.0f * car->pHandling->Transmission.fUnkMaxVelocity);
return 0;
}
case COMMAND_SET_CAR_DRIVING_STYLE:
diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp
index cb16c3ad..f15232f3 100644
--- a/src/core/Camera.cpp
+++ b/src/core/Camera.cpp
@@ -209,7 +209,7 @@ WellBufferMe(float Target, float *CurrentValue, float *CurrentSpeed, float MaxSp
else if(TargetSpeed > 0.0f && *CurrentSpeed > TargetSpeed)
*CurrentSpeed = TargetSpeed;
- *CurrentValue += *CurrentSpeed * min(10.0f, CTimer::GetTimeStep());
+ *CurrentValue += *CurrentSpeed * Min(10.0f, CTimer::GetTimeStep());
}
void
@@ -697,7 +697,7 @@ CCam::Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, fl
// Process height offset to avoid peds and cars
float TargetZOffSet = m_fUnknownZOffSet + m_fDimensionOfHighestNearCar;
- TargetZOffSet = max(TargetZOffSet, m_fPedBetweenCameraHeightOffset);
+ TargetZOffSet = Max(TargetZOffSet, m_fPedBetweenCameraHeightOffset);
float TargetHeight = CameraTarget.z + TargetZOffSet - Source.z;
if(TargetHeight > m_fCamBufferedHeight){
@@ -753,7 +753,7 @@ CCam::Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, fl
}
}
- TargetCoors.z += min(1.0f, m_fCamBufferedHeight/2.0f);
+ TargetCoors.z += Min(1.0f, m_fCamBufferedHeight/2.0f);
m_cvecTargetCoorsForFudgeInter = TargetCoors;
Front = TargetCoors - Source;
@@ -991,7 +991,7 @@ CCam::WorkOutCamHeight(const CVector &TargetCoors, float TargetOrientation, floa
}
if(FoundCamRoof){
// Camera is under something
- float roof = FoundRoofCenter ? min(CamRoof, CarRoof) : CamRoof;
+ float roof = FoundRoofCenter ? Min(CamRoof, CarRoof) : CamRoof;
// Same weirdness again?
TargetAlpha = CGeneral::GetATanOfXY(CA_MAX_DISTANCE, roof - CamTargetZ - 1.5f);
CamClear = false;
@@ -1249,7 +1249,7 @@ void
CCam::Cam_On_A_String_Unobscured(const CVector &TargetCoors, float BaseDist)
{
CA_MAX_DISTANCE = BaseDist + 0.1f + TheCamera.CarZoomValueSmooth;
- CA_MIN_DISTANCE = min(BaseDist*0.6f, 3.5f);
+ CA_MIN_DISTANCE = Min(BaseDist*0.6f, 3.5f);
CVector Dist = Source - TargetCoors;
diff --git a/src/core/Camera.h b/src/core/Camera.h
index c617c3d7..1f38963b 100644
--- a/src/core/Camera.h
+++ b/src/core/Camera.h
@@ -442,7 +442,7 @@ int m_iModeObbeCamIsInForCar;
static bool &m_bUseMouse3rdPerson;
bool Get_Just_Switched_Status() { return m_bJust_Switched; }
- inline const CMatrix GetCameraMatrix(void) { return m_cameraMatrix; }
+ inline const CMatrix& GetCameraMatrix(void) { return m_cameraMatrix; }
CVector &GetGameCamPosition(void) { return m_vecGameCamPos; }
bool IsPointVisible(const CVector &center, const CMatrix *mat);
bool IsSphereVisible(const CVector &center, float radius, const CMatrix *mat);
diff --git a/src/core/CdStream.cpp b/src/core/CdStream.cpp
index 255e46bb..57b1cbe2 100644
--- a/src/core/CdStream.cpp
+++ b/src/core/CdStream.cpp
@@ -5,8 +5,8 @@
#include "rwcore.h"
#include "RwHelper.h"
-#define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", __VA_ARGS__)
-#define CDTRACE(f, ...) printf("%s: " f "\n", "cdvd_stream", __VA_ARGS__)
+#define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__)
+#define CDTRACE(f, ...) printf("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__)
struct CdReadInfo
{
diff --git a/src/core/Collision.cpp b/src/core/Collision.cpp
index 66b29d9f..538bcae6 100644
--- a/src/core/Collision.cpp
+++ b/src/core/Collision.cpp
@@ -153,10 +153,10 @@ CCollision::LoadCollisionWhenINeedIt(bool forceChange)
// on water we expect to be between levels
multipleLevels = true;
}else{
- xmin = max(sx - 1, 0);
- xmax = min(sx + 1, NUMSECTORS_X-1);
- ymin = max(sy - 1, 0);
- ymax = min(sy + 1, NUMSECTORS_Y-1);
+ xmin = Max(sx - 1, 0);
+ xmax = Min(sx + 1, NUMSECTORS_X-1);
+ ymin = Max(sy - 1, 0);
+ ymax = Min(sy + 1, NUMSECTORS_Y-1);
for(x = xmin; x <= xmax; x++)
for(y = ymin; y <= ymax; y++){
diff --git a/src/core/EventList.cpp b/src/core/EventList.cpp
index a833cc8e..caf0cb3f 100644
--- a/src/core/EventList.cpp
+++ b/src/core/EventList.cpp
@@ -4,7 +4,7 @@
#include "ModelIndices.h"
#include "World.h"
#include "Wanted.h"
-#include "Eventlist.h"
+#include "EventList.h"
int32 CEventList::ms_nFirstFreeSlotIndex;
//CEvent gaEvent[NUMEVENTS];
diff --git a/src/core/Explosion.cpp b/src/core/Explosion.cpp
index f55cbcd6..9ccd6e81 100644
--- a/src/core/Explosion.cpp
+++ b/src/core/Explosion.cpp
@@ -3,3 +3,27 @@
#include "Explosion.h"
WRAPPER void CExplosion::AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type, const CVector &pos, uint32) { EAXJMP(0x5591C0); }
+
+WRAPPER
+int8 CExplosion::GetExplosionActiveCounter(uint8 id)
+{
+ EAXJMP(0x559140);
+}
+
+WRAPPER
+CVector *CExplosion::GetExplosionPosition(uint8 id)
+{
+ EAXJMP(0x5591A0);
+}
+
+WRAPPER
+uint8 CExplosion::GetExplosionType(uint8 id)
+{
+ EAXJMP(0x559180);
+}
+
+WRAPPER
+void CExplosion::ResetExplosionActiveCounter(uint8 id)
+{
+ EAXJMP(0x559160);
+}
diff --git a/src/core/Explosion.h b/src/core/Explosion.h
index 93d60ab3..fde4ad7f 100644
--- a/src/core/Explosion.h
+++ b/src/core/Explosion.h
@@ -1,6 +1,7 @@
#pragma once
class CEntity;
+class CVector;
enum eExplosionType
{
@@ -19,5 +20,11 @@ enum eExplosionType
class CExplosion
{
public:
- static void AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type, const CVector &pos, uint32);
+ static void AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type,
+ const CVector &pos, uint32);
+
+ static int8 GetExplosionActiveCounter(uint8 id);
+ static CVector *GetExplosionPosition(uint8 id);
+ static uint8 GetExplosionType(uint8 id);
+ static void ResetExplosionActiveCounter(uint8 id);
};
diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp
index 1de5c94f..c8a00744 100644
--- a/src/core/Frontend.cpp
+++ b/src/core/Frontend.cpp
@@ -1030,7 +1030,7 @@ int CMenuManager::FadeIn(int alpha)
m_nCurrScreen == MENUPAGE_SAVING_IN_PROGRESS ||
m_nCurrScreen == MENUPAGE_DELETING)
return alpha;
- return min(m_nMenuFadeAlpha, alpha);
+ return Min(m_nMenuFadeAlpha, alpha);
}
#endif
diff --git a/src/core/Game.cpp b/src/core/Game.cpp
index e07106ce..b488a217 100644
--- a/src/core/Game.cpp
+++ b/src/core/Game.cpp
@@ -1,7 +1,7 @@
#include "common.h"
#include "patcher.h"
#include "Game.h"
-#include "Main.h"
+#include "main.h"
#include "CdStream.h"
#include "FileMgr.h"
diff --git a/src/core/Instance.h b/src/core/Instance.h
index 1038c005..bb74ea84 100644
--- a/src/core/Instance.h
+++ b/src/core/Instance.h
@@ -7,4 +7,5 @@
class CInstance : CPlaceable
{
public:
+ ~CInstance() = default;
};
diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp
index f334a255..b5086d64 100644
--- a/src/core/Pad.cpp
+++ b/src/core/Pad.cpp
@@ -299,10 +299,10 @@ CControllerState CPad::ReconcileTwoControllersInput(CControllerState const &Stat
{ if ( State1.button || State2.button ) ReconState.button = 255; }
#define _RECONCILE_AXIS_POSITIVE(axis) \
- { if ( State1.axis >= 0 && State2.axis >= 0 ) ReconState.axis = max(State1.axis, State2.axis); }
+ { if ( State1.axis >= 0 && State2.axis >= 0 ) ReconState.axis = Max(State1.axis, State2.axis); }
#define _RECONCILE_AXIS_NEGATIVE(axis) \
- { if ( State1.axis <= 0 && State2.axis <= 0 ) ReconState.axis = min(State1.axis, State2.axis); }
+ { if ( State1.axis <= 0 && State2.axis <= 0 ) ReconState.axis = Min(State1.axis, State2.axis); }
#define _RECONCILE_AXIS(axis) \
{ _RECONCILE_AXIS_POSITIVE(axis); _RECONCILE_AXIS_NEGATIVE(axis); }
diff --git a/src/core/Placeable.cpp b/src/core/Placeable.cpp
index c1fe705e..d2cec82b 100644
--- a/src/core/Placeable.cpp
+++ b/src/core/Placeable.cpp
@@ -7,7 +7,7 @@ CPlaceable::CPlaceable(void)
m_matrix.SetScale(1.0f);
}
-CPlaceable::~CPlaceable(void) { }
+CPlaceable::~CPlaceable(void) = default;
void
CPlaceable::SetHeading(float angle)
diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp
index a7bde91e..8158cd1d 100644
--- a/src/core/Streaming.cpp
+++ b/src/core/Streaming.cpp
@@ -1940,7 +1940,7 @@ CStreaming::ProcessEntitiesInSectorList(CPtrList &list, float x, float y, float
CTimeModelInfo *mi = (CTimeModelInfo*)CModelInfo::GetModelInfo(e->GetModelIndex());
if(mi->m_type != MITYPE_TIME || CClock::GetIsTimeInRange(mi->GetTimeOn(), mi->GetTimeOff())){
lodDistSq = sq(mi->GetLargestLodDistance());
- lodDistSq = min(lodDistSq, sq(STREAM_DIST));
+ lodDistSq = Min(lodDistSq, sq(STREAM_DIST));
pos = CVector2D(e->GetPosition());
if(xmin < pos.x && pos.x < xmax &&
ymin < pos.y && pos.y < ymax &&
@@ -2160,20 +2160,20 @@ CStreaming::DeleteRwObjectsBehindCamera(int32 mem)
if(Abs(TheCamera.GetForward().x) > Abs(TheCamera.GetForward().y)){
// looking west/east
- ymin = max(iy - 10, 0);
- ymax = min(iy + 10, NUMSECTORS_Y);
+ ymin = Max(iy - 10, 0);
+ ymax = Min(iy + 10, NUMSECTORS_Y);
assert(ymin <= ymax);
// Delete a block of sectors that we know is behind the camera
if(TheCamera.GetForward().x > 0){
// looking east
- xmax = max(ix - 2, 0);
- xmin = max(ix - 10, 0);
+ xmax = Max(ix - 2, 0);
+ xmin = Max(ix - 10, 0);
inc = 1;
}else{
// looking west
- xmax = min(ix + 2, NUMSECTORS_X);
- xmin = min(ix + 10, NUMSECTORS_X);
+ xmax = Min(ix + 2, NUMSECTORS_X);
+ xmin = Min(ix + 10, NUMSECTORS_X);
inc = -1;
}
for(y = ymin; y <= ymax; y++){
@@ -2189,13 +2189,13 @@ CStreaming::DeleteRwObjectsBehindCamera(int32 mem)
// Now a block that intersects with the camera's frustum
if(TheCamera.GetForward().x > 0){
// looking east
- xmax = max(ix + 10, 0);
- xmin = max(ix - 2, 0);
+ xmax = Max(ix + 10, 0);
+ xmin = Max(ix - 2, 0);
inc = 1;
}else{
// looking west
- xmax = min(ix - 10, NUMSECTORS_X);
- xmin = min(ix + 2, NUMSECTORS_X);
+ xmax = Min(ix - 10, NUMSECTORS_X);
+ xmin = Min(ix + 2, NUMSECTORS_X);
inc = -1;
}
for(y = ymin; y <= ymax; y++){
@@ -2224,20 +2224,20 @@ CStreaming::DeleteRwObjectsBehindCamera(int32 mem)
}else{
// looking north/south
- xmin = max(ix - 10, 0);
- xmax = min(ix + 10, NUMSECTORS_X);
+ xmin = Max(ix - 10, 0);
+ xmax = Min(ix + 10, NUMSECTORS_X);
assert(xmin <= xmax);
// Delete a block of sectors that we know is behind the camera
if(TheCamera.GetForward().y > 0){
// looking north
- ymax = max(iy - 2, 0);
- ymin = max(iy - 10, 0);
+ ymax = Max(iy - 2, 0);
+ ymin = Max(iy - 10, 0);
inc = 1;
}else{
// looking south
- ymax = min(iy + 2, NUMSECTORS_Y);
- ymin = min(iy + 10, NUMSECTORS_Y);
+ ymax = Min(iy + 2, NUMSECTORS_Y);
+ ymin = Min(iy + 10, NUMSECTORS_Y);
inc = -1;
}
for(x = xmin; x <= xmax; x++){
@@ -2253,13 +2253,13 @@ CStreaming::DeleteRwObjectsBehindCamera(int32 mem)
// Now a block that intersects with the camera's frustum
if(TheCamera.GetForward().y > 0){
// looking north
- ymax = max(iy + 10, 0);
- ymin = max(iy - 2, 0);
+ ymax = Max(iy + 10, 0);
+ ymin = Max(iy - 2, 0);
inc = 1;
}else{
// looking south
- ymax = min(iy - 10, NUMSECTORS_Y);
- ymin = min(iy + 2, NUMSECTORS_Y);
+ ymax = Min(iy - 10, NUMSECTORS_Y);
+ ymin = Min(iy + 2, NUMSECTORS_Y);
inc = -1;
}
for(x = xmin; x <= xmax; x++){
diff --git a/src/core/Wanted.cpp b/src/core/Wanted.cpp
index 26b115e3..daed9155 100644
--- a/src/core/Wanted.cpp
+++ b/src/core/Wanted.cpp
@@ -209,7 +209,7 @@ CWanted::ReportCrimeNow(eCrimeType type, const CVector &coors, bool policeDoesnt
else
sensitivity = m_fCrimeSensitivity;
- wantedLevelDrop = min(CCullZones::GetWantedLevelDrop(), 100);
+ wantedLevelDrop = Min(CCullZones::GetWantedLevelDrop(), 100);
chaos = (1.0f - wantedLevelDrop/100.0f) * sensitivity;
if (policeDoesntCare)
diff --git a/src/core/common.h b/src/core/common.h
index 36f67bfa..73e57c21 100644
--- a/src/core/common.h
+++ b/src/core/common.h
@@ -177,10 +177,10 @@ void re3_assert(const char *expr, const char *filename, unsigned int lineno, con
#define DEBUGBREAK() __debugbreak();
-#define debug(f, ...) re3_debug("[DBG]: " f, __VA_ARGS__)
-#define DEV(f, ...) re3_debug("[DEV]: " f, __VA_ARGS__)
-#define TRACE(f, ...) re3_trace(__FILE__, __LINE__, __FUNCTION__, f, __VA_ARGS__)
-#define Error(f, ...) re3_debug("[ERROR]: " f, __VA_ARGS__)
+#define debug(f, ...) re3_debug("[DBG]: " f, ## __VA_ARGS__)
+#define DEV(f, ...) re3_debug("[DEV]: " f, ## __VA_ARGS__)
+#define TRACE(f, ...) re3_trace(__FILE__, __LINE__, __FUNCTION__, f, ## __VA_ARGS__)
+#define Error(f, ...) re3_debug("[ERROR]: " f, ## __VA_ARGS__)
#define assert(_Expression) (void)( (!!(_Expression)) || (re3_assert(#_Expression, __FILE__, __LINE__, __FUNCTION__), 0) )
#define ASSERT assert
@@ -200,7 +200,6 @@ void re3_assert(const char *expr, const char *filename, unsigned int lineno, con
#define ABS(a) (((a) < 0) ? (-(a)) : (a))
#define norm(value, min, max) (((value) < (min)) ? 0 : (((value) > (max)) ? 1 : (((value) - (min)) / ((max) - (min)))))
-
#define STRINGIFY(x) #x
#define STR(x) STRINGIFY(x)
#define CONCAT_(x,y) x##y
diff --git a/src/core/main.cpp b/src/core/main.cpp
index 50494ef3..a82a2ab8 100644
--- a/src/core/main.cpp
+++ b/src/core/main.cpp
@@ -453,7 +453,7 @@ DoFade(void)
CRGBA fadeColor;
CRect rect;
int fadeValue = CDraw::FadeValue;
- float brightness = min(CMenuManager::m_PrefsBrightness, 256);
+ float brightness = Min(CMenuManager::m_PrefsBrightness, 256);
if(brightness <= 50)
brightness = 50;
if(FrontEndMenuManager.m_bMenuActive)
diff --git a/src/core/re3.cpp b/src/core/re3.cpp
index ad3838bd..0ce5ee3c 100644
--- a/src/core/re3.cpp
+++ b/src/core/re3.cpp
@@ -374,6 +374,32 @@ delayedPatches10(int a, int b)
}
*/
+<<<<<<< HEAD
+=======
+void __declspec(naked) HeadlightsFix()
+{
+ static const float fMinusOne = -1.0f;
+ _asm
+ {
+ fld [esp+708h-690h]
+ fcomp fMinusOne
+ fnstsw ax
+ and ah, 5
+ cmp ah, 1
+ jnz HeadlightsFix_DontLimit
+ fld fMinusOne
+ fstp [esp+708h-690h]
+
+HeadlightsFix_DontLimit:
+ fld [esp+708h-690h]
+ fabs
+ fld st
+ push 0x5382F2
+ retn
+ }
+}
+
+>>>>>>> More audio ped
const int re3_buffsize = 1024;
static char re3_buff[re3_buffsize];
diff --git a/src/core/re3.cpp.autosave b/src/core/re3.cpp.autosave
new file mode 100644
index 00000000..ad3838bd
--- /dev/null
+++ b/src/core/re3.cpp.autosave
@@ -0,0 +1,483 @@
+#include <direct.h>
+#include <csignal>
+#include <windows.h>
+#include "common.h"
+#include "patcher.h"
+#include "Renderer.h"
+#include "Credits.h"
+#include "Camera.h"
+#include "Weather.h"
+#include "Clock.h"
+#include "World.h"
+#include "Vehicle.h"
+#include "ModelIndices.h"
+#include "Streaming.h"
+#include "PathFind.h"
+#include "Boat.h"
+#include "Heli.h"
+#include "Automobile.h"
+#include "Ped.h"
+#include "debugmenu_public.h"
+
+#include <vector>
+#include <list>
+
+std::vector<int32> usedAddresses;
+
+void **rwengine = *(void***)0x5A10E1;
+
+DebugMenuAPI gDebugMenuAPI;
+
+WRAPPER void *gtanew(uint32 sz) { EAXJMP(0x5A0690); }
+WRAPPER void gtadelete(void *p) { EAXJMP(0x5A07E0); }
+
+// overload our own new/delete with GTA's functions
+void *operator new(size_t sz) { return gtanew(sz); }
+void operator delete(void *ptr) noexcept { gtadelete(ptr); }
+
+#ifdef USE_PS2_RAND
+unsigned __int64 myrand_seed = 1;
+#else
+unsigned long int myrand_seed = 1;
+#endif
+
+int
+myrand(void)
+{
+#ifdef USE_PS2_RAND
+ // Use our own implementation of rand, stolen from PS2
+ myrand_seed = 0x5851F42D4C957F2D * myrand_seed + 1;
+ return ((myrand_seed >> 32) & 0x7FFFFFFF);
+#else
+ // or original codewarrior rand
+ myrand_seed = myrand_seed * 1103515245 + 12345;
+ return((myrand_seed >> 16) & 0x7FFF);
+#endif
+}
+
+void
+mysrand(unsigned int seed)
+{
+ myrand_seed = seed;
+}
+
+void (*DebugMenuProcess)(void);
+void (*DebugMenuRender)(void);
+static void stub(void) { }
+
+void
+DebugMenuInit(void)
+{
+ if(DebugMenuLoad()){
+ DebugMenuProcess = (void(*)(void))GetProcAddress(gDebugMenuAPI.module, "DebugMenuProcess");
+ DebugMenuRender = (void(*)(void))GetProcAddress(gDebugMenuAPI.module, "DebugMenuRender");
+ }
+ if(DebugMenuProcess == nil || DebugMenuRender == nil){
+ DebugMenuProcess = stub;
+ DebugMenuRender = stub;
+ }
+
+}
+
+void WeaponCheat();
+void HealthCheat();
+void TankCheat();
+void BlowUpCarsCheat();
+void ChangePlayerCheat();
+void MayhemCheat();
+void EverybodyAttacksPlayerCheat();
+void WeaponsForAllCheat();
+void FastTimeCheat();
+void SlowTimeCheat();
+void MoneyCheat();
+void ArmourCheat();
+void WantedLevelUpCheat();
+void WantedLevelDownCheat();
+void SunnyWeatherCheat();
+void CloudyWeatherCheat();
+void RainyWeatherCheat();
+void FoggyWeatherCheat();
+void FastWeatherCheat();
+void OnlyRenderWheelsCheat();
+void ChittyChittyBangBangCheat();
+void StrongGripCheat();
+void NastyLimbsCheat();
+
+DebugMenuEntry *carCol1;
+DebugMenuEntry *carCol2;
+
+void
+SpawnCar(int id)
+{
+ CVector playerpos;
+ CStreaming::RequestModel(id, 0);
+ CStreaming::LoadAllRequestedModels(false);
+ if(CStreaming::HasModelLoaded(id)){
+ playerpos = FindPlayerCoors();
+ int node = ThePaths.FindNodeClosestToCoors(playerpos, 0, 100.0f, false, false);
+ if(node < 0)
+ return;
+
+ CVehicle *v;
+ if(CModelInfo::IsBoatModel(id))
+ return;
+ else
+ v = new CAutomobile(id, RANDOM_VEHICLE);
+
+ v->bHasBeenOwnedByPlayer = true;
+ if(carCol1)
+ DebugMenuEntrySetAddress(carCol1, &v->m_currentColour1);
+ if(carCol2)
+ DebugMenuEntrySetAddress(carCol2, &v->m_currentColour2);
+
+ v->GetPosition() = ThePaths.m_pathNodes[node].pos;
+ v->GetPosition().z += 4.0f;
+ v->SetOrientation(0.0f, 0.0f, 3.49f);
+ v->m_status = STATUS_ABANDONED;
+ v->m_nDoorLock = CARLOCK_UNLOCKED;
+ CWorld::Add(v);
+ }
+}
+
+static void
+LetThemFollowYou(void) {
+ CPed* player = (CPed*) FindPlayerPed();
+ for (int i = 0; i < player->m_numNearPeds; i++) {
+
+ CPed* nearPed = player->m_nearPeds[i];
+ if (nearPed && !nearPed->IsPlayer()) {
+ nearPed->SetObjective(OBJECTIVE_FOLLOW_PED_IN_FORMATION, (void*)player);
+ nearPed->m_pedFormation = rand() & 7;
+ nearPed->bScriptObjectiveCompleted = false;
+ }
+ }
+}
+
+static void
+FixCar(void)
+{
+ CVehicle *veh = FindPlayerVehicle();
+ if(veh == nil)
+ return;
+ veh->m_fHealth = 1000.0f;
+ if(!veh->IsCar())
+ return;
+ ((CAutomobile*)veh)->Damage.SetEngineStatus(0);
+ ((CAutomobile*)veh)->Fix();
+}
+
+static int engineStatus;
+static void
+SetEngineStatus(void)
+{
+ CVehicle *veh = FindPlayerVehicle();
+ if(veh == nil)
+ return;
+ if(!veh->IsCar())
+ return;
+ ((CAutomobile*)veh)->Damage.SetEngineStatus(engineStatus);
+}
+
+static void
+ToggleComedy(void)
+{
+ CVehicle *veh = FindPlayerVehicle();
+ if(veh == nil)
+ return;
+ veh->bComedyControls = !veh->bComedyControls;
+}
+
+static void
+PlaceOnRoad(void)
+{
+ CVehicle *veh = FindPlayerVehicle();
+ if(veh == nil)
+ return;
+
+ if(veh->IsCar())
+ ((CAutomobile*)veh)->PlaceOnRoadProperly();
+}
+
+static const char *carnames[] = {
+ "landstal", "idaho", "stinger", "linerun", "peren", "sentinel", "patriot", "firetruk", "trash", "stretch", "manana", "infernus", "blista", "pony",
+ "mule", "cheetah", "ambulan", "fbicar", "moonbeam", "esperant", "taxi", "kuruma", "bobcat", "mrwhoop", "bfinject", "corpse", "police", "enforcer",
+ "securica", "banshee", "predator", "bus", "rhino", "barracks", "train", "chopper", "dodo", "coach", "cabbie", "stallion", "rumpo", "rcbandit",
+ "bellyup", "mrwongs", "mafia", "yardie", "yakuza", "diablos", "columb", "hoods", "airtrain", "deaddodo", "speeder", "reefer", "panlant", "flatbed",
+ "yankee", "escape", "borgnine", "toyz", "ghost",
+};
+
+static std::list<CTweakVar *> TweakVarsList;
+static bool bAddTweakVarsNow = false;
+static const char *pTweakVarsDefaultPath = NULL;
+
+void CTweakVars::Add(CTweakVar *var)
+{
+ TweakVarsList.push_back(var);
+
+ if ( bAddTweakVarsNow )
+ var->AddDBG(pTweakVarsDefaultPath);
+}
+
+void CTweakVars::AddDBG(const char *path)
+{
+ pTweakVarsDefaultPath = path;
+
+ for(auto i = TweakVarsList.begin(); i != TweakVarsList.end(); ++i)
+ (*i)->AddDBG(pTweakVarsDefaultPath);
+
+ bAddTweakVarsNow = true;
+}
+
+void CTweakSwitch::AddDBG(const char *path)
+{
+ DebugMenuEntry *e = DebugMenuAddVar(m_pPath == NULL ? path : m_pPath, m_pVarName, (int32_t *)m_pIntVar, m_pFunc, 1, m_nMin, m_nMax, m_aStr);
+ DebugMenuEntrySetWrap(e, true);
+}
+
+void CTweakFunc::AddDBG (const char *path) { DebugMenuAddCmd (m_pPath == NULL ? path : m_pPath, m_pVarName, m_pFunc); }
+void CTweakBool::AddDBG (const char *path) { DebugMenuAddVarBool8(m_pPath == NULL ? path : m_pPath, m_pVarName, (int8_t *)m_pBoolVar, NULL); }
+void CTweakInt8::AddDBG (const char *path) { DebugMenuAddVar (m_pPath == NULL ? path : m_pPath, m_pVarName, (int8_t *)m_pIntVar, NULL, m_nStep, m_nLoawerBound, m_nUpperBound, NULL); }
+void CTweakUInt8::AddDBG (const char *path) { DebugMenuAddVar (m_pPath == NULL ? path : m_pPath, m_pVarName, (uint8_t *)m_pIntVar, NULL, m_nStep, m_nLoawerBound, m_nUpperBound, NULL); }
+void CTweakInt16::AddDBG (const char *path) { DebugMenuAddVar (m_pPath == NULL ? path : m_pPath, m_pVarName, (int16_t *)m_pIntVar, NULL, m_nStep, m_nLoawerBound, m_nUpperBound, NULL); }
+void CTweakUInt16::AddDBG(const char *path) { DebugMenuAddVar (m_pPath == NULL ? path : m_pPath, m_pVarName, (uint16_t *)m_pIntVar, NULL, m_nStep, m_nLoawerBound, m_nUpperBound, NULL); }
+void CTweakInt32::AddDBG (const char *path) { DebugMenuAddVar (m_pPath == NULL ? path : m_pPath, m_pVarName, (int32_t *)m_pIntVar, NULL, m_nStep, m_nLoawerBound, m_nUpperBound, NULL); }
+void CTweakUInt32::AddDBG(const char *path) { DebugMenuAddVar (m_pPath == NULL ? path : m_pPath, m_pVarName, (uint32_t *)m_pIntVar, NULL, m_nStep, m_nLoawerBound, m_nUpperBound, NULL); }
+void CTweakFloat::AddDBG (const char *path) { DebugMenuAddVar (m_pPath == NULL ? path : m_pPath, m_pVarName, (float *)m_pIntVar, NULL, m_nStep, m_nLoawerBound, m_nUpperBound); }
+
+/*
+static const char *wt[] = {
+ "Sunny", "Cloudy", "Rainy", "Foggy"
+ };
+
+SETTWEAKPATH("TEST");
+TWEAKSWITCH(CWeather::NewWeatherType, 0, 3, wt, NULL);
+*/
+
+void
+DebugMenuPopulate(void)
+{
+ if(DebugMenuLoad()){
+ static const char *weathers[] = {
+ "Sunny", "Cloudy", "Rainy", "Foggy"
+ };
+ DebugMenuEntry *e;
+ e = DebugMenuAddVar("Time & Weather", "Current Hour", &CClock::GetHoursRef(), nil, 1, 0, 23, nil);
+ DebugMenuEntrySetWrap(e, true);
+ e = DebugMenuAddVar("Time & Weather", "Current Minute", &CClock::GetMinutesRef(),
+ [](){ CWeather::InterpolationValue = CClock::GetMinutes()/60.0f; }, 1, 0, 59, nil);
+ DebugMenuEntrySetWrap(e, true);
+ e = DebugMenuAddVar("Time & Weather", "Old Weather", (int16*)&CWeather::OldWeatherType, nil, 1, 0, 3, weathers);
+ DebugMenuEntrySetWrap(e, true);
+ e = DebugMenuAddVar("Time & Weather", "New Weather", (int16*)&CWeather::NewWeatherType, nil, 1, 0, 3, weathers);
+ DebugMenuEntrySetWrap(e, true);
+ DebugMenuAddVar("Time & Weather", "Wind", (float*)&CWeather::Wind, nil, 0.1f, 0.0f, 1.0f);
+ DebugMenuAddVar("Time & Weather", "Time scale", (float*)0x8F2C20, nil, 0.1f, 0.0f, 10.0f);
+
+ DebugMenuAddCmd("Cheats", "Weapons", WeaponCheat);
+ DebugMenuAddCmd("Cheats", "Money", MoneyCheat);
+ DebugMenuAddCmd("Cheats", "Health", HealthCheat);
+ DebugMenuAddCmd("Cheats", "Wanted level up", WantedLevelUpCheat);
+ DebugMenuAddCmd("Cheats", "Wanted level down", WantedLevelDownCheat);
+ DebugMenuAddCmd("Cheats", "Tank", TankCheat);
+ DebugMenuAddCmd("Cheats", "Blow up cars", BlowUpCarsCheat);
+ DebugMenuAddCmd("Cheats", "Change player", ChangePlayerCheat);
+ DebugMenuAddCmd("Cheats", "Mayhem", MayhemCheat);
+ DebugMenuAddCmd("Cheats", "Everybody attacks player", EverybodyAttacksPlayerCheat);
+ DebugMenuAddCmd("Cheats", "Weapons for all", WeaponsForAllCheat);
+ DebugMenuAddCmd("Cheats", "Fast time", FastTimeCheat);
+ DebugMenuAddCmd("Cheats", "Slow time", SlowTimeCheat);
+ DebugMenuAddCmd("Cheats", "Armour", ArmourCheat);
+ DebugMenuAddCmd("Cheats", "Sunny weather", SunnyWeatherCheat);
+ DebugMenuAddCmd("Cheats", "Cloudy weather", CloudyWeatherCheat);
+ DebugMenuAddCmd("Cheats", "Rainy weather", RainyWeatherCheat);
+ DebugMenuAddCmd("Cheats", "Foggy weather", FoggyWeatherCheat);
+ DebugMenuAddCmd("Cheats", "Fast weather", FastWeatherCheat);
+ DebugMenuAddCmd("Cheats", "Only render wheels", OnlyRenderWheelsCheat);
+ DebugMenuAddCmd("Cheats", "Chitty chitty bang bang", ChittyChittyBangBangCheat);
+ DebugMenuAddCmd("Cheats", "Strong grip", StrongGripCheat);
+ DebugMenuAddCmd("Cheats", "Nasty limbs", NastyLimbsCheat);
+
+ static int spawnCarId = MI_LANDSTAL;
+ e = DebugMenuAddVar("Spawn", "Spawn Car ID", &spawnCarId, nil, 1, MI_LANDSTAL, MI_GHOST, carnames);
+ DebugMenuEntrySetWrap(e, true);
+ DebugMenuAddCmd("Spawn", "Spawn Car", [](){
+ if(spawnCarId == MI_TRAIN ||
+ spawnCarId == MI_CHOPPER ||
+ spawnCarId == MI_AIRTRAIN ||
+ spawnCarId == MI_DEADDODO ||
+ spawnCarId == MI_ESCAPE)
+ return;
+ SpawnCar(spawnCarId);
+ });
+ static uint8 dummy;
+ carCol1 = DebugMenuAddVar("Spawn", "First colour", &dummy, nil, 1, 0, 255, nil);
+ carCol2 = DebugMenuAddVar("Spawn", "Second colour", &dummy, nil, 1, 0, 255, nil);
+ DebugMenuAddCmd("Spawn", "Spawn Stinger", [](){ SpawnCar(MI_STINGER); });
+ DebugMenuAddCmd("Spawn", "Spawn Infernus", [](){ SpawnCar(MI_INFERNUS); });
+ DebugMenuAddCmd("Spawn", "Spawn Cheetah", [](){ SpawnCar(MI_CHEETAH); });
+ DebugMenuAddCmd("Spawn", "Spawn Esperanto", [](){ SpawnCar(MI_ESPERANT); });
+ DebugMenuAddCmd("Spawn", "Spawn Stallion", [](){ SpawnCar(MI_STALLION); });
+ DebugMenuAddCmd("Spawn", "Spawn Kuruma", [](){ SpawnCar(MI_KURUMA); });
+ 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 Yakuza", [](){ SpawnCar(MI_YAKUZA); });
+ DebugMenuAddCmd("Spawn", "Spawn Yardie", [](){ SpawnCar(MI_YARDIE); });
+ DebugMenuAddCmd("Spawn", "Spawn Dodo", [](){ SpawnCar(MI_DODO); });
+ DebugMenuAddCmd("Spawn", "Spawn Rhino", [](){ SpawnCar(MI_RHINO); });
+ DebugMenuAddCmd("Spawn", "Spawn Firetruck", [](){ SpawnCar(MI_FIRETRUCK); });
+
+ DebugMenuAddVar("Debug", "Engine Status", &engineStatus, nil, 1, 0, 226, nil);
+ DebugMenuAddCmd("Debug", "Set Engine Status", SetEngineStatus);
+ DebugMenuAddCmd("Debug", "Fix Car", FixCar);
+ DebugMenuAddCmd("Debug", "Toggle Comedy Controls", ToggleComedy);
+ DebugMenuAddCmd("Debug", "Place Car on Road", PlaceOnRoad);
+
+ DebugMenuAddVarBool8("Debug", "Catalina Heli On", (int8*)&CHeli::CatalinaHeliOn, nil);
+ DebugMenuAddCmd("Debug", "Catalina Fly By", CHeli::StartCatalinaFlyBy);
+ DebugMenuAddCmd("Debug", "Catalina Take Off", CHeli::CatalinaTakeOff);
+ DebugMenuAddCmd("Debug", "Catalina Fly Away", CHeli::MakeCatalinaHeliFlyAway);
+ DebugMenuAddVarBool8("Debug", "Script Heli On", (int8*)0x95CD43, nil);
+
+ DebugMenuAddVarBool8("Debug", "Show Ped Road Groups", (int8*)&gbShowPedRoadGroups, nil);
+ DebugMenuAddVarBool8("Debug", "Show Car Road Groups", (int8*)&gbShowCarRoadGroups, nil);
+ DebugMenuAddVarBool8("Debug", "Show Collision Lines", (int8*)&gbShowCollisionLines, nil);
+ DebugMenuAddVarBool8("Debug", "Show Collision Polys", (int8*)&gbShowCollisionPolys, nil);
+ DebugMenuAddVarBool8("Debug", "Don't render Buildings", (int8*)&gbDontRenderBuildings, nil);
+ DebugMenuAddVarBool8("Debug", "Don't render Big Buildings", (int8*)&gbDontRenderBigBuildings, nil);
+ DebugMenuAddVarBool8("Debug", "Don't render Peds", (int8*)&gbDontRenderPeds, nil);
+ DebugMenuAddVarBool8("Debug", "Don't render Vehicles", (int8*)&gbDontRenderVehicles, nil);
+ DebugMenuAddVarBool8("Debug", "Don't render Objects", (int8*)&gbDontRenderObjects, nil);
+
+ DebugMenuAddCmd("Debug", "Make peds around you follow you", LetThemFollowYou);
+#ifndef MASTER
+ DebugMenuAddVarBool8("Debug", "Toggle unused fight feature", (int8*)&CPed::bUnusedFightThingOnPlayer, nil);
+#endif
+
+ DebugMenuAddCmd("Debug", "Start Credits", CCredits::Start);
+ DebugMenuAddCmd("Debug", "Stop Credits", CCredits::Stop);
+
+ CTweakVars::AddDBG("Debug");
+ }
+}
+
+/*
+int (*RsEventHandler_orig)(int a, int b);
+int
+delayedPatches10(int a, int b)
+{
+ DebugMenuInit();
+ DebugMenuPopulate();
+
+ return RsEventHandler_orig(a, b);
+}
+*/
+
+const int re3_buffsize = 1024;
+static char re3_buff[re3_buffsize];
+
+void re3_assert(const char *expr, const char *filename, unsigned int lineno, const char *func)
+{
+ int nCode;
+
+ strcpy_s(re3_buff, re3_buffsize, "Assertion failed!" );
+ strcat_s(re3_buff, re3_buffsize, "\n" );
+
+ strcat_s(re3_buff, re3_buffsize, "File: ");
+ strcat_s(re3_buff, re3_buffsize, filename );
+ strcat_s(re3_buff, re3_buffsize, "\n" );
+
+ strcat_s(re3_buff, re3_buffsize, "Line: " );
+ _itoa_s( lineno, re3_buff + strlen(re3_buff), re3_buffsize - strlen(re3_buff), 10 );
+ strcat_s(re3_buff, re3_buffsize, "\n");
+
+ strcat_s(re3_buff, re3_buffsize, "Function: ");
+ strcat_s(re3_buff, re3_buffsize, func );
+ strcat_s(re3_buff, re3_buffsize, "\n" );
+
+ strcat_s(re3_buff, re3_buffsize, "Expression: ");
+ strcat_s(re3_buff, re3_buffsize, expr);
+ strcat_s(re3_buff, re3_buffsize, "\n");
+
+ strcat_s(re3_buff, re3_buffsize, "\n" );
+ strcat_s(re3_buff, re3_buffsize, "(Press Retry to debug the application)");
+
+
+ nCode = ::MessageBoxA(nil, re3_buff, "RE3 Assertion Failed!",
+ MB_ABORTRETRYIGNORE|MB_ICONHAND|MB_SETFOREGROUND|MB_TASKMODAL);
+
+ if (nCode == IDABORT)
+ {
+ raise(SIGABRT);
+ _exit(3);
+ }
+
+ if (nCode == IDRETRY)
+ {
+ __debugbreak();
+ return;
+ }
+
+ if (nCode == IDIGNORE)
+ return;
+
+ abort();
+}
+
+void re3_debug(char *format, ...)
+{
+ va_list va;
+ va_start(va, format);
+ vsprintf_s(re3_buff, re3_buffsize, format, va);
+ va_end(va);
+
+ printf("%s", re3_buff);
+}
+
+void re3_trace(const char *filename, unsigned int lineno, const char *func, char *format, ...)
+{
+ char buff[re3_buffsize *2];
+ va_list va;
+ va_start(va, format);
+ vsprintf_s(re3_buff, re3_buffsize, format, va);
+ va_end(va);
+
+ sprintf_s(buff, re3_buffsize * 2, "[%s.%s:%d]: %s", filename, func, lineno, re3_buff);
+
+ OutputDebugStringA(buff);
+}
+
+void
+patch()
+{
+ StaticPatcher::Apply();
+
+// Patch<float>(0x46BC61+6, 1.0f); // car distance
+ InjectHook(0x59E460, printf, PATCH_JUMP);
+ InjectHook(0x475E00, printf, PATCH_JUMP); // _Error
+
+
+// InterceptCall(&open_script_orig, open_script, 0x438869);
+
+// InterceptCall(&RsEventHandler_orig, delayedPatches10, 0x58275E);
+}
+
+BOOL WINAPI
+DllMain(HINSTANCE hInst, DWORD reason, LPVOID)
+{
+ if(reason == DLL_PROCESS_ATTACH){
+
+ AllocConsole();
+ freopen("CONIN$", "r", stdin);
+ freopen("CONOUT$", "w", stdout);
+ freopen("CONOUT$", "w", stderr);
+
+ if (*(DWORD*)0x5C1E75 == 0xB85548EC) // 1.0
+ patch();
+ else
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp
index fbd1322d..d59e6c59 100644
--- a/src/entities/Physical.cpp
+++ b/src/entities/Physical.cpp
@@ -457,7 +457,7 @@ CPhysical::ApplySpringCollision(float springConst, CVector &springDir, CVector &
{
float compression = 1.0f - springRatio;
if(compression > 0.0f){
- float step = min(CTimer::GetTimeStep(), 3.0f);
+ float step = Min(CTimer::GetTimeStep(), 3.0f);
float impulse = -GRAVITY*m_fMass*step * springConst * compression * bias*2.0f;
ApplyMoveForce(springDir*impulse);
ApplyTurnForce(springDir*impulse, point);
@@ -471,12 +471,12 @@ CPhysical::ApplySpringDampening(float damping, CVector &springDir, CVector &poin
{
float speedA = DotProduct(speed, springDir);
float speedB = DotProduct(GetSpeed(point), springDir);
- float step = min(CTimer::GetTimeStep(), 3.0f);
+ float step = Min(CTimer::GetTimeStep(), 3.0f);
float impulse = -damping * (speedA + speedB)/2.0f * m_fMass * step * 0.53f;
// what is this?
float a = m_fTurnMass / ((point.MagnitudeSqr() + 1.0f) * 2.0f * m_fMass);
- a = min(a, 1.0f);
+ a = Min(a, 1.0f);
float b = Abs(impulse / (speedB * m_fMass));
if(a < b)
impulse *= a/b;
@@ -646,7 +646,7 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl
// positive if B is moving towards A
// not interested in how much B moves into A apparently?
// only interested in cases where A collided into B
- speedB = max(0.0f, DotProduct(B->m_vecMoveSpeed, colpoint.normal));
+ speedB = Max(0.0f, DotProduct(B->m_vecMoveSpeed, colpoint.normal));
// A has moved into B
if(speedA < speedB){
if(!A->bHasHitWall)
@@ -1147,18 +1147,18 @@ CPhysical::ProcessShiftSectorList(CPtrList *lists)
CVector dir = A->GetPosition() - B->GetPosition();
dir.Normalise();
if(dir.z < 0.0f && dir.z < A->GetForward().z && dir.z < A->GetRight().z)
- dir.z = min(0.0f, min(A->GetForward().z, A->GetRight().z));
+ dir.z = Min(0.0f, Min(A->GetForward().z, A->GetRight().z));
shift += dir * colpoints[mostColliding].depth * 0.5f;
}else if(A->IsPed() && B->IsVehicle() && ((CVehicle*)B)->IsBoat()){
CVector dir = colpoints[mostColliding].normal;
- float f = min(Abs(dir.z), 0.9f);
+ float f = Min(Abs(dir.z), 0.9f);
dir.z = 0.0f;
dir.Normalise();
shift += dir * colpoints[mostColliding].depth / (1.0f - f);
boat = B;
}else if(B->IsPed() && A->IsVehicle() && ((CVehicle*)A)->IsBoat()){
CVector dir = colpoints[mostColliding].normal * -1.0f;
- float f = min(Abs(dir.z), 0.9f);
+ float f = Min(Abs(dir.z), 0.9f);
dir.z = 0.0f;
dir.Normalise();
B->GetPosition() += dir * colpoints[mostColliding].depth / (1.0f - f);
@@ -1246,7 +1246,7 @@ collision:
float turnSpeedDiff = (B->m_vecTurnSpeed - A->m_vecTurnSpeed).MagnitudeSqr();
float moveSpeedDiff = (B->m_vecMoveSpeed - A->m_vecMoveSpeed).MagnitudeSqr();
- DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, max(turnSpeedDiff, moveSpeedDiff));
+ DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, Max(turnSpeedDiff, moveSpeedDiff));
}
}else if(A->bHasContacted){
CVector savedMoveFriction = A->m_vecMoveFriction;
@@ -1268,7 +1268,7 @@ collision:
float turnSpeedDiff = (B->m_vecTurnSpeed - A->m_vecTurnSpeed).MagnitudeSqr();
float moveSpeedDiff = (B->m_vecMoveSpeed - A->m_vecMoveSpeed).MagnitudeSqr();
- DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, max(turnSpeedDiff, moveSpeedDiff));
+ DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, Max(turnSpeedDiff, moveSpeedDiff));
if(A->ApplyFriction(B, CSurfaceTable::GetAdhesiveLimit(aColPoints[i])/numCollisions, aColPoints[i])){
A->bHasContacted = true;
@@ -1301,7 +1301,7 @@ collision:
float turnSpeedDiff = (B->m_vecTurnSpeed - A->m_vecTurnSpeed).MagnitudeSqr();
float moveSpeedDiff = (B->m_vecMoveSpeed - A->m_vecMoveSpeed).MagnitudeSqr();
- DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, max(turnSpeedDiff, moveSpeedDiff));
+ DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, Max(turnSpeedDiff, moveSpeedDiff));
if(A->ApplyFriction(B, CSurfaceTable::GetAdhesiveLimit(aColPoints[i])/numCollisions, aColPoints[i])){
A->bHasContacted = true;
@@ -1328,7 +1328,7 @@ collision:
float turnSpeedDiff = (B->m_vecTurnSpeed - A->m_vecTurnSpeed).MagnitudeSqr();
float moveSpeedDiff = (B->m_vecMoveSpeed - A->m_vecMoveSpeed).MagnitudeSqr();
- DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, max(turnSpeedDiff, moveSpeedDiff));
+ DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, Max(turnSpeedDiff, moveSpeedDiff));
if(A->ApplyFriction(B, CSurfaceTable::GetAdhesiveLimit(aColPoints[i])/numCollisions, aColPoints[i])){
A->bHasContacted = true;
@@ -1506,7 +1506,7 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists)
float turnSpeedDiff = A->m_vecTurnSpeed.MagnitudeSqr();
float moveSpeedDiff = A->m_vecMoveSpeed.MagnitudeSqr();
- DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, imp, max(turnSpeedDiff, moveSpeedDiff));
+ DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, imp, Max(turnSpeedDiff, moveSpeedDiff));
}
}else{
for(i = 0; i < numCollisions; i++){
@@ -1527,7 +1527,7 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists)
float turnSpeedDiff = A->m_vecTurnSpeed.MagnitudeSqr();
float moveSpeedDiff = A->m_vecMoveSpeed.MagnitudeSqr();
- DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, imp, max(turnSpeedDiff, moveSpeedDiff));
+ DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, imp, Max(turnSpeedDiff, moveSpeedDiff));
float adhesion = CSurfaceTable::GetAdhesiveLimit(aColPoints[i]) / numCollisions;
@@ -1545,7 +1545,7 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists)
else if(A->GetUp().z > 0.3f)
adhesion = 0.0f;
else
- adhesion *= min(5.0f, 0.03f*impulseA + 1.0f);
+ adhesion *= Min(5.0f, 0.03f*impulseA + 1.0f);
}
if(A->ApplyFriction(adhesion, aColPoints[i]))
@@ -1594,7 +1594,7 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists)
float turnSpeedDiff = (B->m_vecTurnSpeed - A->m_vecTurnSpeed).MagnitudeSqr();
float moveSpeedDiff = (B->m_vecMoveSpeed - A->m_vecMoveSpeed).MagnitudeSqr();
- DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, max(turnSpeedDiff, moveSpeedDiff));
+ DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, Max(turnSpeedDiff, moveSpeedDiff));
}
}else if(A->bHasContacted){
CVector savedMoveFriction = A->m_vecMoveFriction;
@@ -1619,7 +1619,7 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists)
float turnSpeedDiff = (B->m_vecTurnSpeed - A->m_vecTurnSpeed).MagnitudeSqr();
float moveSpeedDiff = (B->m_vecMoveSpeed - A->m_vecMoveSpeed).MagnitudeSqr();
- DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, max(turnSpeedDiff, moveSpeedDiff));
+ DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, Max(turnSpeedDiff, moveSpeedDiff));
if(A->ApplyFriction(B, CSurfaceTable::GetAdhesiveLimit(aColPoints[i])/numCollisions, aColPoints[i])){
A->bHasContacted = true;
@@ -1655,7 +1655,7 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists)
float turnSpeedDiff = (B->m_vecTurnSpeed - A->m_vecTurnSpeed).MagnitudeSqr();
float moveSpeedDiff = (B->m_vecMoveSpeed - A->m_vecMoveSpeed).MagnitudeSqr();
- DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, max(turnSpeedDiff, moveSpeedDiff));
+ DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, Max(turnSpeedDiff, moveSpeedDiff));
if(A->ApplyFriction(B, CSurfaceTable::GetAdhesiveLimit(aColPoints[i])/numCollisions, aColPoints[i])){
A->bHasContacted = true;
@@ -1685,7 +1685,7 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists)
float turnSpeedDiff = (B->m_vecTurnSpeed - A->m_vecTurnSpeed).MagnitudeSqr();
float moveSpeedDiff = (B->m_vecMoveSpeed - A->m_vecMoveSpeed).MagnitudeSqr();
- DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, max(turnSpeedDiff, moveSpeedDiff));
+ DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, Max(turnSpeedDiff, moveSpeedDiff));
if(A->ApplyFriction(B, CSurfaceTable::GetAdhesiveLimit(aColPoints[i])/numCollisions, aColPoints[i])){
A->bHasContacted = true;
@@ -1831,7 +1831,7 @@ CPhysical::ProcessCollision(void)
if(IsPed() && (distSq >= sq(0.2f) || ped->IsPlayer())){
if(ped->IsPlayer())
- n = max(NUMSTEPS(0.2f), 2.0);
+ n = Max(NUMSTEPS(0.2f), 2.0);
else
n = NUMSTEPS(0.3f);
step = savedTimeStep / n;
@@ -1852,7 +1852,7 @@ CPhysical::ProcessCollision(void)
speedDown = Multiply3x3(GetMatrix(), speedDown);
speedUp = GetSpeed(speedUp);
speedDown = GetSpeed(speedDown);
- distSq = max(speedUp.MagnitudeSqr(), speedDown.MagnitudeSqr()) * sq(CTimer::GetTimeStep());
+ distSq = Max(speedUp.MagnitudeSqr(), speedDown.MagnitudeSqr()) * sq(CTimer::GetTimeStep());
if(distSq >= sq(0.3f)){
n = NUMSTEPS(0.3f);
step = savedTimeStep / n;
diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp
index 53d94d86..59395d94 100644
--- a/src/peds/Ped.cpp
+++ b/src/peds/Ped.cpp
@@ -1792,7 +1792,7 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase)
neededPos.z = autoZPos.z;
m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
} else if (neededPos.z <= currentZ && m_pVehicleAnim && vehAnim != ANIM_VAN_CLOSE_L && vehAnim != ANIM_VAN_CLOSE) {
- adjustedTimeStep = min(m_pVehicleAnim->timeStep, 0.1f);
+ adjustedTimeStep = Min(m_pVehicleAnim->timeStep, 0.1f);
// Smoothly change ped position
neededPos.z = currentZ - (currentZ - neededPos.z) / (m_pVehicleAnim->GetTimeLeft() / adjustedTimeStep);
@@ -1807,12 +1807,12 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase)
if (m_pVehicleAnim &&
(vehAnim == ANIM_CAR_GETIN_RHS || vehAnim == ANIM_CAR_GETIN_LOW_RHS || vehAnim == ANIM_CAR_GETIN_LHS || vehAnim == ANIM_CAR_GETIN_LOW_LHS
|| vehAnim == ANIM_CAR_QJACK || vehAnim == ANIM_VAN_GETIN_L || vehAnim == ANIM_VAN_GETIN)) {
- adjustedTimeStep = min(m_pVehicleAnim->timeStep, 0.1f);
+ adjustedTimeStep = Min(m_pVehicleAnim->timeStep, 0.1f);
// Smoothly change ped position
neededPos.z = (neededPos.z - currentZ) / (m_pVehicleAnim->GetTimeLeft() / adjustedTimeStep) + currentZ;
} else if (m_nPedState == PED_ENTER_CAR || m_nPedState == PED_CARJACK) {
- neededPos.z = max(currentZ, autoZPos.z);
+ neededPos.z = Max(currentZ, autoZPos.z);
}
}
}
@@ -3172,7 +3172,7 @@ CPed::CheckIfInTheAir(void)
CEntity *foundEntity;
float startZ = pos.z - 1.54f;
- bool foundGround = CWorld::ProcessVerticalLine(pos, startZ, foundColPoint, foundEntity, true, true, false, true, false, false, false);
+ bool foundGround = CWorld::ProcessVerticalLine(pos, startZ, foundColPoint, foundEntity, true, true, false, true, false, false, nil);
if (!foundGround && m_nPedState != PED_JUMP)
{
pos.z -= 1.04f;
@@ -4771,12 +4771,12 @@ CPed::FightStrike(CVector &touchedNodePos)
float moveMult;
if (m_lastFightMove == FIGHTMOVE_GROUNDKICK) {
- moveMult = min(damageMult * 0.6f, 4.0f);
+ moveMult = Min(damageMult * 0.6f, 4.0f);
} else {
if (nearPed->m_nPedState != PED_DIE || damageMult >= 20) {
moveMult = damageMult;
} else {
- moveMult = min(damageMult * 2.0f, 14.0f);
+ moveMult = Min(damageMult * 2.0f, 14.0f);
}
}
diff --git a/src/peds/Ped.h b/src/peds/Ped.h
index 5922e0e7..ff581150 100644
--- a/src/peds/Ped.h
+++ b/src/peds/Ped.h
@@ -718,6 +718,15 @@ public:
#endif
};
+class cPedParams
+{
+public:
+ char m_bDistanceCalculated;
+ char gap_1[3];
+ float m_fDistance;
+ CPed *m_pPed;
+};
+
void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg);
static_assert(offsetof(CPed, m_nPedState) == 0x224, "CPed: error");
diff --git a/src/peds/PedPlacement.cpp b/src/peds/PedPlacement.cpp
index f292f4fa..d7b7ec75 100644
--- a/src/peds/PedPlacement.cpp
+++ b/src/peds/PedPlacement.cpp
@@ -29,7 +29,7 @@ CPedPlacement::FindZCoorForPed(CVector* pos)
if (CWorld::ProcessVerticalLine(vec, startZ, foundCol, foundEnt, true, false, false, false, true, false, nil))
foundColZ2 = foundCol.point.z;
- zForPed = max(foundColZ, foundColZ2);
+ zForPed = Max(foundColZ, foundColZ2);
if (zForPed > -99.0f)
pos->z = 1.04f + zForPed;
@@ -38,7 +38,7 @@ CPedPlacement::FindZCoorForPed(CVector* pos)
CEntity*
CPedPlacement::IsPositionClearOfCars(CVector* pos)
{
- return CWorld::TestSphereAgainstWorld(*pos, 0.25f, false, true, true, false, false, false, false);
+ return CWorld::TestSphereAgainstWorld(*pos, 0.25f, nil, true, true, false, false, false, false);
}
STARTPATCHES
diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp
index 5ae8c4be..1dcbdf46 100644
--- a/src/peds/PlayerPed.cpp
+++ b/src/peds/PlayerPed.cpp
@@ -97,8 +97,16 @@ CPlayerPed::AnnoyPlayerPed(bool annoyedByPassingEntity)
class CPlayerPed_ : public CPlayerPed
{
public:
+<<<<<<< HEAD
+<<<<<<< HEAD
CPlayerPed* ctor(void) { return ::new (this) CPlayerPed(); }
void dtor(void) { CPlayerPed::~CPlayerPed(); }
+=======
+ void dtor(void) { this->~CPlayerPed(); }
+>>>>>>> More audio ped
+=======
+ void dtor(void) { CPlayerPed::~CPlayerPed(); }
+>>>>>>> fix
};
STARTPATCHES
diff --git a/src/peds/PlayerPed.cpp.autosave b/src/peds/PlayerPed.cpp.autosave
new file mode 100644
index 00000000..1bf1c7fc
--- /dev/null
+++ b/src/peds/PlayerPed.cpp.autosave
@@ -0,0 +1,110 @@
+#include "common.h"
+#include "patcher.h"
+#include "PlayerPed.h"
+#include "Camera.h"
+#include "WeaponEffects.h"
+#include "ModelIndices.h"
+
+CPlayerPed::~CPlayerPed()
+{
+ delete m_pWanted;
+}
+
+WRAPPER void CPlayerPed::ReApplyMoveAnims(void) { EAXJMP(0x4F07C0); }
+WRAPPER void CPlayerPed::SetupPlayerPed(int32) { EAXJMP(0x4EFB60); }
+WRAPPER void CPlayerPed::DeactivatePlayerPed(int32) { EAXJMP(0x4EFC00); }
+WRAPPER void CPlayerPed::ReactivatePlayerPed(int32) { EAXJMP(0x4EFC20); }
+WRAPPER void CPlayerPed::KeepAreaAroundPlayerClear(void) { EAXJMP(0x4F3460); }
+WRAPPER void CPlayerPed::MakeChangesForNewWeapon(int8) { EAXJMP(0x4F2560); }
+WRAPPER void CPlayerPed::SetInitialState(void) { EAXJMP(0x4EFC40); }
+WRAPPER void CPlayerPed::SetMoveAnim(void) { EAXJMP(0x4F3760); }
+WRAPPER void CPlayerPed::ProcessControl(void) { EAXJMP(0x4EFD90); }
+
+CPlayerPed::CPlayerPed(void) : CPed(PEDTYPE_PLAYER1)
+{
+ m_fMoveSpeed = 0.0f;
+ SetModelIndex(MI_PLAYER);
+ SetInitialState();
+
+ m_pWanted = new CWanted();
+ m_pWanted->Initialise();
+ m_pArrestingCop = nil;
+ m_currentWeapon = WEAPONTYPE_UNARMED;
+ m_nSelectedWepSlot = 0;
+ m_nSpeedTimer = 0;
+ m_bSpeedTimerFlag = 0;
+ m_pPointGunAt = nil;
+ m_nPedState = PED_IDLE;
+ m_fMaxStamina = 150.0f;
+ m_fCurrentStamina = m_fMaxStamina;
+ m_fStaminaProgress = 0.0f;
+ m_bShouldEvade = 0;
+ field_1367 = 0;
+ m_nShotDelay = 0;
+ field_1376 = 0.0f;
+ field_1380 = 0;
+ m_bHasLockOnTarget = false;
+ m_bCanBeDamaged = true;
+ m_fWalkAngle = 0.0f;
+ m_fFPSMoveHeading = 0.0f;
+ m_nTargettableObjects[0] = m_nTargettableObjects[1] = m_nTargettableObjects[2] = m_nTargettableObjects[3] = -1;
+ field_1413 = 0;
+ for (int i = 0; i < 6; i++) {
+ m_vecSafePos[i] = CVector(0.0f, 0.0f, 0.0f);
+ field_1488[i] = 0;
+ }
+}
+
+void CPlayerPed::ClearWeaponTarget()
+{
+ if (m_nPedType == PEDTYPE_PLAYER1) {
+ m_pPointGunAt = nil;
+ TheCamera.ClearPlayerWeaponMode();
+ CWeaponEffects::ClearCrosshair();
+ }
+ ClearPointGunAt();
+}
+
+void
+CPlayerPed::SetWantedLevel(int32 level)
+{
+ m_pWanted->SetWantedLevel(level);
+}
+
+void
+CPlayerPed::SetWantedLevelNoDrop(int32 level)
+{
+ m_pWanted->SetWantedLevelNoDrop(level);
+}
+
+// I don't know the actual purpose of parameter
+void
+CPlayerPed::AnnoyPlayerPed(bool annoyedByPassingEntity)
+{
+ if (m_pedStats->m_temper < 52) {
+ m_pedStats->m_temper++;
+ } else {
+ if (annoyedByPassingEntity) {
+ if (m_pedStats->m_temper < 55) {
+ m_pedStats->m_temper++;
+ } else {
+ m_pedStats->m_temper = 46;
+ }
+ }
+ }
+}
+
+class CPlayerPed_ : public CPlayerPed
+{
+public:
+
+ CPlayerPed* ctor(void) { return ::new (this) CPlayerPed(); }
+ void dtor(void) { CPlayerPed::~CPlayerPed(); }
+};
+
+STARTPATCHES
+ InjectHook(0x4EF7E0, &CPlayerPed_::ctor, PATCH_JUMP);
+ InjectHook(0x4EFB30, &CPlayerPed_::dtor, PATCH_JUMP);
+ InjectHook(0x4F28A0, &CPlayerPed::ClearWeaponTarget, PATCH_JUMP);
+ InjectHook(0x4F3700, &CPlayerPed::AnnoyPlayerPed, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/render/Clouds.cpp b/src/render/Clouds.cpp
index 2884894c..a461301c 100644
--- a/src/render/Clouds.cpp
+++ b/src/render/Clouds.cpp
@@ -388,7 +388,7 @@ CClouds::RenderBackground(int16 topred, int16 topgreen, int16 topblue,
ms_colourBottom.b = topblue;
ms_colourBottom.a = alpha;
- botpos = min(SCREEN_HEIGHT, topedge);
+ botpos = Min(SCREEN_HEIGHT, topedge);
CSprite2d::DrawRect(CRect(0, 0, SCREEN_WIDTH, botpos),
ms_colourBottom, ms_colourBottom, ms_colourTop, ms_colourTop);
}
@@ -415,18 +415,18 @@ CClouds::RenderHorizon(void)
if(ms_horizonZ > SCREEN_HEIGHT)
return;
- float z1 = min(ms_horizonZ + SMALLSTRIPHEIGHT, SCREEN_HEIGHT);
+ float z1 = Min(ms_horizonZ + SMALLSTRIPHEIGHT, SCREEN_HEIGHT);
CSprite2d::DrawRectXLU(CRect(0, ms_horizonZ, SCREEN_WIDTH, z1),
ms_colourBottom, ms_colourBottom, ms_colourTop, ms_colourTop);
// This is just weird
float a = SCREEN_HEIGHT/400.0f * HORIZSTRIPHEIGHT +
- SCREEN_HEIGHT/300.0f * max(TheCamera.GetPosition().z, 0.0f);
+ SCREEN_HEIGHT/300.0f * Max(TheCamera.GetPosition().z, 0.0f);
float b = TheCamera.GetUp().z < 0.0f ?
SCREEN_HEIGHT :
SCREEN_HEIGHT * Abs(TheCamera.GetRight().z);
float z2 = z1 + (a + b)*TheCamera.LODDistMultiplier;
- z2 = min(z2, SCREEN_HEIGHT);
+ z2 = Min(z2, SCREEN_HEIGHT);
CSprite2d::DrawRect(CRect(0, z1, SCREEN_WIDTH, z2),
ms_colourBottom, ms_colourBottom, ms_colourTop, ms_colourTop);
}
diff --git a/src/render/Coronas.cpp b/src/render/Coronas.cpp
index 1a6cfea3..9881e764 100644
--- a/src/render/Coronas.cpp
+++ b/src/render/Coronas.cpp
@@ -109,7 +109,7 @@ CCoronas::Update(void)
int i;
static int LastCamLook = 0;
- LightsMult = min(LightsMult + 0.03f * CTimer::GetTimeStep(), 1.0f);
+ LightsMult = Min(LightsMult + 0.03f * CTimer::GetTimeStep(), 1.0f);
int CamLook = 0;
if(TheCamera.Cams[TheCamera.ActiveCam].LookingLeft) CamLook |= 1;
@@ -121,7 +121,7 @@ CCoronas::Update(void)
if(LastCamLook != CamLook)
bChangeBrightnessImmediately = 3;
else
- bChangeBrightnessImmediately = max(bChangeBrightnessImmediately-1, 0);
+ bChangeBrightnessImmediately = Max(bChangeBrightnessImmediately-1, 0);
LastCamLook = CamLook;
for(i = 0; i < NUMCORONAS; i++)
@@ -309,7 +309,7 @@ CCoronas::Render(void)
// render corona itself
if(aCoronas[i].texture){
- float fogscale = CWeather::Foggyness*min(spriteCoors.z, 40.0f)/40.0f + 1.0f;
+ float fogscale = CWeather::Foggyness*Min(spriteCoors.z, 40.0f)/40.0f + 1.0f;
if(CCoronas::aCoronas[i].id == SUN_CORE)
spriteCoors.z = 0.95f * RwCameraGetFarClipPlane(Scene.camera);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(aCoronas[i].texture));
@@ -320,7 +320,7 @@ CCoronas::Render(void)
float f = 1.0f - aCoronas[i].someAngle*2.0f/PI;
float wscale = 6.0f*sq(sq(sq(f))) + 0.5f;
float hscale = 0.35f - (wscale - 0.5f) * 0.06f;
- hscale = max(hscale, 0.15f);
+ hscale = Max(hscale, 0.15f);
CSprite::RenderOneXLUSprite(spriteCoors.x, spriteCoors.y, spriteCoors.z,
spritew * aCoronas[i].size * wscale,
@@ -467,7 +467,7 @@ CCoronas::RenderReflections(void)
float spritew, spriteh;
if(CSprite::CalcScreenCoors(coors, spriteCoors, &spritew, &spriteh, true)){
float drawDist = 0.75f * aCoronas[i].drawDist;
- drawDist = min(drawDist, 50.0f);
+ drawDist = Min(drawDist, 50.0f);
if(spriteCoors.z < drawDist){
float fadeDistance = drawDist / 2.0f;
float distanceFade = spriteCoors.z < fadeDistance ? 1.0f : 1.0f - (spriteCoors.z - fadeDistance)/fadeDistance;
@@ -546,25 +546,25 @@ CRegisteredCorona::Update(void)
(CCoronas::SunBlockedByClouds && id == CCoronas::SUN_CORONA ||
!CWorld::GetIsLineOfSightClear(coors, TheCamera.GetPosition(), true, false, false, false, false, false))){
// Corona is blocked, fade out
- fadeAlpha = max(fadeAlpha - 15.0f*CTimer::GetTimeStep(), 0.0f);
+ fadeAlpha = Max(fadeAlpha - 15.0f*CTimer::GetTimeStep(), 0.0f);
}else if(offScreen){
// Same when off screen
- fadeAlpha = max(fadeAlpha - 15.0f*CTimer::GetTimeStep(), 0.0f);
+ fadeAlpha = Max(fadeAlpha - 15.0f*CTimer::GetTimeStep(), 0.0f);
}else{
// Visible
if(alpha > fadeAlpha){
// fade in
- fadeAlpha = min(fadeAlpha + 15.0f*CTimer::GetTimeStep(), alpha);
+ fadeAlpha = Min(fadeAlpha + 15.0f*CTimer::GetTimeStep(), alpha);
if(CCoronas::bChangeBrightnessImmediately)
fadeAlpha = alpha;
}else if(alpha < fadeAlpha){
// too visible, decrease alpha but not below alpha
- fadeAlpha = max(fadeAlpha - 15.0f*CTimer::GetTimeStep(), alpha);
+ fadeAlpha = Max(fadeAlpha - 15.0f*CTimer::GetTimeStep(), alpha);
}
// darken scene when the sun is visible
if(id == CCoronas::SUN_CORONA)
- CCoronas::LightsMult = max(CCoronas::LightsMult - CTimer::GetTimeStep()*0.06f, 0.6f);
+ CCoronas::LightsMult = Max(CCoronas::LightsMult - CTimer::GetTimeStep()*0.06f, 0.6f);
}
// remove if invisible
diff --git a/src/render/Lights.cpp b/src/render/Lights.cpp
index cd83a898..85d7ba13 100644
--- a/src/render/Lights.cpp
+++ b/src/render/Lights.cpp
@@ -37,9 +37,9 @@ SetLightsWithTimeOfDayColour(RpWorld *)
AmbientLightColourForFrame.green = 1.0f;
AmbientLightColourForFrame.blue = 1.0f;
}
- AmbientLightColourForFrame_PedsCarsAndObjects.red = min(1.0f, AmbientLightColourForFrame.red*1.3f);
- AmbientLightColourForFrame_PedsCarsAndObjects.green = min(1.0f, AmbientLightColourForFrame.green*1.3f);
- AmbientLightColourForFrame_PedsCarsAndObjects.blue = min(1.0f, AmbientLightColourForFrame.blue*1.3f);
+ AmbientLightColourForFrame_PedsCarsAndObjects.red = Min(1.0f, AmbientLightColourForFrame.red*1.3f);
+ AmbientLightColourForFrame_PedsCarsAndObjects.green = Min(1.0f, AmbientLightColourForFrame.green*1.3f);
+ AmbientLightColourForFrame_PedsCarsAndObjects.blue = Min(1.0f, AmbientLightColourForFrame.blue*1.3f);
RpLightSetColor(pAmbient, &AmbientLightColourForFrame);
}
@@ -70,16 +70,16 @@ SetLightsWithTimeOfDayColour(RpWorld *)
float f1 = 2.0f * (CMenuManager::m_PrefsBrightness/256.0f - 1.0f) * 0.6f + 1.0f;
float f2 = 3.0f * (CMenuManager::m_PrefsBrightness/256.0f - 1.0f) * 0.6f + 1.0f;
- AmbientLightColourForFrame.red = min(1.0f, AmbientLightColourForFrame.red * f2);
- AmbientLightColourForFrame.green = min(1.0f, AmbientLightColourForFrame.green * f2);
- AmbientLightColourForFrame.blue = min(1.0f, AmbientLightColourForFrame.blue * f2);
- AmbientLightColourForFrame_PedsCarsAndObjects.red = min(1.0f, AmbientLightColourForFrame_PedsCarsAndObjects.red * f1);
- AmbientLightColourForFrame_PedsCarsAndObjects.green = min(1.0f, AmbientLightColourForFrame_PedsCarsAndObjects.green * f1);
- AmbientLightColourForFrame_PedsCarsAndObjects.blue = min(1.0f, AmbientLightColourForFrame_PedsCarsAndObjects.blue * f1);
+ AmbientLightColourForFrame.red = Min(1.0f, AmbientLightColourForFrame.red * f2);
+ AmbientLightColourForFrame.green = Min(1.0f, AmbientLightColourForFrame.green * f2);
+ AmbientLightColourForFrame.blue = Min(1.0f, AmbientLightColourForFrame.blue * f2);
+ AmbientLightColourForFrame_PedsCarsAndObjects.red = Min(1.0f, AmbientLightColourForFrame_PedsCarsAndObjects.red * f1);
+ AmbientLightColourForFrame_PedsCarsAndObjects.green = Min(1.0f, AmbientLightColourForFrame_PedsCarsAndObjects.green * f1);
+ AmbientLightColourForFrame_PedsCarsAndObjects.blue = Min(1.0f, AmbientLightColourForFrame_PedsCarsAndObjects.blue * f1);
#ifdef FIX_BUGS
- DirectionalLightColourForFrame.red = min(1.0f, DirectionalLightColourForFrame.red * f1);
- DirectionalLightColourForFrame.green = min(1.0f, DirectionalLightColourForFrame.green * f1);
- DirectionalLightColourForFrame.blue = min(1.0f, DirectionalLightColourForFrame.blue * f1);
+ DirectionalLightColourForFrame.red = Min(1.0f, DirectionalLightColourForFrame.red * f1);
+ DirectionalLightColourForFrame.green = Min(1.0f, DirectionalLightColourForFrame.green * f1);
+ DirectionalLightColourForFrame.blue = Min(1.0f, DirectionalLightColourForFrame.blue * f1);
#else
DirectionalLightColourForFrame.red = min(1.0f, AmbientLightColourForFrame.red * f1);
DirectionalLightColourForFrame.green = min(1.0f, AmbientLightColourForFrame.green * f1);
@@ -193,7 +193,7 @@ AddAnExtraDirectionalLight(RpWorld *world, float dirx, float diry, float dirz, f
RwRGBAReal color;
RwV3d *dir;
- strength = max(max(red, green), blue);
+ strength = Max(Max(red, green), blue);
n = -1;
if(NumExtraDirLightsInWorld < NUMEXTRADIRECTIONALS)
n = NumExtraDirLightsInWorld;
@@ -221,7 +221,7 @@ AddAnExtraDirectionalLight(RpWorld *world, float dirx, float diry, float dirz, f
RwFrameUpdateObjects(RpLightGetFrame(pExtraDirectionals[n]));
RpLightSetFlags(pExtraDirectionals[n], rpLIGHTLIGHTATOMICS);
LightStrengths[n] = strength;
- NumExtraDirLightsInWorld = min(NumExtraDirLightsInWorld+1, NUMEXTRADIRECTIONALS);
+ NumExtraDirLightsInWorld = Min(NumExtraDirLightsInWorld+1, NUMEXTRADIRECTIONALS);
}
void
diff --git a/src/render/ParticleMgr.cpp b/src/render/ParticleMgr.cpp
index 7a1804de..9381787c 100644
--- a/src/render/ParticleMgr.cpp
+++ b/src/render/ParticleMgr.cpp
@@ -91,7 +91,7 @@ void cParticleSystemMgr::LoadParticleData()
break;
case CFG_PARAM_INITIAL_COLOR_VARIATION:
- entry->m_InitialColorVariation = min(atoi(value), 100);
+ entry->m_InitialColorVariation = Min(atoi(value), 100);
break;
case CFG_PARAM_FADE_DESTINATION_COLOR_R:
diff --git a/src/render/PointLights.cpp b/src/render/PointLights.cpp
index a015ec54..8e942ce6 100644
--- a/src/render/PointLights.cpp
+++ b/src/render/PointLights.cpp
@@ -98,7 +98,7 @@ CPointLights::GenerateLightsAffectingObject(CVector *objCoors)
if(aLights[i].type == LIGHT_DIRECTIONAL){
float dot = -DotProduct(dir, aLights[i].dir);
- intensity *= max((dot-0.5f)*2.0f, 0.0f);
+ intensity *= Max((dot-0.5f)*2.0f, 0.0f);
}
if(intensity > 0.0f)
diff --git a/src/render/Shadows.cpp b/src/render/Shadows.cpp
index ccdc457c..b5147f02 100644
--- a/src/render/Shadows.cpp
+++ b/src/render/Shadows.cpp
@@ -4,7 +4,7 @@
#include "TxdStore.h"
#include "Timer.h"
#include "Camera.h"
-#include "TimeCycle.h"
+#include "Timecycle.h"
#include "CutsceneMgr.h"
#include "Automobile.h"
#include "Ped.h"
@@ -727,10 +727,10 @@ CShadows::RenderStoredShadows(void)
float fStartY = shadowPos.y - fHeight;
float fEndY = shadowPos.y + fHeight;
- int32 nStartX = max(CWorld::GetSectorIndexX(fStartX), 0);
- int32 nStartY = max(CWorld::GetSectorIndexY(fStartY), 0);
- int32 nEndX = min(CWorld::GetSectorIndexX(fEndX), NUMSECTORS_X-1);
- int32 nEndY = min(CWorld::GetSectorIndexY(fEndY), NUMSECTORS_Y-1);
+ int32 nStartX = Max(CWorld::GetSectorIndexX(fStartX), 0);
+ int32 nStartY = Max(CWorld::GetSectorIndexY(fStartY), 0);
+ int32 nEndX = Min(CWorld::GetSectorIndexX(fEndX), NUMSECTORS_X-1);
+ int32 nEndY = Min(CWorld::GetSectorIndexY(fEndY), NUMSECTORS_Y-1);
CWorld::AdvanceCurrentScanCode();
@@ -873,10 +873,10 @@ CShadows::GeneratePolysForStaticShadow(int16 nStaticShadowID)
float fStartY = shadowPos.y - fHeight;
float fEndY = shadowPos.y + fHeight;
- int32 nStartX = max(CWorld::GetSectorIndexX(fStartX), 0);
- int32 nStartY = max(CWorld::GetSectorIndexY(fStartY), 0);
- int32 nEndX = min(CWorld::GetSectorIndexX(fEndX), NUMSECTORS_X-1);
- int32 nEndY = min(CWorld::GetSectorIndexY(fEndY), NUMSECTORS_Y-1);
+ int32 nStartX = Max(CWorld::GetSectorIndexX(fStartX), 0);
+ int32 nStartY = Max(CWorld::GetSectorIndexY(fStartY), 0);
+ int32 nEndX = Min(CWorld::GetSectorIndexX(fEndX), NUMSECTORS_X-1);
+ int32 nEndY = Min(CWorld::GetSectorIndexY(fEndY), NUMSECTORS_Y-1);
CWorld::AdvanceCurrentScanCode();
@@ -1016,11 +1016,11 @@ CShadows::CastShadowEntity(CEntity *pEntity, float fStartX, float fStartY, floa
Points[3].x = (fLengthRight - fFrontRight) - fSideRight;
Points[3].y = (fLengthForward - fFrontForward) - fSideForward;
- float MinX = min(min(Points[0].x, Points[1].x), min(Points[2].x, Points[3].x));
- float MaxX = max(max(Points[0].x, Points[1].x), max(Points[2].x, Points[3].x));
+ float MinX = Min(Min(Points[0].x, Points[1].x), Min(Points[2].x, Points[3].x));
+ float MaxX = Max(Max(Points[0].x, Points[1].x), Max(Points[2].x, Points[3].x));
- float MinY = min(min(Points[0].y, Points[1].y), min(Points[2].y, Points[3].y));
- float MaxY = max(max(Points[0].y, Points[1].y), max(Points[2].y, Points[3].y));
+ float MinY = Min(Min(Points[0].y, Points[1].y), Min(Points[2].y, Points[3].y));
+ float MaxY = Max(Max(Points[0].y, Points[1].y), Max(Points[2].y, Points[3].y));
float MaxZ = pPosn->z - pEntity->GetPosition().z;
float MinZ = MaxZ - fZDistance;
@@ -1767,7 +1767,7 @@ CShadows::RenderIndicatorShadow(uint32 nID, uint8 ShadowType, RwTexture *pTextur
{
ASSERT(pPosn != NULL);
- C3dMarkers::PlaceMarkerSet(nID, _TODOCONST(4), *pPosn, max(fFrontX, -fSideY),
+ C3dMarkers::PlaceMarkerSet(nID, _TODOCONST(4), *pPosn, Max(fFrontX, -fSideY),
0, 128, 255, 128,
2048, 0.2f, 0);
}
diff --git a/src/render/Timecycle.cpp b/src/render/Timecycle.cpp
index 7ab3e91e..0113c001 100644
--- a/src/render/Timecycle.cpp
+++ b/src/render/Timecycle.cpp
@@ -290,7 +290,7 @@ CTimeCycle::Update(void)
TheCamera.SetMotionBlur(m_fCurrentBlurRed, m_fCurrentBlurGreen, m_fCurrentBlurBlue, m_fCurrentBlurAlpha, MBLUR_NORMAL);
if(m_FogReduction != 0)
- m_fCurrentFarClip = max(m_fCurrentFarClip, m_FogReduction/64.0f * 650.0f);
+ m_fCurrentFarClip = Max(m_fCurrentFarClip, m_FogReduction/64.0f * 650.0f);
m_nCurrentFogColourRed = (m_nCurrentSkyTopRed + 2*m_nCurrentSkyBottomRed) / 3;
m_nCurrentFogColourGreen = (m_nCurrentSkyTopGreen + 2*m_nCurrentSkyBottomGreen) / 3;
m_nCurrentFogColourBlue = (m_nCurrentSkyTopBlue + 2*m_nCurrentSkyBottomBlue) / 3;
@@ -311,9 +311,9 @@ CTimeCycle::Update(void)
if(TheCamera.GetForward().z < -0.9f ||
!CWeather::bScriptsForceRain && (CCullZones::PlayerNoRain() || CCullZones::CamNoRain() || CCutsceneMgr::IsRunning()))
- m_FogReduction = min(m_FogReduction+1, 64);
+ m_FogReduction = Min(m_FogReduction+1, 64);
else
- m_FogReduction = max(m_FogReduction-1, 0);
+ m_FogReduction = Max(m_FogReduction-1, 0);
}
STARTPATCHES
diff --git a/src/render/WaterLevel.cpp b/src/render/WaterLevel.cpp
index 48e8f83b..c711c8c8 100644
--- a/src/render/WaterLevel.cpp
+++ b/src/render/WaterLevel.cpp
@@ -9,7 +9,7 @@
#include "Boat.h"
#include "World.h"
#include "General.h"
-#include "TimeCycle.h"
+#include "Timecycle.h"
#include "ZoneCull.h"
#include "Clock.h"
#include "Particle.h"
@@ -979,7 +979,7 @@ CWaterLevel::RenderOneWavySector(float fX, float fY, float fZ, RwRGBA const &col
SMALL_SECTOR_SIZE / 2,
apBoatList) )
{
- float fWakeColor = fAdd1 - max(255.0f - float(color.blue + color.red + color.green) / 3, fAdd2);
+ float fWakeColor = fAdd1 - Max(255.0f - float(color.blue + color.red + color.green) / 3, fAdd2);
RpGeometry *wavyGeometry = RpAtomicGetGeometry(ms_pWavyAtomic);
RpGeometry *geom = apGeomArray[nGeomUsed++];
@@ -1035,9 +1035,9 @@ CWaterLevel::RenderOneWavySector(float fX, float fY, float fZ, RwRGBA const &col
RwRGBAAssign(&wakeColor, &color);
- wakeColor.red = min(color.red + int32(fWakeColor * fRedMult * fDistMult), 255);
- wakeColor.green = min(color.green + int32(fWakeColor * fGreenMult * fDistMult), 255);
- wakeColor.blue = min(color.blue + int32(fWakeColor * fBlueMult * fDistMult), 255);
+ wakeColor.red = Min(color.red + int32(fWakeColor * fRedMult * fDistMult), 255);
+ wakeColor.green = Min(color.green + int32(fWakeColor * fGreenMult * fDistMult), 255);
+ wakeColor.blue = Min(color.blue + int32(fWakeColor * fBlueMult * fDistMult), 255);
RwRGBAAssign(&geomPreLights[9*i+j], &wakeColor);
@@ -1114,7 +1114,7 @@ CWaterLevel::CalcDistanceToWater(float fX, float fY)
fSectorY + SMALL_SECTOR_SIZE - fY
);
- fDistSqr = min(vecDist.MagnitudeSqr(), fDistSqr);
+ fDistSqr = Min(vecDist.MagnitudeSqr(), fDistSqr);
}
}
}
diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp
index 581b5815..0fe59cd0 100644
--- a/src/vehicles/Automobile.cpp
+++ b/src/vehicles/Automobile.cpp
@@ -7,9 +7,13 @@
#include "ModelIndices.h"
#include "VisibilityPlugins.h"
#include "DMAudio.h"
+<<<<<<< HEAD
#include "Clock.h"
#include "TimeCycle.h"
#include "ZoneCull.h"
+=======
+#include "Timecycle.h"
+>>>>>>> More audio ped
#include "Camera.h"
#include "Darkel.h"
#include "Rubbish.h"
@@ -691,7 +695,7 @@ CAutomobile::ProcessControl(void)
if(m_aSuspensionSpringRatio[i] < 1.0f)
m_aWheelTimer[i] = 4.0f;
else
- m_aWheelTimer[i] = max(m_aWheelTimer[i]-CTimer::GetTimeStep(), 0.0f);
+ m_aWheelTimer[i] = Max(m_aWheelTimer[i]-CTimer::GetTimeStep(), 0.0f);
if(m_aWheelTimer[i] > 0.0f){
m_nWheelsOnGround++;
@@ -1009,7 +1013,7 @@ CAutomobile::ProcessControl(void)
if(m_status != STATUS_PLAYER && m_status != STATUS_PLAYER_REMOTE && m_status != STATUS_PHYSICS){
if(GetModelIndex() == MI_MIAMI_RCRAIDER || GetModelIndex() == MI_MIAMI_SPARROW)
- m_aWheelSpeed[0] = max(m_aWheelSpeed[0]-0.0005f, 0.0f);
+ m_aWheelSpeed[0] = Max(m_aWheelSpeed[0]-0.0005f, 0.0f);
}else if((GetModelIndex() == MI_DODO || CVehicle::bAllDodosCheat) &&
m_vecMoveSpeed.Magnitude() > 0.0f && CTimer::GetTimeStep() > 0.0f){
FlyingControl(FLIGHT_MODEL_DODO);
@@ -1017,7 +1021,7 @@ CAutomobile::ProcessControl(void)
FlyingControl(FLIGHT_MODEL_HELI);
}else if(GetModelIndex() == MI_MIAMI_RCRAIDER || GetModelIndex() == MI_MIAMI_SPARROW || bAllCarCheat){
if(CPad::GetPad(0)->GetCircleJustDown())
- m_aWheelSpeed[0] = max(m_aWheelSpeed[0]-0.03f, 0.0f);
+ 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)
@@ -1129,10 +1133,10 @@ CAutomobile::ProcessControl(void)
if(speed > sq(0.1f)){
speed = Sqrt(speed);
if(suspShake > 0.0f){
- uint8 freq = min(200.0f*suspShake*speed*2000.0f/m_fMass + 100.0f, 250.0f);
+ 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, 145.0f);
CPad::GetPad(0)->StartShake(5000.0f*CTimer::GetTimeStep()/freq, freq);
}
}
@@ -2586,7 +2590,7 @@ CAutomobile::HydraulicControl(void)
float minz = pos.z + extendedLowerLimit - wheelRadius;
if(minz < specialColModel->boundingBox.min.z)
specialColModel->boundingBox.min.z = minz;
- float radius = max(specialColModel->boundingBox.min.Magnitude(), specialColModel->boundingBox.max.Magnitude());
+ float radius = Max(specialColModel->boundingBox.min.Magnitude(), specialColModel->boundingBox.max.Magnitude());
if(specialColModel->boundingSphere.radius < radius)
specialColModel->boundingSphere.radius = radius;
@@ -2685,10 +2689,10 @@ CAutomobile::HydraulicControl(void)
float front = -rear;
float right = CPad::GetPad(0)->GetCarGunLeftRight()/128.0f;
float left = -right;
- suspChange[CARWHEEL_FRONT_LEFT] = max(front+left, 0.0f);
- suspChange[CARWHEEL_REAR_LEFT] = max(rear+left, 0.0f);
- suspChange[CARWHEEL_FRONT_RIGHT] = max(front+right, 0.0f);
- suspChange[CARWHEEL_REAR_RIGHT] = max(rear+right, 0.0f);
+ suspChange[CARWHEEL_FRONT_LEFT] = Max(front+left, 0.0f);
+ suspChange[CARWHEEL_REAR_LEFT] = Max(rear+left, 0.0f);
+ suspChange[CARWHEEL_FRONT_RIGHT] = Max(front+right, 0.0f);
+ suspChange[CARWHEEL_REAR_RIGHT] = Max(rear+right, 0.0f);
if(m_hydraulicState < 100){
// Lowered, move wheels up
@@ -2804,7 +2808,7 @@ CAutomobile::ProcessBuoyancy(void)
ApplyTurnForce(impulse, point);
CVector initialSpeed = m_vecMoveSpeed;
- float timeStep = max(CTimer::GetTimeStep(), 0.01f);
+ 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;
@@ -2897,7 +2901,7 @@ CAutomobile::ProcessBuoyancy(void)
float fSpeed = vSpeed.MagnitudeSqr();
if(fSpeed > sq(0.05f)){
fSpeed = Sqrt(fSpeed);
- float size = min((fSpeed < 0.15f ? 0.25f : 0.75f)*fSpeed, 0.6f);
+ float size = Min((fSpeed < 0.15f ? 0.25f : 0.75f)*fSpeed, 0.6f);
CVector right = 0.2f*fSpeed*GetRight() + 0.2f*vSpeed;
CParticle::AddParticle(PARTICLE_PED_SPLASH,
@@ -2979,11 +2983,11 @@ CAutomobile::DoDriveByShootings(void)
// TODO: what is this?
if(!lookingLeft && m_weaponDoorTimerLeft > 0.0f){
- m_weaponDoorTimerLeft = max(m_weaponDoorTimerLeft - CTimer::GetTimeStep()*0.1f, 0.0f);
+ m_weaponDoorTimerLeft = Max(m_weaponDoorTimerLeft - CTimer::GetTimeStep()*0.1f, 0.0f);
ProcessOpenDoor(CAR_DOOR_LF, NUM_ANIMS, m_weaponDoorTimerLeft);
}
if(!lookingRight && m_weaponDoorTimerRight > 0.0f){
- m_weaponDoorTimerRight = max(m_weaponDoorTimerRight - CTimer::GetTimeStep()*0.1f, 0.0f);
+ m_weaponDoorTimerRight = Max(m_weaponDoorTimerRight - CTimer::GetTimeStep()*0.1f, 0.0f);
ProcessOpenDoor(CAR_DOOR_RF, NUM_ANIMS, m_weaponDoorTimerRight);
}
}
@@ -3131,7 +3135,7 @@ CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece)
FindPlayerPed()->SetWantedLevelNoDrop(1);
if(m_status == STATUS_PLAYER && impulse > 50.0f){
- uint8 freq = min(0.4f*impulse*2000.0f/m_fMass + 100.0f, 250.0f);
+ uint8 freq = Min(0.4f*impulse*2000.0f/m_fMass + 100.0f, 250.0f);
CPad::GetPad(0)->StartShake(40000/freq, freq);
}
@@ -3284,7 +3288,7 @@ CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece)
if(m_pDamageEntity && m_pDamageEntity == FindPlayerVehicle() && impulse > 10.0f){
int money = (doubleMoney ? 2 : 1) * impulse*pHandling->nMonetaryValue/1000000.0f;
- money = min(money, 40);
+ money = Min(money, 40);
if(money > 2){
sprintf(gString, "$%d", money);
CWorld::Players[CWorld::PlayerInFocus].m_nMoney += money;
@@ -3987,7 +3991,7 @@ CAutomobile::SetupSuspensionLines(void)
// adjust col model to include suspension lines
if(colModel->boundingBox.min.z > colModel->lines[0].p1.z)
colModel->boundingBox.min.z = colModel->lines[0].p1.z;
- float radius = max(colModel->boundingBox.min.Magnitude(), colModel->boundingBox.max.Magnitude());
+ float radius = Max(colModel->boundingBox.min.Magnitude(), colModel->boundingBox.max.Magnitude());
if(colModel->boundingSphere.radius < radius)
colModel->boundingSphere.radius = radius;
@@ -4479,8 +4483,16 @@ CAutomobile::SetAllTaxiLights(bool set)
class CAutomobile_ : public CAutomobile
{
public:
+<<<<<<< HEAD
+<<<<<<< HEAD
void ctor(int32 id, uint8 CreatedBy) { ::new (this) CAutomobile(id, CreatedBy); }
void dtor() { CAutomobile::~CAutomobile(); }
+=======
+ void dtor() { this->~CAutomobile(); }
+>>>>>>> More audio ped
+=======
+ void dtor() { CAutomobile::~CAutomobile(); }
+>>>>>>> fix
void SetModelIndex_(uint32 id) { CAutomobile::SetModelIndex(id); }
void ProcessControl_(void) { CAutomobile::ProcessControl(); }
void Teleport_(CVector v) { CAutomobile::Teleport(v); }
diff --git a/src/vehicles/Automobile.cpp.autosave b/src/vehicles/Automobile.cpp.autosave
new file mode 100644
index 00000000..140633b8
--- /dev/null
+++ b/src/vehicles/Automobile.cpp.autosave
@@ -0,0 +1,4560 @@
+#include "common.h"
+#include "main.h"
+#include "patcher.h"
+#include "General.h"
+#include "RwHelper.h"
+#include "Pad.h"
+#include "ModelIndices.h"
+#include "VisibilityPlugins.h"
+#include "DMAudio.h"
+#include "Clock.h"
+#include "Timecycle.h"
+#include "ZoneCull.h"
+#include "Camera.h"
+#include "Darkel.h"
+#include "Rubbish.h"
+#include "Fire.h"
+#include "Explosion.h"
+#include "Particle.h"
+#include "ParticleObject.h"
+#include "Antennas.h"
+#include "Skidmarks.h"
+#include "Shadows.h"
+#include "PointLights.h"
+#include "Coronas.h"
+#include "SpecialFX.h"
+#include "WaterCannon.h"
+#include "WaterLevel.h"
+#include "Floater.h"
+#include "World.h"
+#include "SurfaceTable.h"
+#include "Weather.h"
+#include "HandlingMgr.h"
+#include "Record.h"
+#include "Remote.h"
+#include "Population.h"
+#include "CarCtrl.h"
+#include "CarAI.h"
+#include "Garages.h"
+#include "PathFind.h"
+#include "AnimManager.h"
+#include "RpAnimBlend.h"
+#include "Ped.h"
+#include "PlayerPed.h"
+#include "Object.h"
+#include "Automobile.h"
+
+bool bAllCarCheat; // unused
+
+RwObject *GetCurrentAtomicObjectCB(RwObject *object, void *data);
+
+bool &CAutomobile::m_sAllTaxiLights = *(bool*)0x95CD21;
+
+CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
+ : CVehicle(CreatedBy)
+{
+ int i;
+
+ m_vehType = VEHICLE_TYPE_CAR;
+
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(id);
+ m_fFireBlowUpTimer = 0.0f;
+ field_4E0 = 0;
+ bTaxiLight = m_sAllTaxiLights;
+ m_auto_flagA20 = false;
+ m_auto_flagA40 = false;
+ bWaterTight = false;
+
+ SetModelIndex(id);
+
+ pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)mi->m_handlingId);
+
+ field_49C = 20.0f;
+ field_4D8 = 0;
+
+ mi->ChooseVehicleColour(m_currentColour1, m_currentColour2);
+
+ bIsVan = !!(pHandling->Flags & HANDLING_IS_VAN);
+ bIsBig = !!(pHandling->Flags & HANDLING_IS_BIG);
+ bIsBus = !!(pHandling->Flags & HANDLING_IS_BUS);
+ bLowVehicle = !!(pHandling->Flags & HANDLING_IS_LOW);
+
+ // Doors
+ if(bIsBus){
+ Doors[DOOR_FRONT_LEFT].Init(-HALFPI, 0.0f, 0, 2);
+ Doors[DOOR_FRONT_RIGHT].Init(0.0f, HALFPI, 1, 2);
+ }else{
+ Doors[DOOR_FRONT_LEFT].Init(-PI*0.4f, 0.0f, 0, 2);
+ Doors[DOOR_FRONT_RIGHT].Init(0.0f, PI*0.4f, 1, 2);
+ }
+ if(bIsVan){
+ Doors[DOOR_REAR_LEFT].Init(-HALFPI, 0.0f, 1, 2);
+ Doors[DOOR_REAR_RIGHT].Init(0.0f, HALFPI, 0, 2);
+ }else{
+ Doors[DOOR_REAR_LEFT].Init(-PI*0.4f, 0.0f, 0, 2);
+ Doors[DOOR_REAR_RIGHT].Init(0.0f, PI*0.4f, 1, 2);
+ }
+ if(pHandling->Flags & HANDLING_REV_BONNET)
+ Doors[DOOR_BONNET].Init(-PI*0.3f, 0.0f, 1, 0);
+ else
+ Doors[DOOR_BONNET].Init(0.0f, PI*0.3f, 1, 0);
+ if(pHandling->Flags & HANDLING_HANGING_BOOT)
+ Doors[DOOR_BOOT].Init(PI*0.4f, 0.0f, 0, 0);
+ else if(pHandling->Flags & HANDLING_TAILGATE_BOOT)
+ Doors[DOOR_BOOT].Init(0.0, HALFPI, 1, 0);
+ else
+ Doors[DOOR_BOOT].Init(-PI*0.3f, 0.0f, 1, 0);
+ if(pHandling->Flags & HANDLING_NO_DOORS){
+ Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_MISSING);
+ Damage.SetDoorStatus(DOOR_FRONT_RIGHT, DOOR_STATUS_MISSING);
+ Damage.SetDoorStatus(DOOR_REAR_LEFT, DOOR_STATUS_MISSING);
+ Damage.SetDoorStatus(DOOR_REAR_RIGHT, DOOR_STATUS_MISSING);
+ }
+
+ for(i = 0; i < 6; i++)
+ m_randomValues[i] = CGeneral::GetRandomNumberInRange(-0.15f, 0.15f);
+
+ m_fMass = pHandling->fMass;
+ m_fTurnMass = pHandling->fTurnMass;
+ m_vecCentreOfMass = pHandling->CentreOfMass;
+ m_fAirResistance = pHandling->Dimension.x*pHandling->Dimension.z/m_fMass;
+ m_fElasticity = 0.05f;
+ m_fBuoyancy = pHandling->fBuoyancy;
+
+ m_nBusDoorTimerEnd = 0;
+ m_nBusDoorTimerStart = 0;
+
+ m_fSteerAngle = 0.0f;
+ m_fGasPedal = 0.0f;
+ m_fBrakePedal = 0.0f;
+ m_pSetOnFireEntity = nil;
+ field_594 = 0;
+ bNotDamagedUpsideDown = false;
+ bMoreResistantToDamage = false;
+ m_fVelocityChangeForAudio = 0.0f;
+ m_hydraulicState = 0;
+
+ for(i = 0; i < 4; i++){
+ m_aGroundPhysical[i] = nil;
+ m_aGroundOffset[i] = CVector(0.0f, 0.0f, 0.0f);
+ m_aSuspensionSpringRatio[i] = 1.0f;
+ m_aSuspensionSpringRatioPrev[i] = m_aSuspensionSpringRatio[i];
+ m_aWheelTimer[i] = 0.0f;
+ m_aWheelRotation[i] = 0.0f;
+ m_aWheelSpeed[i] = 0.0f;
+ m_aWheelState[i] = WHEEL_STATE_NORMAL;
+ m_aWheelSkidmarkMuddy[i] = false;
+ m_aWheelSkidmarkBloody[i] = false;
+ }
+
+ m_nWheelsOnGround = 0;
+ m_nDriveWheelsOnGround = 0;
+ m_nDriveWheelsOnGroundPrev = 0;
+ m_fHeightAboveRoad = 0.0f;
+ m_fTraction = 1.0f;
+
+ CColModel *colModel = mi->GetColModel();
+ if(colModel->lines == nil){
+ colModel->lines = (CColLine*)RwMalloc(4*sizeof(CColLine));
+ colModel->numLines = 4;
+ }
+
+ SetupSuspensionLines();
+
+ m_status = STATUS_SIMPLE;
+ bUseCollisionRecords = true;
+
+ m_nNumPassengers = 0;
+
+ m_bombType = CARBOMB_NONE;
+ bHadDriver = false;
+ m_pBombRigger = nil;
+
+ if(m_nDoorLock == CARLOCK_UNLOCKED &&
+ (id == MI_POLICE || id == MI_ENFORCER || id == MI_RHINO))
+ m_nDoorLock = CARLOCK_LOCKED_INITIALLY;
+
+ m_fCarGunLR = 0.0f;
+ m_fCarGunUD = 0.05f;
+ m_fPropellerRotation = 0.0f;
+ m_weaponDoorTimerLeft = 0.0f;
+ m_weaponDoorTimerRight = m_weaponDoorTimerLeft;
+
+ if(GetModelIndex() == MI_DODO){
+ RpAtomicSetFlags(GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]), 0);
+ CMatrix mat1;
+ mat1.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF]));
+ 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_MIAMI_SPARROW || GetModelIndex() == MI_MIAMI_RCRAIDER){
+ RpAtomicSetFlags(GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]), 0);
+ RpAtomicSetFlags(GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]), 0);
+ RpAtomicSetFlags(GetFirstObject(m_aCarNodes[CAR_WHEEL_LB]), 0);
+ RpAtomicSetFlags(GetFirstObject(m_aCarNodes[CAR_WHEEL_RB]), 0);
+ }else if(GetModelIndex() == MI_RHINO){
+ bExplosionProof = true;
+ bBulletProof = true;
+ }
+}
+
+
+void
+CAutomobile::SetModelIndex(uint32 id)
+{
+ CVehicle::SetModelIndex(id);
+ SetupModelNodes();
+}
+
+CVector vecDAMAGE_ENGINE_POS_SMALL(-0.1f, -0.1f, 0.0f);
+CVector vecDAMAGE_ENGINE_POS_BIG(-0.5f, -0.3f, 0.0f);
+
+void
+CAutomobile::ProcessControl(void)
+{
+ int i;
+ CColModel *colModel;
+
+ if(bUsingSpecialColModel)
+ colModel = &CWorld::Players[CWorld::PlayerInFocus].m_ColModel;
+ else
+ colModel = GetColModel();
+ bWarnedPeds = false;
+
+ // skip if the collision isn't for the current level
+ if(colModel->level > LEVEL_NONE && colModel->level != CCollision::ms_collisionInMemory)
+ return;
+
+ // 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;
+ }
+ }
+ }
+ }
+
+ if(bIsBus)
+ ProcessAutoBusDoors();
+
+ ProcessCarAlarm();
+
+ // Scan if this car is committing a crime that the police can see
+ if(m_status != STATUS_ABANDONED && m_status != STATUS_WRECKED &&
+ m_status != STATUS_PLAYER && m_status != STATUS_PLAYER_REMOTE && m_status != STATUS_PLAYER_DISABLED){
+ switch(GetModelIndex())
+ case MI_FBICAR:
+ case MI_POLICE:
+ case MI_ENFORCER:
+ case MI_SECURICA:
+ case MI_RHINO:
+ case MI_BARRACKS:
+ ScanForCrimes();
+ }
+
+ // Process driver
+ if(pDriver){
+ if(!bHadDriver && m_bombType == CARBOMB_ONIGNITIONACTIVE){
+ // If someone enters the car and there is a bomb, detonate
+ m_nBombTimer = 1000;
+ m_pBlowUpEntity = m_pBombRigger;
+ if(m_pBlowUpEntity)
+ m_pBlowUpEntity->RegisterReference((CEntity**)&m_pBlowUpEntity);
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_BOMB_TICK, 1.0f);
+ }
+ bHadDriver = true;
+
+ if(IsUpsideDown() && CanPedEnterCar()){
+ if(!pDriver->IsPlayer() &&
+ !(pDriver->m_leader && pDriver->m_leader->bInVehicle) &&
+ pDriver->CharCreatedBy != MISSION_CHAR)
+ pDriver->SetObjective(OBJECTIVE_LEAVE_VEHICLE, this);
+ }
+ }else
+ bHadDriver = false;
+
+ // Process passengers
+ if(m_nNumPassengers != 0 && IsUpsideDown() && CanPedEnterCar()){
+ for(i = 0; i < m_nNumMaxPassengers; i++)
+ if(pPassengers[i])
+ if(!pPassengers[i]->IsPlayer() &&
+ !(pPassengers[i]->m_leader && pPassengers[i]->m_leader->bInVehicle) &&
+ pPassengers[i]->CharCreatedBy != MISSION_CHAR)
+ pPassengers[i]->SetObjective(OBJECTIVE_LEAVE_VEHICLE, this);
+ }
+
+ CRubbish::StirUp(this);
+
+ // blend in clump
+ int clumpAlpha = CVisibilityPlugins::GetClumpAlpha((RpClump*)m_rwObject);
+ if(bFadeOut){
+ clumpAlpha -= 8;
+ if(clumpAlpha < 0)
+ clumpAlpha = 0;
+ }else if(clumpAlpha < 255){
+ clumpAlpha += 16;
+ if(clumpAlpha > 255)
+ clumpAlpha = 255;
+ }
+ CVisibilityPlugins::SetClumpAlpha((RpClump*)m_rwObject, clumpAlpha);
+
+ AutoPilot.m_bSlowedDownBecauseOfCars = false;
+ AutoPilot.m_bSlowedDownBecauseOfPeds = false;
+
+ // Set Center of Mass to make car more stable
+ if(strongGrip1 || bCheat3)
+ m_vecCentreOfMass.z = 0.3f*m_aSuspensionSpringLength[0] + -1.0*m_fHeightAboveRoad;
+ else if(pHandling->Flags & HANDLING_NONPLAYER_STABILISER && m_status == STATUS_PHYSICS)
+ m_vecCentreOfMass.z = pHandling->CentreOfMass.z - 0.2f*pHandling->Dimension.z;
+ else
+ m_vecCentreOfMass.z = pHandling->CentreOfMass.z;
+
+ // Process depending on status
+
+ bool playerRemote = false;
+ switch(m_status){
+ case STATUS_PLAYER_REMOTE:
+ if(CPad::GetPad(0)->WeaponJustDown()){
+ BlowUpCar(FindPlayerPed());
+ CRemote::TakeRemoteControlledCarFromPlayer();
+ }
+
+ if(GetModelIndex() == MI_RCBANDIT){
+ CVector pos = GetPosition();
+ // FindPlayerCoors unused
+ if(RcbanditCheckHitWheels() || bIsInWater || CPopulation::IsPointInSafeZone(&pos)){
+ if(CPopulation::IsPointInSafeZone(&pos))
+ CGarages::TriggerMessage("HM2_5", -1, 5000, -1);
+ CRemote::TakeRemoteControlledCarFromPlayer();
+ BlowUpCar(FindPlayerPed());
+ }
+ }
+
+ if(CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle == this)
+ playerRemote = true;
+ // fall through
+ case STATUS_PLAYER:
+ if(playerRemote ||
+ pDriver && pDriver->GetPedState() != PED_EXIT_CAR && pDriver->GetPedState() != PED_DRAG_FROM_CAR){
+ // process control input if controlled by player
+ if(playerRemote || pDriver->m_nPedType == PEDTYPE_PLAYER1)
+ ProcessControlInputs(0);
+
+ PruneReferences();
+
+ if(m_status == STATUS_PLAYER && CRecordDataForChase::Status != RECORDSTATE_1)
+ DoDriveByShootings();
+ }
+ break;
+
+ case STATUS_SIMPLE:
+ CCarAI::UpdateCarAI(this);
+ CPhysical::ProcessControl();
+ CCarCtrl::UpdateCarOnRails(this);
+
+ m_nWheelsOnGround = 4;
+ m_nDriveWheelsOnGroundPrev = m_nDriveWheelsOnGround;
+ m_nDriveWheelsOnGround = 4;
+
+ pHandling->Transmission.CalculateGearForSimpleCar(AutoPilot.m_fMaxTrafficSpeed/50.0f, m_nCurrentGear);
+
+ {
+ float wheelRot = ProcessWheelRotation(WHEEL_STATE_NORMAL, GetForward(), m_vecMoveSpeed, 0.35f);
+ for(i = 0; i < 4; i++)
+ m_aWheelRotation[i] += wheelRot;
+ }
+
+ PlayHornIfNecessary();
+ ReduceHornCounter();
+ bVehicleColProcessed = false;
+ // that's all we do for simple vehicles
+ return;
+
+ case STATUS_PHYSICS:
+ CCarAI::UpdateCarAI(this);
+ CCarCtrl::SteerAICarWithPhysics(this);
+ PlayHornIfNecessary();
+ break;
+
+ case STATUS_ABANDONED:
+ m_fBrakePedal = 0.2f;
+ bIsHandbrakeOn = false;
+
+ m_fSteerAngle = 0.0f;
+ m_fGasPedal = 0.0f;
+ m_nCarHornTimer = 0;
+ break;
+
+ case STATUS_WRECKED:
+ m_fBrakePedal = 0.05f;
+ bIsHandbrakeOn = true;
+
+ m_fSteerAngle = 0.0f;
+ m_fGasPedal = 0.0f;
+ m_nCarHornTimer = 0;
+ break;
+
+ case STATUS_PLAYER_DISABLED:
+ m_fBrakePedal = 1.0f;
+ bIsHandbrakeOn = true;
+
+ m_fSteerAngle = 0.0f;
+ m_fGasPedal = 0.0f;
+ m_nCarHornTimer = 0;
+ 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 && (m_status == STATUS_ABANDONED || m_status == STATUS_WRECKED)){
+ bool makeStatic = false;
+ float moveSpeedLimit, turnSpeedLimit, distanceLimit;
+
+ if(!bVehicleColProcessed &&
+ m_vecMoveSpeed.IsZero() &&
+ // BUG? m_aSuspensionSpringRatioPrev[3] is checked twice in the game. also, why 3?
+ m_aSuspensionSpringRatioPrev[3] != 1.0f)
+ makeStatic = true;
+
+ if(m_status == STATUS_WRECKED){
+ moveSpeedLimit = 0.006f;
+ turnSpeedLimit = 0.0015f;
+ distanceLimit = 0.015f;
+ }else{
+ moveSpeedLimit = 0.003f;
+ turnSpeedLimit = 0.0009f;
+ distanceLimit = 0.005f;
+ }
+
+ m_vecMoveSpeedAvg = (m_vecMoveSpeedAvg + m_vecMoveSpeed)/2.0f;
+ m_vecTurnSpeedAvg = (m_vecTurnSpeedAvg + m_vecTurnSpeed)/2.0f;
+
+ if(m_vecMoveSpeedAvg.MagnitudeSqr() <= sq(moveSpeedLimit*CTimer::GetTimeStep()) &&
+ m_vecTurnSpeedAvg.MagnitudeSqr() <= sq(turnSpeedLimit*CTimer::GetTimeStep()) &&
+ m_fDistanceTravelled < distanceLimit ||
+ makeStatic){
+ m_nStaticFrames++;
+
+ if(m_nStaticFrames > 10 || makeStatic)
+ if(!CCarCtrl::MapCouldMoveInThisArea(GetPosition().x, GetPosition().y)){
+ if(!makeStatic || m_nStaticFrames > 10)
+ m_nStaticFrames = 10;
+
+ skipPhysics = true;
+
+ m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
+ m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
+ }
+ }else
+ m_nStaticFrames = 0;
+ }
+
+ // Postpone
+ for(i = 0; i < 4; i++)
+ if(m_aGroundPhysical[i] && !CWorld::bForceProcessControl && m_aGroundPhysical[i]->bIsInSafePosition){
+ bWasPostponed = true;
+ return;
+ }
+
+ VehicleDamage(0.0f, 0);
+
+ // special control
+ switch(GetModelIndex()){
+ case MI_FIRETRUCK:
+ FireTruckControl();
+ break;
+ case MI_RHINO:
+ TankControl();
+ BlowUpCarsInPath();
+ break;
+ case MI_YARDIE:
+ // beta also had esperanto here it seems
+ HydraulicControl();
+ break;
+ default:
+ if(CVehicle::bCheat3){
+ // Make vehicle jump when horn is sounded
+ if(m_status == STATUS_PLAYER && m_vecMoveSpeed.MagnitudeSqr() > sq(0.2f) &&
+ // BUG: game checks [0] four times, instead of all wheels
+ m_aSuspensionSpringRatio[0] < 1.0f &&
+ CPad::GetPad(0)->HornJustDown()){
+
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_1, 0.0f);
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_JUMP, 1.0f);
+
+ CParticle::AddParticle(PARTICLE_ENGINE_STEAM,
+ m_aWheelColPoints[0].point + 0.5f*GetUp(),
+ 1.3f*m_vecMoveSpeed, nil, 2.5f);
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE,
+ m_aWheelColPoints[0].point + 0.5f*GetUp(),
+ 1.2f*m_vecMoveSpeed, nil, 2.0f);
+
+ CParticle::AddParticle(PARTICLE_ENGINE_STEAM,
+ m_aWheelColPoints[2].point + 0.5f*GetUp(),
+ 1.3f*m_vecMoveSpeed, nil, 2.5f);
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE,
+ m_aWheelColPoints[2].point + 0.5f*GetUp(),
+ 1.2f*m_vecMoveSpeed, nil, 2.0f);
+
+ CParticle::AddParticle(PARTICLE_ENGINE_STEAM,
+ m_aWheelColPoints[0].point + 0.5f*GetUp() - GetForward(),
+ 1.3f*m_vecMoveSpeed, nil, 2.5f);
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE,
+ m_aWheelColPoints[0].point + 0.5f*GetUp() - GetForward(),
+ 1.2f*m_vecMoveSpeed, nil, 2.0f);
+
+ CParticle::AddParticle(PARTICLE_ENGINE_STEAM,
+ m_aWheelColPoints[2].point + 0.5f*GetUp() - GetForward(),
+ 1.3f*m_vecMoveSpeed, nil, 2.5f);
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE,
+ m_aWheelColPoints[2].point + 0.5f*GetUp() - GetForward(),
+ 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);
+ }
+ }
+ break;
+ }
+
+ float brake;
+ if(skipPhysics){
+ bHasContacted = false;
+ bIsInSafePosition = false;
+ bWasPostponed = false;
+ bHasHitWall = false;
+ m_nCollisionRecords = 0;
+ bHasCollided = false;
+ bVehicleColProcessed = 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);
+ }else{
+
+ // This has to be done if ProcessEntityCollision wasn't called
+ if(!bVehicleColProcessed){
+ CMatrix mat(GetMatrix());
+ bIsStuck = false;
+ bHasContacted = false;
+ bIsInSafePosition = false;
+ bWasPostponed = false;
+ bHasHitWall = false;
+ m_fDistanceTravelled = 0.0f;
+ field_EF = false;
+ m_phy_flagA80 = false;
+ ApplyMoveSpeed();
+ ApplyTurnSpeed();
+ for(i = 0; CheckCollision() && i < 5; i++){
+ GetMatrix() = mat;
+ ApplyMoveSpeed();
+ ApplyTurnSpeed();
+ }
+ bIsInSafePosition = true;
+ bIsStuck = false;
+ }
+
+ CPhysical::ProcessControl();
+
+ ProcessBuoyancy();
+
+ // Rescale spring ratios, i.e. subtract wheel radius
+ for(i = 0; i < 4; i++){
+ // wheel radius in relation to suspension line
+ float wheelRadius = 1.0f - m_aSuspensionSpringLength[i]/m_aSuspensionLineLength[i];
+ // rescale such that 0.0 is fully compressed and 1.0 is fully extended
+ m_aSuspensionSpringRatio[i] = (m_aSuspensionSpringRatio[i]-wheelRadius)/(1.0f-wheelRadius);
+ }
+
+ float fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward());
+ CVector contactPoints[4]; // relative to model
+ CVector contactSpeeds[4]; // speed at contact points
+ CVector springDirections[4]; // normalized, in model space
+
+ for(i = 0; i < 4; i++){
+ // Set spring under certain circumstances
+ if(Damage.GetWheelStatus(i) == WHEEL_STATUS_MISSING)
+ m_aSuspensionSpringRatio[i] = 1.0f;
+ else if(Damage.GetWheelStatus(i) == WHEEL_STATUS_BURST){
+ // wheel more bumpy the faster we are
+ if(CGeneral::GetRandomNumberInRange(0, (uint16)(40*fwdSpeed) + 98) < 100){
+ m_aSuspensionSpringRatio[i] += 0.3f*(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
+ if(m_aSuspensionSpringRatio[i] < 1.0f){
+ contactPoints[i] = m_aWheelColPoints[i].point - GetPosition();
+ springDirections[i] = Multiply3x3(GetMatrix(), colModel->lines[i].p1 - colModel->lines[i].p0);
+ springDirections[i].Normalise();
+ }
+ }
+
+ // Make springs push up vehicle
+ for(i = 0; i < 4; i++){
+ if(m_aSuspensionSpringRatio[i] < 1.0f){
+ float bias = pHandling->fSuspensionBias;
+ if(i == 1 || i == 3) // rear
+ bias = 1.0f - bias;
+
+ ApplySpringCollision(pHandling->fSuspensionForceLevel,
+ springDirections[i], contactPoints[i],
+ m_aSuspensionSpringRatio[i], bias);
+ m_aWheelSkidmarkMuddy[i] =
+ m_aWheelColPoints[i].surfaceB == SURFACE_GRASS ||
+ m_aWheelColPoints[i].surfaceB == SURFACE_DIRTTRACK ||
+ m_aWheelColPoints[i].surfaceB == SURFACE_SAND;
+ }else{
+ contactPoints[i] = Multiply3x3(GetMatrix(), colModel->lines[i].p1);
+ }
+ }
+
+ // Get speed at contact points
+ for(i = 0; i < 4; i++){
+ contactSpeeds[i] = GetSpeed(contactPoints[i]);
+ if(m_aGroundPhysical[i]){
+ // subtract movement of physical we're standing on
+ contactSpeeds[i] -= m_aGroundPhysical[i]->GetSpeed(m_aGroundOffset[i]);
+#ifndef FIX_BUGS
+ // this shouldn't be reset because we still need it below
+ m_aGroundPhysical[i] = nil;
+#endif
+ }
+ }
+
+ // dampen springs
+ for(i = 0; i < 4; i++)
+ if(m_aSuspensionSpringRatio[i] < 1.0f)
+ ApplySpringDampening(pHandling->fSuspensionDampingLevel,
+ springDirections[i], contactPoints[i], contactSpeeds[i]);
+
+ // Get speed at contact points again
+ for(i = 0; i < 4; i++){
+ contactSpeeds[i] = GetSpeed(contactPoints[i]);
+ if(m_aGroundPhysical[i]){
+ // subtract movement of physical we're standing on
+ contactSpeeds[i] -= m_aGroundPhysical[i]->GetSpeed(m_aGroundOffset[i]);
+ m_aGroundPhysical[i] = nil;
+ }
+ }
+
+
+ bool gripCheat = true;
+ fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward());
+ if(!strongGrip1 && !CVehicle::bCheat3)
+ gripCheat = false;
+ float acceleration = pHandling->Transmission.CalculateDriveAcceleration(m_fGasPedal, m_nCurrentGear, m_fChangeGearTime, fwdSpeed, gripCheat);
+ acceleration /= fForceMultiplier;
+
+ // unused
+ if(GetModelIndex() == MI_MIAMI_RCBARON ||
+ GetModelIndex() == MI_MIAMI_RCRAIDER ||
+ GetModelIndex() == MI_MIAMI_SPARROW)
+ acceleration = 0.0f;
+
+ brake = m_fBrakePedal * pHandling->fBrakeDeceleration * CTimer::GetTimeStep();
+ bool neutralHandling = !!(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);
+
+ // Count how many wheels are touching the ground
+
+ m_nWheelsOnGround = 0;
+ m_nDriveWheelsOnGroundPrev = m_nDriveWheelsOnGround;
+ m_nDriveWheelsOnGround = 0;
+
+ for(i = 0; i < 4; i++){
+ if(m_aSuspensionSpringRatio[i] < 1.0f)
+ m_aWheelTimer[i] = 4.0f;
+ else
+ m_aWheelTimer[i] = Max(m_aWheelTimer[i]-CTimer::GetTimeStep(), 0.0f);
+
+ if(m_aWheelTimer[i] > 0.0f){
+ m_nWheelsOnGround++;
+ switch(pHandling->Transmission.nDriveType){
+ case '4':
+ m_nDriveWheelsOnGround++;
+ break;
+ case 'F':
+ if(i == CARWHEEL_FRONT_LEFT || i == CARWHEEL_FRONT_RIGHT)
+ m_nDriveWheelsOnGround++;
+ break;
+ case 'R':
+ if(i == CARWHEEL_REAR_LEFT || i == CARWHEEL_REAR_RIGHT)
+ m_nDriveWheelsOnGround++;
+ break;
+ }
+ }
+ }
+
+ float traction;
+ if(m_status == STATUS_PHYSICS)
+ traction = 0.004f * m_fTraction;
+ else
+ traction = 0.004f;
+ traction *= pHandling->fTractionMultiplier / 4.0f;
+ traction /= fForceMultiplier;
+ if(CVehicle::bCheat3)
+ traction *= 4.0f;
+
+ if(FindPlayerVehicle() && FindPlayerVehicle() == this){
+ if(CPad::GetPad(0)->WeaponJustDown()){
+ if(m_bombType == CARBOMB_TIMED){
+ m_bombType = CARBOMB_TIMEDACTIVE;
+ m_nBombTimer = 7000;
+ m_pBlowUpEntity = FindPlayerPed();
+ CGarages::TriggerMessage("GA_12", -1, 3000, -1);
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_BOMB_TIMED_ACTIVATED, 1.0f);
+ }else if(m_bombType == CARBOMB_ONIGNITION){
+ m_bombType = CARBOMB_ONIGNITIONACTIVE;
+ CGarages::TriggerMessage("GA_12", -1, 3000, -1);
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_BOMB_ONIGNITION_ACTIVATED, 1.0f);
+ }
+ }
+ }else if(strongGrip1 || CVehicle::bCheat3){
+ traction *= 1.2f;
+ acceleration *= 1.4f;
+ if(strongGrip2 || CVehicle::bCheat3){
+ traction *= 1.3f;
+ acceleration *= 1.4f;
+ }
+ }
+
+ static float fThrust;
+ static tWheelState WheelState[4];
+
+ // Process front wheels on ground
+
+ 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));
+
+ if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] > 0.0f){
+ if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier))
+ fThrust = 0.0f;
+ else
+ fThrust = acceleration;
+
+ m_aWheelColPoints[CARWHEEL_FRONT_LEFT].surfaceA = SURFACE_RUBBER29;
+ float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_FRONT_LEFT])*traction;
+ if(m_status == 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;
+
+ m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].surfaceA = SURFACE_RUBBER29;
+ float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_FRONT_RIGHT])*traction;
+ if(m_status == 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(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];
+ }
+ 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];
+ }
+
+ // Process rear wheels
+
+ if(m_aWheelTimer[CARWHEEL_REAR_LEFT] > 0.0f || m_aWheelTimer[CARWHEEL_REAR_RIGHT] > 0.0f){
+ CVector wheelFwd = GetForward();
+ CVector wheelRight = GetRight();
+
+ if(bIsHandbrakeOn)
+ brake = 20000.0f;
+
+ if(m_aWheelTimer[CARWHEEL_REAR_LEFT] > 0.0f){
+ if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier))
+ fThrust = 0.0f;
+ else
+ fThrust = acceleration;
+
+ m_aWheelColPoints[CARWHEEL_REAR_LEFT].surfaceA = SURFACE_RUBBER29;
+ float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_REAR_LEFT])*traction;
+ if(m_status == STATUS_PLAYER)
+ adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[CARWHEEL_REAR_LEFT].surfaceB);
+ WheelState[CARWHEEL_REAR_LEFT] = m_aWheelState[CARWHEEL_REAR_LEFT];
+
+ if(Damage.GetWheelStatus(VEHWHEEL_REAR_LEFT) == WHEEL_STATUS_BURST)
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[CARWHEEL_REAR_LEFT], contactPoints[CARWHEEL_REAR_LEFT],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBiasRear,
+ adhesion*tractionBiasRear*Damage.m_fWheelDamageEffect,
+ CARWHEEL_REAR_LEFT,
+ &m_aWheelSpeed[CARWHEEL_REAR_LEFT],
+ &WheelState[CARWHEEL_REAR_LEFT],
+ WHEEL_STATUS_BURST);
+ else
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[CARWHEEL_REAR_LEFT], contactPoints[CARWHEEL_REAR_LEFT],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBiasRear,
+ adhesion*tractionBiasRear,
+ CARWHEEL_REAR_LEFT,
+ &m_aWheelSpeed[CARWHEEL_REAR_LEFT],
+ &WheelState[CARWHEEL_REAR_LEFT],
+ WHEEL_STATUS_OK);
+ }
+
+ if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] > 0.0f){
+ if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier))
+ fThrust = 0.0f;
+ else
+ fThrust = acceleration;
+
+ m_aWheelColPoints[CARWHEEL_REAR_RIGHT].surfaceA = SURFACE_RUBBER29;
+ float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_REAR_RIGHT])*traction;
+ if(m_status == STATUS_PLAYER)
+ adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[CARWHEEL_REAR_RIGHT].surfaceB);
+ WheelState[CARWHEEL_REAR_RIGHT] = m_aWheelState[CARWHEEL_REAR_RIGHT];
+
+ if(Damage.GetWheelStatus(VEHWHEEL_REAR_RIGHT) == WHEEL_STATUS_BURST)
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[CARWHEEL_REAR_RIGHT], contactPoints[CARWHEEL_REAR_RIGHT],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBiasRear,
+ adhesion*tractionBiasRear*Damage.m_fWheelDamageEffect,
+ CARWHEEL_REAR_RIGHT,
+ &m_aWheelSpeed[CARWHEEL_REAR_RIGHT],
+ &WheelState[CARWHEEL_REAR_RIGHT],
+ WHEEL_STATUS_BURST);
+ else
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[CARWHEEL_REAR_RIGHT], contactPoints[CARWHEEL_REAR_RIGHT],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBiasRear,
+ adhesion*tractionBiasRear,
+ CARWHEEL_REAR_RIGHT,
+ &m_aWheelSpeed[CARWHEEL_REAR_RIGHT],
+ &WheelState[CARWHEEL_REAR_RIGHT],
+ WHEEL_STATUS_OK);
+ }
+ }
+
+ // 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;
+ }
+ }
+ 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;
+ }
+ }
+ m_aWheelRotation[CARWHEEL_REAR_RIGHT] += m_aWheelSpeed[CARWHEEL_REAR_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;
+ }
+ for(i = 0; i < 4; i++)
+ m_aWheelState[i] = WheelState[i];
+
+ // Process horn
+
+ if(m_status != STATUS_PLAYER){
+ 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(Pads[0].bHornHistory[Pads[0].iCurrHornHistory]){
+ if(Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % 5] &&
+ Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+3) % 5])
+ m_nCarHornTimer = 1;
+ else
+ m_nCarHornTimer = 0;
+ }else if(Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % 5] &&
+ !Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+1) % 5]){
+ m_nCarHornTimer = 0;
+ m_bSirenOrAlarm = !m_bSirenOrAlarm;
+ }else
+ m_nCarHornTimer = 0;
+ }else if(GetModelIndex() != MI_YARDIE && !CVehicle::bCheat3){
+ if(Pads[0].GetHorn())
+ m_nCarHornTimer = 1;
+ else
+ m_nCarHornTimer = 0;
+ }
+ }
+
+ // Flying
+
+ if(m_status != STATUS_PLAYER && m_status != STATUS_PLAYER_REMOTE && m_status != STATUS_PHYSICS){
+ if(GetModelIndex() == MI_MIAMI_RCRAIDER || GetModelIndex() == MI_MIAMI_SPARROW)
+ m_aWheelSpeed[0] = Max(m_aWheelSpeed[0]-0.0005f, 0.0f);
+ }else if((GetModelIndex() == MI_DODO || CVehicle::bAllDodosCheat) &&
+ m_vecMoveSpeed.Magnitude() > 0.0f && CTimer::GetTimeStep() > 0.0f){
+ FlyingControl(FLIGHT_MODEL_DODO);
+ }else if(GetModelIndex() == MI_MIAMI_RCBARON){
+ FlyingControl(FLIGHT_MODEL_HELI);
+ }else if(GetModelIndex() == MI_MIAMI_RCRAIDER || GetModelIndex() == MI_MIAMI_SPARROW || bAllCarCheat){
+ 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)
+ FlyingControl(FLIGHT_MODEL_HELI);
+ }
+ }
+
+
+
+ // Process car on fire
+ // A similar calculation of damagePos is done elsewhere for smoke
+
+ uint8 engineStatus = Damage.GetEngineStatus();
+ CVector damagePos = ((CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()))->m_positions[CAR_POS_HEADLIGHTS];
+
+ switch(Damage.GetDoorStatus(DOOR_BONNET)){
+ case DOOR_STATUS_OK:
+ case DOOR_STATUS_SMASHED:
+ // Bonnet is still there, smoke comes out at the edge
+ damagePos += vecDAMAGE_ENGINE_POS_SMALL;
+ break;
+ case DOOR_STATUS_SWINGING:
+ case DOOR_STATUS_MISSING:
+ // Bonnet is gone, smoke comes out at the engine
+ damagePos += vecDAMAGE_ENGINE_POS_BIG;
+ break;
+ }
+
+ // move fire forward if in first person
+ if(this == FindPlayerVehicle() && TheCamera.GetLookingForwardFirstPerson())
+ if(m_fHealth < 250.0f && m_status != STATUS_WRECKED){
+ if(GetModelIndex() == MI_FIRETRUCK)
+ damagePos += CVector(0.0f, 3.0f, -0.2f);
+ else
+ damagePos += CVector(0.0f, 1.2f, -0.8f);
+ }
+
+ damagePos = GetMatrix()*damagePos;
+ damagePos.z += 0.15f;
+
+ if(m_fHealth < 250.0f && m_status != STATUS_WRECKED){
+ // Car is on fire
+
+ CParticle::AddParticle(PARTICLE_CARFLAME, damagePos,
+ CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(0.01125f, 0.09f)),
+ nil, 0.9f);
+
+ CVector coors = damagePos;
+ coors.x += CGeneral::GetRandomNumberInRange(-0.5625f, 0.5625f),
+ coors.y += CGeneral::GetRandomNumberInRange(-0.5625f, 0.5625f),
+ coors.z += CGeneral::GetRandomNumberInRange(0.5625f, 2.25f);
+ CParticle::AddParticle(PARTICLE_CARFLAME_SMOKE, coors, CVector(0.0f, 0.0f, 0.0f));
+
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE2, damagePos, CVector(0.0f, 0.0f, 0.0f), nil, 0.5f);
+
+ // Blow up car after 5 seconds
+ m_fFireBlowUpTimer += CTimer::GetTimeStepInMilliseconds();
+ if(m_fFireBlowUpTimer > 5000.0f){
+ CWorld::Players[CWorld::PlayerInFocus].AwardMoneyForExplosion(this);
+ BlowUpCar(m_pSetOnFireEntity);
+ }
+ }else
+ m_fFireBlowUpTimer = 0.0f;
+
+ // Decrease car health if engine is damaged badly
+ if(engineStatus > ENGINE_STATUS_ON_FIRE && m_fHealth > 250.0f)
+ m_fHealth -= 2.0f;
+
+ ProcessDelayedExplosion();
+
+
+ if(m_bSirenOrAlarm && (CTimer::GetFrameCounter()&7) == 5 &&
+ UsesSiren(GetModelIndex()) && GetModelIndex() != MI_RCBANDIT)
+ CCarAI::MakeWayForCarWithSiren(this);
+
+
+ // Find out how much to shake the pad depending on suspension and ground surface
+
+ float suspShake = 0.0f;
+ float surfShake = 0.0f;
+ for(i = 0; i < 4; i++){
+ float suspChange = m_aSuspensionSpringRatioPrev[i] - m_aSuspensionSpringRatio[i];
+ if(suspChange > 0.3f){
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_JUMP, suspChange);
+ if(suspChange > suspShake)
+ suspShake = suspChange;
+ }
+
+ uint8 surf = m_aWheelColPoints[i].surfaceB;
+ if(surf == SURFACE_DIRT || surf == SURFACE_PUDDLE || surf == SURFACE_HEDGE){
+ if(surfShake < 0.2f)
+ surfShake = 0.3f;
+ }else if(surf == SURFACE_DIRTTRACK || surf == SURFACE_SAND){
+ if(surfShake < 0.1f)
+ surfShake = 0.2f;
+ }else if(surf == SURFACE_GRASS){
+ if(surfShake < 0.05f)
+ surfShake = 0.1f;
+ }
+
+ m_aSuspensionSpringRatioPrev[i] = m_aSuspensionSpringRatio[i];
+ m_aSuspensionSpringRatio[i] = 1.0f;
+ }
+
+ // Shake pad
+
+ if((suspShake > 0.0f || surfShake > 0.0f) && m_status == STATUS_PLAYER){
+ float speed = m_vecMoveSpeed.MagnitudeSqr();
+ if(speed > sq(0.1f)){
+ speed = Sqrt(speed);
+ if(suspShake > 0.0f){
+ 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);
+ CPad::GetPad(0)->StartShake(5000.0f*CTimer::GetTimeStep()/freq, freq);
+ }
+ }
+ }
+
+ bVehicleColProcessed = false;
+
+ if(!bWarnedPeds)
+ CCarCtrl::ScanForPedDanger(this);
+
+
+ // Turn around at the edge of the world
+ // TODO: make the numbers defines
+
+ float heading;
+ if(GetPosition().x > 1900.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){
+ 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(m_vecMoveSpeed.y > 0.0f)
+ m_vecMoveSpeed.y *= -1.0f;
+ heading = GetForward().Heading();
+ if(heading < HALFPI && heading > 0.0f)
+ SetHeading(PI-heading);
+ else if(heading > -HALFPI && heading < 0.0f)
+ SetHeading(-PI-heading);
+ }else if(GetPosition().y < -1900.0f){
+ if(m_vecMoveSpeed.y < 0.0f)
+ m_vecMoveSpeed.y *= -1.0f;
+ heading = GetForward().Heading();
+ if(heading > HALFPI)
+ SetHeading(PI-heading);
+ else if(heading < -HALFPI)
+ SetHeading(-PI-heading);
+ }
+
+ if(bInfiniteMass){
+ m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
+ m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
+ m_vecMoveFriction = CVector(0.0f, 0.0f, 0.0f);
+ m_vecTurnFriction = CVector(0.0f, 0.0f, 0.0f);
+ }else if(!skipPhysics &&
+ (m_fGasPedal == 0.0f && brake == 0.0f || m_status == STATUS_WRECKED)){
+ if(Abs(m_vecMoveSpeed.x) < 0.005f &&
+ Abs(m_vecMoveSpeed.y) < 0.005f &&
+ Abs(m_vecMoveSpeed.z) < 0.005f){
+ m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
+ m_vecTurnSpeed.z = 0.0f;
+ }
+ }
+}
+
+void
+CAutomobile::Teleport(CVector pos)
+{
+ CWorld::Remove(this);
+
+ GetPosition() = pos;
+ SetOrientation(0.0f, 0.0f, 0.0f);
+ SetMoveSpeed(0.0f, 0.0f, 0.0f);
+ SetTurnSpeed(0.0f, 0.0f, 0.0f);
+
+ ResetSuspension();
+
+ CWorld::Add(this);
+}
+
+void
+CAutomobile::PreRender(void)
+{
+ int i, j, n;
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+
+ if(GetModelIndex() == MI_RCBANDIT){
+ CVector pos = GetMatrix() * CVector(0.218f, -0.444f, 0.391f);
+ CAntennas::RegisterOne((uintptr)this, GetUp(), pos, 1.0f);
+ }
+
+ float fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward())*180.0f;
+
+
+ // Wheel particles
+
+ if(GetModelIndex() == MI_DODO){
+ ; // nothing
+ }else if(GetModelIndex() == MI_RCBANDIT){
+ for(i = 0; i < 4; i++){
+ // Game has same code three times here
+ switch(m_aWheelState[i]){
+ case WHEEL_STATE_SPINNING:
+ case WHEEL_STATE_SKIDDING:
+ case WHEEL_STATE_FIXED:
+ CParticle::AddParticle(PARTICLE_RUBBER_SMOKE,
+ m_aWheelColPoints[i].point + CVector(0.0f, 0.0f, 0.05f),
+ CVector(0.0f, 0.0f, 0.0f), nil, 0.1f);
+ break;
+ }
+ }
+ }else{
+ if(m_status == STATUS_SIMPLE){
+ CMatrix mat;
+ CVector pos;
+
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RB]));
+ pos = mat.GetPosition();
+ pos.z = 1.5f*m_aWheelPosition[CARWHEEL_REAR_RIGHT];
+ m_aWheelColPoints[CARWHEEL_REAR_RIGHT].point = GetMatrix() * pos;
+ m_aWheelColPoints[CARWHEEL_REAR_RIGHT].surfaceB = SURFACE_DEFAULT;
+
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LB]));
+ pos = mat.GetPosition();
+ pos.z = 1.5f*m_aWheelPosition[CARWHEEL_REAR_LEFT];
+ m_aWheelColPoints[CARWHEEL_REAR_LEFT].point = GetMatrix() * pos;
+ m_aWheelColPoints[CARWHEEL_REAR_LEFT].surfaceB = SURFACE_DEFAULT;
+
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF]));
+ pos = mat.GetPosition();
+ pos.z = 1.5f*m_aWheelPosition[CARWHEEL_FRONT_RIGHT];
+ m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].point = GetMatrix() * pos;
+ m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].surfaceB = SURFACE_DEFAULT;
+
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LF]));
+ pos = mat.GetPosition();
+ pos.z = 1.5f*m_aWheelPosition[CARWHEEL_FRONT_LEFT];
+ m_aWheelColPoints[CARWHEEL_FRONT_LEFT].point = GetMatrix() * pos;
+ m_aWheelColPoints[CARWHEEL_FRONT_LEFT].surfaceB = SURFACE_DEFAULT;
+ }
+
+ int drawParticles = Abs(fwdSpeed) < 90.0f;
+ if(m_status == STATUS_SIMPLE || m_status == STATUS_PHYSICS ||
+ m_status == STATUS_PLAYER || m_status == 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++){
+ switch(m_aWheelState[i]){
+ case WHEEL_STATE_SPINNING:
+ if(AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles)){
+ CParticle::AddParticle(PARTICLE_BURNINGRUBBER_SMOKE,
+ m_aWheelColPoints[i].point + CVector(0.0f, 0.0f, 0.25f),
+ CVector(0.0f, 0.0f, 0.0f));
+
+ CParticle::AddParticle(PARTICLE_BURNINGRUBBER_SMOKE,
+ m_aWheelColPoints[i].point + CVector(0.0f, 0.0f, 0.25f),
+ CVector(0.0f, 0.0f, 0.05f));
+ }
+
+ 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]);
+ break;
+
+ case WHEEL_STATE_SKIDDING:
+ if(i == CARWHEEL_REAR_LEFT || i == CARWHEEL_REAR_RIGHT || rearSkidding){
+ // same as below
+
+ 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));
+
+ 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]);
+ }
+ break;
+
+ case WHEEL_STATE_FIXED:
+ 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));
+
+ 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]);
+ break;
+
+ default:
+ if(Abs(fwdSpeed) > 0.5f)
+ AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles);
+ if(m_aWheelSkidmarkBloody[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]);
+ }
+ }
+ }
+ }
+
+ if(m_aCarNodes[CAR_WHEEL_RM]){
+ // assume middle wheels are two units before rear ones
+ CVector offset = GetForward()*2.0f;
+
+ switch(m_aWheelState[CARWHEEL_REAR_LEFT]){
+ // Game has same code three times here
+ case WHEEL_STATE_SPINNING:
+ case WHEEL_STATE_SKIDDING:
+ case WHEEL_STATE_FIXED:
+ CParticle::AddParticle(PARTICLE_RUBBER_SMOKE,
+ m_aWheelColPoints[CARWHEEL_REAR_LEFT].point + CVector(0.0f, 0.0f, 0.25f) + offset,
+ CVector(0.0f, 0.0f, 0.0f));
+
+ if(m_aWheelTimer[CARWHEEL_REAR_LEFT] > 0.0f)
+ 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]);
+ break;
+ }
+
+ switch(m_aWheelState[CARWHEEL_REAR_RIGHT]){
+ // Game has same code three times here
+ case WHEEL_STATE_SPINNING:
+ case WHEEL_STATE_SKIDDING:
+ case WHEEL_STATE_FIXED:
+ CParticle::AddParticle(PARTICLE_RUBBER_SMOKE,
+ m_aWheelColPoints[CARWHEEL_REAR_RIGHT].point + CVector(0.0f, 0.0f, 0.25f) + offset,
+ CVector(0.0f, 0.0f, 0.0f));
+
+ if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] > 0.0f)
+ 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]);
+ break;
+ }
+ }
+
+
+ // Rain on roof
+ if(!CCullZones::CamNoRain() && !CCullZones::PlayerNoRain() &&
+ Abs(fwdSpeed) < 20.0f && CWeather::Rain > 0.02f){
+ CColModel *colModel = GetColModel();
+
+ for(i = 0; i < colModel->numTriangles; i++){
+ CVector p1, p2, p3, c;
+
+ colModel->GetTrianglePoint(p1, colModel->triangles[i].a);
+ p1 = GetMatrix() * p1;
+ colModel->GetTrianglePoint(p2, colModel->triangles[i].b);
+ p2 = GetMatrix() * p2;
+ colModel->GetTrianglePoint(p3, colModel->triangles[i].c);
+ p3 = GetMatrix() * p3;
+ c = (p1 + p2 + p3)/3.0f;
+
+ 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),
+ CVector(0.0f, 0.0f, 0.0f),
+ nil, 0.0f, 0, 0, CGeneral::GetRandomNumber() & 1);
+ }
+ }
+
+ AddDamagedVehicleParticles();
+
+ // Exhaust smoke
+ if(bEngineOn && fwdSpeed < 90.0f){
+ CVector exhaustPos = mi->m_positions[CAR_POS_EXHAUST];
+ CVector pos1, pos2, dir;
+
+ if(exhaustPos != CVector(0.0f, 0.0f, 0.0f)){
+ dir.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;
+ }else{
+ dir.x = m_vecMoveSpeed.x;
+ dir.y = m_vecMoveSpeed.y;
+ }
+
+ bool dblExhaust = false;
+ pos1 = GetMatrix() * exhaustPos;
+ if(pHandling->Flags & HANDLING_DBL_EXHAUST){
+ dblExhaust = true;
+ pos2 = exhaustPos;
+ pos2.x = -pos2.x;
+ pos2 = GetMatrix() * pos2;
+ }
+
+ 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);
+ }
+ else
+ for(i = 0; i <= n; i++)
+ CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos1, dir);
+ }
+ }
+
+
+ // Siren and taxi lights
+ switch(GetModelIndex()){
+ case MI_FIRETRUCK:
+ case MI_AMBULAN:
+ case MI_POLICE:
+ case MI_ENFORCER:
+ if(m_bSirenOrAlarm){
+ CVector pos1, pos2;
+ uint8 r1, g1, b1;
+ uint8 r2, g2, b2;
+ uint8 r, g, b;
+
+ switch(GetModelIndex()){
+ case MI_FIRETRUCK:
+ pos1 = CVector(1.1f, 1.7f, 2.0f);
+ pos2 = CVector(-1.1f, 1.7f, 2.0f);
+ r1 = 255; g1 = 0; b1 = 0;
+ r2 = 255; g2 = 255; b2 = 0;
+ break;
+ case MI_AMBULAN:
+ pos1 = CVector(1.1f, 0.9f, 1.6f);
+ pos2 = CVector(-1.1f, 0.9f, 1.6f);
+ r1 = 255; g1 = 0; b1 = 0;
+ r2 = 255; g2 = 255; b2 = 255;
+ break;
+ case MI_POLICE:
+ pos1 = CVector(0.7f, -0.4f, 1.0f);
+ pos2 = CVector(-0.7f, -0.4f, 1.0f);
+ r1 = 255; g1 = 0; b1 = 0;
+ r2 = 0; g2 = 0; b2 = 255;
+ break;
+ case MI_ENFORCER:
+ pos1 = CVector(1.1f, 0.8f, 1.2f);
+ pos2 = CVector(-1.1f, 0.8f, 1.2f);
+ r1 = 255; g1 = 0; b1 = 0;
+ r2 = 0; g2 = 0; b2 = 255;
+ break;
+ }
+
+ uint32 t = CTimer::GetTimeInMilliseconds() & 0x3FF; // 1023
+ if(t < 512){
+ r = r1/6;
+ g = g1/6;
+ b = b1/6;
+ }else{
+ r = r2/6;
+ g = g2/6;
+ b = b2/6;
+ }
+
+ t = CTimer::GetTimeInMilliseconds() & 0x1FF; // 511
+ if(t < 100){
+ float f = t/100.0f;
+ r *= f;
+ g *= f;
+ b *= f;
+ }else if(t > 412){
+ float f = (512-t)/100.0f;
+ r *= f;
+ g *= f;
+ b *= f;
+ }
+
+ CVector pos = GetPosition();
+ 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);
+
+ CPointLights::AddLight(CPointLights::LIGHT_POINT,
+ pos + GetUp()*2.0f, CVector(0.0f, 0.0f, 0.0f), 12.0f,
+ r*0.02f, g*0.02f, b*0.02f, CPointLights::FOG_NONE, true);
+
+ pos1 = GetMatrix() * pos1;
+ pos2 = GetMatrix() * pos2;
+
+ for(i = 0; i < 4; i++){
+ uint8 sirenTimer = ((CTimer::GetTimeInMilliseconds() + (i<<6))>>8) & 3;
+ pos = (pos1*i + pos2*(3.0f-i))/3.0f;
+
+ switch(sirenTimer){
+ case 0:
+ CCoronas::RegisterCorona((uintptr)this + 21 + i,
+ r1, g1, b1, 255,
+ pos, 0.4f, 50.0f,
+ CCoronas::TYPE_STAR,
+ i == 1 ? CCoronas::FLARE_HEADLIGHTS : CCoronas::FLARE_NONE,
+ CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+ break;
+ case 2:
+ CCoronas::RegisterCorona((uintptr)this + 21 + i,
+ r2, g2, b2, 255,
+ pos, 0.4f, 50.0f,
+ CCoronas::TYPE_STAR,
+ CCoronas::FLARE_NONE,
+ CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+ break;
+ default:
+ CCoronas::UpdateCoronaCoors((uintptr)this + 21 + i, pos, 50.0f, 0.0f);
+ break;
+ }
+ }
+ }
+ break;
+
+ case MI_FBICAR:
+ 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);
+ else
+ CCoronas::UpdateCoronaCoors((uintptr)this + 21, pos, 50.0f, 0.0f);
+ }
+ break;
+
+ case MI_TAXI:
+ case MI_CABBIE:
+ case MI_BORGNINE:
+ if(bTaxiLight){
+ CVector pos = GetPosition() + GetUp()*0.95f;
+ CCoronas::RegisterCorona((uintptr)this + 21,
+ 128, 128, 0, 255,
+ pos, 0.8f, 50.0f,
+ CCoronas::TYPE_NORMAL,
+ CCoronas::FLARE_NONE,
+ CCoronas::REFLECTION_ON, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+ CPointLights::AddLight(CPointLights::LIGHT_POINT,
+ pos, CVector(0.0f, 0.0f, 0.0f), 10.0f,
+ 1.0f, 1.0f, 0.5f, CPointLights::FOG_NONE, true);
+ }
+ break;
+ }
+
+ if(GetModelIndex() == MI_RCBANDIT ||
+ GetModelIndex() == MI_DODO ||
+ GetModelIndex() == MI_RHINO)
+ goto nolights;
+
+ // Turn lights on/off
+ bool shouldLightsBeOn =
+ CClock::GetHours() > 20 ||
+ CClock::GetHours() > 19 && CClock::GetMinutes() > (m_randomSeed & 0x3F) ||
+ CClock::GetHours() < 7 ||
+ CClock::GetHours() < 8 && CClock::GetMinutes() < (m_randomSeed & 0x3F) ||
+ m_randomSeed/50000.0f < CWeather::Foggyness ||
+ m_randomSeed/50000.0f < CWeather::WetRoads;
+ if(shouldLightsBeOn != bLightsOn && m_status != STATUS_WRECKED){
+ if(m_status == STATUS_ABANDONED){
+ // Turn off lights on abandoned vehicles only when we they're far away
+ if(bLightsOn &&
+ Abs(TheCamera.GetPosition().x - GetPosition().x) + Abs(TheCamera.GetPosition().y - GetPosition().y) > 100.0f)
+ bLightsOn = false;
+ }else
+ bLightsOn = shouldLightsBeOn;
+ }
+
+ // Actually render the lights
+ bool alarmOn = false;
+ bool alarmOff = false;
+ if(IsAlarmOn()){
+ if(CTimer::GetTimeInMilliseconds() & 0x100)
+ alarmOn = true;
+ else
+ alarmOff = true;
+ }
+ if(bEngineOn && bLightsOn || alarmOn || alarmOff){
+ CVector lookVector = GetPosition() - TheCamera.GetPosition();
+ float camDist = lookVector.Magnitude();
+ if(camDist != 0.0f)
+ lookVector *= 1.0f/camDist;
+ else
+ 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
+ // Abs not necessary
+ float angle = Abs(Acos(behindness));
+
+ // Headlights
+
+ CVector headLightPos = mi->m_positions[CAR_POS_HEADLIGHTS];
+ CVector lightR = GetMatrix() * headLightPos;
+ CVector lightL = lightR;
+ lightL -= GetRight()*2.0f*headLightPos.x;
+
+ // Headlight coronas
+ if(behindness < 0.0f){
+ // In front of car
+ float intensity = -0.5f*behindness + 0.3f;
+ float size = 1.0f - behindness;
+
+ if(behindness < -0.97f && camDist < 30.0f){
+ // Directly in front and not too far away
+ if(pHandling->Flags & HANDLING_HALOGEN_LIGHTS){
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 6, 150, 150, 195, 255,
+ lightL, 1.2f, 45.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_HEADLIGHT, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, angle);
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 7, 150, 150, 195, 255,
+ lightR, 1.2f, 45.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_HEADLIGHT, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, angle);
+ }else{
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 6, 160, 160, 140, 255,
+ lightL, 1.2f, 45.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_HEADLIGHT, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, angle);
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 7, 160, 160, 140, 255,
+ lightR, 1.2f, 45.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_HEADLIGHT, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, angle);
+ }
+ }
+
+ if(alarmOff){
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this, 0, 0, 0, 0,
+ lightL, size, 0.0f,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 1, 0, 0, 0, 0,
+ lightR, size, 0.0f,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ }else{
+ if(pHandling->Flags & HANDLING_HALOGEN_LIGHTS){
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this, 190*intensity, 190*intensity, 255*intensity, 255,
+ lightL, size, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 1, 190*intensity, 190*intensity, 255*intensity, 255,
+ lightR, size, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ }else{
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this, 210*intensity, 210*intensity, 195*intensity, 255,
+ lightL, size, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 1, 210*intensity, 210*intensity, 195*intensity, 255,
+ lightR, size, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ }
+ }
+ }else{
+ // Behind car
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::UpdateCoronaCoors((uintptr)this, lightL, 50.0f*TheCamera.LODDistMultiplier, angle);
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::UpdateCoronaCoors((uintptr)this + 1, lightR, 50.0f*TheCamera.LODDistMultiplier, angle);
+ }
+
+ // bright lights
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK && !bNoBrightHeadLights)
+ CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->FrontLights + 4);
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK && !bNoBrightHeadLights)
+ CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->FrontLights + 4);
+
+ // Taillights
+
+ CVector tailLightPos = mi->m_positions[CAR_POS_TAILLIGHTS];
+ lightR = GetMatrix() * tailLightPos;
+ lightL = lightR;
+ lightL -= GetRight()*2.0f*tailLightPos.x;
+
+ // Taillight coronas
+ if(behindness > 0.0f){
+ // Behind car
+ float intensity = 0.4f*behindness + 0.4;
+ float size = (behindness + 1.0f)/2.0f;
+
+ if(m_fGasPedal < 0.0f){
+ // reversing
+ intensity += 0.4f;
+ size += 0.3f;
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 2, 128*intensity, 128*intensity, 128*intensity, 255,
+ lightL, size, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 3, 128*intensity, 128*intensity, 128*intensity, 255,
+ lightR, size, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ }else{
+ if(m_fBrakePedal > 0.0){
+ intensity += 0.4f;
+ size += 0.3f;
+ }
+
+ if(alarmOff){
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 2, 0, 0, 0, 0,
+ lightL, size, 0.0f,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 3, 0, 0, 0, 0,
+ lightR, size, 0.0f,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ }else{
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 2, 128*intensity, 0, 0, 255,
+ lightL, size, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 3, 128*intensity, 0, 0, 255,
+ lightR, size, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ }
+ }
+ }else{
+ // In front of car
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::UpdateCoronaCoors((uintptr)this + 2, lightL, 50.0f*TheCamera.LODDistMultiplier, angle);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::UpdateCoronaCoors((uintptr)this + 3, lightR, 50.0f*TheCamera.LODDistMultiplier, angle);
+ }
+
+ // bright lights
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 8);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 8);
+
+ // Light shadows
+ if(!alarmOff){
+ CVector pos = GetPosition();
+ CVector2D fwd(GetForward());
+ fwd.Normalise();
+ float f = headLightPos.y + 6.0f;
+ pos += CVector(f*fwd.x, f*fwd.y, 2.0f);
+
+ 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);
+
+ f = (tailLightPos.y - 2.5f) - (headLightPos.y + 6.0f);
+ pos += CVector(f*fwd.x, f*fwd.y, 0.0f);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK ||
+ Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CShadows::StoreCarLightShadow(this, (uintptr)this + 25, gpShadowExplosionTex, &pos,
+ 3.0f, 0.0f, 0.0f, -3.0f, 35, 0, 0, 4.0f);
+ }
+
+ if(this == FindPlayerVehicle() && !alarmOff){
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK ||
+ Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK)
+ CPointLights::AddLight(CPointLights::LIGHT_DIRECTIONAL, GetPosition(), GetForward(),
+ 20.0f, 1.0f, 1.0f, 1.0f,
+ FindPlayerVehicle()->m_vecMoveSpeed.MagnitudeSqr2D() < sq(0.45f) ? CPointLights::FOG_NORMAL : CPointLights::FOG_NONE,
+ false);
+ CVector pos = GetPosition() - 4.0f*GetForward();
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK ||
+ Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ if(m_fBrakePedal > 0.0f)
+ CPointLights::AddLight(CPointLights::LIGHT_POINT, pos, CVector(0.0f, 0.0f, 0.0f),
+ 10.0f, 1.0f, 0.0f, 0.0f,
+ CPointLights::FOG_NONE, false);
+ else
+ CPointLights::AddLight(CPointLights::LIGHT_POINT, pos, CVector(0.0f, 0.0f, 0.0f),
+ 7.0f, 0.6f, 0.0f, 0.0f,
+ CPointLights::FOG_NONE, false);
+ }
+ }else{
+ // Lights off
+
+ if(m_status == STATUS_ABANDONED || m_status == STATUS_WRECKED)
+ goto nolights;
+
+ CVector lightPos = mi->m_positions[CAR_POS_TAILLIGHTS];
+ CVector lightR = GetMatrix() * lightPos;
+ CVector lightL = lightR;
+ lightL -= GetRight()*2.0f*lightPos.x;
+
+ if(m_fBrakePedal > 0.0f || m_fGasPedal < 0.0f){
+ CVector lookVector = GetPosition() - TheCamera.GetPosition();
+ lookVector.Normalise();
+ float behindness = DotProduct(lookVector, GetForward());
+ if(behindness > 0.0f){
+ if(m_fGasPedal < 0.0f){
+ // reversing
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 2, 120, 120, 120, 255,
+ lightL, 1.2f, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 3, 120, 120, 120, 255,
+ lightR, 1.2f, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 4);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 4);
+ }else{
+ // braking
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 2, 120, 0, 0, 255,
+ lightL, 1.2f, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 3, 120, 0, 0, 255,
+ lightR, 1.2f, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 8);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 8);
+ }
+ }else{
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::UpdateCoronaCoors((uintptr)this + 2, lightL, 50.0f*TheCamera.LODDistMultiplier, 0.0f);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::UpdateCoronaCoors((uintptr)this + 3, lightR, 50.0f*TheCamera.LODDistMultiplier, 0.0f);
+ }
+ }else{
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::UpdateCoronaCoors((uintptr)this + 2, lightL, 50.0f*TheCamera.LODDistMultiplier, 0.0f);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::UpdateCoronaCoors((uintptr)this + 3, lightR, 50.0f*TheCamera.LODDistMultiplier, 0.0f);
+ }
+ }
+
+nolights:
+ CShadows::StoreShadowForCar(this);
+}
+
+void
+CAutomobile::Render(void)
+{
+ int i;
+ CMatrix mat;
+ CVector pos;
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+
+ if(GetModelIndex() == MI_RHINO && m_aCarNodes[CAR_BONNET]){
+ // Rhino has no bonnet...what are we doing here?
+ CMatrix m;
+ CVector p;
+ m.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BONNET]));
+ p = m.GetPosition();
+ m.SetRotateZ(m_fCarGunLR);
+ m.Translate(p);
+ m.UpdateRW();
+ }
+
+ CVector contactPoints[4]; // relative to model
+ CVector contactSpeeds[4]; // speed at contact points
+ CVector frontWheelFwd = Multiply3x3(GetMatrix(), CVector(-Sin(m_fSteerAngle), Cos(m_fSteerAngle), 0.0f));
+ CVector rearWheelFwd = GetForward();
+ for(i = 0; i < 4; i++){
+ contactPoints[i] = m_aWheelColPoints[i].point - GetPosition();
+ contactSpeeds[i] = GetSpeed(contactPoints[i]);
+ if(i == CARWHEEL_FRONT_LEFT || i == CARWHEEL_FRONT_RIGHT)
+ m_aWheelSpeed[i] = ProcessWheelRotation(m_aWheelState[i], frontWheelFwd, contactSpeeds[i], 0.5f*mi->m_wheelScale);
+ else
+ m_aWheelSpeed[i] = ProcessWheelRotation(m_aWheelState[i], rearWheelFwd, contactSpeeds[i], 0.5f*mi->m_wheelScale);
+ m_aWheelRotation[i] += m_aWheelSpeed[i];
+ }
+
+ // Rear right wheel
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RB]));
+ pos.x = mat.GetPosition().x;
+ pos.y = mat.GetPosition().y;
+ 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);
+ 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.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]));
+ else
+ mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI);
+ 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.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);
+ 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.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]));
+ else
+ mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI);
+ 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.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);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ if(CVehicle::bWheelsOnlyCheat)
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]));
+
+ // Rotate propeller
+ if(m_aCarNodes[CAR_WINDSCREEN]){
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WINDSCREEN]));
+ pos = mat.GetPosition();
+ mat.SetRotateY(m_fPropellerRotation);
+ mat.Translate(pos);
+ mat.UpdateRW();
+
+ m_fPropellerRotation += m_fGasPedal != 0.0f ? TWOPI/13.0f : TWOPI/26.0f;
+ if(m_fPropellerRotation > TWOPI)
+ m_fPropellerRotation -= TWOPI;
+ }
+
+ // Rudder
+ if(Damage.GetDoorStatus(DOOR_BOOT) != DOOR_STATUS_MISSING && m_aCarNodes[CAR_BOOT]){
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BOOT]));
+ pos = mat.GetPosition();
+ mat.SetRotate(0.0f, 0.0f, -m_fSteerAngle);
+ mat.Rotate(0.0f, Sin(m_fSteerAngle)*DEGTORAD(22.0f), 0.0f);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ }
+
+ ProcessSwingingDoor(CAR_DOOR_LF, DOOR_FRONT_LEFT);
+ ProcessSwingingDoor(CAR_DOOR_RF, DOOR_FRONT_RIGHT);
+ }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.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.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{
+ // Front right wheel
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF]));
+ pos.x = mat.GetPosition().x;
+ pos.y = mat.GetPosition().y;
+ 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);
+ 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.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]));
+ else
+ mat.SetRotate(-m_aWheelRotation[CARWHEEL_FRONT_LEFT], 0.0f, PI+m_fSteerAngle);
+ 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);
+ ProcessSwingingDoor(CAR_DOOR_LR, DOOR_REAR_LEFT);
+ ProcessSwingingDoor(CAR_DOOR_RR, DOOR_REAR_RIGHT);
+ ProcessSwingingDoor(CAR_BONNET, DOOR_BONNET);
+ ProcessSwingingDoor(CAR_BOOT, DOOR_BOOT);
+
+ mi->SetVehicleColour(m_currentColour1, m_currentColour2);
+ }
+
+ if(!CVehicle::bWheelsOnlyCheat)
+ CEntity::Render();
+}
+
+int32
+CAutomobile::ProcessEntityCollision(CEntity *ent, CColPoint *colpoints)
+{
+ int i;
+ CColModel *colModel;
+
+ if(m_status != STATUS_SIMPLE)
+ bVehicleColProcessed = true;
+
+ if(bUsingSpecialColModel)
+ colModel = &CWorld::Players[CWorld::PlayerInFocus].m_ColModel;
+ else
+ colModel = GetColModel();
+
+ int numWheelCollisions = 0;
+ float prevRatios[4] = { 0.0f, 0.0f, 0.0f, 0.0f};
+ for(i = 0; i < 4; i++)
+ prevRatios[i] = m_aSuspensionSpringRatio[i];
+
+ int numCollisions = CCollision::ProcessColModels(GetMatrix(), *colModel,
+ ent->GetMatrix(), *ent->GetColModel(),
+ colpoints,
+ m_aWheelColPoints, m_aSuspensionSpringRatio);
+
+ // 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(field_EF || m_phy_flagA80 ||
+ GetModelIndex() == MI_DODO && (ent->IsPed() || ent->IsVehicle())){
+ // don't do line collision
+ for(i = 0; i < 4; i++)
+ m_aSuspensionSpringRatio[i] = prevRatios[i];
+ }else{
+ for(i = 0; i < 4; i++)
+ if(m_aSuspensionSpringRatio[i] < 1.0f && m_aSuspensionSpringRatio[i] < prevRatios[i]){
+ numWheelCollisions++;
+
+ // wheel is touching a physical
+ if(ent->IsVehicle() || ent->IsObject()){
+ CPhysical *phys = (CPhysical*)ent;
+
+ m_aGroundPhysical[i] = phys;
+ phys->RegisterReference((CEntity**)&m_aGroundPhysical[i]);
+ m_aGroundOffset[i] = m_aWheelColPoints[i].point - phys->GetPosition();
+
+ if(phys->GetModelIndex() == MI_BODYCAST && m_status == 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->bIsStatic){
+ phys->bIsStatic = false;
+ phys->m_nStaticFrames = 0;
+ phys->ApplyMoveForce(m_vecMoveSpeed / speed);
+ phys->AddToMovingList();
+ }
+ }
+ }
+
+ m_nSurfaceTouched = m_aWheelColPoints[i].surfaceB;
+ if(ent->IsBuilding())
+ m_pCurGroundEntity = ent;
+ }
+ }
+
+ if(numCollisions > 0 || numWheelCollisions > 0){
+ AddCollisionRecord(ent);
+ if(!ent->IsBuilding())
+ ((CPhysical*)ent)->AddCollisionRecord(this);
+
+ if(numCollisions > 0)
+ if(ent->IsBuilding() ||
+ ent->IsObject() && ((CPhysical*)ent)->bInfiniteMass)
+ bHasHitWall = true;
+ }
+
+ return numCollisions;
+}
+
+static int16 nLastControlInput;
+static float fMouseCentreRange = 0.35f;
+static float fMouseSteerSens = -0.0035f;
+static float fMouseCentreMult = 0.975f;
+
+void
+CAutomobile::ProcessControlInputs(uint8 pad)
+{
+ float speed = DotProduct(m_vecMoveSpeed, GetForward());
+
+ if(CPad::GetPad(pad)->GetExitVehicle())
+ bIsHandbrakeOn = true;
+ else
+ bIsHandbrakeOn = !!CPad::GetPad(pad)->GetHandBrake();
+
+ // Steer left/right
+ if(CCamera::m_bUseMouse3rdPerson && !CVehicle::m_bDisableMouseSteering){
+ if(CPad::GetPad(pad)->GetMouseX() != 0.0f){
+ m_fSteerRatio += fMouseSteerSens*CPad::GetPad(pad)->GetMouseX();
+ nLastControlInput = 2;
+ if(Abs(m_fSteerRatio) < fMouseCentreRange)
+ m_fSteerRatio *= Pow(fMouseCentreMult, CTimer::GetTimeStep());
+ }else if(CPad::GetPad(pad)->GetSteeringLeftRight() || nLastControlInput != 2){
+ // mouse hasn't move, steer with pad like below
+ m_fSteerRatio += (-CPad::GetPad(pad)->GetSteeringLeftRight()/128.0f - m_fSteerRatio)*
+ 0.2f*CTimer::GetTimeStep();
+ nLastControlInput = 0;
+ }
+ }else{
+ m_fSteerRatio += (-CPad::GetPad(pad)->GetSteeringLeftRight()/128.0f - m_fSteerRatio)*
+ 0.2f*CTimer::GetTimeStep();
+ nLastControlInput = 0;
+ }
+ m_fSteerRatio = clamp(m_fSteerRatio, -1.0f, 1.0f);
+
+ // Accelerate/Brake
+ float acceleration = (CPad::GetPad(pad)->GetAccelerate() - CPad::GetPad(pad)->GetBrake())/255.0f;
+ if(GetModelIndex() == MI_DODO && acceleration < 0.0f)
+ acceleration *= 0.3f;
+ if(Abs(speed) < 0.01f){
+ // standing still, go into direction we want
+ m_fGasPedal = acceleration;
+ m_fBrakePedal = 0.0f;
+ }else{
+#if 1
+ // simpler than the code below
+ if(speed * acceleration < 0.0f){
+ // if opposite directions, have to brake first
+ m_fGasPedal = 0.0f;
+ m_fBrakePedal = Abs(acceleration);
+ }else{
+ // accelerating in same direction we were already going
+ m_fGasPedal = acceleration;
+ m_fBrakePedal = 0.0f;
+ }
+#else
+ if(speed < 0.0f){
+ // moving backwards currently
+ if(acceleration < 0.0f){
+ // still go backwards
+ m_fGasPedal = acceleration;
+ m_fBrakePedal = 0.0f;
+ }else{
+ // want to go forwards, so brake
+ m_fGasPedal = 0.0f;
+ m_fBrakePedal = acceleration;
+ }
+ }else{
+ // moving forwards currently
+ if(acceleration < 0.0f){
+ // want to go backwards, so brake
+ m_fGasPedal = 0.0f;
+ m_fBrakePedal = -acceleration;
+ }else{
+ // still go forwards
+ m_fGasPedal = acceleration;
+ m_fBrakePedal = 0.0f;
+ }
+ }
+#endif
+ }
+
+ // Actually turn wheels
+ static float fValue; // why static?
+ if(m_fSteerRatio < 0.0f)
+ fValue = -sq(m_fSteerRatio);
+ else
+ fValue = sq(m_fSteerRatio);
+ m_fSteerAngle = DEGTORAD(pHandling->fSteeringLock) * fValue;
+
+ if(bComedyControls){
+ int rnd = CGeneral::GetRandomNumber() % 10;
+ switch(m_comedyControlState){
+ case 0:
+ if(rnd < 2)
+ m_comedyControlState = 1;
+ else if(rnd < 4)
+ m_comedyControlState = 2;
+ break;
+ case 1:
+ m_fSteerAngle += 0.05f;
+ if(rnd < 2)
+ m_comedyControlState = 0;
+ break;
+ case 2:
+ m_fSteerAngle -= 0.05f;
+ if(rnd < 2)
+ m_comedyControlState = 0;
+ break;
+ }
+ }else
+ m_comedyControlState = 0;
+
+ // Brake if player isn't in control
+ // BUG: game always uses pad 0 here
+ if(CPad::GetPad(pad)->DisablePlayerControls){
+ m_fBrakePedal = 1.0f;
+ bIsHandbrakeOn = true;
+ m_fGasPedal = 0.0f;
+
+ FindPlayerPed()->KeepAreaAroundPlayerClear();
+
+ // slow down car immediately
+ speed = m_vecMoveSpeed.Magnitude();
+ if(speed > 0.28f)
+ m_vecMoveSpeed *= 0.28f/speed;
+ }
+}
+
+void
+CAutomobile::FireTruckControl(void)
+{
+ if(this == FindPlayerVehicle()){
+ if(!CPad::GetPad(0)->GetWeapon())
+ return;
+ m_fCarGunLR += CPad::GetPad(0)->GetCarGunLeftRight()*0.00025f*CTimer::GetTimeStep();
+ m_fCarGunUD += CPad::GetPad(0)->GetCarGunUpDown()*0.0001f*CTimer::GetTimeStep();
+ m_fCarGunUD = clamp(m_fCarGunUD, 0.05f, 0.3f);
+
+ CVector cannonPos(0.0f, 1.5f, 1.9f);
+ cannonPos = GetMatrix() * cannonPos;
+ CVector cannonDir(
+ Sin(m_fCarGunLR) * Cos(m_fCarGunUD),
+ Cos(m_fCarGunLR) * Cos(m_fCarGunUD),
+ Sin(m_fCarGunUD));
+ cannonDir = Multiply3x3(GetMatrix(), cannonDir);
+ cannonDir.z += (CGeneral::GetRandomNumber()&0xF)/1000.0f;
+ CWaterCannons::UpdateOne((uintptr)this, &cannonPos, &cannonDir);
+ }else if(m_status == STATUS_PHYSICS){
+ CFire *fire = gFireManager.FindFurthestFire_NeverMindFireMen(GetPosition(), 10.0f, 35.0f);
+ if(fire == nil)
+ return;
+
+ // Target cannon onto fire
+ float targetAngle = CGeneral::GetATanOfXY(fire->m_vecPos.x-GetPosition().x, fire->m_vecPos.y-GetPosition().y);
+ float fwdAngle = CGeneral::GetATanOfXY(GetForward().x, GetForward().y);
+ float targetCannonAngle = fwdAngle - targetAngle;
+ float angleDelta = CTimer::GetTimeStep()*0.01f;
+ float cannonDelta = targetCannonAngle - m_fCarGunLR;
+ while(cannonDelta < PI) cannonDelta += TWOPI;
+ while(cannonDelta > PI) cannonDelta -= TWOPI;
+ if(Abs(cannonDelta) < angleDelta)
+ m_fCarGunLR = targetCannonAngle;
+ else if(cannonDelta > 0.0f)
+ m_fCarGunLR += angleDelta;
+ else
+ m_fCarGunLR -= angleDelta;
+
+ // Go up and down a bit
+ float upDown = Sin((float)(CTimer::GetTimeInMilliseconds() & 0xFFF)/0x1000 * TWOPI);
+ m_fCarGunUD = 0.2f + 0.2f*upDown;
+
+ // Spray water every once in a while
+ if((CTimer::GetTimeInMilliseconds()>>10) & 3){
+ CVector cannonPos(0.0f, 0.0f, 2.2f); // different position than player's firetruck!
+ cannonPos = GetMatrix() * cannonPos;
+ CVector cannonDir(
+ Sin(m_fCarGunLR) * Cos(m_fCarGunUD),
+ Cos(m_fCarGunLR) * Cos(m_fCarGunUD),
+ Sin(m_fCarGunUD));
+ cannonDir = Multiply3x3(GetMatrix(), cannonDir);
+ cannonDir.z += (CGeneral::GetRandomNumber()&0xF)/1000.0f;
+ CWaterCannons::UpdateOne((uintptr)this, &cannonPos, &cannonDir);
+ }
+ }
+}
+
+void
+CAutomobile::TankControl(void)
+{
+ int i;
+
+ // These coords are 1 unit higher then they should be relative to model center
+ CVector turrentBase(0.0f, -1.394f, 2.296f);
+ CVector gunEnd(0.0f, 1.813f, 2.979f);
+ CVector baseToEnd = gunEnd - turrentBase;
+
+ if(this != FindPlayerVehicle())
+ return;
+ if(CWorld::Players[CWorld::PlayerInFocus].m_WBState != WBSTATE_PLAYING)
+ return;
+
+ // Rotate turret
+ float prevAngle = m_fCarGunLR;
+ m_fCarGunLR -= CPad::GetPad(0)->GetCarGunLeftRight() * 0.00015f * CTimer::GetTimeStep();
+ if(m_fCarGunLR < 0.0f)
+ m_fCarGunLR += TWOPI;
+ if(m_fCarGunLR > TWOPI)
+ m_fCarGunLR -= TWOPI;
+ if(m_fCarGunLR != prevAngle)
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_TANK_TURRET_ROTATE, Abs(m_fCarGunLR - prevAngle));
+
+ // Shoot
+ if(CPad::GetPad(0)->CarGunJustDown() &&
+ CTimer::GetTimeInMilliseconds() > CWorld::Players[CWorld::PlayerInFocus].m_nTimeTankShotGun + 800){
+ CWorld::Players[CWorld::PlayerInFocus].m_nTimeTankShotGun = CTimer::GetTimeInMilliseconds();
+
+ // more like -sin(angle), cos(angle), i.e. rotated (0,1,0)
+ CVector turretDir = CVector(Sin(-m_fCarGunLR), Cos(-m_fCarGunLR), 0.0f);
+ turretDir = Multiply3x3(GetMatrix(), turretDir);
+
+ float c = Cos(m_fCarGunLR);
+ float s = Sin(m_fCarGunLR);
+ CVector rotatedEnd(
+ c*baseToEnd.x - s*baseToEnd.y,
+ s*baseToEnd.x + c*baseToEnd.y,
+ baseToEnd.z - 1.0f); // correct offset here
+ rotatedEnd += turrentBase;
+
+ CVector point1 = GetMatrix() * rotatedEnd;
+ CVector point2 = point1 + 60.0f*turretDir;
+ m_vecMoveSpeed -= 0.06f*turretDir;
+ m_vecMoveSpeed.z += 0.05f;
+
+ CWeapon::DoTankDoomAiming(FindPlayerVehicle(), FindPlayerPed(), &point1, &point2);
+ CColPoint colpoint;
+ CEntity *entity = nil;
+ CWorld::ProcessLineOfSight(point1, point2, colpoint, entity, true, true, true, true, true, true, false);
+ if(entity)
+ point2 = colpoint.point - 0.04f*(colpoint.point - point1);
+
+ CExplosion::AddExplosion(nil, FindPlayerPed(), EXPLOSION_TANK_GRENADE, point2, 0);
+
+ // Add particles on the way to the explosion;
+ float shotDist = (point2 - point1).Magnitude();
+ int n = shotDist/4.0f;
+ RwRGBA black = { 0, 0, 0, 0 };
+ for(i = 0; i < n; i++){
+ float f = (float)i/n;
+ CParticle::AddParticle(PARTICLE_HELI_DUST,
+ point1 + f*(point2 - point1),
+ CVector(0.0f, 0.0f, 0.0f),
+ nil, 0.1f, black);
+ }
+
+ // More particles
+ CVector shotDir = point2 - point1;
+ shotDir.Normalise();
+ for(i = 0; i < 15; i++){
+ 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);
+ }
+
+ // And some gun flashes near the gun
+ CVector flashPos = point1;
+ CVector nullDir(0.0f, 0.0f, 0.0f);
+ int lifeSpan = 250;
+ if(m_vecMoveSpeed.Magnitude() > 0.08f){
+ lifeSpan = 125;
+ flashPos.x += 0.5f*m_vecMoveSpeed.x;
+ flashPos.y += 0.5f*m_vecMoveSpeed.y;
+ }
+ CParticle::AddParticle(PARTICLE_GUNFLASH, flashPos, nullDir, nil, 0.4f, black, 0, 0, 0, lifeSpan);
+ flashPos += 0.3f*shotDir;
+ CParticle::AddParticle(PARTICLE_GUNFLASH, flashPos, nullDir, nil, 0.2f, black, 0, 0, 0, lifeSpan);
+ 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();
+ }
+}
+
+void
+CAutomobile::HydraulicControl(void)
+{
+ int i;
+ float wheelPositions[4];
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+ CColModel *normalColModel = mi->GetColModel();
+ float wheelRadius = 0.5f*mi->m_wheelScale;
+ CPlayerInfo *playerInfo = &CWorld::Players[CWorld::PlayerInFocus];
+ CColModel *specialColModel = &playerInfo->m_ColModel;
+
+ if(m_status != STATUS_PLAYER){
+ // reset hydraulics for non-player cars
+
+ if(!bUsingSpecialColModel)
+ return;
+ if(specialColModel != nil) // this is always true
+ for(i = 0; i < 4; i++)
+ wheelPositions[i] = specialColModel->lines[i].p0.z - m_aSuspensionSpringRatio[i]*m_aSuspensionLineLength[i];
+ for(i = 0; i < 4; i++){
+ m_aSuspensionSpringLength[i] = pHandling->fSuspensionUpperLimit - pHandling->fSuspensionLowerLimit;
+ m_aSuspensionLineLength[i] = normalColModel->lines[i].p0.z - normalColModel->lines[i].p1.z;
+ m_aSuspensionSpringRatio[i] = (normalColModel->lines[i].p0.z - wheelPositions[i]) / m_aSuspensionLineLength[i];
+ if(m_aSuspensionSpringRatio[i] > 1.0f)
+ m_aSuspensionSpringRatio[i] = 1.0f;
+ }
+
+ if(m_hydraulicState == 0)
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_1, 0.0f);
+ else if(m_hydraulicState >= 100)
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
+
+ if(playerInfo->m_pVehicleEx == this)
+ playerInfo->m_pVehicleEx = nil;
+ bUsingSpecialColModel = false;
+ m_hydraulicState = 0;
+ return;
+ }
+
+ // Player car
+
+ float normalUpperLimit = pHandling->fSuspensionUpperLimit;
+ float normalLowerLimit = pHandling->fSuspensionLowerLimit;
+ float normalSpringLength = normalUpperLimit - normalLowerLimit;
+ float extendedUpperLimit = normalUpperLimit - 0.2f;
+ float extendedLowerLimit = normalLowerLimit - 0.2f;
+ float extendedSpringLength = extendedUpperLimit - extendedLowerLimit;
+
+ if(!bUsingSpecialColModel){
+ // Init special col model
+
+ if(playerInfo->m_pVehicleEx && playerInfo->m_pVehicleEx == this)
+ playerInfo->m_pVehicleEx->bUsingSpecialColModel = false;
+ playerInfo->m_pVehicleEx = this;
+ playerInfo->m_ColModel = *normalColModel;
+ bUsingSpecialColModel = true;
+ specialColModel = &playerInfo->m_ColModel;
+
+ if(m_fVelocityChangeForAudio > 0.1f)
+ m_hydraulicState = 20;
+ else{
+ m_hydraulicState = 0;
+ normalUpperLimit += -0.12f;
+ normalSpringLength = normalUpperLimit - (normalLowerLimit+0.14f);
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
+ }
+
+ // Setup suspension
+ float normalLineLength = normalSpringLength + wheelRadius;
+ CVector pos;
+ for(i = 0; i < 4; i++){
+ wheelPositions[i] = normalColModel->lines[i].p0.z - m_aSuspensionSpringRatio[i]*m_aSuspensionLineLength[i];
+ mi->GetWheelPosn(i, pos);
+ pos.z += normalUpperLimit;
+ specialColModel->lines[i].p0 = pos;
+ pos.z -= normalLineLength;
+ specialColModel->lines[i].p1 = pos;
+ m_aSuspensionSpringLength[i] = normalSpringLength;
+ m_aSuspensionLineLength[i] = normalLineLength;
+
+ if(m_aSuspensionSpringRatio[i] < 1.0f){
+ m_aSuspensionSpringRatio[i] = (specialColModel->lines[i].p0.z - wheelPositions[i])/m_aSuspensionLineLength[i];
+ if(m_aSuspensionSpringRatio[i] > 1.0f)
+ m_aSuspensionSpringRatio[i] = 1.0f;
+ }
+ }
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
+
+ // Adjust col model
+ mi->GetWheelPosn(0, pos);
+ float minz = pos.z + extendedLowerLimit - wheelRadius;
+ if(minz < specialColModel->boundingBox.min.z)
+ specialColModel->boundingBox.min.z = minz;
+ float radius = Max(specialColModel->boundingBox.min.Magnitude(), specialColModel->boundingBox.max.Magnitude());
+ if(specialColModel->boundingSphere.radius < radius)
+ specialColModel->boundingSphere.radius = radius;
+
+ }
+
+ if(playerInfo->m_WBState != WBSTATE_PLAYING)
+ return;
+
+ bool setPrevRatio = false;
+ if(m_hydraulicState < 20 && m_fVelocityChangeForAudio > 0.2f){
+ if(m_hydraulicState == 0){
+ m_hydraulicState = 20;
+ for(i = 0; i < 4; i++)
+ m_aWheelPosition[i] -= 0.06f;
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_1, 0.0f);
+ setPrevRatio = true;
+ }else{
+ m_hydraulicState++;
+ }
+ }else if(m_hydraulicState != 0){ // must always be true
+ if(m_hydraulicState < 21 && m_fVelocityChangeForAudio < 0.1f){
+ m_hydraulicState--;
+ if(m_hydraulicState == 0)
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
+ }
+ }
+
+ if(CPad::GetPad(0)->HornJustDown()){
+ // Switch between normal and extended
+
+ if(m_hydraulicState < 100)
+ m_hydraulicState = 100;
+ else{
+ if(m_fVelocityChangeForAudio > 0.1f)
+ m_hydraulicState = 20;
+ else
+ m_hydraulicState = 0;
+ }
+
+ if(m_hydraulicState < 100){
+ if(m_hydraulicState == 0){
+ normalUpperLimit += -0.12f;
+ normalLowerLimit += 0.14f;
+ normalSpringLength = normalUpperLimit - normalLowerLimit;
+ }
+
+ // Reset suspension to normal
+ float normalLineLength = normalSpringLength + wheelRadius;
+ CVector pos;
+ for(i = 0; i < 4; i++){
+ wheelPositions[i] = specialColModel->lines[i].p0.z - m_aSuspensionSpringRatio[i]*m_aSuspensionLineLength[i];
+ mi->GetWheelPosn(i, pos);
+ pos.z += normalUpperLimit;
+ specialColModel->lines[i].p0 = pos;
+ pos.z -= normalLineLength;
+ specialColModel->lines[i].p1 = pos;
+ m_aSuspensionSpringLength[i] = normalSpringLength;
+ m_aSuspensionLineLength[i] = normalLineLength;
+
+ if(m_aSuspensionSpringRatio[i] < 1.0f){
+ m_aSuspensionSpringRatio[i] = (specialColModel->lines[i].p0.z - wheelPositions[i])/m_aSuspensionLineLength[i];
+ if(m_aSuspensionSpringRatio[i] > 1.0f)
+ m_aSuspensionSpringRatio[i] = 1.0f;
+ }
+ }
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
+ }else{
+ // Reset suspension to extended
+ float extendedLineLength = extendedSpringLength + wheelRadius;
+ CVector pos;
+ for(i = 0; i < 4; i++){
+ wheelPositions[i] = specialColModel->lines[i].p0.z - m_aSuspensionSpringRatio[i]*m_aSuspensionLineLength[i];
+ mi->GetWheelPosn(i, pos);
+ pos.z += extendedUpperLimit;
+ specialColModel->lines[i].p0 = pos;
+ pos.z -= extendedLineLength;
+ specialColModel->lines[i].p1 = pos;
+ m_aSuspensionSpringLength[i] = extendedSpringLength;
+ m_aSuspensionLineLength[i] = extendedLineLength;
+
+ if(m_aSuspensionSpringRatio[i] < 1.0f){
+ m_aSuspensionSpringRatio[i] = (specialColModel->lines[i].p0.z - wheelPositions[i])/m_aSuspensionLineLength[i];
+ if(m_aSuspensionSpringRatio[i] > 1.0f)
+ m_aSuspensionSpringRatio[i] = 1.0f;
+ }
+
+ setPrevRatio = true;
+ m_aWheelPosition[i] -= 0.05f;
+ }
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
+ }
+ }else{
+ float suspChange[4];
+ float maxDelta = 0.0f;
+ float rear = CPad::GetPad(0)->GetCarGunUpDown()/128.0f;
+ float front = -rear;
+ float right = CPad::GetPad(0)->GetCarGunLeftRight()/128.0f;
+ float left = -right;
+ suspChange[CARWHEEL_FRONT_LEFT] = Max(front+left, 0.0f);
+ suspChange[CARWHEEL_REAR_LEFT] = Max(rear+left, 0.0f);
+ suspChange[CARWHEEL_FRONT_RIGHT] = Max(front+right, 0.0f);
+ suspChange[CARWHEEL_REAR_RIGHT] = Max(rear+right, 0.0f);
+
+ if(m_hydraulicState < 100){
+ // Lowered, move wheels up
+
+ if(m_hydraulicState == 0){
+ normalUpperLimit += -0.12f;
+ normalLowerLimit += 0.14f;
+ normalSpringLength = normalUpperLimit - normalLowerLimit;
+ }
+
+ // Set suspension
+ CVector pos;
+ for(i = 0; i < 4; i++){
+ 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;
+
+ wheelPositions[i] = specialColModel->lines[i].p0.z - m_aSuspensionSpringRatio[i]*m_aSuspensionLineLength[i];
+ mi->GetWheelPosn(i, pos);
+ pos.z += upperLimit;
+ specialColModel->lines[i].p0 = pos;
+ pos.z -= lineLength;
+ if(Abs(pos.z - specialColModel->lines[i].p1.z) > Abs(maxDelta))
+ maxDelta = pos.z - specialColModel->lines[i].p1.z;
+ specialColModel->lines[i].p1 = pos;
+ m_aSuspensionSpringLength[i] = springLength;
+ m_aSuspensionLineLength[i] = lineLength;
+
+ if(m_aSuspensionSpringRatio[i] < 1.0f){
+ 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){
+ m_hydraulicState++;
+ for(i = 0; i < 4; i++)
+ m_aWheelPosition[i] -= 0.1f;
+ }
+
+ if(m_fVelocityChangeForAudio < 0.1f){
+ normalUpperLimit += -0.12f;
+ normalLowerLimit += 0.14f;
+ normalSpringLength = normalUpperLimit - normalLowerLimit;
+ }
+
+ // Set suspension
+ CVector pos;
+ for(i = 0; i < 4; i++){
+ if(suspChange[i] > 1.0f)
+ suspChange[i] = 1.0f;
+
+ float upperLimit = suspChange[i]*(normalUpperLimit-extendedUpperLimit) + extendedUpperLimit;
+ float springLength = suspChange[i]*(normalSpringLength-extendedSpringLength) + extendedSpringLength;
+ float lineLength = springLength + wheelRadius;
+
+ wheelPositions[i] = specialColModel->lines[i].p0.z - m_aSuspensionSpringRatio[i]*m_aSuspensionLineLength[i];
+ mi->GetWheelPosn(i, pos);
+ pos.z += upperLimit;
+ specialColModel->lines[i].p0 = pos;
+ pos.z -= lineLength;
+ if(Abs(pos.z - specialColModel->lines[i].p1.z) > Abs(maxDelta))
+ maxDelta = pos.z - specialColModel->lines[i].p1.z;
+ specialColModel->lines[i].p1 = pos;
+ m_aSuspensionSpringLength[i] = springLength;
+ m_aSuspensionLineLength[i] = lineLength;
+
+ if(m_aSuspensionSpringRatio[i] < 1.0f){
+ m_aSuspensionSpringRatio[i] = (specialColModel->lines[i].p0.z - wheelPositions[i])/m_aSuspensionLineLength[i];
+ if(m_aSuspensionSpringRatio[i] > 1.0f)
+ m_aSuspensionSpringRatio[i] = 1.0f;
+ }
+ }
+ }
+
+ float limitDiff = extendedLowerLimit - normalLowerLimit;
+ if(limitDiff != 0.0f && Abs(maxDelta/limitDiff) > 0.01f){
+ float f = (maxDelta + limitDiff)/2.0f/limitDiff;
+ f = clamp(f, 0.0f, 1.0f);
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_3, f);
+ if(f < 0.4f || f > 0.6f)
+ setPrevRatio = true;
+ if(f < 0.25f)
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
+ else if(f > 0.75f)
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_1, 0.0f);
+ }
+ }
+
+ if(setPrevRatio)
+ for(i = 0; i < 4; i++){
+ // wheel radius in relation to suspension line
+ float wheelRadius = 1.0f - m_aSuspensionSpringLength[i]/m_aSuspensionLineLength[i];
+ m_aSuspensionSpringRatioPrev[i] = (m_aSuspensionSpringRatio[i]-wheelRadius)/(1.0f-wheelRadius);
+ }
+}
+
+void
+CAutomobile::ProcessBuoyancy(void)
+{
+ int i;
+ CVector impulse, point;
+
+ if(mod_Buoyancy.ProcessBuoyancy(this, m_fBuoyancy, &point, &impulse)){
+ m_flagD8 = 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){
+ bIsInWater = true;
+ if(m_vecMoveSpeed.z < -0.1f)
+ m_vecMoveSpeed.z = -0.1f;
+
+ if(pDriver){
+ pDriver->bIsInWater = true;
+ if(pDriver->IsPlayer() || !bWaterTight)
+ pDriver->InflictDamage(nil, WEAPONTYPE_WATER, CTimer::GetTimeStep(), PEDPIECE_TORSO, 0);
+ }
+ for(i = 0; i < m_nNumMaxPassengers; i++)
+ if(pPassengers[i]){
+ pPassengers[i]->bIsInWater = true;
+ if(pPassengers[i]->IsPlayer() || !bWaterTight)
+ pPassengers[i]->InflictDamage(nil, WEAPONTYPE_WATER, CTimer::GetTimeStep(), PEDPIECE_TORSO, 0);
+ }
+ }else
+ bIsInWater = false;
+
+ static uint32 nGenerateRaindrops = 0;
+ static uint32 nGenerateWaterCircles = 0;
+
+ if(initialSpeed.z < -0.3f && impulse.z > 0.3f){
+ 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.alpha = CGeneral::GetRandomNumberInRange(0, 32) + 128;
+ CParticleObject::AddObject(POBJECT_CAR_WATER_SPLASH, GetPosition(),
+ CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(0.15f, 0.3f)),
+ 0.0f, 75, color, true);
+
+ nGenerateRaindrops = CTimer::GetTimeInMilliseconds() + 300;
+ nGenerateWaterCircles = CTimer::GetTimeInMilliseconds() + 60;
+ 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()){
+ CVector pos = GetPosition();
+ float waterLevel = 0.0f;
+ if(CWaterLevel::GetWaterLevel(pos.x, pos.y, pos.z, &waterLevel, false))
+ pos.z = waterLevel;
+ static RwRGBA black;
+ if(pos.z != 0.0f){
+ nGenerateWaterCircles = 0;
+ pos.z += 1.0f;
+ for(i = 0; i < 4; i++){
+ CVector p = pos;
+ p.x += CGeneral::GetRandomNumberInRange(-2.5f, 2.5f);
+ p.y += CGeneral::GetRandomNumberInRange(-2.5f, 2.5f);
+ CParticle::AddParticle(PARTICLE_RAIN_SPLASH_BIGGROW,
+ p, CVector(0.0f, 0.0f, 0.0f),
+ nil, 0.0f, black, 0, 0, 0, 0);
+ }
+ }
+ }
+
+ if(nGenerateRaindrops > 0 && nGenerateRaindrops < CTimer::GetTimeInMilliseconds()){
+ CVector pos = GetPosition();
+ float waterLevel = 0.0f;
+ if(CWaterLevel::GetWaterLevel(pos.x, pos.y, pos.z, &waterLevel, false))
+ pos.z = waterLevel;
+ static RwRGBA black;
+ if(pos.z >= 0.0f){
+ nGenerateRaindrops = 0;
+ pos.z += 0.5;
+ CParticleObject::AddObject(POBJECT_SPLASHES_AROUND,
+ pos, CVector(0.0f, 0.0f, 0.0f), 6.5f, 2500, black, true);
+ }
+ }
+ }else{
+ bIsInWater = false;
+ m_flagD8 = false;
+
+ static RwRGBA splashCol = {155, 155, 185, 196};
+ static RwRGBA smokeCol = {255, 255, 255, 255};
+
+ for(i = 0; i < 4; i++){
+ if(m_aSuspensionSpringRatio[i] < 1.0f && m_aWheelColPoints[i].surfaceB == SURFACE_PUDDLE){
+ CVector pos = m_aWheelColPoints[i].point + 0.3f*GetUp() - GetPosition();
+ CVector vSpeed = GetSpeed(pos);
+ vSpeed.z = 0.0f;
+ float fSpeed = vSpeed.MagnitudeSqr();
+ if(fSpeed > sq(0.05f)){
+ fSpeed = Sqrt(fSpeed);
+ float size = Min((fSpeed < 0.15f ? 0.25f : 0.75f)*fSpeed, 0.6f);
+ CVector right = 0.2f*fSpeed*GetRight() + 0.2f*vSpeed;
+
+ CParticle::AddParticle(PARTICLE_PED_SPLASH,
+ pos + GetPosition(), -0.5f*right,
+ nil, size, splashCol,
+ CGeneral::GetRandomNumberInRange(0.0f, 10.0f),
+ CGeneral::GetRandomNumberInRange(0.0f, 90.0f), 1, 0);
+
+ CParticle::AddParticle(PARTICLE_RUBBER_SMOKE,
+ pos + GetPosition(), -0.6f*right,
+ nil, size, smokeCol, 0, 0, 0, 0);
+
+ if((CTimer::GetFrameCounter() & 0xF) == 0)
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_SPLASH, 2000.0f*fSpeed);
+ }
+ }
+ }
+ }
+}
+
+void
+CAutomobile::DoDriveByShootings(void)
+{
+ CAnimBlendAssociation *anim;
+ CWeapon *weapon = pDriver->GetWeapon();
+ if(weapon->m_eWeaponType != WEAPONTYPE_UZI)
+ return;
+
+ weapon->Update(pDriver->m_audioEntityId);
+
+ bool lookingLeft = false;
+ bool lookingRight = false;
+ if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN1){
+ if(CPad::GetPad(0)->GetLookLeft())
+ lookingLeft = true;
+ if(CPad::GetPad(0)->GetLookRight())
+ lookingRight = true;
+ }else{
+ if(TheCamera.Cams[TheCamera.ActiveCam].LookingLeft)
+ lookingLeft = true;
+ if(TheCamera.Cams[TheCamera.ActiveCam].LookingRight)
+ lookingRight = true;
+ }
+
+ if(lookingLeft || lookingRight){
+ if(lookingLeft){
+ anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_R);
+ if(anim)
+ anim->blendDelta = -1000.0f;
+ anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_L);
+ if(anim == nil || anim->blendDelta < 0.0f)
+ CAnimManager::AddAnimation(pDriver->GetClump(), ASSOCGRP_STD, ANIM_DRIVEBY_L);
+ else
+ anim->SetRun();
+ }else if(pDriver->m_pMyVehicle->pPassengers[0] == nil || TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FIRSTPERSON){
+ anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_L);
+ if(anim)
+ anim->blendDelta = -1000.0f;
+ anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_R);
+ if(anim == nil || anim->blendDelta < 0.0f)
+ CAnimManager::AddAnimation(pDriver->GetClump(), ASSOCGRP_STD, ANIM_DRIVEBY_R);
+ else
+ anim->SetRun();
+ }
+
+ if(CPad::GetPad(0)->GetCarGunFired() && CTimer::GetTimeInMilliseconds() > weapon->m_nTimer){
+ weapon->FireFromCar(this, lookingLeft);
+ weapon->m_nTimer = CTimer::GetTimeInMilliseconds() + 70;
+ }
+ }else{
+ weapon->Reload();
+ anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_L);
+ if(anim)
+ anim->blendDelta = -1000.0f;
+ anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_R);
+ if(anim)
+ anim->blendDelta = -1000.0f;
+ }
+
+ // TODO: what is this?
+ if(!lookingLeft && m_weaponDoorTimerLeft > 0.0f){
+ m_weaponDoorTimerLeft = Max(m_weaponDoorTimerLeft - CTimer::GetTimeStep()*0.1f, 0.0f);
+ ProcessOpenDoor(CAR_DOOR_LF, NUM_ANIMS, m_weaponDoorTimerLeft);
+ }
+ if(!lookingRight && m_weaponDoorTimerRight > 0.0f){
+ m_weaponDoorTimerRight = Max(m_weaponDoorTimerRight - CTimer::GetTimeStep()*0.1f, 0.0f);
+ ProcessOpenDoor(CAR_DOOR_RF, NUM_ANIMS, m_weaponDoorTimerRight);
+ }
+}
+
+int32
+CAutomobile::RcbanditCheckHitWheels(void)
+{
+ int x, xmin, xmax;
+ int y, ymin, ymax;
+
+ xmin = CWorld::GetSectorIndexX(GetPosition().x - 2.0f);
+ if(xmin < 0) xmin = 0;
+ xmax = CWorld::GetSectorIndexX(GetPosition().x + 2.0f);
+ if(xmax > NUMSECTORS_X-1) xmax = NUMSECTORS_X-1;
+ ymin = CWorld::GetSectorIndexX(GetPosition().y - 2.0f);
+ if(ymin < 0) ymin = 0;
+ ymax = CWorld::GetSectorIndexX(GetPosition().y + 2.0f);
+ if(ymax > NUMSECTORS_Y-1) ymax = NUMSECTORS_X-1;
+
+ CWorld::AdvanceCurrentScanCode();
+
+ for(y = ymin; y <= ymax; y++)
+ for(x = xmin; x <= xmax; x++){
+ CSector *s = CWorld::GetSector(x, y);
+ if(RcbanditCheck1CarWheels(s->m_lists[ENTITYLIST_VEHICLES]) ||
+ RcbanditCheck1CarWheels(s->m_lists[ENTITYLIST_VEHICLES_OVERLAP]))
+ return 1;
+ }
+ return 0;
+}
+
+int32
+CAutomobile::RcbanditCheck1CarWheels(CPtrList &list)
+{
+ static CMatrix matW2B;
+ int i;
+ CPtrNode *node;
+ CAutomobile *car;
+ CColModel *colModel = GetColModel();
+ CVehicleModelInfo *mi;
+
+ for(node = list.first; node; node = node->next){
+ car = (CAutomobile*)node->item;
+ if(this != car && car->IsCar() && car->m_scanCode != CWorld::GetCurrentScanCode()){
+ car->m_scanCode = CWorld::GetCurrentScanCode();
+
+ if(Abs(this->GetPosition().x - car->GetPosition().x) < 10.0f &&
+ Abs(this->GetPosition().y - car->GetPosition().y) < 10.0f){
+ mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(car->GetModelIndex());
+
+ for(i = 0; i < 4; i++){
+ if(car->m_aSuspensionSpringRatioPrev[i] < 1.0f || car->m_status == STATUS_SIMPLE){
+ CVector wheelPos;
+ CColSphere sph;
+ mi->GetWheelPosn(i, wheelPos);
+ matW2B = Invert(GetMatrix());
+ sph.center = matW2B * (car->GetMatrix() * wheelPos);
+ sph.radius = mi->m_wheelScale*0.25f;
+ if(CCollision::TestSphereBox(sph, colModel->boundingBox))
+ return 1;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+void
+CAutomobile::PlaceOnRoadProperly(void)
+{
+ CColPoint point;
+ CEntity *entity;
+ CColModel *colModel = GetColModel();
+ float lenFwd, lenBack;
+ float frontZ, rearZ;
+
+ lenFwd = colModel->boundingBox.max.y;
+ lenBack = -colModel->boundingBox.min.y;
+
+ CVector front(GetPosition().x + GetForward().x*lenFwd,
+ GetPosition().y + GetForward().y*lenFwd,
+ GetPosition().z + 5.0f);
+ if(CWorld::ProcessVerticalLine(front, GetPosition().z - 5.0f, point, entity,
+ true, false, false, false, false, false, nil)){
+ frontZ = point.point.z;
+ m_pCurGroundEntity = entity;
+ }else{
+ frontZ = field_21C;
+ }
+
+ CVector rear(GetPosition().x - GetForward().x*lenBack,
+ GetPosition().y - GetForward().y*lenBack,
+ GetPosition().z + 5.0f);
+ if(CWorld::ProcessVerticalLine(rear, GetPosition().z - 5.0f, point, entity,
+ true, false, false, false, false, false, nil)){
+ rearZ = point.point.z;
+ m_pCurGroundEntity = entity;
+ }else{
+ rearZ = field_220;
+ }
+
+ float len = lenFwd + lenBack;
+ float angle = Atan((frontZ - rearZ)/len);
+ float c = Cos(angle);
+ float s = Sin(angle);
+
+ GetRight() = CVector((front.y - rear.y)/len, -(front.x - rear.x)/len, 0.0f);
+ GetForward() = CVector(-c*GetRight().y, c*GetRight().x, s);
+ GetUp() = CrossProduct(GetRight(), GetForward());
+ GetPosition() = CVector((front.x + rear.x)/2.0f, (front.y + rear.y)/2.0f, (frontZ + rearZ)/2.0f + GetHeightAboveRoad());
+}
+
+void
+CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece)
+{
+ int i;
+ float damageMultiplier = 0.2f;
+ bool doubleMoney = false;
+
+ if(impulse == 0.0f){
+ impulse = m_fDamageImpulse;
+ damagedPiece = m_nDamagePieceType;
+ damageMultiplier = 1.0f;
+ }
+
+ CVector pos(0.0f, 0.0f, 0.0f);
+
+ if(!bCanBeDamaged)
+ return;
+
+ // damage flipped over car
+ if(GetUp().z < 0.0f && this != FindPlayerVehicle()){
+ if(bNotDamagedUpsideDown || m_status == STATUS_PLAYER_REMOTE || bIsInWater)
+ return;
+ m_fHealth -= 4.0f*CTimer::GetTimeStep();
+ }
+
+ if(impulse > 25.0f && m_status != STATUS_WRECKED){
+ if(bIsLawEnforcer &&
+ FindPlayerVehicle() && FindPlayerVehicle() == m_pDamageEntity &&
+ m_status != STATUS_ABANDONED &&
+ FindPlayerVehicle()->m_vecMoveSpeed.Magnitude() >= m_vecMoveSpeed.Magnitude() &&
+ FindPlayerVehicle()->m_vecMoveSpeed.Magnitude() > 0.1f)
+ FindPlayerPed()->SetWantedLevelNoDrop(1);
+
+ if(m_status == STATUS_PLAYER && impulse > 50.0f){
+ uint8 freq = Min(0.4f*impulse*2000.0f/m_fMass + 100.0f, 250.0f);
+ CPad::GetPad(0)->StartShake(40000/freq, freq);
+ }
+
+ if(bOnlyDamagedByPlayer){
+ if(m_pDamageEntity != FindPlayerPed() &&
+ m_pDamageEntity != FindPlayerVehicle())
+ return;
+ }
+
+ if(bCollisionProof)
+ return;
+
+ if(m_pDamageEntity){
+ if(m_pDamageEntity->IsBuilding() &&
+ DotProduct(m_vecDamageNormal, GetUp()) > 0.6f)
+ return;
+ }
+
+ int oldLightStatus[4];
+ for(i = 0; i < 4; i++)
+ oldLightStatus[i] = Damage.GetLightStatus((eLights)i);
+
+ if(GetUp().z > 0.0f || m_vecMoveSpeed.MagnitudeSqr() > 0.1f){
+ float impulseMult = bMoreResistantToDamage ? 0.5f : 4.0f;
+
+ 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)){
+ 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)){
+ 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)){
+ 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)){
+ 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)){
+ 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)){
+ 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)){
+ 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)){
+ 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)){
+ 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)){
+ 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)){
+ 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)){
+ SetPanelDamage(CAR_WING_RR, VEHPANEL_REAR_RIGHT);
+ doubleMoney = true;
+ }
+ break;
+
+ case CAR_PIECE_WHEEL_LF:
+ case CAR_PIECE_WHEEL_LR:
+ case CAR_PIECE_WHEEL_RF:
+ case CAR_PIECE_WHEEL_RR:
+ break;
+
+ case CAR_PIECE_WINDSCREEN:
+ if(Damage.ApplyDamage(COMPONENT_PANEL_WINDSCREEN, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ 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;
+ }
+ }
+ 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;
+
+ if(GetModelIndex() == MI_SECURICA && m_pDamageEntity && m_pDamageEntity->m_status == STATUS_PLAYER)
+ damage *= 7.0f;
+
+ if(damage > 0.0f){
+ int oldHealth = m_fHealth;
+ 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;
+ }
+ if(m_fHealth <= 0.0f && oldHealth > 0)
+ m_fHealth = 1.0f;
+ }
+
+ // play sound if a light broke
+ for(i = 0; i < 4; i++)
+ if(oldLightStatus[i] != 1 && Damage.GetLightStatus((eLights)i) == 1){
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_LIGHT_BREAK, i); // BUG? i?
+ break;
+ }
+ }
+
+ if(m_fHealth < 250.0f){
+ // Car is on fire
+ if(Damage.GetEngineStatus() < ENGINE_STATUS_ON_FIRE){
+ // Set engine on fire and remember who did this
+ Damage.SetEngineStatus(ENGINE_STATUS_ON_FIRE);
+ m_fFireBlowUpTimer = 0.0f;
+ m_pSetOnFireEntity = m_pDamageEntity;
+ if(m_pSetOnFireEntity)
+ m_pSetOnFireEntity->RegisterReference(&m_pSetOnFireEntity);
+ }
+ }else{
+ if(GetModelIndex() == MI_BFINJECT){
+ if(m_fHealth < 400.0f)
+ Damage.SetEngineStatus(200);
+ else if(m_fHealth < 600.0f)
+ Damage.SetEngineStatus(100);
+ }
+ }
+}
+
+void
+CAutomobile::dmgDrawCarCollidingParticles(const CVector &pos, float amount)
+{
+ int i, n;
+
+ if(!GetIsOnScreen())
+ return;
+
+ // FindPlayerSpeed() unused
+
+ n = (int)amount/20;
+
+ for(i = 0; i < ((n+4)&0x1F); i++)
+ CParticle::AddParticle(PARTICLE_SPARK_SMALL, pos,
+ CVector(CGeneral::GetRandomNumberInRange(-0.1f, 0.1f),
+ CGeneral::GetRandomNumberInRange(-0.1f, 0.1f),
+ 0.006f));
+
+ for(i = 0; i < n+2; i++)
+ CParticle::AddParticle(PARTICLE_CARCOLLISION_DUST,
+ CVector(CGeneral::GetRandomNumberInRange(-1.2f, 1.2f) + pos.x,
+ CGeneral::GetRandomNumberInRange(-1.2f, 1.2f) + pos.y,
+ pos.z),
+ CVector(0.0f, 0.0f, 0.0f), nil, 0.5f);
+
+ n = (int)amount/50 + 1;
+ for(i = 0; i < n; i++)
+ CParticle::AddParticle(PARTICLE_CAR_DEBRIS, pos,
+ CVector(CGeneral::GetRandomNumberInRange(-0.25f, 0.25f),
+ CGeneral::GetRandomNumberInRange(-0.25f, 0.25f),
+ CGeneral::GetRandomNumberInRange(0.1f, 0.25f)),
+ nil,
+ CGeneral::GetRandomNumberInRange(0.02f, 0.08f),
+ CVehicleModelInfo::ms_vehicleColourTable[m_currentColour1],
+ CGeneral::GetRandomNumberInRange(-40.0f, 40.0f),
+ 0,
+ CGeneral::GetRandomNumberInRange(0.0f, 4.0f));
+}
+
+void
+CAutomobile::AddDamagedVehicleParticles(void)
+{
+ if(this == FindPlayerVehicle() && TheCamera.GetLookingForwardFirstPerson())
+ return;
+
+ uint8 engineStatus = Damage.GetEngineStatus();
+ if(engineStatus < ENGINE_STATUS_STEAM1)
+ return;
+
+ float fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward()) * 180.0f;
+ CVector direction = 0.5f*m_vecMoveSpeed;
+ CVector damagePos = ((CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()))->m_positions[CAR_POS_HEADLIGHTS];
+
+ switch(Damage.GetDoorStatus(DOOR_BONNET)){
+ case DOOR_STATUS_OK:
+ case DOOR_STATUS_SMASHED:
+ // Bonnet is still there, smoke comes out at the edge
+ damagePos += vecDAMAGE_ENGINE_POS_SMALL;
+ break;
+ case DOOR_STATUS_SWINGING:
+ case DOOR_STATUS_MISSING:
+ // Bonnet is gone, smoke comes out at the engine
+ damagePos += vecDAMAGE_ENGINE_POS_BIG;
+ break;
+ }
+
+ if(GetModelIndex() == MI_BFINJECT)
+ damagePos = CVector(0.3f, -1.5f, -0.1f);
+
+ 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);
+ }
+}
+
+int32
+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 waterCol = { 48, 48, 64, 0 };
+
+ if(!belowEffectSpeed)
+ return 0;
+
+ switch(colpoint->surfaceB){
+ case SURFACE_GRASS:
+ dir.x = -0.05f*m_vecMoveSpeed.x;
+ dir.y = -0.05f*m_vecMoveSpeed.y;
+ 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.1f), grassCol);
+ }
+ return 0;
+ case SURFACE_DIRT:
+ dir.x = -0.05f*m_vecMoveSpeed.x;
+ dir.y = -0.05f*m_vecMoveSpeed.y;
+ 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);
+ }
+ return 1;
+ case SURFACE_DIRTTRACK:
+ dir.x = -0.05f*m_vecMoveSpeed.x;
+ dir.y = -0.05f*m_vecMoveSpeed.y;
+ 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);
+ }
+ return 0;
+ default:
+ // Is this even visible?
+ if(CWeather::WetRoads > 0.01f && CTimer::GetFrameCounter() & 1){
+ CParticle::AddParticle(PARTICLE_WATERSPRAY,
+ colpoint->point + CVector(0.0f, 0.0f, 0.25f+0.25f),
+ CVector(0.0f, 0.0f, 1.0f), nil,
+ CGeneral::GetRandomNumberInRange(0.1f, 0.5f), waterCol);
+ return 0;
+ }
+ return 1;
+ }
+}
+
+void
+CAutomobile::GetComponentWorldPosition(int32 component, CVector &pos)
+{
+ if(m_aCarNodes[component] == nil){
+ printf("CarNode missing: %d %d\n", GetModelIndex(), component);
+ return;
+ }
+ RwMatrix *ltm = RwFrameGetLTM(m_aCarNodes[component]);
+ pos = *RwMatrixGetPos(ltm);
+}
+
+bool
+CAutomobile::IsComponentPresent(int32 comp)
+{
+ return m_aCarNodes[comp] != nil;
+}
+
+void
+CAutomobile::SetComponentRotation(int32 component, CVector rotation)
+{
+ CMatrix mat(RwFrameGetMatrix(m_aCarNodes[component]));
+ CVector pos = mat.GetPosition();
+ // BUG: all these set the whole matrix
+ mat.SetRotateX(DEGTORAD(rotation.x));
+ mat.SetRotateY(DEGTORAD(rotation.y));
+ mat.SetRotateZ(DEGTORAD(rotation.z));
+ mat.Translate(pos);
+ mat.UpdateRW();
+}
+
+void
+CAutomobile::OpenDoor(int32 component, eDoors door, float openRatio)
+{
+ CMatrix mat(RwFrameGetMatrix(m_aCarNodes[component]));
+ CVector pos = mat.GetPosition();
+ float axes[3] = { 0.0f, 0.0f, 0.0f };
+ float wasClosed = false;
+
+ if(Doors[door].IsClosed()){
+ // enable angle cull for closed doors
+ RwFrameForAllObjects(m_aCarNodes[component], CVehicleModelInfo::ClearAtomicFlagCB, (void*)ATOMIC_FLAG_NOCULL);
+ wasClosed = true;
+ }
+
+ Doors[door].Open(openRatio);
+
+ if(wasClosed && Doors[door].RetAngleWhenClosed() != Doors[door].m_fAngle){
+ // door opened
+ HideAllComps();
+ // turn off angle cull for swinging door
+ RwFrameForAllObjects(m_aCarNodes[component], CVehicleModelInfo::SetAtomicFlagCB, (void*)ATOMIC_FLAG_NOCULL);
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_DOOR_OPEN_BONNET + door, 0.0f);
+ }
+
+ if(!wasClosed && openRatio == 0.0f){
+ // door closed
+ if(Damage.GetDoorStatus(door) == DOOR_STATUS_SWINGING)
+ Damage.SetDoorStatus(door, DOOR_STATUS_OK); // huh?
+ ShowAllComps();
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_DOOR_CLOSE_BONNET + door, 0.0f);
+ }
+
+ axes[Doors[door].m_nAxis] = Doors[door].m_fAngle;
+ mat.SetRotate(axes[0], axes[1], axes[2]);
+ mat.Translate(pos);
+ mat.UpdateRW();
+}
+
+inline void ProcessDoorOpenAnimation(CAutomobile *car, uint32 component, eDoors door, float time, float start, float end)
+{
+ if(time > start && time < end){
+ float ratio = (time - start)/(end - start);
+ if(car->Doors[door].GetAngleOpenRatio() < ratio)
+ car->OpenDoor(component, door, ratio);
+ }else if(time > end){
+ car->OpenDoor(component, door, 1.0f);
+ }
+}
+
+inline void ProcessDoorCloseAnimation(CAutomobile *car, uint32 component, eDoors door, float time, float start, float end)
+{
+ if(time > start && time < end){
+ float ratio = 1.0f - (time - start)/(end - start);
+ if(car->Doors[door].GetAngleOpenRatio() > ratio)
+ car->OpenDoor(component, door, ratio);
+ }else if(time > end){
+ car->OpenDoor(component, door, 0.0f);
+ }
+}
+
+inline void ProcessDoorOpenCloseAnimation(CAutomobile *car, uint32 component, eDoors door, float time, float start, float mid, float end)
+{
+ if(time > start && time < mid){
+ // open
+ float ratio = (time - start)/(mid - start);
+ if(car->Doors[door].GetAngleOpenRatio() < ratio)
+ car->OpenDoor(component, door, ratio);
+ }else if(time > mid && time < end){
+ // close
+ float ratio = 1.0f - (time - mid)/(end - mid);
+ if(car->Doors[door].GetAngleOpenRatio() > ratio)
+ car->OpenDoor(component, door, ratio);
+ }else if(time > end){
+ car->OpenDoor(component, door, 0.0f);
+ }
+}
+void
+CAutomobile::ProcessOpenDoor(uint32 component, uint32 anim, float time)
+{
+ eDoors door;
+
+ switch(component){
+ case CAR_DOOR_RF: door = DOOR_FRONT_RIGHT; break;
+ case CAR_DOOR_RR: door = DOOR_REAR_RIGHT; break;
+ case CAR_DOOR_LF: door = DOOR_FRONT_LEFT; break;
+ case CAR_DOOR_LR: door = DOOR_REAR_LEFT; break;
+ default: assert(0);
+ }
+
+ if(IsDoorMissing(door))
+ return;
+
+ switch(anim){
+ case ANIM_CAR_QJACK:
+ case ANIM_CAR_OPEN_LHS:
+ case ANIM_CAR_OPEN_RHS:
+ ProcessDoorOpenAnimation(this, component, door, time, 0.66f, 0.8f);
+ 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);
+ break;
+ case ANIM_CAR_ROLLDOOR:
+ case ANIM_CAR_ROLLDOOR_LOW:
+ ProcessDoorOpenCloseAnimation(this, component, door, time, 0.1f, 0.6f, 0.95f);
+ break;
+ break;
+ case ANIM_CAR_GETOUT_LHS:
+ case ANIM_CAR_GETOUT_LOW_LHS:
+ case ANIM_CAR_GETOUT_RHS:
+ case ANIM_CAR_GETOUT_LOW_RHS:
+ ProcessDoorOpenAnimation(this, component, door, time, 0.06f, 0.43f);
+ break;
+ case ANIM_CAR_CLOSE_LHS:
+ case ANIM_CAR_CLOSE_RHS:
+ ProcessDoorCloseAnimation(this, component, door, time, 0.1f, 0.23f);
+ break;
+ case ANIM_CAR_PULLOUT_RHS:
+ case ANIM_CAR_PULLOUT_LOW_RHS:
+ OpenDoor(component, door, 1.0f);
+ case ANIM_COACH_OPEN_L:
+ case ANIM_COACH_OPEN_R:
+ ProcessDoorOpenAnimation(this, component, door, time, 0.66f, 0.8f);
+ break;
+ case ANIM_COACH_OUT_L:
+ ProcessDoorOpenAnimation(this, component, door, time, 0.0f, 0.3f);
+ break;
+ case ANIM_VAN_OPEN_L:
+ case ANIM_VAN_OPEN:
+ ProcessDoorOpenAnimation(this, component, door, time, 0.37f, 0.55f);
+ break;
+ case ANIM_VAN_CLOSE_L:
+ case ANIM_VAN_CLOSE:
+ ProcessDoorCloseAnimation(this, component, door, time, 0.5f, 0.8f);
+ break;
+ case ANIM_VAN_GETOUT_L:
+ case ANIM_VAN_GETOUT:
+ ProcessDoorOpenAnimation(this, component, door, time, 0.5f, 0.6f);
+ break;
+ case NUM_ANIMS:
+ OpenDoor(component, door, time);
+ break;
+ }
+}
+
+bool
+CAutomobile::IsDoorReady(eDoors door)
+{
+ if(Doors[door].IsClosed() || IsDoorMissing(door))
+ return true;
+ int doorflag = 0;
+ // TODO: enum?
+ switch(door){
+ case DOOR_FRONT_LEFT: doorflag = 1; break;
+ case DOOR_FRONT_RIGHT: doorflag = 4; break;
+ case DOOR_REAR_LEFT: doorflag = 2; break;
+ case DOOR_REAR_RIGHT: doorflag = 8; break;
+ }
+ return (doorflag & m_nGettingInFlags) == 0;
+}
+
+bool
+CAutomobile::IsDoorFullyOpen(eDoors door)
+{
+ return Doors[door].IsFullyOpen() || IsDoorMissing(door);
+}
+
+bool
+CAutomobile::IsDoorClosed(eDoors door)
+{
+ return !!Doors[door].IsClosed();
+}
+
+bool
+CAutomobile::IsDoorMissing(eDoors door)
+{
+ return Damage.GetDoorStatus(door) == DOOR_STATUS_MISSING;
+}
+
+void
+CAutomobile::RemoveRefsToVehicle(CEntity *ent)
+{
+ int i;
+ for(i = 0; i < 4; i++)
+ if(m_aGroundPhysical[i] == ent)
+ m_aGroundPhysical[i] = nil;
+}
+
+void
+CAutomobile::BlowUpCar(CEntity *culprit)
+{
+ int i;
+ RpAtomic *atomic;
+
+ if(!bCanBeDamaged)
+ return;
+
+ // explosion pushes vehicle up
+ m_vecMoveSpeed.z += 0.13f;
+ m_status = STATUS_WRECKED;
+ bRenderScorched = true;
+ m_nTimeOfDeath = CTimer::GetTimeInMilliseconds();
+ Damage.FuckCarCompletely();
+
+ if(GetModelIndex() != MI_RCBANDIT){
+ SetBumperDamage(CAR_BUMP_FRONT, VEHBUMPER_FRONT);
+ SetBumperDamage(CAR_BUMP_REAR, VEHBUMPER_REAR);
+ SetDoorDamage(CAR_BONNET, DOOR_BONNET);
+ SetDoorDamage(CAR_BOOT, DOOR_BOOT);
+ SetDoorDamage(CAR_DOOR_LF, DOOR_FRONT_LEFT);
+ SetDoorDamage(CAR_DOOR_RF, DOOR_FRONT_RIGHT);
+ SetDoorDamage(CAR_DOOR_LR, DOOR_REAR_LEFT);
+ SetDoorDamage(CAR_DOOR_RR, DOOR_REAR_RIGHT);
+ SpawnFlyingComponent(CAR_WHEEL_LF, COMPGROUP_WHEEL);
+ atomic = nil;
+ RwFrameForAllObjects(m_aCarNodes[CAR_WHEEL_LF], GetCurrentAtomicObjectCB, &atomic);
+ if(atomic)
+ RpAtomicSetFlags(atomic, 0);
+ }
+
+ m_fHealth = 0.0f;
+ m_nBombTimer = 0;
+ m_bombType = CARBOMB_NONE;
+
+ 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);
+ }
+ }
+
+ bEngineOn = false;
+ bLightsOn = false;
+ m_bSirenOrAlarm = false;
+ bTaxiLight = false;
+ if(bIsAmbulanceOnDuty){
+ bIsAmbulanceOnDuty = false;
+ CCarCtrl::NumAmbulancesOnDuty--;
+ }
+ if(bIsFireTruckOnDuty){
+ bIsFireTruckOnDuty = false;
+ CCarCtrl::NumFiretrucksOnDuty--;
+ }
+ ChangeLawEnforcerState(false);
+
+ gFireManager.StartFire(this, culprit, 0.8f, 1); // TODO
+ CDarkel::RegisterCarBlownUpByPlayer(this);
+ if(GetModelIndex() == MI_RCBANDIT)
+ CExplosion::AddExplosion(this, culprit, EXPLOSION_CAR_QUICK, GetPosition(), 0);
+ else
+ CExplosion::AddExplosion(this, culprit, EXPLOSION_CAR, GetPosition(), 0);
+}
+
+bool
+CAutomobile::SetUpWheelColModel(CColModel *colModel)
+{
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+ CColModel *vehColModel = mi->GetColModel();
+
+ colModel->boundingSphere = vehColModel->boundingSphere;
+ colModel->boundingBox = vehColModel->boundingBox;
+
+ CMatrix mat;
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LF]));
+ colModel->spheres[0].Set(mi->m_wheelScale, mat.GetPosition(), SURFACE_TIRE, CAR_PIECE_WHEEL_LF);
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LB]));
+ colModel->spheres[1].Set(mi->m_wheelScale, mat.GetPosition(), SURFACE_TIRE, CAR_PIECE_WHEEL_LR);
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF]));
+ colModel->spheres[2].Set(mi->m_wheelScale, mat.GetPosition(), SURFACE_TIRE, CAR_PIECE_WHEEL_RF);
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RB]));
+ colModel->spheres[3].Set(mi->m_wheelScale, mat.GetPosition(), SURFACE_TIRE, CAR_PIECE_WHEEL_RR);
+
+ if(m_aCarNodes[CAR_WHEEL_LM] != nil && m_aCarNodes[CAR_WHEEL_RM] != nil){
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LM]));
+ colModel->spheres[4].Set(mi->m_wheelScale, mat.GetPosition(), SURFACE_TIRE, CAR_PIECE_WHEEL_RF);
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RM]));
+ colModel->spheres[5].Set(mi->m_wheelScale, mat.GetPosition(), SURFACE_TIRE, CAR_PIECE_WHEEL_RR);
+ colModel->numSpheres = 6;
+ }else
+ colModel->numSpheres = 4;
+
+ return true;
+}
+
+// this probably isn't used in III yet
+void
+CAutomobile::BurstTyre(uint8 wheel)
+{
+ 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;
+ }
+
+ int status = Damage.GetWheelStatus(wheel);
+ if(status == WHEEL_STATUS_OK){
+ Damage.SetWheelStatus(wheel, WHEEL_STATUS_BURST);
+
+ if(m_status == STATUS_SIMPLE){
+ m_status = STATUS_PHYSICS;
+ CCarCtrl::SwitchVehicleToRealPhysics(this);
+ }
+
+ ApplyMoveForce(GetRight() * CGeneral::GetRandomNumberInRange(-0.3f, 0.3f));
+ ApplyTurnForce(GetRight() * CGeneral::GetRandomNumberInRange(-0.3f, 0.3f), GetForward());
+ }
+}
+
+bool
+CAutomobile::IsRoomForPedToLeaveCar(uint32 component, CVector *doorOffset)
+{
+ CColPoint colpoint;
+ CEntity *ent;
+ colpoint.point = CVector(0.0f, 0.0f, 0.0f);
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+
+ CVector seatPos;
+ switch(component){
+ case CAR_DOOR_RF:
+ seatPos = mi->m_positions[mi->m_vehicleType == VEHICLE_TYPE_BOAT ? BOAT_POS_FRONTSEAT : CAR_POS_FRONTSEAT];
+ break;
+ case CAR_DOOR_LF:
+ seatPos = mi->m_positions[mi->m_vehicleType == VEHICLE_TYPE_BOAT ? BOAT_POS_FRONTSEAT : CAR_POS_FRONTSEAT];
+ seatPos.x = -seatPos.x;
+ break;
+ case CAR_DOOR_RR:
+ seatPos = mi->m_positions[CAR_POS_BACKSEAT];
+ break;
+ case CAR_DOOR_LR:
+ seatPos = mi->m_positions[CAR_POS_BACKSEAT];
+ seatPos.x = -seatPos.x;
+ break;
+ }
+ seatPos = GetMatrix() * seatPos;
+
+ CVector doorPos = CPed::GetPositionToOpenCarDoor(this, component);
+ if(doorOffset){
+ CVector off = *doorOffset;
+ if(component == CAR_DOOR_RF || component == CAR_DOOR_RR)
+ off.x = -off.x;
+ doorPos += Multiply3x3(GetMatrix(), off);
+ }
+
+ if(GetUp().z < 0.0f){
+ seatPos.z += 0.5f;
+ doorPos.z += 0.5f;
+ }
+
+ CVector dist = doorPos - seatPos;
+ float length = dist.Magnitude();
+ CVector pedPos = seatPos + dist*((length+0.6f)/length);
+
+ if(!CWorld::GetIsLineOfSightClear(seatPos, pedPos, true, false, false, true, false, false))
+ return false;
+ if(CWorld::TestSphereAgainstWorld(doorPos, 0.6f, this, true, true, false, true, false, false))
+ return false;
+ if(CWorld::ProcessVerticalLine(doorPos, 1000.0f, colpoint, ent, true, false, false, true, false, false, nil))
+ if(colpoint.point.z > doorPos.z && colpoint.point.z < doorPos.z + 0.6f)
+ return false;
+ float upperZ = colpoint.point.z;
+ if(!CWorld::ProcessVerticalLine(doorPos, -1000.0f, colpoint, ent, true, false, false, true, false, false, nil))
+ return false;
+ if(upperZ != 0.0f && upperZ < colpoint.point.z)
+ return false;
+ return true;
+}
+
+float
+CAutomobile::GetHeightAboveRoad(void)
+{
+ return m_fHeightAboveRoad;
+}
+
+void
+CAutomobile::PlayCarHorn(void)
+{
+ int r;
+
+ if(m_nCarHornTimer != 0)
+ return;
+
+ r = CGeneral::GetRandomNumber() & 7;
+ if(r < 2){
+ m_nCarHornTimer = 45;
+ }else if(r < 4){
+ if(pDriver)
+ pDriver->Say(SOUND_PED_CAR_COLLISION);
+ m_nCarHornTimer = 45;
+ }else{
+ if(pDriver)
+ pDriver->Say(SOUND_PED_CAR_COLLISION);
+ }
+}
+
+void
+CAutomobile::PlayHornIfNecessary(void)
+{
+ if(AutoPilot.m_bSlowedDownBecauseOfPeds ||
+ AutoPilot.m_bSlowedDownBecauseOfCars)
+ if(!HasCarStoppedBecauseOfLight())
+ PlayCarHorn();
+}
+
+
+void
+CAutomobile::ResetSuspension(void)
+{
+ int i;
+ for(i = 0; i < 4; i++){
+ m_aSuspensionSpringRatio[i] = 1.0f;
+ m_aWheelTimer[i] = 0.0f;
+ m_aWheelRotation[i] = 0.0f;
+ m_aWheelState[i] = WHEEL_STATE_NORMAL;
+ }
+}
+
+void
+CAutomobile::SetupSuspensionLines(void)
+{
+ int i;
+ CVector posn;
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+ CColModel *colModel = mi->GetColModel();
+
+ // Each suspension line starts at the uppermost wheel position
+ // and extends down to the lowermost point on the tyre
+ for(i = 0; i < 4; i++){
+ mi->GetWheelPosn(i, posn);
+ m_aWheelPosition[i] = posn.z;
+
+ // uppermost wheel position
+ posn.z += pHandling->fSuspensionUpperLimit;
+ colModel->lines[i].p0 = posn;
+
+ // lowermost wheel position
+ posn.z += pHandling->fSuspensionLowerLimit - pHandling->fSuspensionUpperLimit;
+ // lowest point on tyre
+ posn.z -= mi->m_wheelScale*0.5f;
+ colModel->lines[i].p1 = posn;
+
+ // this is length of the spring at rest
+ m_aSuspensionSpringLength[i] = pHandling->fSuspensionUpperLimit - pHandling->fSuspensionLowerLimit;
+ m_aSuspensionLineLength[i] = colModel->lines[i].p0.z - colModel->lines[i].p1.z;
+ }
+
+ // 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)));
+ for(i = 0; i < 4; i++)
+ m_aWheelPosition[i] = mi->m_wheelScale*0.5f - m_fHeightAboveRoad;
+
+ // adjust col model to include suspension lines
+ if(colModel->boundingBox.min.z > colModel->lines[0].p1.z)
+ colModel->boundingBox.min.z = colModel->lines[0].p1.z;
+ float radius = Max(colModel->boundingBox.min.Magnitude(), colModel->boundingBox.max.Magnitude());
+ if(colModel->boundingSphere.radius < radius)
+ colModel->boundingSphere.radius = radius;
+
+ if(GetModelIndex() == MI_RCBANDIT){
+ colModel->boundingSphere.radius = 2.0f;
+ for(i = 0; i < colModel->numSpheres; i++)
+ colModel->spheres[i].radius = 0.3f;
+ }
+}
+
+// called on police cars
+void
+CAutomobile::ScanForCrimes(void)
+{
+ if(FindPlayerVehicle() && FindPlayerVehicle()->IsCar())
+ if(FindPlayerVehicle()->IsAlarmOn())
+ // if player's alarm is on, increase wanted level
+ if((FindPlayerVehicle()->GetPosition() - GetPosition()).MagnitudeSqr() < sq(20.0f))
+ CWorld::Players[CWorld::PlayerInFocus].m_pPed->SetWantedLevelNoDrop(1);
+}
+
+void
+CAutomobile::BlowUpCarsInPath(void)
+{
+ int i;
+
+ if(m_vecMoveSpeed.Magnitude() > 0.1f)
+ for(i = 0; i < m_nCollisionRecords; i++)
+ if(m_aCollisionRecords[i] &&
+ m_aCollisionRecords[i]->IsVehicle() &&
+ m_aCollisionRecords[i]->GetModelIndex() != MI_RHINO &&
+ !m_aCollisionRecords[i]->bRenderScorched)
+ ((CVehicle*)m_aCollisionRecords[i])->BlowUpCar(this);
+}
+
+bool
+CAutomobile::HasCarStoppedBecauseOfLight(void)
+{
+ int i;
+
+ if(m_status != STATUS_SIMPLE && m_status != STATUS_PHYSICS)
+ return false;
+
+ if(AutoPilot.m_nCurrentRouteNode && AutoPilot.m_nNextRouteNode){
+ CPathNode *curnode = &ThePaths.m_pathNodes[AutoPilot.m_nCurrentRouteNode];
+ for(i = 0; i < curnode->numLinks; i++)
+ if(ThePaths.m_connections[curnode->firstLink + i] == AutoPilot.m_nNextRouteNode)
+ break;
+ if(i < curnode->numLinks &&
+ ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[curnode->firstLink + i]].trafficLightType & 3) // TODO
+ return true;
+ }
+
+ if(AutoPilot.m_nCurrentRouteNode && AutoPilot.m_nPrevRouteNode){
+ CPathNode *curnode = &ThePaths.m_pathNodes[AutoPilot.m_nCurrentRouteNode];
+ for(i = 0; i < curnode->numLinks; i++)
+ if(ThePaths.m_connections[curnode->firstLink + i] == AutoPilot.m_nPrevRouteNode)
+ break;
+ if(i < curnode->numLinks &&
+ ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[curnode->firstLink + i]].trafficLightType & 3) // TODO
+ return true;
+ }
+
+ return false;
+}
+
+void
+CAutomobile::SetBusDoorTimer(uint32 timer, uint8 type)
+{
+ if(timer < 1000)
+ timer = 1000;
+ if(type == 0)
+ // open and close
+ m_nBusDoorTimerStart = CTimer::GetTimeInMilliseconds();
+ else
+ // only close
+ m_nBusDoorTimerStart = CTimer::GetTimeInMilliseconds() - 500;
+ m_nBusDoorTimerEnd = m_nBusDoorTimerStart + timer;
+}
+
+void
+CAutomobile::ProcessAutoBusDoors(void)
+{
+ if(CTimer::GetTimeInMilliseconds() < m_nBusDoorTimerEnd){
+ if(m_nBusDoorTimerEnd != 0 && CTimer::GetTimeInMilliseconds() > m_nBusDoorTimerEnd-500){
+ // close door
+ if(!IsDoorMissing(DOOR_FRONT_LEFT) && (m_nGettingInFlags & 1) == 0){
+ if(IsDoorClosed(DOOR_FRONT_LEFT)){
+ m_nBusDoorTimerEnd = CTimer::GetTimeInMilliseconds();
+ OpenDoor(CAR_DOOR_LF, DOOR_FRONT_LEFT, 0.0f);
+ }else{
+ OpenDoor(CAR_DOOR_LF, DOOR_FRONT_LEFT,
+ 1.0f - (CTimer::GetTimeInMilliseconds() - (m_nBusDoorTimerEnd-500))/500.0f);
+ }
+ }
+
+ if(!IsDoorMissing(DOOR_FRONT_RIGHT) && (m_nGettingInFlags & 4) == 0){
+ if(IsDoorClosed(DOOR_FRONT_RIGHT)){
+ m_nBusDoorTimerEnd = CTimer::GetTimeInMilliseconds();
+ OpenDoor(CAR_DOOR_RF, DOOR_FRONT_RIGHT, 0.0f);
+ }else{
+ OpenDoor(CAR_DOOR_RF, DOOR_FRONT_RIGHT,
+ 1.0f - (CTimer::GetTimeInMilliseconds() - (m_nBusDoorTimerEnd-500))/500.0f);
+ }
+ }
+ }
+ }else{
+ // ended
+ if(m_nBusDoorTimerStart){
+ if(!IsDoorMissing(DOOR_FRONT_LEFT) && (m_nGettingInFlags & 1) == 0)
+ OpenDoor(CAR_DOOR_LF, DOOR_FRONT_LEFT, 0.0f);
+ if(!IsDoorMissing(DOOR_FRONT_RIGHT) && (m_nGettingInFlags & 4) == 0)
+ OpenDoor(CAR_DOOR_RF, DOOR_FRONT_RIGHT, 0.0f);
+ m_nBusDoorTimerStart = 0;
+ m_nBusDoorTimerEnd = 0;
+ }
+ }
+}
+
+void
+CAutomobile::ProcessSwingingDoor(int32 component, eDoors door)
+{
+ if(Damage.GetDoorStatus(door) != DOOR_STATUS_SWINGING)
+ return;
+
+ CMatrix mat(RwFrameGetMatrix(m_aCarNodes[component]));
+ CVector pos = mat.GetPosition();
+ float axes[3] = { 0.0f, 0.0f, 0.0f };
+
+ Doors[door].Process(this);
+ axes[Doors[door].m_nAxis] = Doors[door].m_fAngle;
+ mat.SetRotate(axes[0], axes[1], axes[2]);
+ mat.Translate(pos);
+ mat.UpdateRW();
+}
+
+void
+CAutomobile::Fix(void)
+{
+ int component;
+
+ Damage.ResetDamageStatus();
+
+ if(pHandling->Flags & HANDLING_NO_DOORS){
+ Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_MISSING);
+ Damage.SetDoorStatus(DOOR_FRONT_RIGHT, DOOR_STATUS_MISSING);
+ Damage.SetDoorStatus(DOOR_REAR_LEFT, DOOR_STATUS_MISSING);
+ Damage.SetDoorStatus(DOOR_REAR_RIGHT, DOOR_STATUS_MISSING);
+ }
+
+ bIsDamaged = false;
+ RpClumpForAllAtomics((RpClump*)m_rwObject, CVehicleModelInfo::HideAllComponentsAtomicCB, (void*)ATOMIC_FLAG_DAM);
+
+ for(component = CAR_BUMP_FRONT; component < NUM_CAR_NODES; component++){
+ if(m_aCarNodes[component]){
+ CMatrix mat(RwFrameGetMatrix(m_aCarNodes[component]));
+ mat.SetTranslate(mat.GetPosition());
+ mat.UpdateRW();
+ }
+ }
+}
+
+void
+CAutomobile::SetupDamageAfterLoad(void)
+{
+ if(m_aCarNodes[CAR_BUMP_FRONT])
+ SetBumperDamage(CAR_BUMP_FRONT, VEHBUMPER_FRONT);
+ if(m_aCarNodes[CAR_BONNET])
+ SetDoorDamage(CAR_BONNET, DOOR_BONNET);
+ if(m_aCarNodes[CAR_BUMP_REAR])
+ SetBumperDamage(CAR_BUMP_REAR, VEHBUMPER_REAR);
+ if(m_aCarNodes[CAR_BOOT])
+ SetDoorDamage(CAR_BOOT, DOOR_BOOT);
+ if(m_aCarNodes[CAR_DOOR_LF])
+ SetDoorDamage(CAR_DOOR_LF, DOOR_FRONT_LEFT);
+ if(m_aCarNodes[CAR_DOOR_RF])
+ SetDoorDamage(CAR_DOOR_RF, DOOR_FRONT_RIGHT);
+ if(m_aCarNodes[CAR_DOOR_LR])
+ SetDoorDamage(CAR_DOOR_LR, DOOR_REAR_LEFT);
+ if(m_aCarNodes[CAR_DOOR_RR])
+ SetDoorDamage(CAR_DOOR_RR, DOOR_REAR_RIGHT);
+ if(m_aCarNodes[CAR_WING_LF])
+ SetPanelDamage(CAR_WING_LF, VEHPANEL_FRONT_LEFT);
+ if(m_aCarNodes[CAR_WING_RF])
+ SetPanelDamage(CAR_WING_RF, VEHPANEL_FRONT_RIGHT);
+ if(m_aCarNodes[CAR_WING_LR])
+ SetPanelDamage(CAR_WING_LR, VEHPANEL_REAR_LEFT);
+ if(m_aCarNodes[CAR_WING_RR])
+ SetPanelDamage(CAR_WING_RR, VEHPANEL_REAR_RIGHT);
+}
+
+RwObject*
+GetCurrentAtomicObjectCB(RwObject *object, void *data)
+{
+ RpAtomic *atomic = (RpAtomic*)object;
+ assert(RwObjectGetType(object) == rpATOMIC);
+ if(RpAtomicGetFlags(atomic) & rpATOMICRENDER)
+ *(RpAtomic**)data = atomic;
+ return object;
+}
+
+CColPoint aTempPedColPts[32]; // this name doesn't make any sense
+
+CObject*
+CAutomobile::SpawnFlyingComponent(int32 component, uint32 type)
+{
+ RpAtomic *atomic;
+ RwFrame *frame;
+ RwMatrix *matrix;
+ CObject *obj;
+
+ if(CObject::nNoTempObjects >= NUMTEMPOBJECTS)
+ return nil;
+
+ atomic = nil;
+ RwFrameForAllObjects(m_aCarNodes[component], GetCurrentAtomicObjectCB, &atomic);
+ if(atomic == nil)
+ return nil;
+
+ obj = new CObject;
+ if(obj == nil)
+ return nil;
+
+ if(component == CAR_WINDSCREEN){
+ obj->SetModelIndexNoCreate(MI_CAR_BONNET);
+ }else switch(type){
+ case COMPGROUP_BUMPER:
+ obj->SetModelIndexNoCreate(MI_CAR_BUMPER);
+ break;
+ case COMPGROUP_WHEEL:
+ obj->SetModelIndexNoCreate(MI_CAR_WHEEL);
+ break;
+ case COMPGROUP_DOOR:
+ obj->SetModelIndexNoCreate(MI_CAR_DOOR);
+ obj->SetCenterOfMass(0.0f, -0.5f, 0.0f);
+ break;
+ case COMPGROUP_BONNET:
+ obj->SetModelIndexNoCreate(MI_CAR_BONNET);
+ obj->SetCenterOfMass(0.0f, 0.4f, 0.0f);
+ break;
+ case COMPGROUP_BOOT:
+ obj->SetModelIndexNoCreate(MI_CAR_BOOT);
+ obj->SetCenterOfMass(0.0f, -0.3f, 0.0f);
+ break;
+ case COMPGROUP_PANEL:
+ default:
+ obj->SetModelIndexNoCreate(MI_CAR_PANEL);
+ break;
+ }
+
+ // object needs base model
+ obj->RefModelInfo(GetModelIndex());
+
+ // create new atomic
+ matrix = RwFrameGetLTM(m_aCarNodes[component]);
+ frame = RwFrameCreate();
+ atomic = RpAtomicClone(atomic);
+ *RwFrameGetMatrix(frame) = *matrix;
+ RpAtomicSetFrame(atomic, frame);
+ CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
+ obj->AttachToRwObject((RwObject*)atomic);
+
+ // init object
+ obj->m_fMass = 10.0f;
+ obj->m_fTurnMass = 25.0f;
+ obj->m_fAirResistance = 0.97f;
+ obj->m_fElasticity = 0.1f;
+ obj->m_fBuoyancy = obj->m_fMass*GRAVITY/0.75f;
+ obj->ObjectCreatedBy = TEMP_OBJECT;
+ obj->bIsStatic = false;
+ obj->bIsPickup = false;
+ obj->bUseVehicleColours = true;
+ obj->m_colour1 = m_currentColour1;
+ obj->m_colour2 = m_currentColour2;
+
+ // life time - the more objects the are, the shorter this one will live
+ CObject::nNoTempObjects++;
+ if(CObject::nNoTempObjects > 20)
+ obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 20000/5.0f;
+ else if(CObject::nNoTempObjects > 10)
+ obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 20000/2.0f;
+ else
+ obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 20000;
+
+ obj->m_vecMoveSpeed = m_vecMoveSpeed;
+ if(obj->m_vecMoveSpeed.z > 0.0f){
+ obj->m_vecMoveSpeed.z *= 1.5f;
+ }else if(GetUp().z > 0.0f &&
+ (component == COMPGROUP_BONNET || component == COMPGROUP_BOOT || component == CAR_WINDSCREEN)){
+ obj->m_vecMoveSpeed.z *= -1.5f;
+ obj->m_vecMoveSpeed.z += 0.04f;
+ }else{
+ obj->m_vecMoveSpeed.z *= 0.25f;
+ }
+ obj->m_vecMoveSpeed.x *= 0.75f;
+ obj->m_vecMoveSpeed.y *= 0.75f;
+
+ obj->m_vecTurnSpeed = m_vecTurnSpeed*2.0f;
+
+ // push component away from car
+ CVector dist = obj->GetPosition() - GetPosition();
+ dist.Normalise();
+ if(component == COMPGROUP_BONNET || component == COMPGROUP_BOOT || component == CAR_WINDSCREEN){
+ // push these up some
+ dist += GetUp();
+ if(GetUp().z > 0.0f){
+ // simulate fast upward movement if going fast
+ float speed = CVector2D(m_vecMoveSpeed).MagnitudeSqr();
+ obj->GetPosition() += GetUp()*speed;
+ }
+ }
+ obj->ApplyMoveForce(dist);
+
+ if(type == COMPGROUP_WHEEL){
+ obj->m_fTurnMass = 5.0f;
+ obj->m_vecTurnSpeed.x = 0.5f;
+ obj->m_fAirResistance = 0.99f;
+ }
+
+ if(CCollision::ProcessColModels(obj->GetMatrix(), *obj->GetColModel(),
+ this->GetMatrix(), *this->GetColModel(),
+ aTempPedColPts, nil, nil) > 0)
+ obj->m_pCollidingEntity = this;
+
+ if(bRenderScorched)
+ obj->bRenderScorched = true;
+
+ CWorld::Add(obj);
+
+ return obj;
+}
+
+CObject*
+CAutomobile::RemoveBonnetInPedCollision(void)
+{
+ CObject *obj;
+
+ if(Damage.GetDoorStatus(DOOR_BONNET) != DOOR_STATUS_SWINGING &&
+ Doors[DOOR_BONNET].RetAngleWhenOpen()*0.4f < Doors[DOOR_BONNET].m_fAngle){
+ // BUG? why not COMPGROUP_BONNET?
+ obj = SpawnFlyingComponent(CAR_BONNET, COMPGROUP_DOOR);
+ // make both doors invisible on car
+ SetComponentVisibility(m_aCarNodes[CAR_BONNET], ATOMIC_FLAG_NONE);
+ Damage.SetDoorStatus(DOOR_BONNET, DOOR_STATUS_MISSING);
+ return obj;
+ }
+ return nil;
+}
+
+void
+CAutomobile::SetPanelDamage(int32 component, ePanels panel, bool noFlyingComponents)
+{
+ int status = Damage.GetPanelStatus(panel);
+ if(m_aCarNodes[component] == nil)
+ return;
+ if(status == PANEL_STATUS_SMASHED1){
+ // show damaged part
+ SetComponentVisibility(m_aCarNodes[component], ATOMIC_FLAG_DAM);
+ }else if(status == PANEL_STATUS_MISSING){
+ if(!noFlyingComponents)
+ SpawnFlyingComponent(component, COMPGROUP_PANEL);
+ // hide both
+ SetComponentVisibility(m_aCarNodes[component], ATOMIC_FLAG_NONE);
+ }
+}
+
+void
+CAutomobile::SetBumperDamage(int32 component, ePanels panel, bool noFlyingComponents)
+{
+ int status = Damage.GetPanelStatus(panel);
+ if(m_aCarNodes[component] == nil){
+ printf("Trying to damage component %d of %s\n",
+ component, CModelInfo::GetModelInfo(GetModelIndex())->GetName());
+ return;
+ }
+ if(status == PANEL_STATUS_SMASHED1){
+ // show damaged part
+ SetComponentVisibility(m_aCarNodes[component], ATOMIC_FLAG_DAM);
+ }else if(status == PANEL_STATUS_MISSING){
+ if(!noFlyingComponents)
+ SpawnFlyingComponent(component, COMPGROUP_BUMPER);
+ // hide both
+ SetComponentVisibility(m_aCarNodes[component], ATOMIC_FLAG_NONE);
+ }
+}
+
+void
+CAutomobile::SetDoorDamage(int32 component, eDoors door, bool noFlyingComponents)
+{
+ int status = Damage.GetDoorStatus(door);
+ if(m_aCarNodes[component] == nil){
+ printf("Trying to damage component %d of %s\n",
+ component, CModelInfo::GetModelInfo(GetModelIndex())->GetName());
+ return;
+ }
+
+ 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){
+ // show damaged part
+ SetComponentVisibility(m_aCarNodes[component], ATOMIC_FLAG_DAM);
+ }else if(status == 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){
+ if(!noFlyingComponents){
+ if(door == DOOR_BONNET)
+ SpawnFlyingComponent(component, COMPGROUP_BONNET);
+ else if(door == DOOR_BOOT)
+ SpawnFlyingComponent(component, COMPGROUP_BOOT);
+ else
+ SpawnFlyingComponent(component, COMPGROUP_DOOR);
+ }
+ // hide both
+ SetComponentVisibility(m_aCarNodes[component], ATOMIC_FLAG_NONE);
+ }
+}
+
+
+static RwObject*
+SetVehicleAtomicVisibilityCB(RwObject *object, void *data)
+{
+ uint32 flags = (uint32)(uintptr)data;
+ RpAtomic *atomic = (RpAtomic*)object;
+ if((CVisibilityPlugins::GetAtomicId(atomic) & (ATOMIC_FLAG_OK|ATOMIC_FLAG_DAM)) == flags)
+ RpAtomicSetFlags(atomic, rpATOMICRENDER);
+ else
+ RpAtomicSetFlags(atomic, 0);
+ return object;
+}
+
+void
+CAutomobile::SetComponentVisibility(RwFrame *frame, uint32 flags)
+{
+ HideAllComps();
+ bIsDamaged = true;
+ RwFrameForAllObjects(frame, SetVehicleAtomicVisibilityCB, (void*)flags);
+}
+
+void
+CAutomobile::SetupModelNodes(void)
+{
+ int i;
+ for(i = 0; i < NUM_CAR_NODES; i++)
+ m_aCarNodes[i] = nil;
+ CClumpModelInfo::FillFrameArray((RpClump*)m_rwObject, m_aCarNodes);
+}
+
+void
+CAutomobile::SetTaxiLight(bool light)
+{
+ bTaxiLight = light;
+}
+
+bool
+CAutomobile::GetAllWheelsOffGround(void)
+{
+ return m_nDriveWheelsOnGround == 0;
+}
+
+void
+CAutomobile::HideAllComps(void)
+{
+ // empty
+}
+
+void
+CAutomobile::ShowAllComps(void)
+{
+ // empty
+}
+
+void
+CAutomobile::ReduceHornCounter(void)
+{
+ if(m_nCarHornTimer != 0)
+ m_nCarHornTimer--;
+}
+
+void
+CAutomobile::SetAllTaxiLights(bool set)
+{
+ m_sAllTaxiLights = set;
+}
+
+class CAutomobile_ : public CAutomobile
+{
+public:
+ void ctor(int32 id, uint8 CreatedBy) { ::new (this) CAutomobile(id, CreatedBy); }
+ void dtor() { CAutomobile::~CAutomobile(); }
+ void SetModelIndex_(uint32 id) { CAutomobile::SetModelIndex(id); }
+ void ProcessControl_(void) { CAutomobile::ProcessControl(); }
+ void Teleport_(CVector v) { CAutomobile::Teleport(v); }
+ void PreRender_(void) { CAutomobile::PreRender(); }
+ void Render_(void) { CAutomobile::Render(); }
+
+ int32 ProcessEntityCollision_(CEntity *ent, CColPoint *colpoints){ return CAutomobile::ProcessEntityCollision(ent, colpoints); }
+
+ void ProcessControlInputs_(uint8 pad) { CAutomobile::ProcessControlInputs(pad); }
+ void GetComponentWorldPosition_(int32 component, CVector &pos) { CAutomobile::GetComponentWorldPosition(component, pos); }
+ bool IsComponentPresent_(int32 component) { return CAutomobile::IsComponentPresent(component); }
+ void SetComponentRotation_(int32 component, CVector rotation) { CAutomobile::SetComponentRotation(component, rotation); }
+ void OpenDoor_(int32 component, eDoors door, float ratio) { CAutomobile::OpenDoor(component, door, ratio); }
+ void ProcessOpenDoor_(uint32 component, uint32 anim, float time) { CAutomobile::ProcessOpenDoor(component, anim, time); }
+ bool IsDoorReady_(eDoors door) { return CAutomobile::IsDoorReady(door); }
+ bool IsDoorFullyOpen_(eDoors door) { return CAutomobile::IsDoorFullyOpen(door); }
+ bool IsDoorClosed_(eDoors door) { return CAutomobile::IsDoorClosed(door); }
+ bool IsDoorMissing_(eDoors door) { return CAutomobile::IsDoorMissing(door); }
+ void RemoveRefsToVehicle_(CEntity *ent) { CAutomobile::RemoveRefsToVehicle(ent); }
+ void BlowUpCar_(CEntity *ent) { CAutomobile::BlowUpCar(ent); }
+ bool SetUpWheelColModel_(CColModel *colModel) { return CAutomobile::SetUpWheelColModel(colModel); }
+ void BurstTyre_(uint8 tyre) { CAutomobile::BurstTyre(tyre); }
+ bool IsRoomForPedToLeaveCar_(uint32 door, CVector *pos) { return CAutomobile::IsRoomForPedToLeaveCar(door, pos); }
+ float GetHeightAboveRoad_(void) { return CAutomobile::GetHeightAboveRoad(); }
+ void PlayCarHorn_(void) { CAutomobile::PlayCarHorn(); }
+};
+
+STARTPATCHES
+ InjectHook(0x52C6B0, &CAutomobile_::ctor, PATCH_JUMP);
+ InjectHook(0x52D170, &CAutomobile_::dtor, PATCH_JUMP);
+ InjectHook(0x52D190, &CAutomobile_::SetModelIndex_, PATCH_JUMP);
+ InjectHook(0x531470, &CAutomobile_::ProcessControl_, PATCH_JUMP);
+ InjectHook(0x535180, &CAutomobile_::Teleport_, PATCH_JUMP);
+ InjectHook(0x539EA0, &CAutomobile_::Render_, PATCH_JUMP);
+ InjectHook(0x535B40, &CAutomobile_::PreRender_, PATCH_JUMP);
+ InjectHook(0x53B270, &CAutomobile_::ProcessEntityCollision_, PATCH_JUMP);
+ InjectHook(0x53B660, &CAutomobile_::ProcessControlInputs_, PATCH_JUMP);
+ InjectHook(0x52E5F0, &CAutomobile_::GetComponentWorldPosition_, PATCH_JUMP);
+ InjectHook(0x52E660, &CAutomobile_::IsComponentPresent_, PATCH_JUMP);
+ InjectHook(0x52E680, &CAutomobile_::SetComponentRotation_, PATCH_JUMP);
+ InjectHook(0x52E750, &CAutomobile_::OpenDoor_, PATCH_JUMP);
+ InjectHook(0x52EF10, &CAutomobile_::IsDoorReady_, PATCH_JUMP);
+ InjectHook(0x52EF90, &CAutomobile_::IsDoorFullyOpen_, PATCH_JUMP);
+ InjectHook(0x52EFD0, &CAutomobile_::IsDoorClosed_, PATCH_JUMP);
+ InjectHook(0x52F000, &CAutomobile_::IsDoorMissing_, PATCH_JUMP);
+ InjectHook(0x53BF40, &CAutomobile_::RemoveRefsToVehicle_, PATCH_JUMP);
+ InjectHook(0x53BC60, &CAutomobile_::BlowUpCar_, PATCH_JUMP);
+ InjectHook(0x53BF70, &CAutomobile_::SetUpWheelColModel_, PATCH_JUMP);
+ InjectHook(0x53C0E0, &CAutomobile_::BurstTyre_, PATCH_JUMP);
+ InjectHook(0x53C5B0, &CAutomobile_::IsRoomForPedToLeaveCar_, PATCH_JUMP);
+ InjectHook(0x437690, &CAutomobile_::GetHeightAboveRoad_, PATCH_JUMP);
+ InjectHook(0x53C450, &CAutomobile_::PlayCarHorn_, PATCH_JUMP);
+ InjectHook(0x53E090, &CAutomobile::PlaceOnRoadProperly, PATCH_JUMP);
+ InjectHook(0x52F030, &CAutomobile::dmgDrawCarCollidingParticles, PATCH_JUMP);
+ InjectHook(0x535450, &CAutomobile::AddDamagedVehicleParticles, PATCH_JUMP);
+ InjectHook(0x5357D0, &CAutomobile::AddWheelDirtAndWater, PATCH_JUMP);
+ InjectHook(0x5353A0, &CAutomobile::ResetSuspension, PATCH_JUMP);
+ InjectHook(0x52D210, &CAutomobile::SetupSuspensionLines, PATCH_JUMP);
+ InjectHook(0x53E000, &CAutomobile::BlowUpCarsInPath, PATCH_JUMP);
+ InjectHook(0x42E220, &CAutomobile::HasCarStoppedBecauseOfLight, PATCH_JUMP);
+ InjectHook(0x53D320, &CAutomobile::SetBusDoorTimer, PATCH_JUMP);
+ InjectHook(0x53D370, &CAutomobile::ProcessAutoBusDoors, PATCH_JUMP);
+ InjectHook(0x535250, &CAutomobile::ProcessSwingingDoor, PATCH_JUMP);
+ InjectHook(0x53C240, &CAutomobile::Fix, PATCH_JUMP);
+ InjectHook(0x53C310, &CAutomobile::SetupDamageAfterLoad, PATCH_JUMP);
+ InjectHook(0x530300, &CAutomobile::SpawnFlyingComponent, PATCH_JUMP);
+ InjectHook(0x535320, &CAutomobile::RemoveBonnetInPedCollision, PATCH_JUMP);
+ InjectHook(0x5301A0, &CAutomobile::SetPanelDamage, PATCH_JUMP);
+ InjectHook(0x530120, &CAutomobile::SetBumperDamage, PATCH_JUMP);
+ InjectHook(0x530200, &CAutomobile::SetDoorDamage, PATCH_JUMP);
+ InjectHook(0x5300E0, &CAutomobile::SetComponentVisibility, PATCH_JUMP);
+ InjectHook(0x52D1B0, &CAutomobile::SetupModelNodes, PATCH_JUMP);
+ InjectHook(0x53C420, &CAutomobile::SetTaxiLight, PATCH_JUMP);
+ InjectHook(0x53BC40, &CAutomobile::GetAllWheelsOffGround, PATCH_JUMP);
+ InjectHook(0x5308C0, &CAutomobile::ReduceHornCounter, PATCH_JUMP);
+ InjectHook(0x53C440, &CAutomobile::SetAllTaxiLights, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp
index f614b78f..2b5ff567 100644
--- a/src/vehicles/Boat.cpp
+++ b/src/vehicles/Boat.cpp
@@ -61,7 +61,7 @@ float CBoat::IsVertexAffectedByWake(CVector vecVertex, CBoat *pBoat)
float fDist = vecDist.MagnitudeSqr();
if ( fDist < SQR(fMaxDist) )
- return 1.0f - min(fRangeMult * Sqrt(fDist / SQR(fMaxDist)) + (WAKE_LIFETIME - pBoat->m_afWakePointLifeTime[i]) * fTimeMult, 1.0f);
+ return 1.0f - Min(fRangeMult * Sqrt(fDist / SQR(fMaxDist)) + (WAKE_LIFETIME - pBoat->m_afWakePointLifeTime[i]) * fTimeMult, 1.0f);
}
return 0.0f;
diff --git a/src/vehicles/Heli.cpp b/src/vehicles/Heli.cpp
index 9b1a651d..1c242f0e 100644
--- a/src/vehicles/Heli.cpp
+++ b/src/vehicles/Heli.cpp
@@ -1038,8 +1038,16 @@ void CHeli::ActivateHeli(bool activate) { ScriptHeliOn = activate; }
class CHeli_ : public CHeli
{
public:
+<<<<<<< HEAD
+<<<<<<< HEAD
void ctor(int32 id, uint8 CreatedBy) { ::new (this) CHeli(id, CreatedBy); }
void dtor(void) { CHeli::~CHeli(); }
+=======
+ void dtor(void) { this->~CHeli(); }
+>>>>>>> More audio ped
+=======
+ void dtor(void) { CHeli::~CHeli(); }
+>>>>>>> fix
};
STARTPATCHES
diff --git a/src/vehicles/Heli.cpp.autosave b/src/vehicles/Heli.cpp.autosave
new file mode 100644
index 00000000..9b1a651d
--- /dev/null
+++ b/src/vehicles/Heli.cpp.autosave
@@ -0,0 +1,1055 @@
+#include "common.h"
+#include "main.h"
+#include "patcher.h"
+#include "General.h"
+#include "Darkel.h"
+#include "Stats.h"
+#include "SurfaceTable.h"
+#include "ModelIndices.h"
+#include "Streaming.h"
+#include "Camera.h"
+#include "VisibilityPlugins.h"
+#include "ZoneCull.h"
+#include "Particle.h"
+#include "Shadows.h"
+#include "Coronas.h"
+#include "Explosion.h"
+#include "TimeCycle.h"
+#include "TempColModels.h"
+#include "World.h"
+#include "WaterLevel.h"
+#include "PlayerPed.h"
+#include "Object.h"
+#include "HandlingMgr.h"
+#include "Heli.h"
+
+enum
+{
+ HELI_STATUS_HOVER,
+ HELI_STATUS_CHASE_PLAYER,
+ HELI_STATUS_FLY_AWAY,
+ HELI_STATUS_SHOT_DOWN,
+ HELI_STATUS_HOVER2,
+};
+
+CHeli **CHeli::pHelis = (CHeli**)0x72CF50;
+int16 &CHeli::NumRandomHelis = *(int16*)0x95CCAA;
+uint32 &CHeli::TestForNewRandomHelisTimer = *(uint32*)0x8F1A7C;
+int16 CHeli::NumScriptHelis; // unused
+bool &CHeli::CatalinaHeliOn = *(bool*)0x95CD85;
+bool &CHeli::CatalinaHasBeenShotDown = *(bool*)0x95CD56;
+bool &CHeli::ScriptHeliOn = *(bool*)0x95CD43;
+
+CHeli::CHeli(int32 id, uint8 CreatedBy)
+ : CVehicle(CreatedBy)
+{
+ int i;
+
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(id);
+ m_vehType = VEHICLE_TYPE_HELI;
+ pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)mi->m_handlingId);
+ SetModelIndex(id);
+ m_heliStatus = HELI_STATUS_HOVER;
+ m_pathState = 0;
+
+ m_fMass = 100000000.0f;
+ m_fTurnMass = 100000000.0f;
+ m_fAirResistance = 0.9994f;
+ m_fElasticity = 0.05f;
+
+ m_nHeliId = 0;
+ m_fRotorRotation = 0.0f;
+ m_nBulletDamage = 0;
+ m_fAngularSpeed = 0.0f;
+ m_fRotation = 0.0f;
+ m_nSearchLightTimer = CTimer::GetTimeInMilliseconds();
+ for(i = 0; i < 6; i++){
+ m_aSearchLightHistoryX[i] = 0.0f;
+ m_aSearchLightHistoryY[i] = 0.0f;
+ }
+
+ for(i = 0; i < 8; i++)
+ m_fHeliDustZ[i] = -50.0f;
+
+ m_nPoliceShoutTimer = CTimer::GetTimeInMilliseconds();
+ m_status = STATUS_HELI;
+ m_bTestRight = true;
+ m_fTargetOffset = 0.0f;
+ m_fSearchLightX = m_fSearchLightY = 0.0f;
+}
+
+void
+CHeli::SetModelIndex(uint32 id)
+{
+ int i;
+
+ CVehicle::SetModelIndex(id);
+ for(i = 0; i < NUM_HELI_NODES; i++)
+ m_aHeliNodes[i] = nil;
+ CClumpModelInfo::FillFrameArray(GetClump(), m_aHeliNodes);
+}
+
+static float CatalinaTargetX[7] = { -478.0, -677.0, -907.0, -1095.0, -1152.0, -1161.0, -1161.0 };
+static float CatalinaTargetY[7] = { 227.0, 206.0, 210.0, 242.0, 278.0, 341.0, 341.0 };
+static float CatalinaTargetZ[7] = { 77.0, 66.0, 60.0, 53.0, 51.0, 46.0, 30.0 };
+static float DamPathX[6] = { -1191.0, -1176.0, -1128.0, -1072.0, -1007.0, -971.0 };
+static float DamPathY[6] = { 350.0, 388.0, 429.0, 447.0, 449.0, 416.0 };
+static float DamPathZ[6] = { 42.0, 37.0, 28.0, 28.0, 31.0, 33.0 };
+static float ShortPathX[4] = { -974.0, -1036.0, -1112.0, -1173.0 };
+static float ShortPathY[4] = { 340.0, 312.0, 317.0, 294.0 };
+static float ShortPathZ[4] = { 41.0, 38.0, 32.0, 39.0 };
+static float LongPathX[7] = { -934.0, -905.0, -906.0, -1063.0, -1204.0, -1233.0, -1207.0 };
+static float LongPathY[7] = { 371.0, 362.0, 488.0, 548.0, 451.0, 346.0, 308.0 };
+static float LongPathZ[7] = { 57.0, 90.0, 105.0, 100.0, 81.0, 79.0, 70.0 };
+
+static int PathPoint;
+
+void
+CHeli::ProcessControl(void)
+{
+ int i;
+
+ if(gbModelViewer)
+ return;
+
+ // Find target
+ CVector target(0.0f, 0.0f, 0.0f);
+ CVector2D vTargetDist;
+ if(m_heliType == HELI_TYPE_CATALINA && m_heliStatus != HELI_STATUS_SHOT_DOWN){
+ switch(m_pathState){
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ target.x = CatalinaTargetX[m_pathState];
+ target.y = CatalinaTargetY[m_pathState];
+ target.z = CatalinaTargetZ[m_pathState];
+ if((target - GetPosition()).Magnitude() < 9.0f)
+ m_pathState++;
+ break;
+ case 6:
+ target.x = CatalinaTargetX[m_pathState];
+ target.y = CatalinaTargetY[m_pathState];
+ target.z = CatalinaTargetZ[m_pathState];
+ if(GetPosition().z > 31.55f)
+ break;
+ m_pathState = 7;
+ GetPosition().z = 31.55f;
+ m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
+ break;
+ case 7:
+ GetPosition().z = 31.55f;
+ target = GetPosition();
+ break;
+
+
+ // Take off
+ case 8:
+ target.x = GetPosition().x;
+ target.y = GetPosition().y;
+ target.z = 74.0f;
+ if(GetPosition().z < 40.0f)
+ break;
+ PathPoint = 2;
+ m_pathState = 9;
+ break;
+ // Circle around dam
+ case 9:
+ target.x = DamPathX[PathPoint];
+ target.y = DamPathY[PathPoint];
+ target.z = DamPathZ[PathPoint];
+ if((target - GetPosition()).Magnitude() < 9.0f){
+ PathPoint++;
+ if(PathPoint >= 6){
+ m_pathState = 10;
+ PathPoint = 0;
+ }
+ }
+ break;
+ case 10:
+ target.x = ShortPathX[PathPoint];
+ target.y = ShortPathY[PathPoint];
+ target.z = ShortPathZ[PathPoint];
+ if((target - GetPosition()).Magnitude() < 9.0f){
+ PathPoint++;
+ if(PathPoint >= 3){
+ m_pathState = 9;
+ PathPoint = 1;
+ }
+ }
+ break;
+ // how do we get here?
+ case 11:
+ target.x = LongPathX[PathPoint];
+ target.y = LongPathY[PathPoint];
+ target.z = LongPathZ[PathPoint];
+ if((target - GetPosition()).Magnitude() < 9.0f){
+ PathPoint++;
+ if(PathPoint >= 7){
+ m_pathState = 9;
+ PathPoint = 0;
+ }
+ }
+ break;
+
+
+ // Fly away
+ case 12:
+ target.x = GetPosition().x;
+ target.y = GetPosition().y;
+ target.z = 200.0f;
+ break;
+ }
+
+ vTargetDist = target - GetPosition();
+ m_fTargetZ = target.z;
+ if(m_pathState == 6){
+ GetPosition().x = GetPosition().x*0.99f + target.x*0.01f;
+ GetPosition().y = GetPosition().y*0.99f + target.y*0.01f;
+ }
+ }else{
+ vTargetDist = FindPlayerCoors() - GetPosition();
+ m_fTargetZ = FindPlayerCoors().z;
+
+ // Heli flies away to (0, 0)
+ if(m_heliStatus == HELI_STATUS_FLY_AWAY && GetPosition().z > 20.0f){
+ vTargetDist.x = 0.0f - GetPosition().x;
+ vTargetDist.y = 0.0f - GetPosition().y;
+ }
+
+ float groundZ;
+ switch(m_heliStatus){
+ case HELI_STATUS_HOVER:
+ groundZ = CWorld::FindGroundZFor3DCoord(GetPosition().x, GetPosition().y, 1000.0f, nil);
+ m_fTargetZ = max(groundZ, m_fTargetZ) + 8.0f;
+ break;
+ case HELI_STATUS_SHOT_DOWN:
+ groundZ = CWorld::FindGroundZFor3DCoord(GetPosition().x, GetPosition().y, 1000.0f, nil);
+ m_fTargetZ = max(groundZ, m_fTargetZ) + 8.0f + m_fTargetOffset;
+ break;
+ case HELI_STATUS_HOVER2:
+ groundZ = CWorld::FindGroundZFor3DCoord(GetPosition().x, GetPosition().y, 1000.0f, nil);
+ m_fTargetZ = max(groundZ, m_fTargetZ) + 8.0f + m_fTargetOffset;
+ break;
+ default:
+ groundZ = CWorld::FindGroundZFor3DCoord(GetPosition().x, GetPosition().y, 1000.0f, nil);
+ m_fTargetZ = max(groundZ, m_fTargetZ) + 12.0f;
+ break;
+ }
+
+ // Move up if too low
+ if(GetPosition().z - 2.0f < groundZ && m_heliStatus != HELI_STATUS_SHOT_DOWN)
+ m_vecMoveSpeed.z += CTimer::GetTimeStep()*0.01f;
+ m_vecMoveSpeed.z = clamp(m_vecMoveSpeed.z, -0.3f, 0.3f);
+ }
+
+ float fTargetDist = vTargetDist.Magnitude();
+
+ switch(m_heliStatus){
+ case HELI_STATUS_HOVER:
+ case HELI_STATUS_HOVER2:{
+ float targetHeight;
+ if(m_heliType == HELI_TYPE_CATALINA)
+ targetHeight = 8.0f;
+ else
+ targetHeight = 40.0f - m_nHeliId*10.0f;
+ if(fTargetDist > targetHeight)
+ m_heliStatus = HELI_STATUS_CHASE_PLAYER;
+ }
+ // fall through, BUG?
+ case HELI_STATUS_CHASE_PLAYER:{
+ float targetHeight;
+ if(m_heliType == HELI_TYPE_CATALINA)
+ targetHeight = 4.0f;
+ else
+ targetHeight = 30.0f - m_nHeliId*7.5f;
+ if(fTargetDist < 1.0f ||
+ fTargetDist < targetHeight && CWorld::GetIsLineOfSightClear(GetPosition(), FindPlayerCoors(), true, false, false, false, false, false))
+ m_heliStatus = HELI_STATUS_HOVER;
+ }
+ }
+
+ // Find xy speed
+ float speed;
+ if(fTargetDist > 100.0f)
+ speed = 1.0f;
+ else if(fTargetDist > 75.0f)
+ speed = 0.7f;
+ else
+ speed = 0.4f;
+ if(m_heliStatus == HELI_STATUS_HOVER || m_heliStatus == HELI_STATUS_HOVER2 || m_heliStatus == HELI_STATUS_SHOT_DOWN)
+ speed = 0.0f;
+
+ if(fTargetDist != 0.0f)
+ vTargetDist /= fTargetDist;
+ else
+ vTargetDist.x = 1.0f;
+ CVector2D targetSpeed = vTargetDist * speed;
+
+ if(m_heliStatus == HELI_STATUS_HOVER2 || m_heliStatus == HELI_STATUS_SHOT_DOWN){
+ bool force = !!((CTimer::GetFrameCounter() + m_randomSeed) & 8);
+ if(m_bTestRight){
+ if(force || CWorld::TestSphereAgainstWorld(GetPosition() + 4.0f*GetRight(), 2.0f, this, true, false, false, false, false, false) == nil){
+ if(m_heliStatus == HELI_STATUS_SHOT_DOWN){
+ m_fTargetOffset -= CTimer::GetTimeStep()*0.05f;
+ targetSpeed.x -= -vTargetDist.x*0.15f;
+ targetSpeed.y -= vTargetDist.y*0.15f;
+ }else{
+ targetSpeed.x -= -vTargetDist.x*0.05f;
+ targetSpeed.y -= vTargetDist.y*0.05f;
+ }
+ }else{
+ m_bTestRight = false;
+ if(m_heliStatus == HELI_STATUS_HOVER2)
+ m_fTargetOffset += 5.0f;
+ else
+ m_fTargetOffset -= 5.0f;
+ }
+ }else{
+ if(force || CWorld::TestSphereAgainstWorld(GetPosition() - 4.0f*GetRight(), 2.0f, this, true, false, false, false, false, false) == nil){
+ if(m_heliStatus == HELI_STATUS_SHOT_DOWN){
+ m_fTargetOffset -= CTimer::GetTimeStep()*0.05f;
+ targetSpeed.x += -vTargetDist.x*0.15f;
+ targetSpeed.y += vTargetDist.y*0.15f;
+ }else{
+ targetSpeed.x += -vTargetDist.x*0.05f;
+ targetSpeed.y += vTargetDist.y*0.05f;
+ }
+ }else{
+ m_bTestRight = true;
+ if(m_heliStatus == HELI_STATUS_HOVER2)
+ m_fTargetOffset += 5.0f;
+ else
+ m_fTargetOffset -= 5.0f;
+ }
+ }
+
+ if(m_fTargetOffset > 30.0f)
+ m_fTargetOffset = 30.0f;
+
+ if(m_heliStatus == HELI_STATUS_SHOT_DOWN && force){
+ if(CWorld::TestSphereAgainstWorld(GetPosition() + 1.5f*GetForward(), 2.0f, this, true, false, false, false, false, false) ||
+ CWorld::TestSphereAgainstWorld(GetPosition() - 1.5f*GetForward(), 2.0f, this, true, false, false, false, false, false))
+ m_nExplosionTimer = CTimer::GetPreviousTimeInMilliseconds();
+ }
+ }else
+ if(m_fTargetOffset >= 2.0f)
+ m_fTargetOffset -= 2.0f;
+
+ if(m_heliType == HELI_TYPE_CATALINA)
+ if(m_pathState == 9 || m_pathState == 11 || m_pathState == 10){
+ float f = Pow(0.997f, CTimer::GetTimeStep());
+ m_vecMoveSpeed.x *= f;
+ m_vecMoveSpeed.y *= f;
+ }
+
+ CVector2D speedDir = targetSpeed - m_vecMoveSpeed;
+ float speedDiff = speedDir.Magnitude();
+ if(speedDiff != 0.0f)
+ speedDir /= speedDiff;
+ else
+ speedDir.x = 1.0f;
+ float speedInc = CTimer::GetTimeStep()*0.002f;
+ if(speedDiff < speedInc){
+ m_vecMoveSpeed.x = targetSpeed.x;
+ m_vecMoveSpeed.y = targetSpeed.y;
+ }else{
+ m_vecMoveSpeed.x += speedDir.x*speedInc;
+ m_vecMoveSpeed.y += speedDir.y*speedInc;
+ }
+ GetPosition().x += m_vecMoveSpeed.x*CTimer::GetTimeStep();
+ GetPosition().y += m_vecMoveSpeed.y*CTimer::GetTimeStep();
+
+ // Find z target
+ if(m_heliStatus == HELI_STATUS_FLY_AWAY)
+ m_fTargetZ = 1000.0f;
+ if((CTimer::GetTimeInMilliseconds() + 800*m_nHeliId) & 0x800)
+ m_fTargetZ += 2.0f;
+ m_fTargetZ += m_nHeliId*5.0f;
+
+ // Find z speed
+ float targetSpeedZ = (m_fTargetZ - GetPosition().z)*0.01f;
+ float speedDiffZ = targetSpeedZ - m_vecMoveSpeed.z;
+ float speedIncZ = CTimer::GetTimeStep()*0.001f;
+ if(m_heliStatus == HELI_STATUS_FLY_AWAY)
+ speedIncZ *= 1.5f;
+ if(Abs(speedDiffZ) < speedIncZ)
+ m_vecMoveSpeed.z = targetSpeedZ;
+ else if(speedDiffZ < 0.0f)
+ m_vecMoveSpeed.z -= speedIncZ;
+ else
+ m_vecMoveSpeed.z += speedIncZ*1.5f;
+ GetPosition().z += m_vecMoveSpeed.z*CTimer::GetTimeStep();
+
+ // Find angular speed
+ float targetAngularSpeed;
+ m_fAngularSpeed *= Pow(0.995f, CTimer::GetTimeStep());
+ if(fTargetDist < 8.0f)
+ targetAngularSpeed = 0.0f;
+ else{
+ float rotationDiff = CGeneral::GetATanOfXY(vTargetDist.x, vTargetDist.y) - m_fRotation;
+ while(rotationDiff < -3.14f) rotationDiff += 6.28f;
+ while(rotationDiff > 3.14f) rotationDiff -= 6.28f;
+ if(Abs(rotationDiff) > 0.4f){
+ if(rotationDiff < 0.0f)
+ targetAngularSpeed = -0.2f;
+ else
+ targetAngularSpeed = 0.2f;
+ }else
+ targetAngularSpeed = 0.0f;
+ }
+ float angularSpeedDiff = targetAngularSpeed - m_fAngularSpeed;
+ float angularSpeedInc = CTimer::GetTimeStep()*0.0001f;
+ if(Abs(angularSpeedDiff) < angularSpeedInc)
+ m_fAngularSpeed = targetAngularSpeed;
+ else if(angularSpeedDiff < 0.0f)
+ m_fAngularSpeed -= angularSpeedInc;
+ else
+ m_fAngularSpeed += angularSpeedInc;
+ m_fRotation += m_fAngularSpeed * CTimer::GetTimeStep();
+
+ // Set matrix
+ CVector up(3.0f*m_vecMoveSpeed.x, 3.0f*m_vecMoveSpeed.y, 1.0f);
+ up.Normalise();
+ CVector fwd(-Cos(m_fRotation), -Sin(m_fRotation), 0.0f); // not really forward
+ CVector right = CrossProduct(up, fwd);
+ fwd = CrossProduct(up, right);
+ GetRight() = right;
+ GetForward() = fwd;
+ GetUp() = up;
+
+ // Search light and shooting
+ if(m_heliStatus == HELI_STATUS_FLY_AWAY || m_heliType == HELI_TYPE_CATALINA || CCullZones::PlayerNoRain())
+ m_fSearchLightIntensity = 0.0f;
+ else{
+ // Update search light history once every 1000ms
+ int timeDiff = CTimer::GetTimeInMilliseconds() - m_nSearchLightTimer;
+ while(timeDiff > 1000){
+ for(i = 5; i > 0; i--){
+ m_aSearchLightHistoryX[i] = m_aSearchLightHistoryX[i-1];
+ m_aSearchLightHistoryY[i] = m_aSearchLightHistoryY[i-1];
+ }
+ m_aSearchLightHistoryX[0] = FindPlayerCoors().x + FindPlayerSpeed().x*50.0f*(m_nHeliId+2);
+ m_aSearchLightHistoryY[0] = FindPlayerCoors().y + FindPlayerSpeed().y*50.0f*(m_nHeliId+2);
+
+ timeDiff -= 1000;
+ m_nSearchLightTimer += 1000;
+ }
+ assert(timeDiff <= 1000);
+ float f1 = timeDiff/1000.0f;
+ float f2 = 1.0f - f1;
+ m_fSearchLightX = m_aSearchLightHistoryX[m_nHeliId+2]*f2 + m_aSearchLightHistoryX[m_nHeliId+2-1]*f1;
+ m_fSearchLightY = m_aSearchLightHistoryY[m_nHeliId+2]*f2 + m_aSearchLightHistoryY[m_nHeliId+2-1]*f1;
+
+ float searchLightDist = (CVector2D(m_fSearchLightX, m_fSearchLightY) - GetPosition()).Magnitude();
+ if(searchLightDist > 60.0f)
+ m_fSearchLightIntensity = 0.0f;
+ else if(searchLightDist < 40.0f)
+ m_fSearchLightIntensity = 1.0f;
+ else
+ m_fSearchLightIntensity = 1.0f - (40.0f-searchLightDist)/40.0f;
+
+ if(m_fSearchLightIntensity < 0.9f || sq(FindPlayerCoors().x-m_fSearchLightX) + sq(FindPlayerCoors().y-m_fSearchLightY) > sq(7.0f))
+ m_nShootTimer = CTimer::GetTimeInMilliseconds();
+ else if(CTimer::GetTimeInMilliseconds() > m_nPoliceShoutTimer){
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_PED_HELI_PLAYER_FOUND, 0.0f);
+ m_nPoliceShoutTimer = CTimer::GetTimeInMilliseconds() + 4500 + (CGeneral::GetRandomNumber()&0xFFF);
+ }
+
+ // Shoot
+ int shootTimeout;
+ if(m_heliType == HELI_TYPE_RANDOM){
+ switch(FindPlayerPed()->m_pWanted->m_nWantedLevel){
+ case 0:
+ case 1:
+ case 2: shootTimeout = 999999; break;
+ case 3: shootTimeout = 10000; break;
+ case 4: shootTimeout = 5000; break;
+ case 5: shootTimeout = 3500; break;
+ case 6: shootTimeout = 2000; break;
+ }
+ if(CCullZones::NoPolice())
+ shootTimeout /= 2;
+ }else
+ shootTimeout = 1500;
+
+ if(FindPlayerPed()->m_pWanted->IsIgnored())
+ m_nShootTimer = CTimer::GetTimeInMilliseconds();
+ else{
+ // Check if line of sight is clear
+ if(CTimer::GetTimeInMilliseconds() > m_nShootTimer + shootTimeout &&
+ CTimer::GetPreviousTimeInMilliseconds() <= m_nShootTimer + shootTimeout){
+ if(CWorld::GetIsLineOfSightClear(GetPosition(), FindPlayerCoors(), true, false, false, false, false, false)){
+ if(m_heliStatus == HELI_STATUS_HOVER2)
+ m_heliStatus = HELI_STATUS_HOVER;
+ }else{
+ m_nShootTimer = CTimer::GetTimeInMilliseconds();
+ if(m_heliStatus == HELI_STATUS_HOVER)
+ m_heliStatus = HELI_STATUS_HOVER2;
+ }
+ }
+
+ // Shoot!
+ if(CTimer::GetTimeInMilliseconds() > m_nShootTimer + shootTimeout &&
+ CTimer::GetTimeInMilliseconds() > m_nLastShotTime + 200){
+ CVector shotTarget = FindPlayerCoors();
+ // some inaccuracy
+ shotTarget.x += ((CGeneral::GetRandomNumber()&0xFF)-128)/50.0f;
+ shotTarget.y += ((CGeneral::GetRandomNumber()&0xFF)-128)/50.0f;
+ CVector direction = FindPlayerCoors() - GetPosition();
+ direction.Normalise();
+ shotTarget += 3.0f*direction;
+ CVector shotSource = GetPosition();
+ shotSource += 3.0f*direction;
+ FireOneInstantHitRound(&shotSource, &shotTarget, 20);
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_SHOT_FIRED, 0.0f);
+ m_nLastShotTime = CTimer::GetTimeInMilliseconds();
+ }
+ }
+ }
+
+ // Drop Catalina's bombs
+ if(m_heliType == HELI_TYPE_CATALINA && m_pathState > 8 && (CTimer::GetTimeInMilliseconds()>>9) != (CTimer::GetPreviousTimeInMilliseconds()>>9)){
+ CVector bombPos = GetPosition() - 60.0f*m_vecMoveSpeed;
+ if(sq(FindPlayerCoors().x-bombPos.x) + sq(FindPlayerCoors().y-bombPos.y) < sq(35.0f)){
+ bool found;
+ float groundZ = CWorld::FindGroundZFor3DCoord(bombPos.x, bombPos.y, bombPos.z, &found);
+ float waterZ;
+ if(!CWaterLevel::GetWaterLevelNoWaves(bombPos.x, bombPos.y, bombPos.z, &waterZ))
+ waterZ = 0.0f;
+ if(groundZ > waterZ){
+ bombPos.z = groundZ + 2.0f;
+ CExplosion::AddExplosion(nil, this, EXPLOSION_HELI_BOMB, bombPos, 0);
+ }else{
+ bombPos.z = waterZ;
+ CVector dir;
+ for(i = 0; i < 16; i++){
+ dir.x = ((CGeneral::GetRandomNumber()&0xFF)-127)*0.001f;
+ dir.y = ((CGeneral::GetRandomNumber()&0xFF)-127)*0.001f;
+ dir.z = 0.5f;
+ CParticle::AddParticle(PARTICLE_BOAT_SPLASH, bombPos, dir, nil, 0.2f);
+ }
+ }
+ }
+ }
+
+ RemoveAndAdd();
+ bIsInSafePosition = true;
+ GetMatrix().UpdateRW();
+ UpdateRwFrame();
+}
+
+void
+CHeli::PreRender(void)
+{
+ float angle;
+ uint8 i;
+ CColPoint point;
+ CEntity *entity;
+ uint8 r, g, b;
+ float testLowZ = FindPlayerCoors().z - 10.0f;
+ float radius = (GetPosition().z - FindPlayerCoors().z - 10.0f - 1.0f) * 0.3f + 10.0f;
+ int frm = CTimer::GetFrameCounter() & 7;
+
+ i = 0;
+ for(angle = 0.0f; angle < TWOPI; angle += TWOPI/32){
+ CVector pos(radius*Cos(angle), radius*Sin(angle), 0.0f);
+ CVector dir = pos*0.01f;
+ pos += GetPosition();
+
+ if(CWorld::ProcessVerticalLine(pos, testLowZ, point, entity, true, false, false, false, true, false, nil))
+ m_fHeliDustZ[frm] = point.point.z;
+ else
+ m_fHeliDustZ[frm] = -101.0f;
+
+ switch(point.surfaceB){
+ default:
+ case SURFACE_TARMAC:
+ r = 10;
+ g = 10;
+ b = 10;
+ break;
+ case SURFACE_GRASS:
+ r = 10;
+ g = 6;
+ b = 3;
+ break;
+ case SURFACE_DIRT:
+ r = 10;
+ g = 8;
+ b = 7;
+ break;
+ case SURFACE_DIRTTRACK:
+ r = 10;
+ g = 6;
+ b = 3;
+ break;
+ }
+ RwRGBA col = { r, g, b, 32 };
+ pos.z = m_fHeliDustZ[(i - (i&3))/4]; // advance every 4 iterations, why not just /4?
+ if(pos.z > -200.0f && GetPosition().z - pos.z < 20.0f)
+ CParticle::AddParticle(PARTICLE_HELI_DUST, pos, dir, nil, 0.0f, col);
+ i++;
+ }
+}
+
+void
+CHeli::Render(void)
+{
+ CMatrix mat;
+ CVector pos;
+
+ mat.Attach(RwFrameGetMatrix(m_aHeliNodes[HELI_TOPROTOR]));
+ pos = mat.GetPosition();
+ mat.SetRotateZ(m_fRotorRotation);
+ mat.Translate(pos);
+ mat.UpdateRW();
+
+ m_fRotorRotation += 3.14f/6.5f;
+ if(m_fRotorRotation > 6.28f)
+ m_fRotorRotation -= 6.28f;
+
+ mat.Attach(RwFrameGetMatrix(m_aHeliNodes[HELI_BACKROTOR]));
+ pos = mat.GetPosition();
+ mat.SetRotateX(m_fRotorRotation);
+ mat.Translate(pos);
+ mat.UpdateRW();
+
+ CEntity::Render();
+}
+
+void
+CHeli::PreRenderAlways(void)
+{
+ CVector shadowPos(m_fSearchLightX, m_fSearchLightY, GetPosition().z);
+ if(m_fSearchLightIntensity > 0.0f){
+ CShadows::StoreShadowToBeRendered(SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &shadowPos,
+ 6.0f, 0.0f, 0.0f, -6.0f,
+ 80*m_fSearchLightIntensity, 80*m_fSearchLightIntensity, 80*m_fSearchLightIntensity, 80*m_fSearchLightIntensity,
+ 50.0f, true, 1.0f);
+
+ CVector front = GetMatrix() * CVector(0.0f, 7.0f, 0.0f);
+ CVector toPlayer = FindPlayerCoors() - front;
+ toPlayer.Normalise();
+ float intensity = m_fSearchLightIntensity*sq(CTimeCycle::GetSpriteBrightness());
+ if(DotProduct(toPlayer, TheCamera.GetForward()) < -0.8f)
+ CCoronas::RegisterCorona((uintptr)this, 255*intensity, 255*intensity, 255*intensity, 255,
+ front, 10.0f, 60.0f, CCoronas::TYPE_STAR,
+ CCoronas::FLARE_HEADLIGHTS, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+ else
+ CCoronas::RegisterCorona((uintptr)this, 200*intensity, 200*intensity, 200*intensity, 255,
+ front, 8.0f, 60.0f, CCoronas::TYPE_STAR,
+ CCoronas::FLARE_HEADLIGHTS, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+ }
+
+ CVector back = GetMatrix() * CVector(0.0f, -9.0f, 0.0f);
+ if(CTimer::GetTimeInMilliseconds() & 0x100)
+ CCoronas::RegisterCorona((uintptr)this + 2, 255, 0, 0, 255,
+ back, 1.0f, 60.0f, CCoronas::TYPE_STAR,
+ CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+ else
+ CCoronas::RegisterCorona((uintptr)this + 2, 0, 0, 0, 255,
+ back, 1.0f, 60.0f, CCoronas::TYPE_STAR,
+ CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+}
+
+RwObject*
+GetHeliAtomicObjectCB(RwObject *object, void *data)
+{
+ RpAtomic *atomic = (RpAtomic*)object;
+ assert(RwObjectGetType(object) == rpATOMIC);
+ if(RpAtomicGetFlags(atomic) & rpATOMICRENDER)
+ *(RpAtomic**)data = atomic;
+ return object;
+}
+
+CObject*
+CHeli::SpawnFlyingComponent(int32 component)
+{
+ RpAtomic *atomic;
+ RwFrame *frame;
+ RwMatrix *matrix;
+ CObject *obj;
+
+ if(m_aHeliNodes[component] == nil)
+ return nil;
+
+ atomic = nil;
+ RwFrameForAllObjects(m_aHeliNodes[component], GetHeliAtomicObjectCB, &atomic);
+ if(atomic == nil)
+ return nil;
+
+ obj = new CObject;
+ if(obj == nil)
+ return nil;
+
+ obj->SetModelIndexNoCreate(MI_CAR_WHEEL);
+ // object needs base model
+ obj->RefModelInfo(GetModelIndex());
+
+ // create new atomic
+ matrix = RwFrameGetLTM(m_aHeliNodes[component]);
+ frame = RwFrameCreate();
+ atomic = RpAtomicClone(atomic);
+ *RwFrameGetMatrix(frame) = *matrix;
+ RpAtomicSetFrame(atomic, frame);
+ CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
+ obj->AttachToRwObject((RwObject*)atomic);
+
+ // init object
+ obj->m_fMass = 10.0f;
+ obj->m_fTurnMass = 25.0f;
+ obj->m_fAirResistance = 0.99f;
+ obj->m_fElasticity = 0.1f;
+ obj->m_fBuoyancy = obj->m_fMass*GRAVITY/0.75f;
+ obj->ObjectCreatedBy = TEMP_OBJECT;
+ obj->bIsStatic = false;
+ obj->bIsPickup = false;
+
+ // life time
+ CObject::nNoTempObjects++;
+ if(component == HELI_TOPROTOR)
+ obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 1000;
+ else
+ obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 3000;
+
+ obj->m_vecMoveSpeed = m_vecMoveSpeed;
+ if(obj->m_vecMoveSpeed.z > 0.0f)
+ obj->m_vecMoveSpeed.z = 0.3f;
+ else
+ obj->m_vecMoveSpeed.z = 0.0f;
+
+ obj->m_vecTurnSpeed = m_vecTurnSpeed*2.0f;
+
+ if(component == HELI_BACKROTOR)
+ obj->m_vecTurnSpeed.x = 0.5f;
+ else if(component == HELI_TOPROTOR || component == HELI_TOPKNOT)
+ obj->m_vecTurnSpeed.z = 0.5f;
+ else
+ obj->m_vecTurnSpeed.y = 0.5f;
+
+ obj->bRenderScorched = true;
+
+ CWorld::Add(obj);
+
+ atomic = nil;
+ RwFrameForAllObjects(m_aHeliNodes[component], GetHeliAtomicObjectCB, &atomic);
+ if(atomic)
+ RpAtomicSetFlags(atomic, 0);
+
+ return obj;
+}
+
+
+
+void
+CHeli::InitHelis(void)
+{
+ int i;
+
+ NumRandomHelis = 0;
+ TestForNewRandomHelisTimer = 0;
+ NumScriptHelis = 0;
+ CatalinaHeliOn = false;
+ ScriptHeliOn = false;
+ for(i = 0; i < NUM_HELIS; i++)
+ pHelis[i] = nil;
+
+ ((CVehicleModelInfo*)CModelInfo::GetModelInfo(MI_ESCAPE))->SetColModel(&CTempColModels::ms_colModelPed1);
+ ((CVehicleModelInfo*)CModelInfo::GetModelInfo(MI_CHOPPER))->SetColModel(&CTempColModels::ms_colModelPed1);
+}
+
+CHeli*
+GenerateHeli(bool catalina)
+{
+ CHeli *heli;
+ CVector heliPos;
+ int i;
+
+ if(catalina)
+ heli = new CHeli(MI_ESCAPE, PERMANENT_VEHICLE);
+ else
+ heli = new CHeli(MI_CHOPPER, PERMANENT_VEHICLE);
+
+ if(catalina)
+ heliPos = CVector(-224.0f, 201.0f, 83.0f);
+ else{
+ heliPos = FindPlayerCoors();
+ float angle = (float)(CGeneral::GetRandomNumber() & 0xFF)/0xFF * 6.28f;
+ heliPos.x += 250.0f*Sin(angle);
+ heliPos.y += 250.0f*Cos(angle);
+ if(heliPos.x < -2000.0f || heliPos.x > 2000.0f || heliPos.y < -2000.0f || heliPos.y > 2000.0f){
+ // directly above player
+ heliPos.x -= 250.0f*Sin(angle);
+ heliPos.y -= 250.0f*Cos(angle);
+ }
+ heliPos.z += 50.0f;
+ }
+ heli->GetMatrix().SetTranslate(heliPos);
+ if(catalina)
+ heli->GetMatrix().SetRotateZOnly(DEGTORAD(270.0f)); // game actually uses 3.14 here
+
+ heli->m_status = STATUS_ABANDONED;
+
+ int id = -1;
+ bool found = false;
+ while(!found){
+ id++;
+ found = true;
+ for(i = 0; i < 4; i++)
+ if(CHeli::pHelis[i] && CHeli::pHelis[i]->m_nHeliId == id)
+ found = false;
+ }
+ heli->m_nHeliId = id;
+
+ CWorld::Add(heli);
+
+ return heli;
+}
+
+void
+CHeli::UpdateHelis(void)
+{
+ int i, j;
+
+ // Spawn new police helis
+ int numHelisRequired = FindPlayerPed()->m_pWanted->NumOfHelisRequired();
+ if(CStreaming::HasModelLoaded(MI_CHOPPER) && CTimer::GetTimeInMilliseconds() > TestForNewRandomHelisTimer){
+ // Spawn a police heli
+ TestForNewRandomHelisTimer = CTimer::GetTimeInMilliseconds() + 15000;
+ if(NumRandomHelis < numHelisRequired){
+ NumRandomHelis++;
+ CHeli *heli = GenerateHeli(false);
+ heli->m_heliType = HELI_TYPE_RANDOM;
+ if(pHelis[HELI_RANDOM0] == nil)
+ pHelis[HELI_RANDOM0] = heli;
+ else if(pHelis[HELI_RANDOM1] == nil)
+ pHelis[HELI_RANDOM1] = heli;
+ else
+ assert(0 && "too many helis");
+ }
+ }
+
+ // Handle script heli
+ if(ScriptHeliOn){
+ if(CStreaming::HasModelLoaded(MI_CHOPPER) && pHelis[HELI_SCRIPT] == nil){
+ pHelis[HELI_SCRIPT] = GenerateHeli(false);
+ pHelis[HELI_SCRIPT]->m_heliType = HELI_TYPE_SCRIPT;
+ }else
+ CStreaming::RequestModel(MI_CHOPPER, 0);
+ }else{
+ if(pHelis[HELI_SCRIPT])
+ pHelis[HELI_SCRIPT]->m_heliStatus = HELI_STATUS_FLY_AWAY;
+ }
+
+ // Handle Catalina's heli
+ if(CatalinaHeliOn){
+ if(CStreaming::HasModelLoaded(MI_ESCAPE) && pHelis[HELI_CATALINA] == nil){
+ pHelis[HELI_CATALINA] = GenerateHeli(true);
+ pHelis[HELI_CATALINA]->m_heliType = HELI_TYPE_CATALINA;
+ }else
+ CStreaming::RequestModel(MI_ESCAPE, STREAMFLAGS_DONT_REMOVE);
+ }else{
+ if(pHelis[HELI_CATALINA])
+ pHelis[HELI_CATALINA]->m_heliStatus = HELI_STATUS_FLY_AWAY;
+ }
+
+ // Delete helis that we no longer need
+ for(i = 0; i < NUM_HELIS; i++)
+ if(pHelis[i] && pHelis[i]->m_heliStatus == HELI_STATUS_FLY_AWAY && pHelis[i]->GetPosition().z > 150.0f){
+ CWorld::Remove(pHelis[i]);
+ delete pHelis[i];
+ pHelis[i] = nil;
+ if(i != HELI_SCRIPT && i != HELI_CATALINA)
+ NumRandomHelis--;
+ }
+
+ // Handle explosions
+ for(i = 0; i < NUM_HELIS; i++){
+ if(pHelis[i] && pHelis[i]->m_heliStatus == HELI_STATUS_SHOT_DOWN && CTimer::GetTimeInMilliseconds() > pHelis[i]->m_nExplosionTimer){
+ // Second part of explosion
+ static int nFrameGen;
+ CRGBA colors[8];
+
+ TheCamera.CamShake(0.7f, pHelis[i]->GetPosition().x, pHelis[i]->GetPosition().y, pHelis[i]->GetPosition().z);
+
+ colors[0] = CRGBA(0, 0, 0, 255);
+ colors[1] = CRGBA(224, 230, 238, 255);
+ colors[2] = CRGBA(0, 0, 0, 255);
+ colors[3] = CRGBA(0, 0, 0, 255);
+ colors[4] = CRGBA(66, 162, 252, 255);
+ colors[5] = CRGBA(0, 0, 0, 255);
+ colors[6] = CRGBA(0, 0, 0, 255);
+ colors[7] = CRGBA(0, 0, 0, 255);
+
+ CVector pos = pHelis[i]->GetPosition();
+ CVector dir;
+ for(j = 0; j < 40; j++){
+ dir.x = CGeneral::GetRandomNumberInRange(-2.0f, 2.0f);
+ dir.y = CGeneral::GetRandomNumberInRange(-2.0f, 2.0f);
+ dir.z = CGeneral::GetRandomNumberInRange(0.0f, 2.0f);
+ int rotSpeed = CGeneral::GetRandomNumberInRange(10, 30);
+ if(CGeneral::GetRandomNumber() & 1)
+ rotSpeed = -rotSpeed;
+ int f = ++nFrameGen & 3;
+ CParticle::AddParticle(PARTICLE_HELI_DEBRIS, pos, dir,
+ nil, CGeneral::GetRandomNumberInRange(0.1f, 1.0f),
+ colors[nFrameGen], rotSpeed, 0, f, 0);
+ }
+
+ CExplosion::AddExplosion(nil, nil, EXPLOSION_HELI, pos, 0);
+
+ pHelis[i]->SpawnFlyingComponent(HELI_SKID_LEFT);
+ pHelis[i]->SpawnFlyingComponent(HELI_SKID_RIGHT);
+ pHelis[i]->SpawnFlyingComponent(HELI_TOPROTOR);
+
+ CDarkel::RegisterCarBlownUpByPlayer(pHelis[i]);
+ CWorld::Remove(pHelis[i]);
+ delete pHelis[i];
+ pHelis[i] = nil;
+ if(i != HELI_SCRIPT && i != HELI_CATALINA)
+ NumRandomHelis--;
+ if(i == HELI_CATALINA)
+ CatalinaHasBeenShotDown = true;
+
+ CStats::HelisDestroyed++;
+ CStats::PeopleKilledByOthers += 2;
+ CStats::PedsKilledOfThisType[PEDTYPE_COP] += 2;
+ CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 250;
+ pos = CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetPosition();
+ CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->RegisterCrime_Immediately(CRIME_SHOOT_HELI,
+ pos, i + 19843, false);
+
+ TestForNewRandomHelisTimer = CTimer::GetTimeInMilliseconds() + 50000;
+ }else if(pHelis[i] && pHelis[i]->m_heliStatus == HELI_STATUS_SHOT_DOWN && CTimer::GetTimeInMilliseconds()+7000 > pHelis[i]->m_nExplosionTimer){
+ // First part of explosion
+ if(CTimer::GetPreviousTimeInMilliseconds()+7000 < pHelis[i]->m_nExplosionTimer){
+ pHelis[i]->SpawnFlyingComponent(HELI_BACKROTOR);
+ pHelis[i]->SpawnFlyingComponent(HELI_TAIL);
+ pHelis[i]->m_fAngularSpeed *= -2.5f;
+ pHelis[i]->bRenderScorched = true;
+
+ TheCamera.CamShake(0.4f, pHelis[i]->GetPosition().x, pHelis[i]->GetPosition().y, pHelis[i]->GetPosition().z);
+
+ CVector pos = pHelis[i]->GetPosition() - 2.5f*pHelis[i]->GetUp();
+ CExplosion::AddExplosion(nil, nil, EXPLOSION_HELI, pos, 0);
+ }else
+ pHelis[i]->m_fAngularSpeed *= 1.03f;
+ }
+ }
+
+ // Find police helis to remove
+ for(i = 0; i < 2; i++)
+ if(pHelis[i] && pHelis[i]->m_heliStatus != HELI_STATUS_FLY_AWAY){
+ if(numHelisRequired > 0)
+ numHelisRequired--;
+ else
+ pHelis[i]->m_heliStatus = HELI_STATUS_FLY_AWAY;
+ }
+
+ // Remove all helis if in a tunnel
+ if(FindPlayerCoors().z < - 2.0f)
+ for(i = 0; i < NUM_HELIS; i++)
+ if(pHelis[i] && pHelis[i]->m_heliStatus != HELI_STATUS_SHOT_DOWN)
+ pHelis[i]->m_heliStatus = HELI_STATUS_FLY_AWAY;
+}
+
+void
+CHeli::SpecialHeliPreRender(void)
+{
+ int i;
+ for(i = 0; i < NUM_HELIS; i++)
+ if(pHelis[i])
+ pHelis[i]->PreRenderAlways();
+}
+
+bool
+CHeli::TestRocketCollision(CVector *rocketPos)
+{
+ int i;
+ bool hit = false;
+
+ for(i = 0; i < NUM_HELIS; i++){
+ if(pHelis[i] && !pHelis[i]->bExplosionProof && (*rocketPos - pHelis[i]->GetPosition()).MagnitudeSqr() < sq(8.0f)){
+ pHelis[i]->m_fAngularSpeed = (CGeneral::GetRandomNumber() < RAND_MAX/2) ? 0.05f : -0.05f;
+ pHelis[i]->m_heliStatus = HELI_STATUS_SHOT_DOWN;
+ pHelis[i]->m_nExplosionTimer = CTimer::GetTimeInMilliseconds() + 10000;
+ hit = true;
+ }
+ }
+ return hit;
+}
+
+bool
+CHeli::TestBulletCollision(CVector *line0, CVector *line1, CVector *bulletPos, int32 damage)
+{
+ int i;
+ bool hit = false;
+
+ for(i = 0; i < NUM_HELIS; i++)
+ if(pHelis[i] && !pHelis[i]->bBulletProof && CCollision::DistToLine(line0, line1, &pHelis[i]->GetPosition()) < 5.0f){
+ // Find bullet position
+ float distToHeli = (pHelis[i]->GetPosition() - *line0).Magnitude();
+ CVector line = (*line1 - *line0);
+ float lineLength = line.Magnitude();
+ *bulletPos = *line0 + line*max(1.0f, distToHeli-5.0f);
+
+ pHelis[i]->m_nBulletDamage += damage;
+
+ if(pHelis[i]->m_heliType == HELI_CATALINA && pHelis[i]->m_nBulletDamage > 400 ||
+ pHelis[i]->m_heliType != HELI_CATALINA && pHelis[i]->m_nBulletDamage > 700){
+ pHelis[i]->m_fAngularSpeed = (CGeneral::GetRandomNumber() < RAND_MAX/2) ? 0.05f : -0.05f;
+ pHelis[i]->m_heliStatus = HELI_STATUS_SHOT_DOWN;
+ pHelis[i]->m_nExplosionTimer = CTimer::GetTimeInMilliseconds() + 10000;
+ }
+
+ hit = true;
+ }
+ return hit;
+}
+
+void CHeli::StartCatalinaFlyBy(void)
+{
+ CatalinaHeliOn = true;
+ CatalinaHasBeenShotDown = false;
+}
+
+void
+CHeli::RemoveCatalinaHeli(void)
+{
+ CatalinaHeliOn = false;
+ if(pHelis[HELI_CATALINA]){
+ CWorld::Remove(pHelis[HELI_CATALINA]);
+ delete pHelis[HELI_CATALINA];
+ pHelis[HELI_CATALINA] = nil;
+ }
+}
+
+CHeli *CHeli::FindPointerToCatalinasHeli(void) { return pHelis[HELI_CATALINA]; }
+void CHeli::CatalinaTakeOff(void) { pHelis[HELI_CATALINA]->m_pathState = 8; }
+void CHeli::MakeCatalinaHeliFlyAway(void) { pHelis[HELI_CATALINA]->m_pathState = 12; }
+bool CHeli::HasCatalinaBeenShotDown(void) { return CatalinaHasBeenShotDown; }
+
+void CHeli::ActivateHeli(bool activate) { ScriptHeliOn = activate; }
+
+
+class CHeli_ : public CHeli
+{
+public:
+ void ctor(int32 id, uint8 CreatedBy) { ::new (this) CHeli(id, CreatedBy); }
+ void dtor(void) { CHeli::~CHeli(); }
+};
+
+STARTPATCHES
+ InjectHook(0x547220, &CHeli_::ctor, PATCH_JUMP);
+ InjectHook(0x5474A0, &CHeli_::dtor, PATCH_JUMP);
+ InjectHook(0x54AE50, &CHeli::SpawnFlyingComponent, PATCH_JUMP);
+ InjectHook(0x549970, CHeli::InitHelis, PATCH_JUMP);
+ InjectHook(0x5499F0, CHeli::UpdateHelis, PATCH_JUMP);
+ InjectHook(0x54AE10, CHeli::SpecialHeliPreRender, PATCH_JUMP);
+ InjectHook(0x54AA30, CHeli::TestRocketCollision, PATCH_JUMP);
+ InjectHook(0x54AB30, CHeli::TestBulletCollision, PATCH_JUMP);
+ InjectHook(0x54A640, GenerateHeli, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/vehicles/Plane.cpp b/src/vehicles/Plane.cpp
index 775cf572..771f36e1 100644
--- a/src/vehicles/Plane.cpp
+++ b/src/vehicles/Plane.cpp
@@ -968,8 +968,16 @@ bool CPlane::HasDropOffCesnaBeenShotDown(void) { return DropOffCesnaMissionStatu
class CPlane_ : public CPlane
{
public:
+<<<<<<< HEAD
+<<<<<<< HEAD
void ctor(int32 id, uint8 CreatedBy) { ::new (this) CPlane(id, CreatedBy); }
void dtor(void) { CPlane::~CPlane(); }
+=======
+ void dtor(void) { this->~CPlane(); }
+>>>>>>> More audio ped
+=======
+ void dtor(void) { CPlane::~CPlane(); }
+>>>>>>> fix
};
STARTPATCHES
diff --git a/src/vehicles/Plane.cpp.autosave b/src/vehicles/Plane.cpp.autosave
new file mode 100644
index 00000000..775cf572
--- /dev/null
+++ b/src/vehicles/Plane.cpp.autosave
@@ -0,0 +1,985 @@
+#include "common.h"
+#include "main.h"
+#include "patcher.h"
+#include "General.h"
+#include "ModelIndices.h"
+#include "FileMgr.h"
+#include "Streaming.h"
+#include "Replay.h"
+#include "Camera.h"
+#include "Coronas.h"
+#include "Particle.h"
+#include "Explosion.h"
+#include "World.h"
+#include "HandlingMgr.h"
+#include "Plane.h"
+
+CPlaneNode *&pPathNodes = *(CPlaneNode**)0x8F1B68;
+CPlaneNode *&pPath2Nodes = *(CPlaneNode**)0x885B8C;
+CPlaneNode *&pPath3Nodes = *(CPlaneNode**)0x885B78;
+CPlaneNode *&pPath4Nodes = *(CPlaneNode**)0x885AD8;
+int32 &NumPathNodes = *(int32*)0x8F2BE4;
+int32 &NumPath2Nodes = *(int32*)0x941498;
+int32 &NumPath3Nodes = *(int32*)0x9414D8;
+int32 &NumPath4Nodes = *(int32*)0x9412C8;
+float &TotalLengthOfFlightPath = *(float*)0x8F2C6C;
+float &TotalLengthOfFlightPath2 = *(float*)0x64CFBC;
+float &TotalLengthOfFlightPath3 = *(float*)0x64CFD0;
+float &TotalLengthOfFlightPath4 = *(float*)0x64CFDC;
+float &TotalDurationOfFlightPath = *(float*)0x64CFB8;
+float &TotalDurationOfFlightPath2 = *(float*)0x64CFC0;
+float &TotalDurationOfFlightPath3 = *(float*)0x64CFD4;
+float &TotalDurationOfFlightPath4 = *(float*)0x64CFE0;
+float &LandingPoint = *(float*)0x8F2C7C;
+float &TakeOffPoint = *(float*)0x8E28A4;
+CPlaneInterpolationLine *aPlaneLineBits = (CPlaneInterpolationLine*)0x734168; //[6]
+
+float *PlanePathPosition = (float*)0x8F5FC8; //[3]
+float *OldPlanePathPosition = (float*)0x8F5FBC; //[3]
+float *PlanePathSpeed = (float*)0x941538; //[3]
+float *PlanePath2Position = (float*)0x64CFC4; //[3]
+float &PlanePath3Position = *(float*)0x64CFD8;
+float &PlanePath4Position = *(float*)0x64CFE4;
+float *PlanePath2Speed = (float*)0x8F1A54; //[3]
+float &PlanePath3Speed = *(float*)0x8F1A94;
+float &PlanePath4Speed = *(float*)0x8F1AFC;
+
+
+enum
+{
+ CESNA_STATUS_NONE, // doesn't even exist
+ CESNA_STATUS_FLYING,
+ CESNA_STATUS_DESTROYED,
+ CESNA_STATUS_LANDED,
+};
+
+int32 &CesnaMissionStatus = *(int32*)0x64CFE8;
+int32 &CesnaMissionStartTime = *(int32*)0x64CFEC;
+CPlane *&pDrugRunCesna = *(CPlane**)0x8F5F80;
+int32 &DropOffCesnaMissionStatus = *(int32*)0x64CFF0;
+int32 &DropOffCesnaMissionStartTime = *(int32*)0x64CFF4;
+CPlane *&pDropOffCesna = *(CPlane**)0x8E2A38;
+
+
+CPlane::CPlane(int32 id, uint8 CreatedBy)
+ : CVehicle(CreatedBy)
+{
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(id);
+ m_vehType = VEHICLE_TYPE_PLANE;
+ pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)mi->m_handlingId);
+ SetModelIndex(id);
+
+ m_fMass = 100000000.0f;
+ m_fTurnMass = 100000000.0f;
+ m_fAirResistance = 0.9994f;
+ m_fElasticity = 0.05f;
+
+ bUsesCollision = false;
+ m_bHasBeenHit = false;
+ m_bIsDrugRunCesna = false;
+ m_bIsDropOffCesna = false;
+
+ m_status = STATUS_PLANE;
+ bIsBIGBuilding = true;
+ m_level = LEVEL_NONE;
+}
+
+CPlane::~CPlane()
+{
+ DeleteRwObject();
+}
+
+void
+CPlane::SetModelIndex(uint32 id)
+{
+ CVehicle::SetModelIndex(id);
+}
+
+void
+CPlane::DeleteRwObject(void)
+{
+ if(m_rwObject && RwObjectGetType(m_rwObject) == rpATOMIC){
+ m_matrix.Detach();
+ if(RwObjectGetType(m_rwObject) == rpATOMIC){ // useless check
+ RwFrame *f = RpAtomicGetFrame((RpAtomic*)m_rwObject);
+ RpAtomicDestroy((RpAtomic*)m_rwObject);
+ RwFrameDestroy(f);
+ }
+ m_rwObject = nil;
+ }
+ CEntity::DeleteRwObject();
+}
+
+// There's a LOT of copy and paste in here. Maybe this could be refactored somehow
+void
+CPlane::ProcessControl(void)
+{
+ int i;
+ CVector pos;
+
+ // Explosion
+ if(m_bHasBeenHit){
+ // BUG: since this is all based on frames, you can skip the explosion processing when you go into the menu
+ if(GetModelIndex() == MI_AIRTRAIN){
+ int frm = CTimer::GetFrameCounter() - m_nFrameWhenHit;
+ if(frm == 20){
+ static int nFrameGen;
+ CRGBA colors[8];
+
+ CExplosion::AddExplosion(nil, FindPlayerPed(), EXPLOSION_HELI, GetMatrix() * CVector(0.0f, 0.0f, 0.0f), 0);
+
+ colors[0] = CRGBA(0, 0, 0, 255);
+ colors[1] = CRGBA(224, 230, 238, 255);
+ colors[2] = CRGBA(224, 230, 238, 255);
+ colors[3] = CRGBA(0, 0, 0, 255);
+ colors[4] = CRGBA(224, 230, 238, 255);
+ colors[5] = CRGBA(0, 0, 0, 255);
+ colors[6] = CRGBA(0, 0, 0, 255);
+ colors[7] = CRGBA(224, 230, 238, 255);
+
+ CVector dir;
+ for(i = 0; i < 40; i++){
+ dir.x = CGeneral::GetRandomNumberInRange(-2.0f, 2.0f);
+ dir.y = CGeneral::GetRandomNumberInRange(-2.0f, 2.0f);
+ dir.z = CGeneral::GetRandomNumberInRange(0.0f, 2.0f);
+ int rotSpeed = CGeneral::GetRandomNumberInRange(10, 30);
+ if(CGeneral::GetRandomNumber() & 1)
+ rotSpeed = -rotSpeed;
+ int f = ++nFrameGen & 3;
+ CParticle::AddParticle(PARTICLE_HELI_DEBRIS, GetMatrix() * CVector(0.0f, 0.0f, 0.0f), dir,
+ nil, CGeneral::GetRandomNumberInRange(0.1f, 1.0f),
+ colors[nFrameGen], rotSpeed, 0, f, 0);
+ }
+ }
+ if(frm >= 40 && frm <= 80 && frm & 1){
+ if(frm & 1){
+ pos.x = ((CGeneral::GetRandomNumber() & 0x3F) - 32) * 0.2f;
+ pos.z = ((CGeneral::GetRandomNumber() & 0x3F) - 32) * 0.2f;
+ pos.y = frm - 40;
+ pos = GetMatrix() * pos;
+ }else{
+ pos.x = ((CGeneral::GetRandomNumber() & 0x3F) - 32) * 0.2f;
+ pos.z = ((CGeneral::GetRandomNumber() & 0x3F) - 32) * 0.2f;
+ pos.y = 40 - frm;
+ pos = GetMatrix() * pos;
+ }
+ CExplosion::AddExplosion(nil, FindPlayerPed(), EXPLOSION_HELI, pos, 0);
+ }
+ if(frm == 60)
+ bRenderScorched = true;
+ if(frm == 82){
+ TheCamera.SetFadeColour(255, 255, 255);
+ TheCamera.Fade(0.0f, FADE_OUT);
+ TheCamera.ProcessFade();
+ TheCamera.Fade(1.0f, FADE_IN);
+ FlagToDestroyWhenNextProcessed();
+ }
+ }else{
+ int frm = CTimer::GetFrameCounter() - m_nFrameWhenHit;
+ if(frm == 20){
+ static int nFrameGen;
+ CRGBA colors[8];
+
+ CExplosion::AddExplosion(nil, FindPlayerPed(), EXPLOSION_HELI, GetMatrix() * CVector(0.0f, 0.0f, 0.0f), 0);
+
+ colors[0] = CRGBA(0, 0, 0, 255);
+ colors[1] = CRGBA(224, 230, 238, 255);
+ colors[2] = CRGBA(224, 230, 238, 255);
+ colors[3] = CRGBA(0, 0, 0, 255);
+ colors[4] = CRGBA(252, 66, 66, 255);
+ colors[5] = CRGBA(0, 0, 0, 255);
+ colors[6] = CRGBA(0, 0, 0, 255);
+ colors[7] = CRGBA(252, 66, 66, 255);
+
+ for(i = 0; i < 40; i++){
+ int rotSpeed = CGeneral::GetRandomNumberInRange(30.0f, 20.0f);
+ if(CGeneral::GetRandomNumber() & 1)
+ rotSpeed = -rotSpeed;
+ int f = ++nFrameGen & 3;
+ CParticle::AddParticle(PARTICLE_HELI_DEBRIS, GetMatrix() * CVector(0.0f, 0.0f, 0.0f),
+ CVector(CGeneral::GetRandomNumberInRange(-2.0f, 2.0f),
+ CGeneral::GetRandomNumberInRange(-2.0f, 2.0f),
+ CGeneral::GetRandomNumberInRange(0.0f, 2.0f)),
+ nil, CGeneral::GetRandomNumberInRange(0.1f, 1.0f),
+ colors[nFrameGen], rotSpeed, 0, f, 0);
+ }
+ }
+ if(frm >= 40 && frm <= 60 && frm & 1){
+ if(frm & 1){
+ pos.x = ((CGeneral::GetRandomNumber() & 0x3F) - 32) * 0.1f;
+ pos.z = ((CGeneral::GetRandomNumber() & 0x3F) - 32) * 0.1f;
+ pos.y = (frm - 40)*0.3f;
+ pos = GetMatrix() * pos;
+ }else{
+ pos.x = ((CGeneral::GetRandomNumber() & 0x3F) - 32) * 0.1f;
+ pos.z = ((CGeneral::GetRandomNumber() & 0x3F) - 32) * 0.1f;
+ pos.y = (40 - frm)*0.3f;
+ pos = GetMatrix() * pos;
+ }
+ CExplosion::AddExplosion(nil, FindPlayerPed(), EXPLOSION_HELI, pos, 0);
+ }
+ if(frm == 30)
+ bRenderScorched = true;
+ if(frm == 61){
+ TheCamera.SetFadeColour(200, 200, 200);
+ TheCamera.Fade(0.0f, FADE_OUT);
+ TheCamera.ProcessFade();
+ TheCamera.Fade(1.0f, FADE_IN);
+ if(m_bIsDrugRunCesna){
+ CesnaMissionStatus = CESNA_STATUS_DESTROYED;
+ pDrugRunCesna = nil;
+ }
+ if(m_bIsDropOffCesna){
+ DropOffCesnaMissionStatus = CESNA_STATUS_DESTROYED;
+ pDropOffCesna = nil;
+ }
+ FlagToDestroyWhenNextProcessed();
+ }
+ }
+ }
+
+ // Update plane position and speed
+ if(GetModelIndex() == MI_AIRTRAIN || !m_isFarAway || ((CTimer::GetFrameCounter() + m_randomSeed) & 7) == 0){
+ if(GetModelIndex() == MI_AIRTRAIN){
+ float pathPositionRear = PlanePathPosition[m_nPlaneId] - 30.0f;
+ if(pathPositionRear < 0.0f)
+ pathPositionRear += TotalLengthOfFlightPath;
+ float pathPosition = pathPositionRear + 30.0f;
+
+ float pitch = 0.0f;
+ float distSinceTakeOff = pathPosition - TakeOffPoint;
+ if(distSinceTakeOff <= 0.0f && distSinceTakeOff > -70.0f){
+ // shortly before take off
+ pitch = 1.0f - distSinceTakeOff/-70.0f;
+ }else if(distSinceTakeOff >= 0.0f && distSinceTakeOff < 100.0f){
+ // shortly after take off
+ pitch = 1.0f - distSinceTakeOff/100.0f;
+ }
+
+ float distSinceLanding = pathPosition - LandingPoint;
+ if(distSinceLanding <= 0.0f && distSinceLanding > -200.0f){
+ // shortly before landing
+ pitch = 1.0f - distSinceLanding/-200.0f;
+ }else if(distSinceLanding >= 0.0f && distSinceLanding < 70.0f){
+ // shortly after landing
+ pitch = 1.0f - distSinceLanding/70.0f;
+ }
+
+
+ // Advance current node to appropriate position
+ float pos1, pos2;
+ int nextTrackNode = m_nCurPathNode + 1;
+ pos1 = pPathNodes[m_nCurPathNode].t;
+ if(nextTrackNode < NumPathNodes)
+ pos2 = pPathNodes[nextTrackNode].t;
+ else{
+ nextTrackNode = 0;
+ pos2 = TotalLengthOfFlightPath;
+ }
+ while(pathPositionRear < pos1 || pathPositionRear > pos2){
+ m_nCurPathNode = (m_nCurPathNode+1) % NumPathNodes;
+ nextTrackNode = m_nCurPathNode + 1;
+ pos1 = pPathNodes[m_nCurPathNode].t;
+ if(nextTrackNode < NumPathNodes)
+ pos2 = pPathNodes[nextTrackNode].t;
+ else{
+ nextTrackNode = 0;
+ pos2 = TotalLengthOfFlightPath;
+ }
+ }
+ bool bothOnGround = pPathNodes[m_nCurPathNode].bOnGround && pPathNodes[nextTrackNode].bOnGround;
+ if(PlanePathPosition[m_nPlaneId] >= LandingPoint && OldPlanePathPosition[m_nPlaneId] < LandingPoint)
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_PLANE_ON_GROUND, 0.0f);
+ float dist = pPathNodes[nextTrackNode].t - pPathNodes[m_nCurPathNode].t;
+ if(dist < 0.0f)
+ dist += TotalLengthOfFlightPath;
+ float f = (pathPositionRear - pPathNodes[m_nCurPathNode].t)/dist;
+ CVector posRear = (1.0f - f)*pPathNodes[m_nCurPathNode].p + f*pPathNodes[nextTrackNode].p;
+
+ // Same for the front
+ float pathPositionFront = pathPositionRear + 60.0f;
+ if(pathPositionFront > TotalLengthOfFlightPath)
+ pathPositionFront -= TotalLengthOfFlightPath;
+ int curPathNodeFront = m_nCurPathNode;
+ int nextPathNodeFront = curPathNodeFront + 1;
+ pos1 = pPathNodes[curPathNodeFront].t;
+ if(nextPathNodeFront < NumPathNodes)
+ pos2 = pPathNodes[nextPathNodeFront].t;
+ else{
+ nextPathNodeFront = 0;
+ pos2 = TotalLengthOfFlightPath;
+ }
+ while(pathPositionFront < pos1 || pathPositionFront > pos2){
+ curPathNodeFront = (curPathNodeFront+1) % NumPathNodes;
+ nextPathNodeFront = curPathNodeFront + 1;
+ pos1 = pPathNodes[curPathNodeFront].t;
+ if(nextPathNodeFront < NumPathNodes)
+ pos2 = pPathNodes[nextPathNodeFront].t;
+ else{
+ nextPathNodeFront = 0;
+ pos2 = TotalLengthOfFlightPath;
+ }
+ }
+ dist = pPathNodes[nextPathNodeFront].t - pPathNodes[curPathNodeFront].t;
+ if(dist < 0.0f)
+ dist += TotalLengthOfFlightPath;
+ f = (pathPositionFront - pPathNodes[curPathNodeFront].t)/dist;
+ CVector posFront = (1.0f - f)*pPathNodes[curPathNodeFront].p + f*pPathNodes[nextPathNodeFront].p;
+
+ // And for another point 60 units in front of the plane, used to calculate roll
+ float pathPositionFront2 = pathPositionFront + 60.0f;
+ if(pathPositionFront2 > TotalLengthOfFlightPath)
+ pathPositionFront2 -= TotalLengthOfFlightPath;
+ int curPathNodeFront2 = m_nCurPathNode;
+ int nextPathNodeFront2 = curPathNodeFront2 + 1;
+ pos1 = pPathNodes[curPathNodeFront2].t;
+ if(nextPathNodeFront2 < NumPathNodes)
+ pos2 = pPathNodes[nextPathNodeFront2].t;
+ else{
+ nextPathNodeFront2 = 0;
+ pos2 = TotalLengthOfFlightPath;
+ }
+ while(pathPositionFront2 < pos1 || pathPositionFront2 > pos2){
+ curPathNodeFront2 = (curPathNodeFront2+1) % NumPathNodes;
+ nextPathNodeFront2 = curPathNodeFront2 + 1;
+ pos1 = pPathNodes[curPathNodeFront2].t;
+ if(nextPathNodeFront2 < NumPathNodes)
+ pos2 = pPathNodes[nextPathNodeFront2].t;
+ else{
+ nextPathNodeFront2 = 0;
+ pos2 = TotalLengthOfFlightPath;
+ }
+ }
+ dist = pPathNodes[nextPathNodeFront2].t - pPathNodes[curPathNodeFront2].t;
+ if(dist < 0.0f)
+ dist += TotalLengthOfFlightPath;
+ f = (pathPositionFront2 - pPathNodes[curPathNodeFront2].t)/dist;
+ CVector posFront2 = (1.0f - f)*pPathNodes[curPathNodeFront2].p + f*pPathNodes[nextPathNodeFront2].p;
+
+ // Now set matrix
+ GetPosition() = (posRear + posFront)/2.0f;
+ GetPosition().z += 4.3f;
+ CVector fwd = posFront - posRear;
+ fwd.Normalise();
+ if(pitch != 0.0f){
+ fwd.z += 0.4f*pitch;
+ fwd.Normalise();
+ }
+ CVector fwd2 = posFront2 - posRear;
+ fwd2.Normalise();
+ CVector roll = CrossProduct(fwd, fwd2);
+ CVector right = CrossProduct(fwd, CVector(0.0f, 0.0f, 1.0f));
+ if(!bothOnGround)
+ right.z += 3.0f*roll.z;
+ right.Normalise();
+ CVector up = CrossProduct(right, fwd);
+ GetRight() = right;
+ GetUp() = up;
+ GetForward() = fwd;
+
+ // Set speed
+ m_vecMoveSpeed = fwd*PlanePathSpeed[m_nPlaneId]/60.0f;
+ m_fSpeed = PlanePathSpeed[m_nPlaneId]/60.0f;
+ m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
+
+ m_isFarAway = !((posFront - TheCamera.GetPosition()).Magnitude2D() < sq(300.0f));
+ }else{
+ float planePathPosition;
+ float totalLengthOfFlightPath;
+ CPlaneNode *pathNodes;
+ float planePathSpeed;
+ int numPathNodes;
+
+ if(m_bIsDrugRunCesna){
+ planePathPosition = PlanePath3Position;
+ totalLengthOfFlightPath = TotalLengthOfFlightPath3;
+ pathNodes = pPath3Nodes;
+ planePathSpeed = PlanePath3Speed;
+ numPathNodes = NumPath3Nodes;
+ if(CesnaMissionStatus == CESNA_STATUS_LANDED){
+ pDrugRunCesna = false;
+ FlagToDestroyWhenNextProcessed();
+ }
+ }else if(m_bIsDropOffCesna){
+ planePathPosition = PlanePath4Position;
+ totalLengthOfFlightPath = TotalLengthOfFlightPath4;
+ pathNodes = pPath4Nodes;
+ planePathSpeed = PlanePath4Speed;
+ numPathNodes = NumPath4Nodes;
+ if(DropOffCesnaMissionStatus == CESNA_STATUS_LANDED){
+ pDropOffCesna = false;
+ FlagToDestroyWhenNextProcessed();
+ }
+ }else{
+ planePathPosition = PlanePath2Position[m_nPlaneId];
+ totalLengthOfFlightPath = TotalLengthOfFlightPath2;
+ pathNodes = pPath2Nodes;
+ planePathSpeed = PlanePath2Speed[m_nPlaneId];
+ numPathNodes = NumPath2Nodes;
+ }
+
+ // Advance current node to appropriate position
+ float pathPositionRear = planePathPosition - 10.0f;
+ if(pathPositionRear < 0.0f)
+ pathPositionRear += totalLengthOfFlightPath;
+ float pos1, pos2;
+ int nextTrackNode = m_nCurPathNode + 1;
+ pos1 = pathNodes[m_nCurPathNode].t;
+ if(nextTrackNode < numPathNodes)
+ pos2 = pathNodes[nextTrackNode].t;
+ else{
+ nextTrackNode = 0;
+ pos2 = totalLengthOfFlightPath;
+ }
+ while(pathPositionRear < pos1 || pathPositionRear > pos2){
+ m_nCurPathNode = (m_nCurPathNode+1) % numPathNodes;
+ nextTrackNode = m_nCurPathNode + 1;
+ pos1 = pathNodes[m_nCurPathNode].t;
+ if(nextTrackNode < numPathNodes)
+ pos2 = pathNodes[nextTrackNode].t;
+ else{
+ nextTrackNode = 0;
+ pos2 = totalLengthOfFlightPath;
+ }
+ }
+ float dist = pathNodes[nextTrackNode].t - pathNodes[m_nCurPathNode].t;
+ if(dist < 0.0f)
+ dist += totalLengthOfFlightPath;
+ float f = (pathPositionRear - pathNodes[m_nCurPathNode].t)/dist;
+ CVector posRear = (1.0f - f)*pathNodes[m_nCurPathNode].p + f*pathNodes[nextTrackNode].p;
+
+ // Same for the front
+ float pathPositionFront = pathPositionRear + 20.0f;
+ if(pathPositionFront > totalLengthOfFlightPath)
+ pathPositionFront -= totalLengthOfFlightPath;
+ int curPathNodeFront = m_nCurPathNode;
+ int nextPathNodeFront = curPathNodeFront + 1;
+ pos1 = pathNodes[curPathNodeFront].t;
+ if(nextPathNodeFront < numPathNodes)
+ pos2 = pathNodes[nextPathNodeFront].t;
+ else{
+ nextPathNodeFront = 0;
+ pos2 = totalLengthOfFlightPath;
+ }
+ while(pathPositionFront < pos1 || pathPositionFront > pos2){
+ curPathNodeFront = (curPathNodeFront+1) % numPathNodes;
+ nextPathNodeFront = curPathNodeFront + 1;
+ pos1 = pathNodes[curPathNodeFront].t;
+ if(nextPathNodeFront < numPathNodes)
+ pos2 = pathNodes[nextPathNodeFront].t;
+ else{
+ nextPathNodeFront = 0;
+ pos2 = totalLengthOfFlightPath;
+ }
+ }
+ dist = pathNodes[nextPathNodeFront].t - pathNodes[curPathNodeFront].t;
+ if(dist < 0.0f)
+ dist += totalLengthOfFlightPath;
+ f = (pathPositionFront - pathNodes[curPathNodeFront].t)/dist;
+ CVector posFront = (1.0f - f)*pathNodes[curPathNodeFront].p + f*pathNodes[nextPathNodeFront].p;
+
+ // And for another point 60 units in front of the plane, used to calculate roll
+ float pathPositionFront2 = pathPositionFront + 30.0f;
+ if(pathPositionFront2 > totalLengthOfFlightPath)
+ pathPositionFront2 -= totalLengthOfFlightPath;
+ int curPathNodeFront2 = m_nCurPathNode;
+ int nextPathNodeFront2 = curPathNodeFront2 + 1;
+ pos1 = pathNodes[curPathNodeFront2].t;
+ if(nextPathNodeFront2 < numPathNodes)
+ pos2 = pathNodes[nextPathNodeFront2].t;
+ else{
+ nextPathNodeFront2 = 0;
+ pos2 = totalLengthOfFlightPath;
+ }
+ while(pathPositionFront2 < pos1 || pathPositionFront2 > pos2){
+ curPathNodeFront2 = (curPathNodeFront2+1) % numPathNodes;
+ nextPathNodeFront2 = curPathNodeFront2 + 1;
+ pos1 = pathNodes[curPathNodeFront2].t;
+ if(nextPathNodeFront2 < numPathNodes)
+ pos2 = pathNodes[nextPathNodeFront2].t;
+ else{
+ nextPathNodeFront2 = 0;
+ pos2 = totalLengthOfFlightPath;
+ }
+ }
+ dist = pathNodes[nextPathNodeFront2].t - pathNodes[curPathNodeFront2].t;
+ if(dist < 0.0f)
+ dist += totalLengthOfFlightPath;
+ f = (pathPositionFront2 - pathNodes[curPathNodeFront2].t)/dist;
+ CVector posFront2 = (1.0f - f)*pathNodes[curPathNodeFront2].p + f*pathNodes[nextPathNodeFront2].p;
+
+ // Now set matrix
+ GetPosition() = (posRear + posFront)/2.0f;
+ GetPosition().z += 1.0f;
+ CVector fwd = posFront - posRear;
+ fwd.Normalise();
+ CVector fwd2 = posFront2 - posRear;
+ fwd2.Normalise();
+ CVector roll = CrossProduct(fwd, fwd2);
+ CVector right = CrossProduct(fwd, CVector(0.0f, 0.0f, 1.0f));
+ right.z += 3.0f*roll.z;
+ right.Normalise();
+ CVector up = CrossProduct(right, fwd);
+ GetRight() = right;
+ GetUp() = up;
+ GetForward() = fwd;
+
+ // Set speed
+ m_vecMoveSpeed = fwd*planePathSpeed/60.0f;
+ m_fSpeed = planePathSpeed/60.0f;
+ m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
+
+ m_isFarAway = !((posFront - TheCamera.GetPosition()).Magnitude2D() < sq(300.0f));
+ }
+ }
+
+ bIsInSafePosition = true;
+ GetMatrix().UpdateRW();
+ UpdateRwFrame();
+
+ // Handle streaming and such
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+ if(m_isFarAway){
+ // Switch to LOD model
+ if(m_rwObject && RwObjectGetType(m_rwObject) == rpCLUMP){
+ DeleteRwObject();
+ if(mi->m_planeLodId != -1){
+ m_rwObject = CModelInfo::GetModelInfo(mi->m_planeLodId)->CreateInstance();
+ if(m_rwObject)
+ m_matrix.Attach(RwFrameGetMatrix(RpAtomicGetFrame((RpAtomic*)m_rwObject)));
+ }
+ }
+ }else if(CStreaming::HasModelLoaded(GetModelIndex())){
+ if(m_rwObject && RwObjectGetType(m_rwObject) == rpATOMIC){
+ // Get rid of LOD model
+ m_matrix.Detach();
+ if(m_rwObject){ // useless check
+ if(RwObjectGetType(m_rwObject) == rpATOMIC){ // useless check
+ RwFrame *f = RpAtomicGetFrame((RpAtomic*)m_rwObject);
+ RpAtomicDestroy((RpAtomic*)m_rwObject);
+ RwFrameDestroy(f);
+ }
+ m_rwObject = nil;
+ }
+ }
+ // Set high detail model
+ if(m_rwObject == nil){
+ int id = GetModelIndex();
+ m_modelIndex = -1;
+ SetModelIndex(id);
+ }
+ }else{
+ CStreaming::RequestModel(GetModelIndex(), STREAMFLAGS_DEPENDENCY);
+ }
+}
+
+void
+CPlane::PreRender(void)
+{
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+
+ CVector lookVector = GetPosition() - TheCamera.GetPosition();
+ float camDist = lookVector.Magnitude();
+ if(camDist != 0.0f)
+ lookVector *= 1.0f/camDist;
+ else
+ lookVector = CVector(1.0f, 0.0f, 0.0f);
+ float behindness = DotProduct(lookVector, GetForward());
+
+ // Wing lights
+ if(behindness < 0.0f){
+ // in front of plane
+ CVector lightPos = mi->m_positions[PLANE_POS_LIGHT_RIGHT];
+ CVector lightR = GetMatrix() * lightPos;
+ CVector lightL = lightR;
+ lightL -= GetRight()*2.0f*lightPos.x;
+
+ float intensity = -0.6f*behindness + 0.4f;
+ float size = 1.0f - behindness;
+
+ if(behindness < -0.9f && camDist < 50.0f){
+ // directly in front
+ CCoronas::RegisterCorona((uintptr)this + 10, 255*intensity, 255*intensity, 255*intensity, 255,
+ lightL, size, 240.0f,
+ CCoronas::TYPE_NORMAL, CCoronas::FLARE_HEADLIGHTS, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
+ CCoronas::RegisterCorona((uintptr)this + 11, 255*intensity, 255*intensity, 255*intensity, 255,
+ lightR, size, 240.0f,
+ CCoronas::TYPE_NORMAL, CCoronas::FLARE_HEADLIGHTS, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
+ }else{
+ CCoronas::RegisterCorona((uintptr)this + 10, 255*intensity, 255*intensity, 255*intensity, 255,
+ lightL, size, 240.0f,
+ CCoronas::TYPE_NORMAL, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
+ CCoronas::RegisterCorona((uintptr)this + 11, 255*intensity, 255*intensity, 255*intensity, 255,
+ lightR, size, 240.0f,
+ CCoronas::TYPE_NORMAL, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
+ }
+ }
+
+ // Tail light
+ if(CTimer::GetTimeInMilliseconds() & 0x200){
+ CVector pos = GetMatrix() * mi->m_positions[PLANE_POS_LIGHT_TAIL];
+
+ CCoronas::RegisterCorona((uintptr)this + 12, 255, 0, 0, 255,
+ pos, 1.0f, 120.0f,
+ CCoronas::TYPE_NORMAL, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
+ }
+}
+
+void
+CPlane::Render(void)
+{
+ CEntity::Render();
+}
+
+#define CRUISE_SPEED (50.0f)
+#define TAXI_SPEED (5.0f)
+
+void
+CPlane::InitPlanes(void)
+{
+ int i;
+
+ CesnaMissionStatus = CESNA_STATUS_NONE;
+
+ // Jumbo
+ if(pPathNodes == nil){
+ pPathNodes = LoadPath("data\\paths\\flight.dat", NumPathNodes, TotalLengthOfFlightPath, true);
+
+ // Figure out which nodes are on ground
+ CColPoint colpoint;
+ CEntity *entity;
+ for(i = 0; i < NumPathNodes; i++){
+ if(CWorld::ProcessVerticalLine(pPathNodes[i].p, 1000.0f, colpoint, entity, true, false, false, false, true, false, nil)){
+ pPathNodes[i].p.z = colpoint.point.z;
+ pPathNodes[i].bOnGround = true;
+ }else
+ pPathNodes[i].bOnGround = false;
+ }
+
+ // Find lading and takeoff points
+ LandingPoint = -1.0f;
+ TakeOffPoint = -1.0f;
+ bool lastOnGround = pPathNodes[NumPathNodes-1].bOnGround;
+ for(i = 0; i < NumPathNodes; i++){
+ if(pPathNodes[i].bOnGround && !lastOnGround)
+ LandingPoint = pPathNodes[i].t;
+ else if(!pPathNodes[i].bOnGround && lastOnGround)
+ TakeOffPoint = pPathNodes[i].t;
+ lastOnGround = pPathNodes[i].bOnGround;
+ }
+
+ // Animation
+ float time = 0.0f;
+ float position = 0.0f;
+ // Start on ground with slow speed
+ aPlaneLineBits[0].type = 1;
+ aPlaneLineBits[0].time = time;
+ aPlaneLineBits[0].position = position;
+ aPlaneLineBits[0].speed = TAXI_SPEED;
+ aPlaneLineBits[0].acceleration = 0.0f;
+ float dist = (TakeOffPoint-600.0f) - position;
+ time += dist/TAXI_SPEED;
+ position += dist;
+
+ // Accelerate to take off
+ aPlaneLineBits[1].type = 2;
+ aPlaneLineBits[1].time = time;
+ aPlaneLineBits[1].position = position;
+ aPlaneLineBits[1].speed = TAXI_SPEED;
+ aPlaneLineBits[1].acceleration = 33.0f/32.0f;
+ time += 600.0f/((CRUISE_SPEED+TAXI_SPEED)/2.0f);
+ position += 600.0f;
+
+ // Fly at cruise speed
+ aPlaneLineBits[2].type = 1;
+ aPlaneLineBits[2].time = time;
+ aPlaneLineBits[2].position = position;
+ aPlaneLineBits[2].speed = CRUISE_SPEED;
+ aPlaneLineBits[2].acceleration = 0.0f;
+ dist = LandingPoint - TakeOffPoint;
+ time += dist/CRUISE_SPEED;
+ position += dist;
+
+ // Brake after landing
+ aPlaneLineBits[3].type = 2;
+ aPlaneLineBits[3].time = time;
+ aPlaneLineBits[3].position = position;
+ aPlaneLineBits[3].speed = CRUISE_SPEED;
+ aPlaneLineBits[3].acceleration = -33.0f/32.0f;
+ time += 600.0f/((CRUISE_SPEED+TAXI_SPEED)/2.0f);
+ position += 600.0f;
+
+ // Taxi
+ aPlaneLineBits[4].type = 1;
+ aPlaneLineBits[4].time = time;
+ aPlaneLineBits[4].position = position;
+ aPlaneLineBits[4].speed = TAXI_SPEED;
+ aPlaneLineBits[4].acceleration = 0.0f;
+ time += (TotalLengthOfFlightPath - position)/TAXI_SPEED;
+
+ // end
+ aPlaneLineBits[5].time = time;
+ TotalDurationOfFlightPath = time;
+ }
+
+ // Dodo
+ if(pPath2Nodes == nil){
+ pPath2Nodes = LoadPath("data\\paths\\flight2.dat", NumPath2Nodes, TotalLengthOfFlightPath2, true);
+ TotalDurationOfFlightPath2 = TotalLengthOfFlightPath2/CRUISE_SPEED;
+ }
+
+ // Mission Cesna
+ if(pPath3Nodes == nil){
+ pPath3Nodes = LoadPath("data\\paths\\flight3.dat", NumPath3Nodes, TotalLengthOfFlightPath3, false);
+ TotalDurationOfFlightPath3 = TotalLengthOfFlightPath3/CRUISE_SPEED;
+ }
+
+ // Mission Cesna
+ if(pPath4Nodes == nil){
+ pPath4Nodes = LoadPath("data\\paths\\flight4.dat", NumPath4Nodes, TotalLengthOfFlightPath4, false);
+ TotalDurationOfFlightPath4 = TotalLengthOfFlightPath4/CRUISE_SPEED;
+ }
+
+ CStreaming::LoadAllRequestedModels(false);
+ CStreaming::RequestModel(MI_AIRTRAIN, 0);
+ CStreaming::LoadAllRequestedModels(false);
+
+ for(i = 0; i < 3; i++){
+ CPlane *plane = new CPlane(MI_AIRTRAIN, PERMANENT_VEHICLE);
+ plane->GetMatrix().SetTranslate(0.0f, 0.0f, 0.0f);
+ plane->m_status = STATUS_ABANDONED;
+ plane->bIsLocked = true;
+ plane->m_nPlaneId = i;
+ plane->m_nCurPathNode = 0;
+ CWorld::Add(plane);
+ }
+
+
+ CStreaming::RequestModel(MI_DEADDODO, 0);
+ CStreaming::LoadAllRequestedModels(false);
+
+ for(i = 0; i < 3; i++){
+ CPlane *plane = new CPlane(MI_DEADDODO, PERMANENT_VEHICLE);
+ plane->GetMatrix().SetTranslate(0.0f, 0.0f, 0.0f);
+ plane->m_status = STATUS_ABANDONED;
+ plane->bIsLocked = true;
+ plane->m_nPlaneId = i;
+ plane->m_nCurPathNode = 0;
+ CWorld::Add(plane);
+ }
+}
+
+void
+CPlane::Shutdown(void)
+{
+ delete[] pPathNodes;
+ delete[] pPath2Nodes;
+ delete[] pPath3Nodes;
+ delete[] pPath4Nodes;
+ pPathNodes = nil;
+ pPath2Nodes = nil;
+ pPath3Nodes = nil;
+ pPath4Nodes = nil;
+}
+
+CPlaneNode*
+CPlane::LoadPath(char const *filename, int32 &numNodes, float &totalLength, bool loop)
+{
+ int bp, lp;
+ int i;
+
+ CFileMgr::LoadFile(filename, work_buff, sizeof(work_buff), "r");
+ *gString = '\0';
+ for(bp = 0, lp = 0; work_buff[bp] != '\n'; bp++, lp++)
+ gString[lp] = work_buff[bp];
+ bp++;
+ gString[lp] = '\0';
+ sscanf(gString, "%d", &numNodes);
+ CPlaneNode *nodes = new CPlaneNode[numNodes];
+
+ for(i = 0; i < numNodes; i++){
+ *gString = '\0';
+ for(lp = 0; work_buff[bp] != '\n'; bp++, lp++)
+ gString[lp] = work_buff[bp];
+ bp++;
+ // BUG: game doesn't terminate string
+ gString[lp] = '\0';
+ sscanf(gString, "%f %f %f", &nodes[i].p.x, &nodes[i].p.y, &nodes[i].p.z);
+ }
+
+ // Calculate length of segments and path
+ totalLength = 0.0f;
+ for(i = 0; i < numNodes; i++){
+ nodes[i].t = totalLength;
+ float l = (nodes[(i+1) % numNodes].p - nodes[i].p).Magnitude2D();
+ if(!loop && i == numNodes-1)
+ l = 0.0f;
+ totalLength += l;
+ }
+
+ return nodes;
+}
+
+void
+CPlane::UpdatePlanes(void)
+{
+ int i, j;
+ uint32 time;
+ float t, deltaT;
+
+ if(CReplay::IsPlayingBack())
+ return;
+
+ // Jumbo jets
+ time = CTimer::GetTimeInMilliseconds();
+ for(i = 0; i < 3; i++){
+ t = TotalDurationOfFlightPath * (float)(time & 0x7FFFF)/0x80000;
+ // find current frame
+ for(j = 0; t > aPlaneLineBits[j+1].time; j++);
+
+ OldPlanePathPosition[i] = PlanePathPosition[i];
+ deltaT = t - aPlaneLineBits[j].time;
+ switch(aPlaneLineBits[j].type){
+ case 0: // standing still
+ PlanePathPosition[i] = aPlaneLineBits[j].position;
+ PlanePathSpeed[i] = 0.0f;
+ break;
+ case 1: // moving with constant speed
+ PlanePathPosition[i] = aPlaneLineBits[j].position + aPlaneLineBits[j].speed*deltaT;
+ PlanePathSpeed[i] = (TotalDurationOfFlightPath*1000.0f/0x80000) * aPlaneLineBits[j].speed;
+ break;
+ case 2: // accelerating/braking
+ PlanePathPosition[i] = aPlaneLineBits[j].position + (aPlaneLineBits[j].speed + aPlaneLineBits[j].acceleration*deltaT)*deltaT;
+ PlanePathSpeed[i] = (TotalDurationOfFlightPath*1000.0f/0x80000)*aPlaneLineBits[j].speed + 2.0f*aPlaneLineBits[j].acceleration*deltaT;
+ break;
+ }
+
+ // time offset for each plane
+ time += 0x80000/3;
+ }
+
+ time = CTimer::GetTimeInMilliseconds();
+
+ t = TotalDurationOfFlightPath2/0x80000;
+ PlanePath2Position[0] = CRUISE_SPEED * (time & 0x7FFFF)*t;
+ PlanePath2Position[1] = CRUISE_SPEED * ((time + 0x80000/3) & 0x7FFFF)*t;
+ PlanePath2Position[2] = CRUISE_SPEED * ((time + 0x80000/3*2) & 0x7FFFF)*t;
+ PlanePath2Speed[0] = CRUISE_SPEED*t;
+ PlanePath2Speed[1] = CRUISE_SPEED*t;
+ PlanePath2Speed[2] = CRUISE_SPEED*t;
+
+ if(CesnaMissionStatus == CESNA_STATUS_FLYING){
+ PlanePath3Speed = CRUISE_SPEED*TotalDurationOfFlightPath3/0x20000;
+ PlanePath3Position = PlanePath3Speed * ((time - CesnaMissionStartTime) & 0x1FFFF);
+ if(time - CesnaMissionStartTime >= 128072)
+ CesnaMissionStatus = CESNA_STATUS_LANDED;
+ }
+
+ if(DropOffCesnaMissionStatus == CESNA_STATUS_FLYING){
+ PlanePath4Speed = CRUISE_SPEED*TotalDurationOfFlightPath4/0x80000;
+ PlanePath4Position = PlanePath4Speed * ((time - DropOffCesnaMissionStartTime) & 0x7FFFF);
+ if(time - DropOffCesnaMissionStartTime >= 521288)
+ DropOffCesnaMissionStatus = CESNA_STATUS_LANDED;
+ }
+}
+
+bool
+CPlane::TestRocketCollision(CVector *rocketPos)
+{
+ int i;
+
+ i = CPools::GetVehiclePool()->GetSize();
+ while(--i >= 0){
+ CPlane *plane = (CPlane*)CPools::GetVehiclePool()->GetSlot(i);
+ if(plane &&
+#ifdef EXPLODING_AIRTRAIN
+ (plane->GetModelIndex() == MI_AIRTRAIN || plane->GetModelIndex() == MI_DODO) &&
+#else
+ plane->GetModelIndex() != MI_AIRTRAIN && plane->GetModelIndex() == MI_DODO && // strange check
+#endif
+ !plane->m_bHasBeenHit && (*rocketPos - plane->GetPosition()).Magnitude() < 25.0f){
+ plane->m_nFrameWhenHit = CTimer::GetFrameCounter();
+ plane->m_bHasBeenHit = true;
+ CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->RegisterCrime_Immediately(CRIME_DESTROYED_CESSNA,
+ plane->GetPosition(), i+1983, false);
+ return true;
+ }
+ }
+ return false;
+}
+
+// BUG: not in CPlane in the game
+void
+CPlane::CreateIncomingCesna(void)
+{
+ if(CesnaMissionStatus == CESNA_STATUS_FLYING){
+ CWorld::Remove(pDrugRunCesna);
+ delete pDrugRunCesna;
+ pDrugRunCesna = nil;
+ }
+ pDrugRunCesna = new CPlane(MI_DEADDODO, PERMANENT_VEHICLE);
+ pDrugRunCesna->GetMatrix().SetTranslate(0.0f, 0.0f, 0.0f);
+ pDrugRunCesna->m_status = STATUS_ABANDONED;
+ pDrugRunCesna->bIsLocked = true;
+ pDrugRunCesna->m_nPlaneId = 0;
+ pDrugRunCesna->m_nCurPathNode = 0;
+ pDrugRunCesna->m_bIsDrugRunCesna = true;
+ CWorld::Add(pDrugRunCesna);
+
+ CesnaMissionStatus = CESNA_STATUS_FLYING;
+ CesnaMissionStartTime = CTimer::GetTimeInMilliseconds();
+ printf("CPlane::CreateIncomingCesna(void)\n");
+}
+
+void
+CPlane::CreateDropOffCesna(void)
+{
+ if(DropOffCesnaMissionStatus == CESNA_STATUS_FLYING){
+ CWorld::Remove(pDropOffCesna);
+ delete pDropOffCesna;
+ pDropOffCesna = nil;
+ }
+ pDropOffCesna = new CPlane(MI_DEADDODO, PERMANENT_VEHICLE);
+ pDropOffCesna->GetMatrix().SetTranslate(0.0f, 0.0f, 0.0f);
+ pDropOffCesna->m_status = STATUS_ABANDONED;
+ pDropOffCesna->bIsLocked = true;
+ pDropOffCesna->m_nPlaneId = 0;
+ pDropOffCesna->m_nCurPathNode = 0;
+ pDropOffCesna->m_bIsDropOffCesna = true;
+ CWorld::Add(pDropOffCesna);
+
+ DropOffCesnaMissionStatus = CESNA_STATUS_FLYING;
+ DropOffCesnaMissionStartTime = CTimer::GetTimeInMilliseconds();
+ printf("CPlane::CreateDropOffCesna(void)\n");
+}
+
+CVector CPlane::FindDrugPlaneCoordinates(void) { return pDrugRunCesna->GetPosition(); }
+CVector CPlane::FindDropOffCesnaCoordinates(void) { return pDrugRunCesna->GetPosition(); }
+bool CPlane::HasCesnaLanded(void) { return CesnaMissionStatus == CESNA_STATUS_LANDED; }
+bool CPlane::HasCesnaBeenDestroyed(void) { return CesnaMissionStatus == CESNA_STATUS_DESTROYED; }
+bool CPlane::HasDropOffCesnaBeenShotDown(void) { return DropOffCesnaMissionStatus == CESNA_STATUS_DESTROYED; }
+
+
+class CPlane_ : public CPlane
+{
+public:
+ void ctor(int32 id, uint8 CreatedBy) { ::new (this) CPlane(id, CreatedBy); }
+ void dtor(void) { CPlane::~CPlane(); }
+};
+
+STARTPATCHES
+ InjectHook(0x54B170, &CPlane_::ctor, PATCH_JUMP);
+ InjectHook(0x54B270, &CPlane_::dtor, PATCH_JUMP);
+ InjectHook(0x54B820, CPlane::InitPlanes, PATCH_JUMP);
+ InjectHook(0x54BCD0, CPlane::Shutdown, PATCH_JUMP);
+ InjectHook(0x54BD50, CPlane::LoadPath, PATCH_JUMP);
+ InjectHook(0x54BEC0, CPlane::UpdatePlanes, PATCH_JUMP);
+ InjectHook(0x54DE90, CPlane::TestRocketCollision, PATCH_JUMP);
+ InjectHook(0x54E000, CPlane::CreateIncomingCesna, PATCH_JUMP);
+ InjectHook(0x54E160, CPlane::CreateDropOffCesna, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp
index 775689f7..dd15d910 100644
--- a/src/vehicles/Vehicle.cpp
+++ b/src/vehicles/Vehicle.cpp
@@ -273,7 +273,7 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
right = -contactSpeedRight/wheelsOnGround;
if(wheelStatus == WHEEL_STATUS_BURST){
- float fwdspeed = min(contactSpeedFwd, 0.3f);
+ float fwdspeed = Min(contactSpeedFwd, 0.3f);
right += fwdspeed * CGeneral::GetRandomNumberInRange(-0.1f, 0.1f);
}
}
@@ -363,7 +363,7 @@ CVehicle::ProcessWheelRotation(tWheelState state, const CVector &fwd, const CVec
void
CVehicle::ExtinguishCarFire(void)
{
- m_fHealth = max(m_fHealth, 300.0f);
+ m_fHealth = Max(m_fHealth, 300.0f);
if(m_pCarFire)
m_pCarFire->Extinguish();
if(IsCar()){
@@ -638,13 +638,13 @@ CVehicle::SetDriver(CPed *driver)
if(bFreebies && driver == FindPlayerPed()){
if(GetModelIndex() == MI_AMBULAN)
- FindPlayerPed()->m_fHealth = min(FindPlayerPed()->m_fHealth + 20.0f, 100.0f);
+ FindPlayerPed()->m_fHealth = Min(FindPlayerPed()->m_fHealth + 20.0f, 100.0f);
else if(GetModelIndex() == MI_TAXI)
CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 25;
else if(GetModelIndex() == MI_POLICE)
driver->GiveWeapon(WEAPONTYPE_SHOTGUN, 5);
else if(GetModelIndex() == MI_ENFORCER)
- driver->m_fArmour = max(driver->m_fArmour, 100.0f);
+ driver->m_fArmour = Max(driver->m_fArmour, 100.0f);
else if(GetModelIndex() == MI_CABBIE || GetModelIndex() == MI_BORGNINE)
CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 25;
bFreebies = false;