summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/animation/AnimBlendAssociation.cpp15
-rw-r--r--src/animation/AnimBlendAssociation.h4
-rw-r--r--src/animation/AnimBlendClumpData.cpp14
-rw-r--r--src/animation/AnimBlendClumpData.h4
-rw-r--r--src/audio/AudioManager.cpp508
-rw-r--r--src/audio/AudioManager.h4
-rw-r--r--src/audio/AudioScriptObject.cpp51
-rw-r--r--src/audio/AudioScriptObject.h251
-rw-r--r--src/audio/DMAudio.h3
-rw-r--r--src/audio/MusicManager.cpp5
-rw-r--r--src/audio/PoliceRadio.h2
-rw-r--r--src/control/AutoPilot.cpp4
-rw-r--r--src/control/Bridge.h3
-rw-r--r--src/control/CarAI.cpp3
-rw-r--r--src/control/CarCtrl.cpp12
-rw-r--r--src/control/Curves.cpp10
-rw-r--r--src/control/Darkel.cpp17
-rw-r--r--src/control/Darkel.h2
-rw-r--r--src/control/GameLogic.cpp3
-rw-r--r--src/control/Gangs.cpp13
-rw-r--r--src/control/Gangs.h8
-rw-r--r--src/control/Garages.cpp2374
-rw-r--r--src/control/Garages.h176
-rw-r--r--src/control/PathFind.cpp17
-rw-r--r--src/control/PathFind.h9
-rw-r--r--src/control/Phones.cpp1
-rw-r--r--src/control/Pickups.cpp32
-rw-r--r--src/control/Remote.cpp2
-rw-r--r--src/control/Replay.cpp127
-rw-r--r--src/control/Replay.h10
-rw-r--r--src/control/RoadBlocks.cpp34
-rw-r--r--src/control/RoadBlocks.h4
-rw-r--r--src/control/SceneEdit.cpp6
-rw-r--r--src/control/SceneEdit.h6
-rw-r--r--src/control/Script.cpp57
-rw-r--r--src/control/Script.h2
-rw-r--r--src/core/AnimViewer.cpp7
-rw-r--r--src/core/Cam.cpp5292
-rw-r--r--src/core/Camera.cpp4287
-rw-r--r--src/core/Camera.h349
-rw-r--r--src/core/CdStream.cpp1
-rw-r--r--src/core/CdStream.h1
-rw-r--r--src/core/Collision.cpp19
-rw-r--r--src/core/Collision.h4
-rw-r--r--src/core/ControllerConfig.cpp10
-rw-r--r--src/core/CutsceneMgr.cpp548
-rw-r--r--src/core/CutsceneMgr.h1
-rw-r--r--src/core/Debug.cpp131
-rw-r--r--src/core/Debug.h25
-rw-r--r--src/core/EventList.cpp9
-rw-r--r--src/core/EventList.h2
-rw-r--r--src/core/Fire.cpp424
-rw-r--r--src/core/Fire.h37
-rw-r--r--src/core/Frontend.cpp364
-rw-r--r--src/core/Frontend.h27
-rw-r--r--src/core/Game.cpp448
-rw-r--r--src/core/Game.h20
-rw-r--r--src/core/General.h2
-rw-r--r--src/core/MenuScreens.h3
-rw-r--r--src/core/Pad.cpp76
-rw-r--r--src/core/Pad.h19
-rw-r--r--src/core/Placeable.cpp2
-rw-r--r--src/core/PlayerInfo.cpp3
-rw-r--r--src/core/PlayerSkin.cpp72
-rw-r--r--src/core/Radar.cpp179
-rw-r--r--src/core/RwHelper.cpp20
-rw-r--r--src/core/RwHelper.h9
-rw-r--r--src/core/Stats.h2
-rw-r--r--src/core/Streaming.cpp3
-rw-r--r--src/core/Timer.cpp9
-rw-r--r--src/core/Timer.h14
-rw-r--r--src/core/TxdStore.cpp4
-rw-r--r--src/core/TxdStore.h2
-rw-r--r--src/core/Wanted.cpp125
-rw-r--r--src/core/Wanted.h4
-rw-r--r--src/core/World.cpp87
-rw-r--r--src/core/World.h9
-rw-r--r--src/core/Zones.cpp1
-rw-r--r--src/core/common.h18
-rw-r--r--src/core/config.h21
-rw-r--r--src/core/main.cpp79
-rw-r--r--src/core/main.h1
-rw-r--r--src/core/obrstr.cpp119
-rw-r--r--src/core/obrstr.h9
-rw-r--r--src/core/patcher.cpp57
-rw-r--r--src/core/patcher.h72
-rw-r--r--src/core/re3.cpp46
-rw-r--r--src/core/timebars.cpp121
-rw-r--r--src/core/timebars.h6
-rw-r--r--src/entities/Building.cpp2
-rw-r--r--src/entities/Entity.cpp2
-rw-r--r--src/math/Vector.h8
-rw-r--r--src/modelinfo/VehicleModelInfo.cpp2
-rw-r--r--src/modelinfo/VehicleModelInfo.h1
-rw-r--r--src/objects/DummyObject.cpp2
-rw-r--r--src/objects/Object.cpp7
-rw-r--r--src/objects/Object.h6
-rw-r--r--src/objects/Projectile.cpp2
-rw-r--r--src/peds/CivilianPed.cpp4
-rw-r--r--src/peds/CopPed.cpp485
-rw-r--r--src/peds/CopPed.h5
-rw-r--r--src/peds/EmergencyPed.cpp3
-rw-r--r--src/peds/Ped.cpp60
-rw-r--r--src/peds/Ped.h11
-rw-r--r--src/peds/PedIK.cpp2
-rw-r--r--src/peds/PedIK.h3
-rw-r--r--src/peds/PedPlacement.cpp1
-rw-r--r--src/peds/PedPlacement.h2
-rw-r--r--src/peds/PlayerPed.cpp92
-rw-r--r--src/peds/PlayerPed.h6
-rw-r--r--src/peds/Population.cpp12
-rw-r--r--src/peds/Population.h4
-rw-r--r--src/render/Coronas.cpp3
-rw-r--r--src/render/Font.cpp1151
-rw-r--r--src/render/Font.h38
-rw-r--r--src/render/Glass.cpp720
-rw-r--r--src/render/Glass.h51
-rw-r--r--src/render/Hud.cpp88
-rw-r--r--src/render/Renderer.cpp6
-rw-r--r--src/render/Rubbish.cpp1
-rw-r--r--src/render/Rubbish.h1
-rw-r--r--src/render/Shadows.h1
-rw-r--r--src/render/Skidmarks.cpp1
-rw-r--r--src/render/Skidmarks.h1
-rw-r--r--src/render/SpecialFX.cpp1
-rw-r--r--src/render/SpecialFX.h1
-rw-r--r--src/render/WaterCannon.cpp320
-rw-r--r--src/render/WaterCannon.h37
-rw-r--r--src/render/WeaponEffects.cpp113
-rw-r--r--src/render/WeaponEffects.h30
-rw-r--r--src/save/GenericGameStorage.cpp47
-rw-r--r--src/save/PCSave.cpp15
-rw-r--r--src/skel/win/resource.h1
-rw-r--r--src/skel/win/win.cpp2
-rw-r--r--src/skel/win/win.rc12
-rw-r--r--src/text/Pager.h28
-rw-r--r--src/text/Text.cpp547
-rw-r--r--src/vehicles/Automobile.cpp23
-rw-r--r--src/vehicles/Boat.cpp2
-rw-r--r--src/vehicles/Heli.cpp3
-rw-r--r--src/vehicles/Plane.cpp3
-rw-r--r--src/vehicles/Train.cpp3
-rw-r--r--src/vehicles/Vehicle.cpp212
-rw-r--r--src/vehicles/Vehicle.h4
-rw-r--r--src/weapons/Explosion.cpp2
-rw-r--r--src/weapons/ShotInfo.cpp140
-rw-r--r--src/weapons/ShotInfo.h23
-rw-r--r--src/weapons/Weapon.cpp2
-rw-r--r--src/weapons/Weapon.h15
-rw-r--r--src/weapons/WeaponInfo.cpp2
-rw-r--r--src/weapons/WeaponInfo.h7
151 files changed, 17520 insertions, 3852 deletions
diff --git a/src/animation/AnimBlendAssociation.cpp b/src/animation/AnimBlendAssociation.cpp
index ec42191b..246322ba 100644
--- a/src/animation/AnimBlendAssociation.cpp
+++ b/src/animation/AnimBlendAssociation.cpp
@@ -203,6 +203,15 @@ CAnimBlendAssociation::UpdateBlend(float timeDelta)
return true;
}
+#include <new>
+
+class CAnimBlendAssociation_ : public CAnimBlendAssociation
+{
+public:
+ CAnimBlendAssociation *ctor1(void) { return ::new (this) CAnimBlendAssociation(); }
+ CAnimBlendAssociation *ctor2(CAnimBlendAssociation &other) { return ::new (this) CAnimBlendAssociation(other); }
+ void dtor(void) { this->CAnimBlendAssociation::~CAnimBlendAssociation(); }
+};
STARTPATCHES
InjectHook(0x4016A0, &CAnimBlendAssociation::AllocateAnimBlendNodeArray, PATCH_JUMP);
@@ -219,7 +228,7 @@ STARTPATCHES
InjectHook(0x4031F0, &CAnimBlendAssociation::UpdateTime, PATCH_JUMP);
InjectHook(0x4032B0, &CAnimBlendAssociation::UpdateBlend, PATCH_JUMP);
- InjectHook(0x401460, &CAnimBlendAssociation::ctor1, PATCH_JUMP);
- InjectHook(0x4014C0, &CAnimBlendAssociation::ctor2, PATCH_JUMP);
- InjectHook(0x401520, &CAnimBlendAssociation::dtor, PATCH_JUMP);
+ InjectHook(0x401460, &CAnimBlendAssociation_::ctor1, PATCH_JUMP);
+ InjectHook(0x4014C0, &CAnimBlendAssociation_::ctor2, PATCH_JUMP);
+ InjectHook(0x401520, &CAnimBlendAssociation_::dtor, PATCH_JUMP);
ENDPATCHES
diff --git a/src/animation/AnimBlendAssociation.h b/src/animation/AnimBlendAssociation.h
index aec28f56..d35db1db 100644
--- a/src/animation/AnimBlendAssociation.h
+++ b/src/animation/AnimBlendAssociation.h
@@ -85,9 +85,5 @@ public:
static CAnimBlendAssociation *FromLink(CAnimBlendLink *l) {
return (CAnimBlendAssociation*)((uint8*)l - offsetof(CAnimBlendAssociation, link));
}
-
- CAnimBlendAssociation *ctor1(void) { return ::new (this) CAnimBlendAssociation(); }
- CAnimBlendAssociation *ctor2(CAnimBlendAssociation &other) { return ::new (this) CAnimBlendAssociation(other); }
- void dtor(void) { this->CAnimBlendAssociation::~CAnimBlendAssociation(); }
};
static_assert(sizeof(CAnimBlendAssociation) == 0x40, "CAnimBlendAssociation: error");
diff --git a/src/animation/AnimBlendClumpData.cpp b/src/animation/AnimBlendClumpData.cpp
index 06625eb5..cc4281d6 100644
--- a/src/animation/AnimBlendClumpData.cpp
+++ b/src/animation/AnimBlendClumpData.cpp
@@ -36,9 +36,19 @@ CAnimBlendClumpData::ForAllFrames(void (*cb)(AnimBlendFrameData*, void*), void *
cb(&frames[i], arg);
}
+#include <new>
+
+class CAnimBlendClumpData_ : public CAnimBlendClumpData
+{
+public:
+ CAnimBlendClumpData *ctor(void) { return ::new (this) CAnimBlendClumpData(); }
+ void dtor(void) { this->CAnimBlendClumpData::~CAnimBlendClumpData(); }
+};
+
+
STARTPATCHES
- InjectHook(0x401880, &CAnimBlendClumpData::ctor, PATCH_JUMP);
- InjectHook(0x4018B0, &CAnimBlendClumpData::dtor, PATCH_JUMP);
+ InjectHook(0x401880, &CAnimBlendClumpData_::ctor, PATCH_JUMP);
+ InjectHook(0x4018B0, &CAnimBlendClumpData_::dtor, PATCH_JUMP);
InjectHook(0x4018F0, &CAnimBlendClumpData::SetNumberOfFrames, PATCH_JUMP);
InjectHook(0x401930, &CAnimBlendClumpData::ForAllFrames, PATCH_JUMP);
ENDPATCHES
diff --git a/src/animation/AnimBlendClumpData.h b/src/animation/AnimBlendClumpData.h
index df2fbc56..1c8c391d 100644
--- a/src/animation/AnimBlendClumpData.h
+++ b/src/animation/AnimBlendClumpData.h
@@ -49,9 +49,5 @@ public:
void SetNumberOfBones(int n) { SetNumberOfFrames(n); }
#endif
void ForAllFrames(void (*cb)(AnimBlendFrameData*, void*), void *arg);
-
-
- CAnimBlendClumpData *ctor(void) { return ::new (this) CAnimBlendClumpData(); }
- void dtor(void) { this->CAnimBlendClumpData::~CAnimBlendClumpData(); }
};
static_assert(sizeof(CAnimBlendClumpData) == 0x14, "CAnimBlendClumpData: error");
diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp
index 539c9e91..8e8d024a 100644
--- a/src/audio/AudioManager.cpp
+++ b/src/audio/AudioManager.cpp
@@ -20,6 +20,7 @@
#include "MusicManager.h"
#include "Pad.h"
#include "Ped.h"
+#include "Fire.h"
#include "Physical.h"
#include "Placeable.h"
#include "Plane.h"
@@ -67,6 +68,7 @@ const int molotovVolume = 50;
const int rainOnVehicleIntensity = 22;
const int reverseGearIntensity = 30;
+const int engineDamageIntensity = 40;
const bool hornPatternsArray[8][44] = {
@@ -416,7 +418,7 @@ cAudioManager::AddReleasingSounds()
}
sample.field_56 = 0;
}
- memcpy(&m_sQueueSample, &sample, sizeof(sample));
+ memcpy(&m_sQueueSample, &sample, sizeof(tSound));
AddSampleToRequestedQueue();
}
}
@@ -2742,11 +2744,215 @@ cAudioManager::PreTerminateGameSpecificShutdown()
}
}
-WRAPPER
void
cAudioManager::ProcessActiveQueues()
{
- EAXJMP(0x57BA60);
+ bool flag;
+ float position2;
+ float position1;
+
+ uint32 v28;
+ uint32 v29;
+
+ float x;
+ float usedX;
+ float usedY;
+ float usedZ;
+
+ uint8 vol;
+ uint8 emittingVol;
+ CVector position;
+
+ for (int32 i = 0; i < m_bActiveSamples; i++) {
+ m_asSamples[m_bActiveSampleQueue][i].m_bIsProcessed = 0;
+ m_asActiveSamples[i].m_bIsProcessed = 0;
+ }
+
+ for (int32 i = 0; i < m_bSampleRequestQueuesStatus[m_bActiveSampleQueue]; ++i) {
+ tSound& sample = m_asSamples[m_bActiveSampleQueue][m_abSampleQueueIndexTable[m_bActiveSampleQueue][i]];
+ if (sample.m_nSampleIndex != NO_SAMPLE) {
+ for (int32 j = 0; j < m_bActiveSamples; ++j) {
+ if (sample.m_nEntityIndex == m_asActiveSamples[j].m_nEntityIndex &&
+ sample.m_counter == m_asActiveSamples[j].m_counter &&
+ sample.m_nSampleIndex == m_asActiveSamples[j].m_nSampleIndex) {
+ if (sample.m_nLoopCount) {
+ if (m_FrameCounter & 1) {
+ flag = !!(j & 1);
+ }
+ else {
+ flag = !(j & 1);
+ }
+ if (flag && !SampleManager.GetChannelUsedFlag(j)) {
+ sample.m_bLoopEnded = 1;
+ m_asActiveSamples[j].m_bLoopEnded = 1;
+ m_asActiveSamples[j].m_nSampleIndex = NO_SAMPLE;
+ m_asActiveSamples[j].m_nEntityIndex = AEHANDLE_NONE;
+ continue;
+ }
+ }
+ sample.m_bIsProcessed = 1;
+ m_asActiveSamples[j].m_bIsProcessed = 1;
+ sample.field_88 = -1;
+ if (!sample.field_56) {
+ if (sample.m_bIsDistant) {
+ if (field_4) {
+ emittingVol = 2 * min(63, sample.m_bEmittingVolume);
+ }
+ else {
+ emittingVol = sample.m_bEmittingVolume;
+ }
+ SampleManager.SetChannelFrequency(j, sample.m_nFrequency);
+ SampleManager.SetChannelEmittingVolume(j, emittingVol);
+ }
+ else {
+ m_asActiveSamples[j].m_fDistance = sample.m_fDistance;
+ position2 = sample.m_fDistance;
+ position1 = m_asActiveSamples[j].m_fDistance;
+ sample.m_nFrequency = ComputeDopplerEffectedFrequency(
+ sample.m_nFrequency, position1, position2, sample.field_48);
+ if (sample.m_nFrequency != m_asActiveSamples[j].m_nFrequency) {
+ int32 freq;
+ if (sample.m_nFrequency <=
+ m_asActiveSamples[j].m_nFrequency) {
+ freq = max(sample.m_nFrequency,
+ m_asActiveSamples[j].m_nFrequency -
+ 6000);
+ }
+ else {
+ freq = min(sample.m_nFrequency,
+ m_asActiveSamples[j].m_nFrequency +
+ 6000);
+ }
+ m_asActiveSamples[j].m_nFrequency = freq;
+ SampleManager.SetChannelFrequency(j, freq);
+ }
+
+ if (sample.m_bEmittingVolume !=
+ m_asActiveSamples[j].m_bEmittingVolume) {
+ if (sample.m_bEmittingVolume <=
+ m_asActiveSamples[j].m_bEmittingVolume) {
+ vol = max(
+ m_asActiveSamples[j].m_bEmittingVolume - 10,
+ sample.m_bEmittingVolume);
+ }
+ else {
+ vol = min(
+ m_asActiveSamples[j].m_bEmittingVolume + 10,
+ sample.m_bEmittingVolume);
+ }
+
+ uint8 emittingVol;
+ if (field_4) {
+ emittingVol = 2 * min(63, vol);
+ }
+ else {
+ emittingVol = vol;
+ }
+ SampleManager.SetChannelEmittingVolume(j, emittingVol);
+ m_asActiveSamples[j].m_bEmittingVolume = vol;
+ }
+ TranslateEntity(&sample.m_vecPos, &position);
+ SampleManager.SetChannel3DPosition(j, position.x, position.y,
+ position.z);
+ SampleManager.SetChannel3DDistances(
+ j, sample.m_fSoundIntensity,
+ 0.25f * sample.m_fSoundIntensity);
+ }
+ SampleManager.SetChannelReverbFlag(j, sample.m_bReverbFlag);
+ continue;
+ }
+ sample.m_bIsProcessed = 0;
+ m_asActiveSamples[j].m_bIsProcessed = 0;
+ break;
+ }
+ }
+ }
+ }
+ for (int32 i = 0; i < m_bActiveSamples; i++) {
+ if (m_asActiveSamples[i].m_nSampleIndex != NO_SAMPLE && !m_asActiveSamples[i].m_bIsProcessed) {
+ SampleManager.StopChannel(i);
+ m_asActiveSamples[i].m_nSampleIndex = NO_SAMPLE;
+ m_asActiveSamples[i].m_nEntityIndex = -5;
+ }
+ }
+ for (int32 i = 0; i < m_bSampleRequestQueuesStatus[m_bActiveSampleQueue]; ++i) {
+
+ tSound& sample = m_asSamples[m_bActiveSampleQueue][m_abSampleQueueIndexTable[m_bActiveSampleQueue][i]];
+ if (!sample.m_bIsProcessed && !sample.m_bLoopEnded &&
+ m_asAudioEntities[sample.m_nEntityIndex].m_bIsUsed && sample.m_nSampleIndex < NO_SAMPLE) {
+ if (sample.m_counter > 255 && sample.m_nLoopCount && sample.m_bLoopsRemaining) {
+ --sample.m_bLoopsRemaining;
+ sample.field_76 = 1;
+ }
+ else {
+ for (int32 j = 0; j < m_bActiveSamples; ++j) {
+ if (!m_asActiveSamples[j].m_bIsProcessed) {
+ if (sample.m_nLoopCount) {
+ v28 = sample.m_nFrequency / field_19192;
+ v29 = sample.m_nLoopCount *
+ SampleManager.GetSampleLength(sample.m_nSampleIndex);
+ if (v28 == 0) continue;
+ sample.field_76 = v29 / v28 + 1;
+ }
+ memcpy(&m_asActiveSamples[j], &sample, sizeof(tSound));
+ if (!m_asActiveSamples[j].m_bIsDistant)
+ TranslateEntity(&m_asActiveSamples[j].m_vecPos, &position);
+ if (field_4) {
+ emittingVol =
+ 2 * min(63, m_asActiveSamples[j].m_bEmittingVolume);
+ }
+ else {
+ emittingVol = m_asActiveSamples[j].m_bEmittingVolume;
+ }
+ if (SampleManager.InitialiseChannel(j,
+ m_asActiveSamples[j].m_nSampleIndex,
+ m_asActiveSamples[j].m_bBankIndex)) {
+ SampleManager.SetChannelFrequency(
+ j, m_asActiveSamples[j].m_nFrequency);
+ SampleManager.SetChannelEmittingVolume(j, emittingVol);
+ SampleManager.SetChannelLoopPoints(
+ j, m_asActiveSamples[j].m_nLoopStart,
+ m_asActiveSamples[j].m_nLoopEnd);
+ SampleManager.SetChannelLoopCount(
+ j, m_asActiveSamples[j].m_nLoopCount);
+ SampleManager.SetChannelReverbFlag(
+ j, m_asActiveSamples[j].m_bReverbFlag);
+ if (m_asActiveSamples[j].m_bIsDistant) {
+ uint8 offset = m_asActiveSamples[j].m_bOffset;
+ if (offset == 63) {
+ x = 0.f;
+ }
+ else if (offset >= 63) {
+ x = (offset - 63) * 1000.f / 63;
+ }
+ else {
+ x = -(63 - offset) * 1000.f / 63;
+ }
+ usedX = x;
+ usedY = 0.f;
+ usedZ = 0.f;
+ m_asActiveSamples[j].m_fSoundIntensity = 100000.0f;
+ }
+ else {
+ usedX = position.x;
+ usedY = position.y;
+ usedZ = position.z;
+ }
+ SampleManager.SetChannel3DPosition(j, usedX, usedY, usedZ);
+ SampleManager.SetChannel3DDistances(
+ j, m_asActiveSamples[j].m_fSoundIntensity,
+ 0.25f * m_asActiveSamples[j].m_fSoundIntensity);
+ SampleManager.StartChannel(j);
+ }
+ m_asActiveSamples[j].m_bIsProcessed = 1;
+ sample.m_bIsProcessed = 1;
+ sample.field_88 = -1;
+ break;
+ }
+ }
+ }
+ }
+ }
}
bool
@@ -3056,7 +3262,7 @@ cAudioManager::ProcessBridgeMotor()
m_sQueueSample.m_bVolume = ComputeVolume(maxVolume, bridgeIntensity, m_sQueueSample.m_fDistance);
if(m_sQueueSample.m_bVolume) {
m_sQueueSample.m_counter = 1;
- m_sQueueSample.m_nSampleIndex = SFX_FISHING_BOAT_IDLE;
+ m_sQueueSample.m_nSampleIndex = SFX_FISHING_BOAT_IDLE; // todo check sfx name
m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
m_sQueueSample.m_bIsDistant = false;
m_sQueueSample.field_16 = 1;
@@ -3127,7 +3333,7 @@ cAudioManager::ProcessBridgeWarning()
m_sQueueSample.m_bVolume = ComputeVolume(100, 450.f, m_sQueueSample.m_fDistance);
if(m_sQueueSample.m_bVolume) {
m_sQueueSample.m_counter = 0;
- m_sQueueSample.m_nSampleIndex = 457;
+ m_sQueueSample.m_nSampleIndex = SFX_BRIDGE_OPEN_WARNING;
m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
m_sQueueSample.m_bIsDistant = false;
m_sQueueSample.field_16 = 1;
@@ -3153,7 +3359,7 @@ cAudioManager::ProcessCarBombTick(cVehicleParams *params)
{
CAutomobile *automobile;
- if(params->m_fDistance >= 1600.f) return false;
+ if(params->m_fDistance >= SQR(40.f)) return false;
automobile = (CAutomobile *)params->m_pVehicle;
if(automobile->bEngineOn && automobile->m_bombType == CARBOMB_TIMEDACTIVE) {
CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
@@ -3410,11 +3616,11 @@ cAudioManager::ProcessEngineDamage(cVehicleParams *params)
uint8 engineStatus;
uint8 emittingVolume;
- if(params->m_fDistance >= 1600.f) return false;
+ if(params->m_fDistance >= SQR(engineDamageIntensity)) return false;
veh = (CAutomobile *)params->m_pVehicle;
if(veh->bEngineOn) {
engineStatus = veh->Damage.GetEngineStatus();
- if(engineStatus > 250u || engineStatus < 100) return true;
+ if(engineStatus > 250 || engineStatus < 100) return true;
if(engineStatus < 225) {
m_sQueueSample.m_nSampleIndex = SFX_JUMBO_TAXI;
emittingVolume = 6;
@@ -3427,7 +3633,7 @@ cAudioManager::ProcessEngineDamage(cVehicleParams *params)
m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CAR_ON_FIRE);
}
CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
- m_sQueueSample.m_bVolume = ComputeVolume(emittingVolume, 40.f, m_sQueueSample.m_fDistance);
+ m_sQueueSample.m_bVolume = ComputeVolume(emittingVolume, engineDamageIntensity, m_sQueueSample.m_fDistance);
if(m_sQueueSample.m_bVolume) {
m_sQueueSample.m_counter = 28;
m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
@@ -3438,7 +3644,7 @@ cAudioManager::ProcessEngineDamage(cVehicleParams *params)
SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
m_sQueueSample.field_48 = 2.0f;
- m_sQueueSample.m_fSoundIntensity = 40.0f;
+ m_sQueueSample.m_fSoundIntensity = engineDamageIntensity;
m_sQueueSample.field_56 = 0;
m_sQueueSample.field_76 = 3;
m_sQueueSample.m_bReverbFlag = true;
@@ -3534,7 +3740,7 @@ cAudioManager::ProcessExplosions(int32 explosion)
CVector *pos;
float distSquared;
- for(uint8 i = 0; i < 48; i++) {
+ for(uint8 i = 0; i < ARRAY_SIZE(gaExplosion); i++) {
if(CExplosion::GetExplosionActiveCounter(i) == 1) {
CExplosion::ResetExplosionActiveCounter(i);
type = CExplosion::GetExplosionType(i);
@@ -3732,7 +3938,7 @@ cAudioManager::ProcessFrontEnd()
break;
case SOUND_GARAGE_NO_MONEY:
case SOUND_GARAGE_BAD_VEHICLE:
- case SOUND_3C:
+ case SOUND_GARAGE_BOMB_ALREADY_SET:
m_sQueueSample.m_nSampleIndex = SFX_PICKUP_ERROR_LEFT;
stereo = true;
break;
@@ -3889,7 +4095,7 @@ cAudioManager::ProcessGarages()
CalculateDistance(distCalculated, distSquared); \
m_sQueueSample.m_bVolume = ComputeVolume(60, 80.f, m_sQueueSample.m_fDistance); \
if(m_sQueueSample.m_bVolume) { \
- if(CGarages::Garages[i].m_eGarageType == GARAGE_CRUSHER) { \
+ if(CGarages::aGarages[i].m_eGarageType == GARAGE_CRUSHER) { \
m_sQueueSample.m_nSampleIndex = SFX_COL_CAR_PANEL_2; \
m_sQueueSample.m_nFrequency = 6735; \
} else if(m_asAudioEntities[m_sQueueSample.m_nEntityIndex] \
@@ -3905,7 +4111,7 @@ cAudioManager::ProcessGarages()
m_sQueueSample.m_bEmittingVolume = 60; \
m_sQueueSample.field_48 = 0.0f; \
m_sQueueSample.m_fSoundIntensity = 80.0f; \
- m_sQueueSample.field_16 = 4; \
+ /*m_sQueueSample.field_16 = 4;*/ \
m_sQueueSample.m_bReverbFlag = true; \
/*m_sQueueSample.m_bReverbFlag = true;*/ \
m_sQueueSample.m_bIsDistant = false; \
@@ -3915,7 +4121,7 @@ cAudioManager::ProcessGarages()
m_sQueueSample.m_nLoopEnd = -1; \
m_sQueueSample.m_counter = iSound++; \
if(iSound < 32) iSound = 32; \
- m_sQueueSample.m_bRequireReflection = 1; \
+ m_sQueueSample.m_bRequireReflection = true; \
AddSampleToRequestedQueue(); \
} \
} \
@@ -3925,20 +4131,20 @@ cAudioManager::ProcessGarages()
}
for(uint32 i = 0; i < CGarages::NumGarages; ++i) {
- if(CGarages::Garages[i].m_eGarageType == GARAGE_NONE) continue;
- entity = CGarages::Garages[i].m_pDoor1;
+ if(CGarages::aGarages[i].m_eGarageType == GARAGE_NONE) continue;
+ entity = CGarages::aGarages[i].m_pDoor1;
if(!entity) continue;
m_sQueueSample.m_vecPos = entity->GetPosition();
distCalculated = false;
distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
if(distSquared < 6400.f) {
- state = CGarages::Garages[i].m_eGarageState;
+ state = CGarages::aGarages[i].m_eGarageState;
if(state == GS_OPENING || state == GS_CLOSING || state == GS_AFTERDROPOFF) {
CalculateDistance(distCalculated, distSquared);
- m_sQueueSample.m_bVolume = ComputeVolume(90u, 80.f, m_sQueueSample.m_fDistance);
+ m_sQueueSample.m_bVolume = ComputeVolume(90, 80.f, m_sQueueSample.m_fDistance);
if(m_sQueueSample.m_bVolume) {
- if(CGarages::Garages[i].m_eGarageType == GARAGE_CRUSHER) {
- if(CGarages::Garages[i].m_eGarageState == GS_AFTERDROPOFF) {
+ if(CGarages::aGarages[i].m_eGarageType == GARAGE_CRUSHER) {
+ if(CGarages::aGarages[i].m_eGarageState == GS_AFTERDROPOFF) {
if(!(m_FrameCounter & 1)) {
LOOP_HELPER
continue;
@@ -3955,11 +4161,11 @@ cAudioManager::ProcessGarages()
m_sQueueSample.m_nSampleIndex) >>
1;
m_sQueueSample.m_nFrequency +=
- RandomDisplacement((int32)m_sQueueSample.m_nFrequency >> 4);
+ RandomDisplacement(m_sQueueSample.m_nFrequency >> 4);
m_sQueueSample.m_nLoopCount = 1;
m_sQueueSample.field_56 = 1;
m_sQueueSample.m_counter = iSound++;
- if(iSound < 32u) iSound = 32;
+ if(iSound < 32) iSound = 32;
m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
m_sQueueSample.m_bIsDistant = false;
m_sQueueSample.field_16 = 3;
@@ -4001,9 +4207,9 @@ cAudioManager::ProcessGarages()
m_sQueueSample.m_bReverbFlag = true;
m_sQueueSample.m_bRequireReflection = false;
AddSampleToRequestedQueue();
- LOOP_HELPER
}
}
+ LOOP_HELPER
}
}
#undef LOOP_HELPER
@@ -4183,11 +4389,8 @@ cAudioManager::ProcessJumboAccel(CPlane *plane)
void
cAudioManager::ProcessJumboDecel(CPlane *plane)
{
- float modificator;
-
if(SetupJumboFlySound(20) && SetupJumboTaxiSound(75)) {
- modificator = (plane->m_fSpeed - 0.10334f) * 1.676f;
- if(modificator > 1.0f) modificator = 1.0f;
+ const float modificator = min(1.f, (plane->m_fSpeed - 0.10334f) * 1.676f);
SetupJumboEngineSound(maxVolume * modificator, 6050.f * modificator + 16000);
SetupJumboWhineSound(18, 29500);
}
@@ -4202,7 +4405,7 @@ cAudioManager::ProcessJumboFlying()
void
cAudioManager::ProcessJumboLanding(CPlane *plane)
{
- float modificator = (LandingPoint - PlanePathPosition[plane->m_nPlaneId]) / 350.f;
+ const float modificator = (LandingPoint - PlanePathPosition[plane->m_nPlaneId]) / 350.f;
if(SetupJumboFlySound(107.f * modificator + 20)) {
if(SetupJumboTaxiSound(75.f * (1.f - modificator))) {
SetupJumboEngineSound(maxVolume, 22050);
@@ -4214,7 +4417,7 @@ cAudioManager::ProcessJumboLanding(CPlane *plane)
void
cAudioManager::ProcessJumboTakeOff(CPlane *plane)
{
- float modificator = (PlanePathPosition[plane->m_nPlaneId] - TakeOffPoint) / 300.f;
+ const float modificator = (PlanePathPosition[plane->m_nPlaneId] - TakeOffPoint) / 300.f;
if(SetupJumboFlySound((107.f * modificator) + 20) && SetupJumboRumbleSound(maxVolume * (1.f - modificator))) {
if(SetupJumboEngineSound(maxVolume, 22050)) SetupJumboWhineSound(18.f * (1.f - modificator), 44100);
@@ -5003,13 +5206,11 @@ cAudioManager::ProcessMissionAudio()
void
cAudioManager::ProcessModelCarEngine(cVehicleParams *params)
{
- cAudioManager *v2;
CAutomobile *automobile;
float allowedVelocity;
int32 emittingVol;
float velocityChange;
- v2 = this;
if(params->m_fDistance < 900.f) {
automobile = (CAutomobile *)params->m_pVehicle;
if(automobile->bEngineOn) {
@@ -5311,13 +5512,13 @@ cAudioManager::ProcessPed(CPhysical *ped)
{
cPedParams params;
- params.m_pPed = 0;
- params.m_bDistanceCalculated = 0;
+ params.m_pPed = nil;
+ params.m_bDistanceCalculated = false;
params.m_fDistance = 0.0f;
m_sQueueSample.m_vecPos = ped->GetPosition();
- params.m_bDistanceCalculated = 0;
+ //params.m_bDistanceCalculated = false;
params.m_pPed = (CPed *)ped;
params.m_fDistance = GetDistanceSquared(&m_sQueueSample.m_vecPos);
if(ped->m_modelIndex == MI_FATMALE02) ProcessPedHeadphones(&params);
@@ -5328,7 +5529,7 @@ void
cAudioManager::ProcessPedHeadphones(cPedParams *params)
{
CPed *ped;
- CVehicle *veh;
+ CAutomobile *veh;
uint8 emittingVol;
if(params->m_fDistance < 49.f) {
@@ -5337,9 +5538,9 @@ cAudioManager::ProcessPedHeadphones(cPedParams *params)
CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
if(ped->bInVehicle && ped->m_nPedState == PED_DRIVING) {
emittingVol = 10;
- veh = ped->m_pMyVehicle;
+ veh = (CAutomobile*)ped->m_pMyVehicle;
if(veh && veh->IsCar()) {
- for(int32 i = 2; i < 6; i++) {
+ for(int32 i = 2; i < ARRAYSIZE(veh->Doors); i++) {
if(!veh->IsDoorClosed((eDoors)i) || veh->IsDoorMissing((eDoors)i)) {
emittingVol = 42;
break;
@@ -7234,11 +7435,224 @@ cAudioManager::ProcessVehicleDoors(cVehicleParams *params)
return true;
}
-WRAPPER
-bool
-cAudioManager::ProcessVehicleEngine(cVehicleParams *params)
-{
- EAXJMP(0x56A610);
+void
+cAudioManager::ProcessVehicleEngine(cVehicleParams* params)
+{
+ CVehicle* playerVeh;
+ CVehicle* veh;
+ CAutomobile* automobile;
+ float relativeGearChange;
+ float relativeChange;
+ float reverseRelativechange;
+ uint8 volume;
+ eSfxSample accelerationSample;
+ int32 freq;
+ uint8 emittingVol;
+ cTransmission* transmission;
+ uint8 currentGear;
+ float modificator;
+ float traction = 0.f;
+
+ if (params->m_fDistance < SQR(50.f)) {
+ playerVeh = FindPlayerVehicle();
+ veh = params->m_pVehicle;
+ if (playerVeh == veh && veh->m_status == STATUS_WRECKED) {
+ SampleManager.StopChannel(m_bActiveSamples);
+ return;
+ }
+ if (veh->bEngineOn) {
+ CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
+ automobile = (CAutomobile*)params->m_pVehicle;
+ if (params->m_nIndex == DODO) {
+ ProcessCesna(params);
+ return;
+ }
+ if (FindPlayerVehicle() == veh) {
+ ProcessPlayersVehicleEngine(params, automobile);
+ return;
+ }
+ transmission = params->m_pTransmission;
+ if (transmission) {
+ currentGear = params->m_pVehicle->m_nCurrentGear;
+ if (automobile->m_nWheelsOnGround) {
+ if (automobile->bIsHandbrakeOn) {
+ if (0.f == params->m_fVelocityChange) traction = 0.9f;
+ }
+ else if (params->m_pVehicle->m_status == STATUS_SIMPLE) {
+ traction = 0.f;
+ }
+ else {
+ switch (transmission->nDriveType) {
+ case '4':
+ for (int32 i = 0; i < ARRAY_SIZE(automobile->m_aWheelState); i++) {
+ if (automobile->m_aWheelState[i] == WHEEL_STATE_SPINNING)
+ traction += 0.05f;
+ }
+ break;
+ case 'F':
+ if (automobile->m_aWheelState[0] == WHEEL_STATE_SPINNING)
+ traction += 0.1f;
+ if (automobile->m_aWheelState[2] == WHEEL_STATE_SPINNING)
+ traction += 0.1f;
+ break;
+ case 'R':
+ if (automobile->m_aWheelState[1] == WHEEL_STATE_SPINNING)
+ traction += 0.1f;
+ if (automobile->m_aWheelState[3] == WHEEL_STATE_SPINNING)
+ traction += 0.1f;
+ break;
+ }
+ }
+ if (transmission->fMaxVelocity <= 0.f) {
+ relativeChange = 0.f;
+ }
+ else if (currentGear) {
+ if ((params->m_fVelocityChange -
+ transmission->Gears[currentGear].fShiftDownVelocity) /
+ transmission->fMaxVelocity * 2.5f <=
+ 1.f)
+ relativeGearChange =
+ (params->m_fVelocityChange -
+ transmission->Gears[currentGear].fShiftDownVelocity) /
+ transmission->fMaxVelocity * 2.5f;
+ else
+ relativeGearChange = 1.f;
+ if (0.f == traction && automobile->m_status != STATUS_SIMPLE &&
+ params->m_fVelocityChange >=
+ transmission->Gears[1].fShiftUpVelocity) {
+ traction = 0.7f;
+ }
+ relativeChange = traction * automobile->m_fGasPedalAudio * 0.95f +
+ (1.f - traction) * relativeGearChange;
+ }
+ else {
+ reverseRelativechange =
+ Abs((params->m_fVelocityChange -
+ transmission->Gears[0].fShiftDownVelocity) /
+ transmission->fMaxReverseVelocity);
+ if (1.f - reverseRelativechange <= 1.f) {
+ relativeChange = 1.f - reverseRelativechange;
+ }
+ else {
+ relativeChange = 1.f;
+ }
+ }
+ }
+ else {
+ if (automobile->m_nDriveWheelsOnGround)
+ automobile->m_fGasPedalAudio = automobile->m_fGasPedalAudio * 0.4f;
+ relativeChange = automobile->m_fGasPedalAudio;
+ }
+ modificator = relativeChange;
+ if (currentGear || !automobile->m_nWheelsOnGround)
+ freq = 1200 * currentGear + 18000.f * modificator + 14000;
+ else
+ freq = 13000.f * modificator + 14000;
+ if (modificator >= 0.75f) {
+ emittingVol = 120;
+ volume = ComputeVolume(120, 50.f, m_sQueueSample.m_fDistance);
+ }
+ else {
+ emittingVol = modificator * 4 / 3 * 40.f + 80.f;
+ volume = ComputeVolume(emittingVol, 50.f, m_sQueueSample.m_fDistance);
+ }
+ }
+ else {
+ modificator = 0.f;
+ emittingVol = 80;
+ volume = ComputeVolume(80, 50.f, m_sQueueSample.m_fDistance);
+ }
+ m_sQueueSample.m_bVolume = volume;
+ if (m_sQueueSample.m_bVolume) {
+ if (automobile->m_status == STATUS_SIMPLE) {
+ if (modificator < 0.02f) {
+ m_sQueueSample.m_nSampleIndex =
+ CarSounds[params->m_nIndex].m_bEngineSoundType + SFX_CAR_REV_10;
+ freq = 10000.f * modificator + 22050;
+ m_sQueueSample.m_counter = 52;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.m_nFrequency =
+ freq + 100 * m_sQueueSample.m_nEntityIndex % 1000;
+ if (m_sQueueSample.m_nSampleIndex == SFX_CAR_IDLE_6 ||
+ m_sQueueSample.m_nSampleIndex == SFX_CAR_REV_6)
+ m_sQueueSample.m_nFrequency = m_sQueueSample.m_nFrequency >> 1;
+ m_sQueueSample.m_nLoopCount = 0;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_nLoopStart = SampleManager.GetSampleLoopStartOffset(
+ m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nLoopEnd =
+ SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.field_48 = 6.0f;
+ m_sQueueSample.m_fSoundIntensity = 50.0f;
+ m_sQueueSample.field_56 = 0;
+ m_sQueueSample.field_76 = 8;
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ return;
+ }
+ accelerationSample = CarSounds[params->m_nIndex].m_nAccelerationSampleIndex;
+ }
+ else {
+ if (automobile->m_fGasPedal < 0.05f) {
+ m_sQueueSample.m_nSampleIndex =
+ CarSounds[params->m_nIndex].m_bEngineSoundType +
+ SFX_CAR_REV_10; // to recheck idle sounds start 1 postion later
+ freq = 10000.f * modificator + 22050;
+ m_sQueueSample.m_counter = 52;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.m_nFrequency =
+ freq + 100 * m_sQueueSample.m_nEntityIndex % 1000;
+ if (m_sQueueSample.m_nSampleIndex == SFX_CAR_IDLE_6 ||
+ m_sQueueSample.m_nSampleIndex == SFX_CAR_REV_6)
+ m_sQueueSample.m_nFrequency = m_sQueueSample.m_nFrequency >> 1;
+ m_sQueueSample.m_nLoopCount = 0;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_nLoopStart = SampleManager.GetSampleLoopStartOffset(
+ m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nLoopEnd =
+ SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.field_48 = 6.0f;
+ m_sQueueSample.m_fSoundIntensity = 50.0f;
+ m_sQueueSample.field_56 = 0;
+ m_sQueueSample.field_76 = 8;
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ return;
+ }
+ accelerationSample = CarSounds[params->m_nIndex].m_nAccelerationSampleIndex;
+ }
+ m_sQueueSample.m_nSampleIndex = accelerationSample;
+ m_sQueueSample.m_counter = 2;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.m_nFrequency = freq + 100 * m_sQueueSample.m_nEntityIndex % 1000;
+ if (m_sQueueSample.m_nSampleIndex == SFX_CAR_IDLE_6 ||
+ m_sQueueSample.m_nSampleIndex == SFX_CAR_REV_6)
+ m_sQueueSample.m_nFrequency = m_sQueueSample.m_nFrequency >> 1;
+ m_sQueueSample.m_nLoopCount = 0;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_nLoopStart =
+ SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nLoopEnd =
+ SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.field_48 = 6.0f;
+ m_sQueueSample.m_fSoundIntensity = 50.0f;
+ m_sQueueSample.field_56 = 0;
+ m_sQueueSample.field_76 = 8;
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ return;
+ }
+ }
+ }
}
void
@@ -7358,7 +7772,7 @@ cAudioManager::ProcessVehicleRoadNoise(cVehicleParams *params)
freq = 6050 * emittingVol / 30 + 16000;
} else {
m_sQueueSample.m_nSampleIndex = SFX_ROAD_NOISE;
- modificator = m_sQueueSample.m_fDistance * 1.f / 95.f * 0.5f;
+ modificator = m_sQueueSample.m_fDistance / 190.f;
sampleFreq = SampleManager.GetSampleBaseFrequency(
SFX_ROAD_NOISE);
freq = (sampleFreq * modificator) + ((3 * sampleFreq) >> 2);
@@ -7533,8 +7947,8 @@ cAudioManager::ProcessVehicleSkidding(cVehicleParams *params)
void cAudioManager::ProcessWaterCannon(int32)
{
for(int32 i = 0; i < NUM_WATERCANNONS; i++) {
- if(aCannons[i].m_nId) {
- m_sQueueSample.m_vecPos = aCannons[0].m_avecPos[aCannons[i].m_wIndex];
+ if(CWaterCannons::aCannons[i].m_nId) {
+ m_sQueueSample.m_vecPos = CWaterCannons::aCannons[0].m_avecPos[CWaterCannons::aCannons[i].m_nCur];
float distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
if(distSquared < 900.f) {
m_sQueueSample.m_fDistance = Sqrt(distSquared);
@@ -7647,7 +8061,7 @@ cAudioManager::ProcessWetRoadNoise(cVehicleParams *params)
m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
m_sQueueSample.m_bIsDistant = false;
m_sQueueSample.field_16 = 3;
- modificator = m_sQueueSample.m_fDistance * 1.f / 3.f * 0.5f;
+ modificator = m_sQueueSample.m_fDistance / 6.f;
freq = SampleManager.GetSampleBaseFrequency(SFX_ROAD_NOISE);
m_sQueueSample.m_nFrequency = freq + freq * modificator;
m_sQueueSample.m_nLoopCount = 0;
diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h
index 70281237..0be1e38a 100644
--- a/src/audio/AudioManager.h
+++ b/src/audio/AudioManager.h
@@ -489,7 +489,7 @@ public:
void PreloadMissionAudio(const char *name); /// ok
void PreTerminateGameSpecificShutdown(); /// ok
/// processX - main logic of adding new sounds
- void ProcessActiveQueues(); // todo
+ void ProcessActiveQueues(); /// ok
bool ProcessAirBrakes(cVehicleParams *params); /// ok
void ProcessAirportScriptObject(uint8 sound); /// ok
bool ProcessBoatEngine(cVehicleParams *params); /// ok
@@ -544,7 +544,7 @@ public:
bool ProcessTrainNoise(cVehicleParams *params); /// ok
void ProcessVehicle(CVehicle *vehicle); /// ok
bool ProcessVehicleDoors(cVehicleParams *params); /// ok
- bool ProcessVehicleEngine(cVehicleParams *params); // todo
+ void ProcessVehicleEngine(cVehicleParams *params); /// ok
void ProcessVehicleHorn(cVehicleParams *params); /// ok
void ProcessVehicleOneShots(void *); // todo
bool ProcessVehicleReverseWarning(cVehicleParams *params); /// ok
diff --git a/src/audio/AudioScriptObject.cpp b/src/audio/AudioScriptObject.cpp
index 796cd88b..0ae3834a 100644
--- a/src/audio/AudioScriptObject.cpp
+++ b/src/audio/AudioScriptObject.cpp
@@ -2,13 +2,12 @@
#include "patcher.h"
#include "AudioScriptObject.h"
#include "Pools.h"
-
-WRAPPER void cAudioScriptObject::SaveAllAudioScriptObjects(uint8 *buf, uint32 *size) { EAXJMP(0x57c460); }
+#include "DMAudio.h"
void
cAudioScriptObject::Reset()
{
- AudioId = 125;
+ AudioId = SCRSOUND_INVALID;
Posn = CVector(0.0f, 0.0f, 0.0f);
AudioEntity = AEHANDLE_NONE;
}
@@ -18,16 +17,19 @@ 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)
{
@@ -35,6 +37,47 @@ cAudioScriptObject::operator delete(void *p, int handle)
}
void
+cAudioScriptObject::LoadAllAudioScriptObjects(uint8 *buf, uint32 size)
+{
+ INITSAVEBUF
+
+ CheckSaveHeader(buf, 'A', 'U', 'D', '\0', size - SAVE_HEADER_SIZE);
+
+ int32 pool_size = ReadSaveBuf<int32>(buf);
+ for (int32 i = 0; i < pool_size; i++) {
+ int handle = ReadSaveBuf<int32>(buf);
+ cAudioScriptObject *p = new(handle) cAudioScriptObject;
+ assert(p != nil);
+ *p = ReadSaveBuf<cAudioScriptObject>(buf);
+ p->AudioEntity = DMAudio.CreateLoopingScriptObject(p);
+ }
+
+ VALIDATESAVEBUF(size);
+}
+
+void
+cAudioScriptObject::SaveAllAudioScriptObjects(uint8 *buf, uint32 *size)
+{
+ INITSAVEBUF
+
+ int32 pool_size = CPools::GetAudioScriptObjectPool()->GetNoOfUsedSpaces();
+ *size = SAVE_HEADER_SIZE + pool_size * (sizeof(cAudioScriptObject) + sizeof(int32));
+ WriteSaveHeader(buf, 'A', 'U', 'D', '\0', *size - SAVE_HEADER_SIZE);
+ WriteSaveBuf(buf, pool_size);
+
+ int32 i = CPools::GetAudioScriptObjectPool()->GetSize();
+ while (i--) {
+ cAudioScriptObject *p = CPools::GetAudioScriptObjectPool()->GetSlot(i);
+ if (p != nil) {
+ WriteSaveBuf(buf, CPools::GetAudioScriptObjectPool()->GetIndex(p));
+ WriteSaveBuf(buf, *p);
+ }
+ }
+
+ VALIDATESAVEBUF(*size);
+}
+
+void
PlayOneShotScriptObject(uint8 id, CVector const &pos)
{
cAudioScriptObject *audioScriptObject = new cAudioScriptObject();
@@ -47,4 +90,6 @@ PlayOneShotScriptObject(uint8 id, CVector const &pos)
STARTPATCHES
InjectHook(0x57C430, &cAudioScriptObject::Reset, PATCH_JUMP);
InjectHook(0x57C5F0, &PlayOneShotScriptObject, PATCH_JUMP);
+InjectHook(0x57C560, &cAudioScriptObject::LoadAllAudioScriptObjects, PATCH_JUMP);
+InjectHook(0x57c460, &cAudioScriptObject::SaveAllAudioScriptObjects, PATCH_JUMP);
ENDPATCHES \ No newline at end of file
diff --git a/src/audio/AudioScriptObject.h b/src/audio/AudioScriptObject.h
index 1db19865..4308faee 100644
--- a/src/audio/AudioScriptObject.h
+++ b/src/audio/AudioScriptObject.h
@@ -2,130 +2,132 @@
enum
{
- SCRSOUND_TEST_1 = 0,
- _SCRSOUND_UNK_1 = 1,
- _SCRSOUND_UNK_2 = 2,
- _SCRSOUND_UNK_3 = 3,
- _SCRSOUND_CLUB_1_S = 4,
- _SCRSOUND_CLUB_1_L = 5,
- _SCRSOUND_CLUB_2_S = 6,
- _SCRSOUND_CLUB_2_L = 7,
- _SCRSOUND_CLUB_3_S = 8,
- _SCRSOUND_CLUB_3_L = 9,
- _SCRSOUND_CLUB_4_S = 10,
- _SCRSOUND_CLUB_4_L = 11,
- _SCRSOUND_CLUB_5_S = 12,
- _SCRSOUND_CLUB_5_L = 13,
- _SCRSOUND_CLUB_6_S = 14,
- _SCRSOUND_CLUB_6_L = 15,
- _SCRSOUND_CLUB_7_S = 16,
- _SCRSOUND_CLUB_7_L = 17,
- _SCRSOUND_CLUB_8_S = 18,
- _SCRSOUND_CLUB_8_L = 19,
- _SCRSOUND_CLUB_9_S = 20,
- _SCRSOUND_CLUB_9_L = 21,
- _SCRSOUND_CLUB_10_S = 22,
- _SCRSOUND_CLUB_10_L = 23,
- _SCRSOUND_CLUB_11_S = 24,
- _SCRSOUND_CLUB_11_L = 25,
- _SCRSOUND_CLUB_12_S = 26,
- _SCRSOUND_CLUB_12_L = 27,
- _SCRSOUND_CLUB_RAGGA_S = 28,
- _SCRSOUND_CLUB_RAGGA_L = 29,
- SCRSOUND_STRIP_CLUB_LOOP_1_S = 30,
- _SCRSOUND_STRIP_CLUB_LOOP_1_L = 31,
- SCRSOUND_STRIP_CLUB_LOOP_2_S = 32,
- _SCRSOUND_STRIP_CLUB_LOOP_2_L = 33,
- _SCRSOUND_SFX_WORKSHOP_1 = 34,
- _SCRSOUND_SFX_WORKSHOP_2 = 35,
- _SCRSOUND_SAWMILL_LOOP_S = 36,
- SCRSOUND_SAWMILL_LOOP_L = 37,
- _SCRSOUND_DOG_FOOD_FACTORY_S = 38,
- _SCRSOUND_DOG_FOOD_FACTORY_L = 39,
- _SCRSOUND_LAUNDERETTE_1 = 40,
- _SCRSOUND_LAUNDERETTE_2 = 41,
- _SCRSOUND_RESTAURANT_CHINATOWN_S = 42,
- _SCRSOUND_RESTAURANT_CHINATOWN_L = 43,
- _SCRSOUND_RESTAURANT_ITALY_S = 44,
- _SCRSOUND_RESTAURANT_ITALY_L = 45,
- _SCRSOUND_RESTAURANT_GENERIC_1_S = 46,
- _SCRSOUND_RESTAURANT_GENERIC_1_L = 47,
- _SCRSOUND_RESTAURANT_GENERIC_2_S = 48,
- _SCRSOUND_RESTAURANT_GENERIC_2_L = 49,
- _SCRSOUND_AIRPORT_ANNOUNCEMENT_S = 50,
- _SCRSOUND_AIRPORT_ANNOUNCEMENT_L = 51,
- _SCRSOUND_SHOP_LOOP_1 = 52,
- _SCRSOUND_SHOP_LOOP_2 = 53,
- _SCRSOUND_CINEMA_S = 54,
- _SCRSOUND_CINEMA_L = 55,
- _SCRSOUND_DOCKS_FOGHORN_S = 56,
- _SCRSOUND_DOCKS_FOGHORN_L = 57,
- _SCRSOUND_HOME_S = 58,
- _SCRSOUND_HOME_L = 59,
- _SCRSOUND_PIANO_BAR = 60,
- _SCRSOUND_CLUB = 61,
- SCRSOUND_PORN_CINEMA_1_S = 62,
- _SCRSOUND_PORN_CINEMA_1_L = 63,
- SCRSOUND_PORN_CINEMA_2_S = 64,
- _SCRSOUND_PORN_CINEMA_2_L = 65,
- SCRSOUND_PORN_CINEMA_3_S = 66,
- _SCRSOUND_PORN_CINEMA_3_L = 67,
- _SCRSOUND_BANK_ALARM_LOOP_S = 68,
- SCRSOUND_BANK_ALARM_LOOP_L = 69,
- _SCRSOUND_POLICE_BALL_LOOP_S = 70,
- SCRSOUND_POLICE_BALL_LOOP_L = 71,
- _SCRSOUND_RAVE_LOOP_INDUSTRIAL_S = 72,
- SCRSOUND_RAVE_LOOP_INDUSTRIAL_L = 73,
- _SCRSOUND_UNK_74 = 74,
- _SCRSOUND_UNK_75 = 75,
- _SCRSOUND_POLICE_CELL_BEATING_LOOP_S = 76,
- SCRSOUND_POLICE_CELL_BEATING_LOOP_L = 77,
- SCRSOUND_INJURED_PED_MALE_OUCH_S = 78,
- SCRSOUND_INJURED_PED_MALE_OUCH_L = 79,
- SCRSOUND_INJURED_PED_FEMALE_OUCH_S = 80,
- SCRSOUND_INJURED_PED_FEMALE_OUCH_L = 81,
- SCRSOUND_EVIDENCE_PICKUP = 82,
- SCRSOUND_UNLOAD_GOLD = 83,
- _SCRSOUND_RAVE_INDUSTRIAL_S = 84,
- _SCRSOUND_RAVE_INDUSTRIAL_L = 85,
- _SCRSOUND_RAVE_COMMERCIAL_S = 86,
- _SCRSOUND_RAVE_COMMERCIAL_L = 87,
- _SCRSOUND_RAVE_SUBURBAN_S = 88,
- _SCRSOUND_RAVE_SUBURBAN_L = 89,
- _SCRSOUND_GROAN_S = 90,
- _SCRSOUND_GROAN_L = 91,
- SCRSOUND_GATE_START_CLUNK = 92,
- SCRSOUND_GATE_STOP_CLUNK = 93,
- SCRSOUND_PART_MISSION_COMPLETE = 94,
- SCRSOUND_CHUNKY_RUN_SHOUT = 95,
- SCRSOUND_SECURITY_GUARD_RUN_AWAY_SHOUT = 96,
- SCRSOUND_RACE_START_1 = 97,
- SCRSOUND_RACE_START_2 = 98,
- SCRSOUND_RACE_START_3 = 99,
- SCRSOUND_RACE_START_GO = 100,
- SCRSOUND_SWAT_PED_SHOUT = 101,
- SCRSOUND_PRETEND_FIRE_LOOP = 102,
- SCRSOUND_AMMUNATION_CHAT_1 = 103,
- SCRSOUND_AMMUNATION_CHAT_2 = 104,
- SCRSOUND_AMMUNATION_CHAT_3 = 105,
- _SCRSOUND_BULLET_WALL_1 = 106,
- _SCRSOUND_BULLET_WALL_2 = 107,
- _SCRSOUND_BULLET_WALL_3 = 108,
- _SCRSOUND_UNK_109 = 109,
- _SCRSOUND_GLASSFX2_1 = 110,
- _SCRSOUND_GLASSFX2_2 = 111,
- _SCRSOUND_PHONE_RING = 112,
- _SCRSOUND_UNK_113 = 113,
- _SCRSOUND_GLASS_SMASH_1 = 114,
- _SCRSOUND_GLASS_SMASH_2 = 115,
- _SCRSOUND_GLASS_CRACK = 116,
- _SCRSOUND_GLASS_SHARD = 117,
- _SCRSOUND_WOODEN_BOX_SMASH = 118,
- _SCRSOUND_CARDBOARD_BOX_SMASH = 119,
- _SCRSOUND_COL_CAR = 120,
- _SCRSOUND_TYRE_BUMP = 121,
- _SCRSOUND_BULLET_SHELL_HIT_GROUND_1 = 122,
- _SCRSOUND_BULLET_SHELL_HIT_GROUND_2 = 123,
+ SCRSOUND_TEST_1,
+ _SCRSOUND_UNK_1,
+ _SCRSOUND_UNK_2,
+ _SCRSOUND_UNK_3,
+ _SCRSOUND_CLUB_1_S,
+ _SCRSOUND_CLUB_1_L,
+ _SCRSOUND_CLUB_2_S,
+ _SCRSOUND_CLUB_2_L,
+ _SCRSOUND_CLUB_3_S,
+ _SCRSOUND_CLUB_3_L,
+ _SCRSOUND_CLUB_4_S,
+ _SCRSOUND_CLUB_4_L,
+ _SCRSOUND_CLUB_5_S,
+ _SCRSOUND_CLUB_5_L,
+ _SCRSOUND_CLUB_6_S,
+ _SCRSOUND_CLUB_6_L,
+ _SCRSOUND_CLUB_7_S,
+ _SCRSOUND_CLUB_7_L,
+ _SCRSOUND_CLUB_8_S,
+ _SCRSOUND_CLUB_8_L,
+ _SCRSOUND_CLUB_9_S,
+ _SCRSOUND_CLUB_9_L,
+ _SCRSOUND_CLUB_10_S,
+ _SCRSOUND_CLUB_10_L,
+ _SCRSOUND_CLUB_11_S,
+ _SCRSOUND_CLUB_11_L,
+ _SCRSOUND_CLUB_12_S,
+ _SCRSOUND_CLUB_12_L,
+ _SCRSOUND_CLUB_RAGGA_S,
+ _SCRSOUND_CLUB_RAGGA_L,
+ SCRSOUND_STRIP_CLUB_LOOP_1_S,
+ _SCRSOUND_STRIP_CLUB_LOOP_1_L,
+ SCRSOUND_STRIP_CLUB_LOOP_2_S,
+ _SCRSOUND_STRIP_CLUB_LOOP_2_L,
+ _SCRSOUND_SFX_WORKSHOP_1,
+ _SCRSOUND_SFX_WORKSHOP_2,
+ _SCRSOUND_SAWMILL_LOOP_S,
+ SCRSOUND_SAWMILL_LOOP_L,
+ _SCRSOUND_DOG_FOOD_FACTORY_S,
+ _SCRSOUND_DOG_FOOD_FACTORY_L,
+ _SCRSOUND_LAUNDERETTE_1,
+ _SCRSOUND_LAUNDERETTE_2,
+ _SCRSOUND_RESTAURANT_CHINATOWN_S,
+ _SCRSOUND_RESTAURANT_CHINATOWN_L,
+ _SCRSOUND_RESTAURANT_ITALY_S,
+ _SCRSOUND_RESTAURANT_ITALY_L,
+ _SCRSOUND_RESTAURANT_GENERIC_1_S,
+ _SCRSOUND_RESTAURANT_GENERIC_1_L,
+ _SCRSOUND_RESTAURANT_GENERIC_2_S,
+ _SCRSOUND_RESTAURANT_GENERIC_2_L,
+ _SCRSOUND_AIRPORT_ANNOUNCEMENT_S,
+ _SCRSOUND_AIRPORT_ANNOUNCEMENT_L,
+ _SCRSOUND_SHOP_LOOP_1,
+ _SCRSOUND_SHOP_LOOP_2,
+ _SCRSOUND_CINEMA_S,
+ _SCRSOUND_CINEMA_L,
+ _SCRSOUND_DOCKS_FOGHORN_S,
+ _SCRSOUND_DOCKS_FOGHORN_L,
+ _SCRSOUND_HOME_S,
+ _SCRSOUND_HOME_L,
+ _SCRSOUND_PIANO_BAR,
+ _SCRSOUND_CLUB,
+ SCRSOUND_PORN_CINEMA_1_S,
+ _SCRSOUND_PORN_CINEMA_1_L,
+ SCRSOUND_PORN_CINEMA_2_S,
+ _SCRSOUND_PORN_CINEMA_2_L,
+ SCRSOUND_PORN_CINEMA_3_S,
+ _SCRSOUND_PORN_CINEMA_3_L,
+ _SCRSOUND_BANK_ALARM_LOOP_S,
+ SCRSOUND_BANK_ALARM_LOOP_L,
+ _SCRSOUND_POLICE_BALL_LOOP_S,
+ SCRSOUND_POLICE_BALL_LOOP_L,
+ _SCRSOUND_RAVE_LOOP_INDUSTRIAL_S,
+ SCRSOUND_RAVE_LOOP_INDUSTRIAL_L,
+ _SCRSOUND_UNK_74,
+ _SCRSOUND_UNK_75,
+ _SCRSOUND_POLICE_CELL_BEATING_LOOP_S,
+ SCRSOUND_POLICE_CELL_BEATING_LOOP_L,
+ SCRSOUND_INJURED_PED_MALE_OUCH_S,
+ SCRSOUND_INJURED_PED_MALE_OUCH_L,
+ SCRSOUND_INJURED_PED_FEMALE_OUCH_S,
+ SCRSOUND_INJURED_PED_FEMALE_OUCH_L,
+ SCRSOUND_EVIDENCE_PICKUP,
+ SCRSOUND_UNLOAD_GOLD,
+ _SCRSOUND_RAVE_INDUSTRIAL_S,
+ _SCRSOUND_RAVE_INDUSTRIAL_L,
+ _SCRSOUND_RAVE_COMMERCIAL_S,
+ _SCRSOUND_RAVE_COMMERCIAL_L,
+ _SCRSOUND_RAVE_SUBURBAN_S,
+ _SCRSOUND_RAVE_SUBURBAN_L,
+ _SCRSOUND_GROAN_S,
+ _SCRSOUND_GROAN_L,
+ SCRSOUND_GATE_START_CLUNK,
+ SCRSOUND_GATE_STOP_CLUNK,
+ SCRSOUND_PART_MISSION_COMPLETE,
+ SCRSOUND_CHUNKY_RUN_SHOUT,
+ SCRSOUND_SECURITY_GUARD_RUN_AWAY_SHOUT,
+ SCRSOUND_RACE_START_1,
+ SCRSOUND_RACE_START_2,
+ SCRSOUND_RACE_START_3,
+ SCRSOUND_RACE_START_GO,
+ SCRSOUND_SWAT_PED_SHOUT,
+ SCRSOUND_PRETEND_FIRE_LOOP,
+ SCRSOUND_AMMUNATION_CHAT_1,
+ SCRSOUND_AMMUNATION_CHAT_2,
+ SCRSOUND_AMMUNATION_CHAT_3,
+ _SCRSOUND_BULLET_WALL_1,
+ _SCRSOUND_BULLET_WALL_2,
+ _SCRSOUND_BULLET_WALL_3,
+ _SCRSOUND_UNK_109,
+ _SCRSOUND_GLASSFX2_1,
+ _SCRSOUND_GLASSFX2_2,
+ _SCRSOUND_PHONE_RING,
+ _SCRSOUND_UNK_113,
+ _SCRSOUND_GLASS_SMASH_1,
+ _SCRSOUND_GLASS_SMASH_2,
+ _SCRSOUND_GLASS_CRACK,
+ _SCRSOUND_GLASS_SHARD,
+ _SCRSOUND_WOODEN_BOX_SMASH,
+ _SCRSOUND_CARDBOARD_BOX_SMASH,
+ _SCRSOUND_COL_CAR,
+ _SCRSOUND_TYRE_BUMP,
+ _SCRSOUND_BULLET_SHELL_HIT_GROUND_1,
+ _SCRSOUND_BULLET_SHELL_HIT_GROUND_2,
+ TOTAL_SCRSOUNDS,
+ SCRSOUND_INVALID
};
class cAudioScriptObject
@@ -142,6 +144,7 @@ public:
static void operator delete(void*, size_t);
static void operator delete(void*, int);
+ static void LoadAllAudioScriptObjects(uint8 *buf, uint32 size);
static void SaveAllAudioScriptObjects(uint8 *buf, uint32 *size);
};
diff --git a/src/audio/DMAudio.h b/src/audio/DMAudio.h
index 125263f0..d2cdf466 100644
--- a/src/audio/DMAudio.h
+++ b/src/audio/DMAudio.h
@@ -1,7 +1,6 @@
#pragma once
#include "audio_enums.h"
-#include "Wanted.h"
enum eSound : int16
{
@@ -65,7 +64,7 @@ enum eSound : int16
SOUND_GARAGE_NO_MONEY = 57,
SOUND_GARAGE_BAD_VEHICLE = 58,
SOUND_GARAGE_OPENING = 59,
- SOUND_3C = 60,
+ SOUND_GARAGE_BOMB_ALREADY_SET = 60,
SOUND_GARAGE_BOMB1_SET = 61,
SOUND_GARAGE_BOMB2_SET = 62,
SOUND_GARAGE_BOMB3_SET = 63,
diff --git a/src/audio/MusicManager.cpp b/src/audio/MusicManager.cpp
index 1fac8a23..d840c57b 100644
--- a/src/audio/MusicManager.cpp
+++ b/src/audio/MusicManager.cpp
@@ -8,6 +8,7 @@
#include "Hud.h"
#include "ModelIndices.h"
#include "Replay.h"
+#include "Pad.h"
#include "Text.h"
#include "Timer.h"
#include "World.h"
@@ -16,8 +17,6 @@
cMusicManager &MusicManager = *(cMusicManager *)0x8F3964;
int32 &gNumRetunePresses = *(int32 *)0x650B80;
-wchar *pCurrentStation = (wchar *)0x650B9C;
-uint8 &cDisplay = *(uint8 *)0x650BA1;
int32 &gRetuneCounter = *(int32*)0x650B84;
bool& bHasStarted = *(bool*)0x650B7C;
@@ -71,6 +70,8 @@ cMusicManager::DisplayRadioStationName()
int8 pRetune;
int8 gStreamedSound;
int8 gRetuneCounter;
+ static wchar *pCurrentStation = nil;
+ static uint8 cDisplay = 0;
if(!CTimer::GetIsPaused() && !TheCamera.m_WideScreenOn && PlayerInCar() &&
!CReplay::IsPlayingBack()) {
diff --git a/src/audio/PoliceRadio.h b/src/audio/PoliceRadio.h
index 152a5ee2..4c7030f1 100644
--- a/src/audio/PoliceRadio.h
+++ b/src/audio/PoliceRadio.h
@@ -1,5 +1,7 @@
#pragma once
+#include "Wanted.h"
+
struct cAMCrime {
int32 type;
CVector position;
diff --git a/src/control/AutoPilot.cpp b/src/control/AutoPilot.cpp
index e3d5c9e9..70099291 100644
--- a/src/control/AutoPilot.cpp
+++ b/src/control/AutoPilot.cpp
@@ -6,9 +6,6 @@
#include "Curves.h"
#include "PathFind.h"
-#if 0
-WRAPPER void CAutoPilot::ModifySpeed(float) { EAXJMP(0x4137B0); }
-#else
void CAutoPilot::ModifySpeed(float speed)
{
m_fMaxTrafficSpeed = max(0.01f, speed);
@@ -41,7 +38,6 @@ void CAutoPilot::ModifySpeed(float speed)
m_nTimeEnteredCurve = CTimer::GetTimeInMilliseconds() - positionBetweenNodes * m_nSpeedScaleFactor;
#endif
}
-#endif
void CAutoPilot::RemoveOnePathNode()
{
diff --git a/src/control/Bridge.h b/src/control/Bridge.h
index 377c8bf8..63f41578 100644
--- a/src/control/Bridge.h
+++ b/src/control/Bridge.h
@@ -1,5 +1,6 @@
#pragma once
-#include "Entity.h"
+
+class CEntity;
enum bridgeStates {
STATE_BRIDGE_LOCKED,
diff --git a/src/control/CarAI.cpp b/src/control/CarAI.cpp
index c5d62c48..e47e3d5e 100644
--- a/src/control/CarAI.cpp
+++ b/src/control/CarAI.cpp
@@ -9,6 +9,9 @@
#include "HandlingMgr.h"
#include "ModelIndices.h"
#include "PlayerPed.h"
+#include "Wanted.h"
+#include "DMAudio.h"
+#include "Fire.h"
#include "Pools.h"
#include "Timer.h"
#include "TrafficLights.h"
diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp
index de8c799e..3174a253 100644
--- a/src/control/CarCtrl.cpp
+++ b/src/control/CarCtrl.cpp
@@ -19,6 +19,7 @@
#include "Ped.h"
#include "PlayerInfo.h"
#include "PlayerPed.h"
+#include "Wanted.h"
#include "Pools.h"
#include "Renderer.h"
#include "RoadBlocks.h"
@@ -27,7 +28,7 @@
#include "Streaming.h"
#include "VisibilityPlugins.h"
#include "Vehicle.h"
-#include "Wanted.h"
+#include "Fire.h"
#include "World.h"
#include "Zones.h"
@@ -880,9 +881,7 @@ CCarCtrl::SlowCarOnRailsDownForTrafficAndLights(CVehicle* pVehicle)
pVehicle->AutoPilot.ModifySpeed(max(maxSpeed, curSpeed - 0.5f * CTimer::GetTimeStep()));
}
}
-#if 0
-WRAPPER void CCarCtrl::SlowCarDownForPedsSectorList(CPtrList&, CVehicle*, float, float, float, float, float*, float) { EAXJMP(0x419300); }
-#else
+
void CCarCtrl::SlowCarDownForPedsSectorList(CPtrList& lst, CVehicle* pVehicle, float x_inf, float y_inf, float x_sup, float y_sup, float* pSpeed, float curSpeed)
{
float frontOffset = pVehicle->GetModelInfo()->GetColModel()->boundingBox.max.y;
@@ -990,7 +989,6 @@ void CCarCtrl::SlowCarDownForPedsSectorList(CPtrList& lst, CVehicle* pVehicle, f
}
}
}
-#endif
void CCarCtrl::SlowCarDownForCarsSectorList(CPtrList& lst, CVehicle* pVehicle, float x_inf, float y_inf, float x_sup, float y_sup, float* pSpeed, float curSpeed)
{
@@ -1054,9 +1052,6 @@ void CCarCtrl::SlowCarDownForOtherCar(CEntity* pOtherEntity, CVehicle* pVehicle,
}
}
-#if 0
-WRAPPER float CCarCtrl::TestCollisionBetween2MovingRects(CVehicle* pVehicleA, CVehicle* pVehicleB, float projectionX, float projectionY, CVector* pForwardA, CVector* pForwardB, uint8 id) { EAXJMP(0x41A020); }
-#else
float CCarCtrl::TestCollisionBetween2MovingRects(CVehicle* pVehicleA, CVehicle* pVehicleB, float projectionX, float projectionY, CVector* pForwardA, CVector* pForwardB, uint8 id)
{
CVector2D vecBToA = pVehicleA->GetPosition() - pVehicleB->GetPosition();
@@ -1179,7 +1174,6 @@ float CCarCtrl::TestCollisionBetween2MovingRects(CVehicle* pVehicleA, CVehicle*
}
return proximity;
}
-#endif
float CCarCtrl::FindAngleToWeaveThroughTraffic(CVehicle* pVehicle, CPhysical* pTarget, float angleToTarget, float angleForward)
{
diff --git a/src/control/Curves.cpp b/src/control/Curves.cpp
index c5f64bf7..5c6ef06d 100644
--- a/src/control/Curves.cpp
+++ b/src/control/Curves.cpp
@@ -2,9 +2,6 @@
#include "patcher.h"
#include "Curves.h"
-#if 0
-WRAPPER float CCurves::CalcSpeedScaleFactor(CVector*, CVector*, float, float, float, float) { EAXJMP(0x420410); }
-#else
float CCurves::CalcSpeedScaleFactor(CVector* pPoint1, CVector* pPoint2, float dir1X, float dir1Y, float dir2X, float dir2Y)
{
CVector2D dir1(dir1X, dir1Y);
@@ -16,11 +13,7 @@ float CCurves::CalcSpeedScaleFactor(CVector* pPoint1, CVector* pPoint2, float di
else
return ((1.0f - dp) * 0.2f + 1.0f) * distance;
}
-#endif
-#if 0
-WRAPPER void CCurves::CalcCurvePoint(CVector*, CVector*, CVector*, CVector*, float, int32, CVector*, CVector*) { EAXJMP(0x4204D0); }
-#else
void CCurves::CalcCurvePoint(CVector* pPos1, CVector* pPos2, CVector* pDir1, CVector* pDir2, float between, int32 timeOnCurve, CVector* pOutPos, CVector* pOutDir)
{
float actualFactor = CalcSpeedScaleFactor(pPos1, pPos2, pDir1->x, pDir1->y, pDir2->x, pDir2->y);
@@ -35,5 +28,4 @@ void CCurves::CalcCurvePoint(CVector* pPos1, CVector* pPos2, CVector* pDir1, CVe
(dir1.x * (1.0f - curveCoef) + dir2.x * curveCoef) / (timeOnCurve * 0.001f),
(dir1.y * (1.0f - curveCoef) + dir2.y * curveCoef) / (timeOnCurve * 0.001f),
0.0f);
-}
-#endif \ No newline at end of file
+} \ No newline at end of file
diff --git a/src/control/Darkel.cpp b/src/control/Darkel.cpp
index b7ae0726..b4d15abf 100644
--- a/src/control/Darkel.cpp
+++ b/src/control/Darkel.cpp
@@ -3,6 +3,7 @@
#include "main.h"
#include "Darkel.h"
#include "PlayerPed.h"
+#include "Wanted.h"
#include "Timer.h"
#include "DMAudio.h"
#include "Population.h"
@@ -161,9 +162,6 @@ CDarkel::ReadStatus()
return Status;
}
-#if 0
-WRAPPER void CDarkel::RegisterCarBlownUpByPlayer(CVehicle *vehicle) { EAXJMP(0x421070); }
-#else
void
CDarkel::RegisterCarBlownUpByPlayer(CVehicle *vehicle)
{
@@ -177,11 +175,7 @@ CDarkel::RegisterCarBlownUpByPlayer(CVehicle *vehicle)
RegisteredKills[vehicle->GetModelIndex()]++;
CStats::CarsExploded++;
}
-#endif
-#if 0
-WRAPPER void CDarkel::RegisterKillByPlayer(CPed *victim, eWeaponType weapontype, bool headshot) { EAXJMP(0x420F60); }
-#else
void
CDarkel::RegisterKillByPlayer(CPed *victim, eWeaponType weapon, bool headshot)
{
@@ -206,7 +200,6 @@ CDarkel::RegisterKillByPlayer(CPed *victim, eWeaponType weapon, bool headshot)
CStats::HeadsPopped++;
CStats::KillsSinceLastCheckpoint++;
}
-#endif
void
CDarkel::RegisterKillNotByPlayer(CPed* victim, eWeaponType weapontype)
@@ -221,9 +214,6 @@ CDarkel::ResetModelsKilledByPlayer()
RegisteredKills[i] = 0;
}
-#if 0
-WRAPPER void CDarkel::ResetOnPlayerDeath() { EAXJMP(0x420E70); }
-#else
void
CDarkel::ResetOnPlayerDeath()
{
@@ -252,11 +242,7 @@ CDarkel::ResetOnPlayerDeath()
player->MakeChangesForNewWeapon(player->m_currentWeapon);
}
}
-#endif
-#if 0
-WRAPPER void CDarkel::StartFrenzy(eWeaponType weaponType, int32 time, uint16 kill, int32 modelId0, wchar *text, int32 modelId2, int32 modelId3, int32 modelId4, bool standardSound, bool needHeadShot) { EAXJMP(0x4210E0); }
-#else
void
CDarkel::StartFrenzy(eWeaponType weaponType, int32 time, uint16 kill, int32 modelId0, wchar *text, int32 modelId2, int32 modelId3, int32 modelId4, bool standardSound, bool needHeadShot)
{
@@ -305,7 +291,6 @@ CDarkel::StartFrenzy(eWeaponType weaponType, int32 time, uint16 kill, int32 mode
if (CDarkel::bStandardSoundAndMessages)
DMAudio.PlayFrontEndSound(SOUND_RAMPAGE_START, 0);
}
-#endif
void
CDarkel::Update()
diff --git a/src/control/Darkel.h b/src/control/Darkel.h
index f17d7581..12ce4451 100644
--- a/src/control/Darkel.h
+++ b/src/control/Darkel.h
@@ -1,9 +1,9 @@
#pragma once
-#include "Weapon.h"
#include "ModelIndices.h"
class CVehicle;
class CPed;
+enum eWeaponType;
enum
{
diff --git a/src/control/GameLogic.cpp b/src/control/GameLogic.cpp
index 1e5b72c3..0abae7d6 100644
--- a/src/control/GameLogic.cpp
+++ b/src/control/GameLogic.cpp
@@ -9,6 +9,7 @@
#include "CutsceneMgr.h"
#include "World.h"
#include "PlayerPed.h"
+#include "Wanted.h"
#include "Camera.h"
#include "Messages.h"
#include "CarCtrl.h"
@@ -56,7 +57,7 @@ CGameLogic::SortOutStreamingAndMemory(const CVector &pos)
CStreaming::FlushRequestList();
CStreaming::DeleteRwObjectsAfterDeath(pos);
CStreaming::RemoveUnusedModelsInLoadedList();
- CGame::DrasticTidyUpMemory();
+ CGame::DrasticTidyUpMemory(true);
CStreaming::LoadScene(pos);
CTimer::Update();
}
diff --git a/src/control/Gangs.cpp b/src/control/Gangs.cpp
index f9cb4698..ac32ad98 100644
--- a/src/control/Gangs.cpp
+++ b/src/control/Gangs.cpp
@@ -1,7 +1,8 @@
#include "common.h"
#include "patcher.h"
#include "ModelIndices.h"
-#include "Gangs.h"
+#include "Gangs.h"
+#include "Weapon.h"
//CGangInfo(&CGangs::Gang)[NUM_GANGS] = *(CGangInfo(*)[NUM_GANGS])*(uintptr*)0x6EDF78;
CGangInfo CGangs::Gang[NUM_GANGS];
@@ -13,7 +14,7 @@ CGangInfo::CGangInfo() :
m_Weapon2(WEAPONTYPE_UNARMED)
{}
-void CGangs::Initialize(void)
+void CGangs::Initialise(void)
{
Gang[GANG_MAFIA].m_nVehicleMI = MI_MAFIA;
Gang[GANG_TRIAD].m_nVehicleMI = MI_BELLYUP;
@@ -38,8 +39,8 @@ void CGangs::SetGangVehicleModel(int16 gang, int32 model)
void CGangs::SetGangWeapons(int16 gang, int32 weapon1, int32 weapon2)
{
CGangInfo *gi = GetGangInfo(gang);
- gi->m_Weapon1 = (eWeaponType)weapon1;
- gi->m_Weapon2 = (eWeaponType)weapon2;
+ gi->m_Weapon1 = weapon1;
+ gi->m_Weapon2 = weapon2;
}
void CGangs::SetGangPedModelOverride(int16 gang, int8 ovrd)
@@ -66,7 +67,7 @@ VALIDATESAVEBUF(*size);
void CGangs::LoadAllGangData(uint8 *buf, uint32 size)
{
- Initialize();
+ Initialise();
INITSAVEBUF
// original: SkipSaveBuf(buf, SAVE_HEADER_SIZE);
@@ -78,7 +79,7 @@ VALIDATESAVEBUF(size);
}
STARTPATCHES
- InjectHook(0x4C3FB0, CGangs::Initialize, PATCH_JUMP);
+ InjectHook(0x4C3FB0, CGangs::Initialise, PATCH_JUMP);
InjectHook(0x4C4010, CGangs::SetGangVehicleModel, PATCH_JUMP);
InjectHook(0x4C4030, CGangs::SetGangWeapons, PATCH_JUMP);
InjectHook(0x4C4050, CGangs::SetGangPedModelOverride, PATCH_JUMP);
diff --git a/src/control/Gangs.h b/src/control/Gangs.h
index a348f259..dd7a7f93 100644
--- a/src/control/Gangs.h
+++ b/src/control/Gangs.h
@@ -1,13 +1,11 @@
#pragma once
-#include "Weapon.h"
-
struct CGangInfo
{
int32 m_nVehicleMI;
int8 m_nPedModelOverride;
- eWeaponType m_Weapon1;
- eWeaponType m_Weapon2;
+ int32 m_Weapon1;
+ int32 m_Weapon2;
CGangInfo();
};
@@ -30,7 +28,7 @@ enum {
class CGangs
{
public:
- static void Initialize(void);
+ static void Initialise(void);
static void SetGangVehicleModel(int16, int32);
static void SetGangWeapons(int16, int32, int32);
static void SetGangPedModelOverride(int16, int8);
diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp
index 5ac15377..7e9fc0fa 100644
--- a/src/control/Garages.cpp
+++ b/src/control/Garages.cpp
@@ -1,152 +1,1384 @@
#include "common.h"
#include "patcher.h"
-#include "main.h"
-#include "ModelIndices.h"
#include "Garages.h"
-#include "Timer.h"
+#include "main.h"
+
+#ifdef FIX_BUGS
+#include "Boat.h"
+#endif
+#include "DMAudio.h"
+#include "General.h"
#include "Font.h"
+#include "HandlingMgr.h"
+#include "Hud.h"
#include "Messages.h"
+#include "ModelIndices.h"
+#include "Pad.h"
+#include "Particle.h"
#include "PlayerPed.h"
+#include "Replay.h"
+#include "Stats.h"
+#include "Streaming.h"
#include "Text.h"
+#include "Timer.h"
+#include "Vehicle.h"
+#include "Wanted.h"
#include "World.h"
-int32 &CGarages::BankVansCollected = *(int32 *)0x8F1B34;
-bool &CGarages::BombsAreFree = *(bool *)0x95CD7A;
-bool &CGarages::RespraysAreFree = *(bool *)0x95CD1D;
-int32 &CGarages::CarsCollected = *(int32 *)0x880E18;
-int32 (&CGarages::CarTypesCollected)[TOTAL_COLLECTCARS_GARAGES] = *(int32 (*)[TOTAL_COLLECTCARS_GARAGES])*(uintptr*)0x8E286C;
-int32 &CGarages::CrushedCarId = *(int32 *)0x943060;
-uint32 &CGarages::LastTimeHelpMessage = *(uint32 *)0x8F1B58;
-int32 &CGarages::MessageNumberInString = *(int32 *)0x885BA8;
-const char *CGarages::MessageIDString = (const char *)0x878358;
-int32 &CGarages::MessageNumberInString2 = *(int32 *)0x8E2C14;
-uint32 &CGarages::MessageStartTime = *(uint32 *)0x8F2530;
-uint32 &CGarages::MessageEndTime = *(uint32 *)0x8F597C;
-uint32 &CGarages::NumGarages = *(uint32 *)0x8F29F4;
-bool &CGarages::PlayerInGarage = *(bool *)0x95CD83;
-int32 &CGarages::PoliceCarsCollected = *(int32 *)0x941444;
-uint32 &CGarages::GarageToBeTidied = *(uint32 *)0x623570;
-
-CGarage(&CGarages::Garages)[NUM_GARAGES] = *(CGarage(*)[NUM_GARAGES])*(uintptr*)0x72BCD0;
-
-WRAPPER void CGarages::Init(void) { EAXJMP(0x421C60); }
-WRAPPER void CGarages::Update(void) { EAXJMP(0x421E40); }
-WRAPPER void CGarages::Load(uint8* buf, uint32 size) { EAXJMP(0x428940); }
-WRAPPER void CGarages::Save(uint8* buf, uint32 *size) { EAXJMP(0x4284e0); }
+#define CRUSHER_GARAGE_X1 (1135.5f)
+#define CRUSHER_GARAGE_Y1 (57.0f)
+#define CRUSHER_GARAGE_Z1 (-1.0f)
+#define CRUSHER_GARAGE_X2 (1149.5f)
+#define CRUSHER_GARAGE_Y2 (63.7f)
+#define CRUSHER_GARAGE_Z2 (3.5f)
-bool
-CGarages::IsModelIndexADoor(uint32 id)
+#define ROTATED_DOOR_OPEN_SPEED (0.015f)
+#define ROTATED_DOOR_CLOSE_SPEED (0.02f)
+#define DEFAULT_DOOR_OPEN_SPEED (0.035f)
+#define DEFAULT_DOOR_CLOSE_SPEED (0.04f)
+#define CRUSHER_CRANE_SPEED (0.005f)
+
+// Prices
+#define BOMB_PRICE (1000)
+#define RESPRAY_PRICE (1000)
+
+// Distances
+#define DISTANCE_TO_CALL_OFF_CHASE (10.0f)
+#define DISTANCE_FOR_MRWHOOP_HACK (4.0f)
+#define DISTANCE_TO_ACTIVATE_GARAGE (8.0f)
+#define DISTANCE_TO_ACTIVATE_KEEPCAR_GARAGE (17.0f)
+#define DISTANCE_TO_CLOSE_MISSION_GARAGE (30.0f)
+#define DISTANCE_TO_CLOSE_COLLECTSPECIFICCARS_GARAGE (25.0f)
+#define DISTANCE_TO_CLOSE_COLLECTCARS_GARAGE (40.0f)
+#define DISTANCE_TO_CLOSE_HIDEOUT_GARAGE_ON_FOOT (2.2f)
+#define DISTANCE_TO_CLOSE_HIDEOUT_GARAGE_IN_CAR (15.0f)
+#define DISTANCE_TO_FORCE_CLOSE_HIDEOUT_GARAGE (70.0f)
+#define DISTANCE_TO_OPEN_HIDEOUT_GARAGE_ON_FOOT (1.7f)
+#define DISTANCE_TO_OPEN_HIDEOUT_GARAGE_IN_CAR (10.0f)
+#define DISTANCE_TO_SHOW_HIDEOUT_MESSAGE (5.0f)
+
+#define DISTANCE_TO_CONSIDER_DOOR_FOR_GARAGE (20.0f)
+
+// Time
+#define TIME_TO_RESPRAY (2000)
+#define TIME_TO_SETUP_BOMB (2000)
+#define TIME_TO_CRUSH_CAR (3000)
+#define TIME_TO_PROCESS_KEEPCAR_GARAGE (2000)
+
+// Respray stuff
+#define FREE_RESPRAY_HEALTH_THRESHOLD (970.0f)
+#define NUM_PARTICLES_IN_RESPRAY (200)
+#define RESPRAY_CENTERING_COEFFICIENT (0.75f)
+
+// Bomb stuff
+#define KGS_OF_EXPLOSIVES_IN_BOMB (10)
+
+// Collect specific cars stuff
+#define REWARD_FOR_FIRST_POLICE_CAR (5000)
+#define REWARD_FOR_FIRST_BANK_VAN (5000)
+#define MAX_POLICE_CARS_TO_COLLECT (10)
+#define MAX_BANK_VANS_TO_COLLECT (10)
+
+// Collect cars stuff
+#define MAX_SPEED_TO_SHOW_COLLECTED_MESSAGE (0.03f)
+#define IMPORT_REWARD (1000)
+#define IMPORT_ALLCARS_REWARD (200000)
+
+// Crusher stuff
+#define CRUSHER_VEHICLE_TEST_SPAN (8)
+#define CRUSHER_MIN_REWARD (25)
+#define CRUSHER_MAX_REWARD (125)
+#define CRUSHER_REWARD_COEFFICIENT (1.0f/500000)
+
+// Hideout stuff
+#define MAX_STORED_CARS_IN_INDUSTRIAL (1)
+#define MAX_STORED_CARS_IN_COMMERCIAL (NUM_GARAGE_STORED_CARS)
+#define MAX_STORED_CARS_IN_SUBURBAN (NUM_GARAGE_STORED_CARS)
+#define LIMIT_CARS_IN_INDUSTRIAL (1)
+#define LIMIT_CARS_IN_COMMERCIAL (2)
+#define LIMIT_CARS_IN_SUBURBAN (3)
+#define HIDEOUT_DOOR_SPEED_COEFFICIENT (1.7f)
+#define TIME_BETWEEN_HIDEOUT_MESSAGES (18000)
+
+// Camera stuff
+#define MARGIN_FOR_CAMERA_COLLECTCARS (1.3f)
+#define MARGIN_FOR_CAMERA_DEFAULT (4.0f)
+
+const int32 gaCarsToCollectInCraigsGarages[TOTAL_COLLECTCARS_GARAGES][TOTAL_COLLECTCARS_CARS] =
{
- return id == MI_GARAGEDOOR1 ||
- id == MI_GARAGEDOOR2 ||
- id == MI_GARAGEDOOR3 ||
- id == MI_GARAGEDOOR4 ||
- id == MI_GARAGEDOOR5 ||
- id == MI_GARAGEDOOR6 ||
- id == MI_GARAGEDOOR7 ||
- id == MI_GARAGEDOOR9 ||
- id == MI_GARAGEDOOR10 ||
- id == MI_GARAGEDOOR11 ||
- id == MI_GARAGEDOOR12 ||
- id == MI_GARAGEDOOR13 ||
- id == MI_GARAGEDOOR14 ||
- id == MI_GARAGEDOOR15 ||
- id == MI_GARAGEDOOR16 ||
- id == MI_GARAGEDOOR17 ||
- id == MI_GARAGEDOOR18 ||
- id == MI_GARAGEDOOR19 ||
- id == MI_GARAGEDOOR20 ||
- id == MI_GARAGEDOOR21 ||
- id == MI_GARAGEDOOR22 ||
- id == MI_GARAGEDOOR23 ||
- id == MI_GARAGEDOOR24 ||
- id == MI_GARAGEDOOR25 ||
- id == MI_GARAGEDOOR26 ||
- id == MI_GARAGEDOOR27 ||
- id == MI_GARAGEDOOR28 ||
- id == MI_GARAGEDOOR29 ||
- id == MI_GARAGEDOOR30 ||
- id == MI_GARAGEDOOR31 ||
- id == MI_GARAGEDOOR32 ||
- id == MI_CRUSHERBODY ||
- id == MI_CRUSHERLID;
+ { MI_SECURICA, MI_MOONBEAM, MI_COACH, MI_FLATBED, MI_LINERUN, MI_TRASH, MI_PATRIOT, MI_MRWHOOP, MI_BLISTA, MI_MULE, MI_YANKEE, MI_BOBCAT, MI_DODO, MI_BUS, MI_RUMPO, MI_PONY },
+ { MI_SENTINEL, MI_CHEETAH, MI_BANSHEE, MI_IDAHO, MI_INFERNUS, MI_TAXI, MI_KURUMA, MI_STRETCH, MI_PEREN, MI_STINGER, MI_MANANA, MI_LANDSTAL, MI_STALLION, MI_BFINJECT, MI_CABBIE, MI_ESPERANT },
+ { MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_CHEETAH, MI_TAXI, MI_ESPERANT, MI_SENTINEL, MI_IDAHO }
+};
+
+int32& CGarages::BankVansCollected = *(int32*)0x8F1B34;
+bool& CGarages::BombsAreFree = *(bool*)0x95CD7A;
+bool& CGarages::RespraysAreFree = *(bool*)0x95CD1D;
+int32& CGarages::CarsCollected = *(int32*)0x880E18;
+int32(&CGarages::CarTypesCollected)[TOTAL_COLLECTCARS_GARAGES] = *(int32(*)[TOTAL_COLLECTCARS_GARAGES]) * (uintptr*)0x8E286C;
+int32& CGarages::CrushedCarId = *(int32*)0x943060;
+uint32& CGarages::LastTimeHelpMessage = *(uint32*)0x8F1B58;
+int32& CGarages::MessageNumberInString = *(int32*)0x885BA8;
+char(&CGarages::MessageIDString)[MESSAGE_LENGTH] = *(char(*)[MESSAGE_LENGTH]) * (uintptr*)0x878358;
+int32& CGarages::MessageNumberInString2 = *(int32*)0x8E2C14;
+uint32& CGarages::MessageStartTime = *(uint32*)0x8F2530;
+uint32& CGarages::MessageEndTime = *(uint32*)0x8F597C;
+uint32& CGarages::NumGarages = *(uint32*)0x8F29F4;
+bool& CGarages::PlayerInGarage = *(bool*)0x95CD83;
+int32& CGarages::PoliceCarsCollected = *(int32*)0x941444;
+uint32& CGarages::GarageToBeTidied = *(uint32*)0x623570;
+CStoredCar(&CGarages::aCarsInSafeHouse1)[NUM_GARAGE_STORED_CARS] = *(CStoredCar(*)[NUM_GARAGE_STORED_CARS]) * (uintptr*)0x6FA210;
+CStoredCar(&CGarages::aCarsInSafeHouse2)[NUM_GARAGE_STORED_CARS] = *(CStoredCar(*)[NUM_GARAGE_STORED_CARS]) * (uintptr*)0x6FA300;
+CStoredCar(&CGarages::aCarsInSafeHouse3)[NUM_GARAGE_STORED_CARS] = *(CStoredCar(*)[NUM_GARAGE_STORED_CARS]) * (uintptr*)0x6FA3F0;
+int32& CGarages::AudioEntity = *(int32*)0x5ECEA8;
+CGarage(&CGarages::aGarages)[NUM_GARAGES] = *(CGarage(*)[NUM_GARAGES]) * (uintptr*)0x72BCD0;
+bool& CGarages::bCamShouldBeOutisde = *(bool*)0x95CDB2;
+
+void CGarages::Init(void)
+{
+ CrushedCarId = -1;
+ NumGarages = 0;
+ MessageEndTime = 0;
+ MessageStartTime = 0;
+ PlayerInGarage = false;
+ BombsAreFree = false;
+ CarsCollected = 0;
+ BankVansCollected = 0;
+ PoliceCarsCollected = 0;
+ for (int i = 0; i < TOTAL_COLLECTCARS_GARAGES; i++)
+ CarTypesCollected[i] = 0;
+ LastTimeHelpMessage = 0;
+ for (int i = 0; i < NUM_GARAGE_STORED_CARS; i++)
+ aCarsInSafeHouse1[i].Init();
+ for (int i = 0; i < NUM_GARAGE_STORED_CARS; i++)
+ aCarsInSafeHouse2[i].Init();
+ for (int i = 0; i < NUM_GARAGE_STORED_CARS; i++)
+ aCarsInSafeHouse3[i].Init();
+ AudioEntity = DMAudio.CreateEntity(AUDIOTYPE_GARAGE, (void*)1);
+ if (AudioEntity >= 0)
+ DMAudio.SetEntityStatus(AudioEntity, 1);
+ AddOne(
+ CRUSHER_GARAGE_X1, CRUSHER_GARAGE_Y1, CRUSHER_GARAGE_Z1,
+ CRUSHER_GARAGE_X2, CRUSHER_GARAGE_Y2, CRUSHER_GARAGE_Z2,
+ GARAGE_CRUSHER, 0);
}
-bool CGarages::HasCarBeenCrushed(int32 handle)
+#ifndef PS2
+void CGarages::Shutdown(void)
{
- return CrushedCarId == handle;
+ NumGarages = 0;
+ if (AudioEntity < 0)
+ return;
+ DMAudio.DestroyEntity(AudioEntity);
+ AudioEntity = AEHANDLE_NONE;
}
+#endif
-WRAPPER void CGarages::TriggerMessage(const char *text, int16, uint16 time, int16) { EAXJMP(0x426B20); }
-WRAPPER bool CGarages::IsPointWithinHideOutGarage(CVector&) { EAXJMP(0x428260); }
-WRAPPER bool CGarages::IsPointWithinAnyGarage(CVector&) { EAXJMP(0x428320); }
-WRAPPER void CGarages::PlayerArrestedOrDied() { EAXJMP(0x427F60); }
-WRAPPER int16 CGarages::AddOne(float, float, float, float, float, float, uint8, uint32) { EAXJMP(0x421FA0); }
-WRAPPER void CGarages::SetTargetCarForMissonGarage(int16, CVehicle*) { EAXJMP(0x426BD0); }
-WRAPPER bool CGarages::HasCarBeenDroppedOffYet(int16) { EAXJMP(0x426C20); }
-WRAPPER void CGarages::DeActivateGarage(int16) { EAXJMP(0x426C40); }
-WRAPPER void CGarages::ActivateGarage(int16) { EAXJMP(0x426C60); }
+void CGarages::Update(void)
+{
+ static int GarageToBeTidied = 0;
+#ifndef PS2
+ if (CReplay::IsPlayingBack())
+ return;
+#endif
+ bCamShouldBeOutisde = false;
+ TheCamera.pToGarageWeAreIn = nil;
+ TheCamera.pToGarageWeAreInForHackAvoidFirstPerson = nil;
+ for (int i = 0; i < NUM_GARAGES; i++) {
+ if (aGarages[i].IsUsed())
+ aGarages[i].Update();
+ }
+ if ((CTimer::GetFrameCounter() & 0xF) != 0xC)
+ return;
+ if (++GarageToBeTidied >= NUM_GARAGES)
+ GarageToBeTidied = 0;
+ if (!aGarages[GarageToBeTidied].IsUsed())
+ return;
+ if (!aGarages[GarageToBeTidied].IsFar())
+ aGarages[GarageToBeTidied].TidyUpGarageClose();
+ else
+ aGarages[GarageToBeTidied].TidyUpGarage();
+}
-int32 CGarages::QueryCarsCollected(int16 garage)
+int16 CGarages::AddOne(float X1, float Y1, float Z1, float X2, float Y2, float Z2, eGarageType type, int32 targetId)
{
- return 0;
+ if (NumGarages >= NUM_GARAGES) {
+ assert(0);
+ return NumGarages++;
+ }
+ CGarage* pGarage = &aGarages[NumGarages];
+ pGarage->m_fX1 = min(X1, X2);
+ pGarage->m_fX2 = max(X1, X2);
+ pGarage->m_fY1 = min(Y1, Y2);
+ pGarage->m_fY2 = max(Y1, Y2);
+ pGarage->m_fZ1 = min(Z1, Z2);
+ pGarage->m_fZ2 = max(Z1, Z2);
+ pGarage->m_pDoor1 = nil;
+ pGarage->m_pDoor2 = nil;
+ pGarage->m_fDoor1Z = Z1;
+ pGarage->m_fDoor2Z = Z1;
+ pGarage->m_eGarageType = type;
+ pGarage->m_bRecreateDoorOnNextRefresh = false;
+ pGarage->m_bRotatedDoor = false;
+ pGarage->m_bCameraFollowsPlayer = false;
+ pGarage->RefreshDoorPointers(true);
+ if (pGarage->m_pDoor1) {
+ pGarage->m_fDoor1Z = pGarage->m_pDoor1->GetPosition().z;
+ pGarage->m_fDoor1X = pGarage->m_pDoor1->GetPosition().x;
+ pGarage->m_fDoor1Y = pGarage->m_pDoor1->GetPosition().y;
+ }
+ if (pGarage->m_pDoor2) {
+ pGarage->m_fDoor2Z = pGarage->m_pDoor2->GetPosition().z;
+ pGarage->m_fDoor2X = pGarage->m_pDoor2->GetPosition().x;
+ pGarage->m_fDoor2Y = pGarage->m_pDoor2->GetPosition().y;
+ }
+ pGarage->m_fDoorHeight = pGarage->m_pDoor1 ? FindDoorHeightForMI(pGarage->m_pDoor1->GetModelIndex()) : 4.0f;
+ pGarage->m_fDoorPos = 0.0f;
+ pGarage->m_eGarageState = GS_FULLYCLOSED;
+ pGarage->m_nTimeToStartAction = 0;
+ pGarage->field_2 = false;
+ pGarage->m_nTargetModelIndex = targetId;
+ pGarage->field_96 = nil;
+ pGarage->m_bCollectedCarsState = 0;
+ pGarage->m_bDeactivated = false;
+ pGarage->m_bResprayHappened = false;
+ switch (type) {
+ case GARAGE_MISSION:
+ case GARAGE_COLLECTORSITEMS:
+ case GARAGE_COLLECTSPECIFICCARS:
+ case GARAGE_COLLECTCARS_1:
+ case GARAGE_COLLECTCARS_2:
+ case GARAGE_COLLECTCARS_3:
+ case GARAGE_FORCARTOCOMEOUTOF:
+ case GARAGE_60SECONDS:
+ case GARAGE_MISSION_KEEPCAR:
+ case GARAGE_FOR_SCRIPT_TO_OPEN:
+ case GARAGE_HIDEOUT_ONE:
+ case GARAGE_HIDEOUT_TWO:
+ case GARAGE_HIDEOUT_THREE:
+ case GARAGE_FOR_SCRIPT_TO_OPEN_AND_CLOSE:
+ case GARAGE_KEEPS_OPENING_FOR_SPECIFIC_CAR:
+ case GARAGE_MISSION_KEEPCAR_REMAINCLOSED:
+ pGarage->m_eGarageState = GS_FULLYCLOSED;
+ pGarage->m_fDoorPos = 0.0f;
+ break;
+ case GARAGE_BOMBSHOP1:
+ case GARAGE_BOMBSHOP2:
+ case GARAGE_BOMBSHOP3:
+ case GARAGE_RESPRAY:
+ pGarage->m_eGarageState = GS_OPENED;
+ pGarage->m_fDoorPos = pGarage->m_fDoorHeight;
+ break;
+ case GARAGE_CRUSHER:
+ pGarage->m_eGarageState = GS_OPENED;
+ pGarage->m_fDoorPos = HALFPI;
+ break;
+ default:
+ assert(false);
+ }
+ if (type == GARAGE_CRUSHER)
+ pGarage->UpdateCrusherAngle();
+ else
+ pGarage->UpdateDoorsHeight();
+ return NumGarages++;
}
-void CGarages::GivePlayerDetonator()
+void CGarages::ChangeGarageType(int16 garage, eGarageType type, int32 mi)
{
- FindPlayerPed()->GiveWeapon(WEAPONTYPE_DETONATOR, 1);
- FindPlayerPed()->GetWeapon(FindPlayerPed()->GetWeaponSlot(WEAPONTYPE_DETONATOR)).m_eWeaponState = WEAPONSTATE_READY;
+ CGarage* pGarage = &aGarages[garage];
+ pGarage->m_eGarageType = type;
+ pGarage->m_nTargetModelIndex = mi;
+ pGarage->m_eGarageState = GS_FULLYCLOSED;
+}
+
+void CGarage::Update()
+{
+ if (m_eGarageType != GARAGE_CRUSHER) {
+ switch (m_eGarageState) {
+ case GS_FULLYCLOSED:
+ case GS_OPENED:
+ case GS_CLOSING:
+ case GS_OPENING:
+ case GS_OPENEDCONTAINSCAR:
+ case GS_CLOSEDCONTAINSCAR:
+ if (FindPlayerPed() && !m_bCameraFollowsPlayer) {
+ CVehicle* pVehicle = FindPlayerVehicle();
+ if (IsEntityEntirelyInside3D(FindPlayerPed(), 0.25f)) {
+ TheCamera.pToGarageWeAreIn = this;
+ CGarages::bCamShouldBeOutisde = true;
+ }
+ if (pVehicle) {
+ if (IsEntityEntirelyOutside(pVehicle, 0.0f))
+ TheCamera.pToGarageWeAreInForHackAvoidFirstPerson = this;
+ if (pVehicle->GetModelIndex() == MI_MRWHOOP) {
+ if (pVehicle->IsWithinArea(
+ m_fX1 - DISTANCE_FOR_MRWHOOP_HACK,
+ m_fX2 + DISTANCE_FOR_MRWHOOP_HACK,
+ m_fY1 - DISTANCE_FOR_MRWHOOP_HACK,
+ m_fY2 + DISTANCE_FOR_MRWHOOP_HACK)) {
+ TheCamera.pToGarageWeAreIn = this;
+ CGarages::bCamShouldBeOutisde = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (m_bDeactivated && m_eGarageState == GS_FULLYCLOSED)
+ return;
+ switch (m_eGarageType) {
+ case GARAGE_RESPRAY:
+ switch (m_eGarageState) {
+ case GS_OPENED:
+ if (IsStaticPlayerCarEntirelyInside() && !IsAnyOtherCarTouchingGarage(FindPlayerVehicle())) {
+ if (CGarages::IsCarSprayable(FindPlayerVehicle())) {
+ if (CWorld::Players[CWorld::PlayerInFocus].m_nMoney >= RESPRAY_PRICE || CGarages::RespraysAreFree) {
+ m_eGarageState = GS_CLOSING;
+ CPad::GetPad(0)->SetDisablePlayerControls(PLAYERCONTROL_GARAGE);
+ FindPlayerPed()->m_pWanted->m_bIgnoredByCops = true;
+ }
+ else {
+ CGarages::TriggerMessage("GA_3", -1, 4000, -1); // No more freebies. $1000 to respray!
+ m_eGarageState = GS_OPENEDCONTAINSCAR;
+ DMAudio.PlayFrontEndSound(SOUND_GARAGE_NO_MONEY, 1);
+ }
+ }
+ else {
+ CGarages::TriggerMessage("GA_1", -1, 4000, -1); // Whoa! I don't touch nothing THAT hot!
+ m_eGarageState = GS_OPENEDCONTAINSCAR;
+ DMAudio.PlayFrontEndSound(SOUND_GARAGE_BAD_VEHICLE, 1);
+ }
+ }
+ if (FindPlayerVehicle()) {
+ if (CalcDistToGarageRectangleSquared(FindPlayerVehicle()->GetPosition().x, FindPlayerVehicle()->GetPosition().y) < SQR(DISTANCE_TO_ACTIVATE_GARAGE))
+ CWorld::CallOffChaseForArea(
+ m_fX1 - DISTANCE_TO_CALL_OFF_CHASE,
+ m_fY1 - DISTANCE_TO_CALL_OFF_CHASE,
+ m_fX2 + DISTANCE_TO_CALL_OFF_CHASE,
+ m_fY2 + DISTANCE_TO_CALL_OFF_CHASE);
+ }
+ break;
+ case GS_CLOSING:
+ m_fDoorPos = max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep());
+ if (m_fDoorPos == 0.0f) {
+ m_eGarageState = GS_FULLYCLOSED;
+ m_nTimeToStartAction = CTimer::GetTimeInMilliseconds() + TIME_TO_RESPRAY;
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f);
+ CStats::CheckPointReachedSuccessfully();
+ }
+ UpdateDoorsHeight();
+#ifdef FIX_BUGS
+ if (FindPlayerVehicle() && FindPlayerVehicle()->IsCar())
+#else
+ if (FindPlayerVehicle())
+#endif
+ ((CAutomobile*)(FindPlayerVehicle()))->m_fFireBlowUpTimer = 0.0f;
+ CWorld::CallOffChaseForArea(
+ m_fX1 - DISTANCE_TO_CALL_OFF_CHASE,
+ m_fY1 - DISTANCE_TO_CALL_OFF_CHASE,
+ m_fX2 + DISTANCE_TO_CALL_OFF_CHASE,
+ m_fY2 + DISTANCE_TO_CALL_OFF_CHASE);
+ break;
+ case GS_FULLYCLOSED:
+ if (CTimer::GetTimeInMilliseconds() > m_nTimeToStartAction) {
+ m_eGarageState = GS_OPENING;
+ DMAudio.PlayFrontEndSound(SOUND_GARAGE_OPENING, 1);
+ bool bTakeMoney = false;
+ if (FindPlayerPed()->m_pWanted->m_nWantedLevel != 0)
+ bTakeMoney = true;
+ FindPlayerPed()->m_pWanted->Reset();
+ CPad::GetPad(0)->SetEnablePlayerControls(PLAYERCONTROL_GARAGE);
+ FindPlayerPed()->m_pWanted->m_bIgnoredByCops = true;
+#ifdef FIX_BUGS
+ bool bChangedColour = false;
+#else
+ bool bChangedColour;
+#endif
+ if (FindPlayerVehicle() && FindPlayerVehicle()->IsCar()) {
+ if (FindPlayerVehicle()->m_fHealth < FREE_RESPRAY_HEALTH_THRESHOLD)
+ bTakeMoney = true;
+ FindPlayerVehicle()->m_fHealth = 1000.0f;
+ ((CAutomobile*)(FindPlayerVehicle()))->m_fFireBlowUpTimer = 0.0f;
+ ((CAutomobile*)(FindPlayerVehicle()))->Fix();
+ if (FindPlayerVehicle()->GetUp().z < 0.0f) {
+ FindPlayerVehicle()->GetUp() = -FindPlayerVehicle()->GetUp();
+ FindPlayerVehicle()->GetRight() = -FindPlayerVehicle()->GetRight();
+ }
+ bChangedColour = false;
+ if (!((CAutomobile*)(FindPlayerVehicle()))->bFixedColour) {
+ uint8 colour1, colour2;
+ uint16 attempt;
+ ((CVehicleModelInfo*)CModelInfo::GetModelInfo(FindPlayerVehicle()->GetModelIndex()))->ChooseVehicleColour(colour1, colour2);
+ for (attempt = 0; attempt < 10; attempt++) {
+ if (colour1 != FindPlayerVehicle()->m_currentColour1 || colour2 != FindPlayerVehicle()->m_currentColour2)
+ break;
+ ((CVehicleModelInfo*)CModelInfo::GetModelInfo(FindPlayerVehicle()->GetModelIndex()))->ChooseVehicleColour(colour1, colour2);
+ }
+ bChangedColour = (attempt < 10);
+ FindPlayerVehicle()->m_currentColour1 = colour1;
+ FindPlayerVehicle()->m_currentColour2 = colour2;
+ if (bChangedColour) {
+ for (int i = 0; i < NUM_PARTICLES_IN_RESPRAY; i++) {
+ CVector pos;
+#ifdef FIX_BUGS
+ pos.x = CGeneral::GetRandomNumberInRange(m_fX1 + 0.5f, m_fX2 - 0.5f);
+ pos.y = CGeneral::GetRandomNumberInRange(m_fY1 + 0.5f, m_fY2 - 0.5f);
+ pos.z = CGeneral::GetRandomNumberInRange(m_fDoor1Z - 3.0f, m_fDoor1Z + 1.0f);
+#else
+ // wtf is this
+ pos.x = m_fX1 + 0.5f + (uint8)(CGeneral::GetRandomNumber()) / 256.0f * (m_fX2 - m_fX1 - 1.0f);
+ pos.y = m_fY1 + 0.5f + (uint8)(CGeneral::GetRandomNumber()) / 256.0f * (m_fY2 - m_fY1 - 1.0f);
+ pos.z = m_fDoor1Z - 3.0f + (uint8)(CGeneral::GetRandomNumber()) / 256.0f * 4.0f;
+#endif
+ CParticle::AddParticle(PARTICLE_GARAGEPAINT_SPRAY, pos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, CVehicleModelInfo::ms_vehicleColourTable[colour1]);
+ }
+ }
+ }
+ CenterCarInGarage(FindPlayerVehicle());
+ }
+ if (bTakeMoney) {
+ if (!CGarages::RespraysAreFree)
+ CWorld::Players[CWorld::PlayerInFocus].m_nMoney = max(0, CWorld::Players[CWorld::PlayerInFocus].m_nMoney - RESPRAY_PRICE);
+ CGarages::TriggerMessage("GA_2", -1, 4000, -1); // New engine and paint job. The cops won't recognize you!
+ }
+ else if (bChangedColour) {
+ if (CGeneral::GetRandomTrueFalse())
+ CGarages::TriggerMessage("GA_15", -1, 4000, -1); // Hope you like the new color.
+ else
+ CGarages::TriggerMessage("GA_16", -1, 4000, -1); // Respray is complementary.
+ }
+ m_bResprayHappened = true;
+ }
+ CWorld::CallOffChaseForArea(
+ m_fX1 - DISTANCE_TO_CALL_OFF_CHASE,
+ m_fY1 - DISTANCE_TO_CALL_OFF_CHASE,
+ m_fX2 + DISTANCE_TO_CALL_OFF_CHASE,
+ m_fY2 + DISTANCE_TO_CALL_OFF_CHASE);
+ break;
+ case GS_OPENING:
+ m_fDoorPos = min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep());
+ if (m_fDoorPos == m_fDoorHeight) {
+ m_eGarageState = GS_OPENEDCONTAINSCAR;
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f);
+ }
+ UpdateDoorsHeight();
+ break;
+ case GS_OPENEDCONTAINSCAR:
+ if (IsPlayerOutsideGarage())
+ m_eGarageState = GS_OPENED;
+ break;
+ //case GS_CLOSEDCONTAINSCAR:
+ //case GS_AFTERDROPOFF:
+ default:
+ break;
+ }
+ break;
+ case GARAGE_BOMBSHOP1:
+ case GARAGE_BOMBSHOP2:
+ case GARAGE_BOMBSHOP3:
+ switch (m_eGarageState) {
+ case GS_OPENED:
+ if (IsStaticPlayerCarEntirelyInside() && !IsAnyOtherCarTouchingGarage(FindPlayerVehicle())) {
+#ifdef FIX_BUGS // FindPlayerVehicle() can never be NULL here because IsStaticPlayerCarEntirelyInside() is true, and there is no IsCar() check
+ if (FindPlayerVehicle()->IsCar() && ((CAutomobile*)FindPlayerVehicle())->m_bombType) {
+#else
+ if (!FindPlayerVehicle() || ((CAutomobile*)FindPlayerVehicle())->m_bombType) {
+#endif
+ CGarages::TriggerMessage("GA_5", -1, 4000, -1); //"Your car is already fitted with a bomb"
+ m_eGarageState = GS_OPENEDCONTAINSCAR;
+ DMAudio.PlayFrontEndSound(SOUND_GARAGE_BOMB_ALREADY_SET, 1);
+ break;
+ }
+ if (!CGarages::BombsAreFree && CWorld::Players[CWorld::PlayerInFocus].m_nMoney < BOMB_PRICE) {
+ CGarages::TriggerMessage("GA_4", -1, 4000, -1); // "Car bombs are $1000 each"
+ m_eGarageState = GS_OPENEDCONTAINSCAR;
+ DMAudio.PlayFrontEndSound(SOUND_GARAGE_NO_MONEY, 1);
+ break;
+ }
+ m_eGarageState = GS_CLOSING;
+ CPad::GetPad(0)->SetDisablePlayerControls(PLAYERCONTROL_GARAGE);
+ FindPlayerPed()->m_pWanted->m_bIgnoredByCops = true;
+ }
+ break;
+ case GS_CLOSING:
+ m_fDoorPos = max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep());
+ if (m_fDoorPos == 0.0f) {
+ m_eGarageState = GS_FULLYCLOSED;
+ m_nTimeToStartAction = CTimer::GetTimeInMilliseconds() + TIME_TO_SETUP_BOMB;
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f);
+ }
+ UpdateDoorsHeight();
+ break;
+ case GS_FULLYCLOSED:
+ if (CTimer::GetTimeInMilliseconds() > m_nTimeToStartAction) {
+ switch (m_eGarageType) {
+ case GARAGE_BOMBSHOP1: DMAudio.PlayFrontEndSound(SOUND_GARAGE_BOMB1_SET, 1); break;
+ case GARAGE_BOMBSHOP2: DMAudio.PlayFrontEndSound(SOUND_GARAGE_BOMB2_SET, 1); break;
+ case GARAGE_BOMBSHOP3: DMAudio.PlayFrontEndSound(SOUND_GARAGE_BOMB3_SET, 1); break;
+ }
+ m_eGarageState = GS_OPENING;
+ if (!CGarages::BombsAreFree)
+ CWorld::Players[CWorld::PlayerInFocus].m_nMoney = max(0, CWorld::Players[CWorld::PlayerInFocus].m_nMoney - BOMB_PRICE);
+ if (FindPlayerVehicle() && FindPlayerVehicle()->IsCar()) {
+ ((CAutomobile*)(FindPlayerVehicle()))->m_bombType = CGarages::GetBombTypeForGarageType(m_eGarageType);
+ ((CAutomobile*)(FindPlayerVehicle()))->m_pBombRigger = FindPlayerPed();
+ if (m_eGarageType == GARAGE_BOMBSHOP3)
+ CGarages::GivePlayerDetonator();
+ CStats::KgOfExplosivesUsed += KGS_OF_EXPLOSIVES_IN_BOMB;
+ }
+ switch (m_eGarageType) {
+ case GARAGE_BOMBSHOP1:
+ switch (CPad::GetPad(0)->Mode) {
+ case 0:
+ case 1:
+ case 2:
+ CHud::SetHelpMessage(TheText.Get("GA_6"), false); // Arm with ~h~~k~~PED_FIREWEAPON~ button~w~. Bomb will go off when engine is started.
+ break;
+ case 3:
+ CHud::SetHelpMessage(TheText.Get("GA_6B"), false); // Arm with ~h~~k~~PED_FIREWEAPON~ button~w~. Bomb will go off when engine is started.
+ break;
+ }
+ break;
+ case GARAGE_BOMBSHOP2:
+ switch (CPad::GetPad(0)->Mode) {
+ case 0:
+ case 1:
+ case 2:
+ CHud::SetHelpMessage(TheText.Get("GA_7"), false); // Park it, prime it by pressing the ~h~~k~~PED_FIREWEAPON~ button~w~ and LEG IT!
+ break;
+ case 3:
+ CHud::SetHelpMessage(TheText.Get("GA_7B"), false); // Park it, prime it by pressing the ~h~~k~~PED_FIREWEAPON~ button~w~ and LEG IT!
+ break;
+ }
+ break;
+ case GARAGE_BOMBSHOP3:
+ CHud::SetHelpMessage(TheText.Get("GA_8"), false); // Use the detonator to activate the bomb.
+ break;
+ }
+ CPad::GetPad(0)->SetEnablePlayerControls(PLAYERCONTROL_GARAGE);
+ FindPlayerPed()->m_pWanted->m_bIgnoredByCops = false;
+ }
+ break;
+ case GS_OPENING:
+ m_fDoorPos = min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep());
+ if (m_fDoorPos == m_fDoorHeight) {
+ m_eGarageState = GS_OPENEDCONTAINSCAR;
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f);
+ }
+ UpdateDoorsHeight();
+ break;
+ case GS_OPENEDCONTAINSCAR:
+ if (IsPlayerOutsideGarage())
+ m_eGarageState = GS_OPENED;
+ break;
+ //case GS_CLOSEDCONTAINSCAR:
+ //case GS_AFTERDROPOFF:
+ default:
+ break;
+ }
+ break;
+ case GARAGE_MISSION:
+ switch (m_eGarageState) {
+ case GS_OPENED:
+ if (((CVector2D)FindPlayerCoors() - CVector2D(GetGarageCenterX(), GetGarageCenterY())).MagnitudeSqr() > SQR(DISTANCE_TO_CLOSE_MISSION_GARAGE)) {
+ if ((CTimer::GetFrameCounter() & 0x1F) == 0 && !IsAnyOtherCarTouchingGarage(nil)) {
+ m_eGarageState = GS_CLOSING;
+ m_bClosingWithoutTargetCar = true;
+ }
+ }
+ else if (!FindPlayerVehicle() && m_pTarget && IsEntityEntirelyInside3D(m_pTarget, 0.0f) &&
+ !IsAnyOtherCarTouchingGarage(m_pTarget) && IsEntityEntirelyOutside(FindPlayerPed(), 2.0f)) {
+ CPad::GetPad(0)->SetDisablePlayerControls(PLAYERCONTROL_GARAGE);
+ FindPlayerPed()->m_pWanted->m_bIgnoredByCops = true;
+ m_eGarageState = GS_CLOSING;
+ m_bClosingWithoutTargetCar = false;
+ }
+ break;
+ case GS_CLOSING:
+ m_fDoorPos = max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep());
+ if (m_fDoorPos == 0.0f) {
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f);
+ if (m_bClosingWithoutTargetCar)
+ m_eGarageState = GS_FULLYCLOSED;
+ else {
+ if (m_pTarget) {
+ m_eGarageState = GS_CLOSEDCONTAINSCAR;
+ DestroyVehicleAndDriverAndPassengers(m_pTarget);
+ m_pTarget = nil;
+ }
+ else {
+ m_eGarageState = GS_FULLYCLOSED;
+ }
+ CPad::GetPad(0)->SetEnablePlayerControls(PLAYERCONTROL_GARAGE);
+ FindPlayerPed()->m_pWanted->m_bIgnoredByCops = false;
+ }
+ }
+ UpdateDoorsHeight();
+ break;
+ case GS_FULLYCLOSED:
+ if (FindPlayerVehicle() == m_pTarget && m_pTarget) {
+ if (CalcDistToGarageRectangleSquared(
+ FindPlayerVehicle()->GetPosition().x,
+ FindPlayerVehicle()->GetPosition().y) < SQR(DISTANCE_TO_ACTIVATE_GARAGE))
+ m_eGarageState = GS_OPENING;
+ }
+ break;
+ case GS_OPENING:
+ m_fDoorPos = min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep());
+ if (m_fDoorPos == m_fDoorHeight) {
+ m_eGarageState = GS_OPENED;
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f);
+ }
+ UpdateDoorsHeight();
+ break;
+ //case GS_OPENEDCONTAINSCAR:
+ //case GS_CLOSEDCONTAINSCAR:
+ //case GS_AFTERDROPOFF:
+ default:
+ break;
+ }
+ break;
+ case GARAGE_COLLECTSPECIFICCARS:
+ switch (m_eGarageState) {
+ case GS_OPENED:
+ if (FindPlayerVehicle() && m_nTargetModelIndex == FindPlayerVehicle()->GetModelIndex()) {
+ m_pTarget = FindPlayerVehicle();
+ m_pTarget->RegisterReference((CEntity**)&m_pTarget);
+ }
+ if (!FindPlayerVehicle()) {
+ if (m_pTarget && IsEntityEntirelyInside3D(m_pTarget, 0.0f) && !IsAnyOtherCarTouchingGarage(m_pTarget)) {
+ if (IsEntityEntirelyOutside(FindPlayerPed(), 2.0f)) {
+ CPad::GetPad(0)->SetDisablePlayerControls(PLAYERCONTROL_GARAGE);
+ FindPlayerPed()->m_pWanted->m_bIgnoredByCops = true;
+ m_eGarageState = GS_CLOSING;
+ }
+ }
+ else if (Abs(FindPlayerCoors().x - GetGarageCenterX()) > DISTANCE_TO_CLOSE_COLLECTSPECIFICCARS_GARAGE ||
+ Abs(FindPlayerCoors().y - GetGarageCenterY()) > DISTANCE_TO_CLOSE_COLLECTSPECIFICCARS_GARAGE) {
+ m_eGarageState = GS_CLOSING;
+ m_pTarget = nil;
+ }
+ }
+ break;
+ case GS_CLOSING:
+ m_fDoorPos = max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep());
+ if (m_fDoorPos == 0.0f) {
+ m_eGarageState = GS_FULLYCLOSED;
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f);
+ if (m_pTarget) {
+ DestroyVehicleAndDriverAndPassengers(m_pTarget);
+ m_pTarget = nil;
+ CPad::GetPad(0)->SetEnablePlayerControls(PLAYERCONTROL_GARAGE);
+ FindPlayerPed()->m_pWanted->m_bIgnoredByCops = false;
+ int16 reward;
+ switch (m_nTargetModelIndex) {
+ case MI_POLICE:
+ reward = REWARD_FOR_FIRST_POLICE_CAR * (MAX_POLICE_CARS_TO_COLLECT - CGarages::PoliceCarsCollected++) / MAX_POLICE_CARS_TO_COLLECT;
+ break;
+ case MI_SECURICA:
+ reward = REWARD_FOR_FIRST_BANK_VAN * (MAX_BANK_VANS_TO_COLLECT - CGarages::BankVansCollected++) / MAX_BANK_VANS_TO_COLLECT;
+ break;
+#ifdef FIX_BUGS // not possible though
+ default:
+ reward = 0;
+ break;
+#endif
+ }
+ if (reward > 0) {
+ CWorld::Players[CWorld::PlayerInFocus].m_nMoney += reward;
+ CGarages::TriggerMessage("GA_10", reward, 4000, -1); // Nice one. Here's your $~1~
+ DMAudio.PlayFrontEndSound(SOUND_GARAGE_VEHICLE_ACCEPTED, 1);
+ }
+ else {
+ CGarages::TriggerMessage("GA_11", -1, 4000, -1); // We got these wheels already. It's worthless to us!
+ DMAudio.PlayFrontEndSound(SOUND_GARAGE_VEHICLE_DECLINED, 1);
+ }
+ }
+ }
+ UpdateDoorsHeight();
+ break;
+ case GS_FULLYCLOSED:
+ if (FindPlayerVehicle() && m_nTargetModelIndex == FindPlayerVehicle()->GetModelIndex()) {
+ if (CalcDistToGarageRectangleSquared(FindPlayerVehicle()->GetPosition().x, FindPlayerVehicle()->GetPosition().y) < SQR(DISTANCE_TO_ACTIVATE_GARAGE))
+ m_eGarageState = GS_OPENING;
+ }
+ break;
+ case GS_OPENING:
+ if (FindPlayerVehicle() && m_nTargetModelIndex == FindPlayerVehicle()->GetModelIndex()) {
+ m_pTarget = FindPlayerVehicle();
+ m_pTarget->RegisterReference((CEntity**)&m_pTarget);
+ }
+ m_fDoorPos = min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep());
+ if (m_fDoorPos == m_fDoorHeight) {
+ m_eGarageState = GS_OPENED;
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f);
+ }
+ UpdateDoorsHeight();
+ break;
+ //case GS_OPENEDCONTAINSCAR:
+ //case GS_CLOSEDCONTAINSCAR:
+ //case GS_AFTERDROPOFF:
+ default:
+ break;
+ }
+ break;
+ case GARAGE_COLLECTCARS_1:
+ case GARAGE_COLLECTCARS_2:
+ case GARAGE_COLLECTCARS_3:
+ switch (m_eGarageState) {
+ case GS_OPENED:
+ if (FindPlayerVehicle() && DoesCraigNeedThisCar(FindPlayerVehicle()->GetModelIndex())) {
+ m_pTarget = FindPlayerVehicle();
+ m_pTarget->RegisterReference((CEntity**)&m_pTarget);
+ }
+ if (Abs(FindPlayerCoors().x - GetGarageCenterX()) > DISTANCE_TO_CLOSE_COLLECTCARS_GARAGE ||
+ Abs(FindPlayerCoors().y - GetGarageCenterY()) > DISTANCE_TO_CLOSE_COLLECTCARS_GARAGE) {
+ m_eGarageState = GS_CLOSING;
+ m_pTarget = nil;
+ break;
+ }
+ if (m_pTarget && !FindPlayerVehicle() && IsEntityEntirelyInside3D(m_pTarget, 0.0f) &&
+ !IsAnyOtherCarTouchingGarage(m_pTarget) && IsEntityEntirelyOutside(FindPlayerPed(), 2.0f)) {
+#ifdef FIX_BUGS
+ if (!m_pTarget->IsCar() ||
+ ((CAutomobile*)(m_pTarget))->Damage.GetEngineStatus() <= ENGINE_STATUS_ON_FIRE &&
+ ((CAutomobile*)(m_pTarget))->m_fFireBlowUpTimer == 0.0f) {
+#else
+ if (((CAutomobile*)(m_pTarget))->Damage.GetEngineStatus() <= ENGINE_STATUS_ON_FIRE &&
+ ((CAutomobile*)(m_pTarget))->m_fFireBlowUpTimer == 0.0f) {
+#endif
+ if (m_pTarget->m_status != STATUS_WRECKED) {
+ CPad::GetPad(0)->SetDisablePlayerControls(PLAYERCONTROL_GARAGE);
+ FindPlayerPed()->m_pWanted->m_bIgnoredByCops = true;
+ m_eGarageState = GS_CLOSING;
+ TheCamera.SetCameraDirectlyBehindForFollowPed_CamOnAString();
+ }
+ }
+ }
+ break;
+ case GS_CLOSING:
+ m_fDoorPos = max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep());
+ if (m_fDoorPos == 0.0f) {
+ m_eGarageState = GS_FULLYCLOSED;
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f);
+ if (m_pTarget) {
+ MarkThisCarAsCollectedForCraig(m_pTarget->GetModelIndex());
+ DestroyVehicleAndDriverAndPassengers(m_pTarget);
+ m_pTarget = nil;
+ CPad::GetPad(0)->SetEnablePlayerControls(PLAYERCONTROL_GARAGE);
+ FindPlayerPed()->m_pWanted->m_bIgnoredByCops = false;
+ }
+ }
+ UpdateDoorsHeight();
+ break;
+ case GS_FULLYCLOSED:
+ if (FindPlayerVehicle() &&
+ CalcSmallestDistToGarageDoorSquared(
+ FindPlayerVehicle()->GetPosition().x,
+ FindPlayerVehicle()->GetPosition().y
+ ) < SQR(DISTANCE_TO_ACTIVATE_GARAGE)) {
+ if (DoesCraigNeedThisCar(FindPlayerVehicle()->GetModelIndex())) {
+ if (FindPlayerVehicle()->VehicleCreatedBy == MISSION_VEHICLE)
+ CGarages::TriggerMessage("GA_1A", -1, 5000, -1); // Come back when you're not so busy...
+ else
+ m_eGarageState = GS_OPENING;
+ }
+ else {
+ if (HasCraigCollectedThisCar(FindPlayerVehicle()->GetModelIndex()))
+ CGarages::TriggerMessage("GA_20", -1, 5000, -1); // We got more of these than we can shift. Sorry man, no deal.
+ else if (FindPlayerSpeed().Magnitude() < MAX_SPEED_TO_SHOW_COLLECTED_MESSAGE)
+ CGarages::TriggerMessage("GA_19", -1, 5000, -1); // We're not interested in that model.
+ }
+ }
+ m_pTarget = nil;
+ break;
+ case GS_OPENING:
+ if (FindPlayerVehicle() && DoesCraigNeedThisCar(FindPlayerVehicle()->GetModelIndex())) {
+ m_pTarget = FindPlayerVehicle();
+ m_pTarget->RegisterReference((CEntity**)&m_pTarget);
+ }
+ m_fDoorPos = min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep());
+ if (m_fDoorPos == m_fDoorHeight) {
+ m_eGarageState = GS_OPENED;
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f);
+ }
+ UpdateDoorsHeight();
+ break;
+ //case GS_OPENEDCONTAINSCAR:
+ //case GS_CLOSEDCONTAINSCAR:
+ //case GS_AFTERDROPOFF:
+ default:
+ break;
+ }
+ break;
+ case GARAGE_FORCARTOCOMEOUTOF:
+ switch (m_eGarageState) {
+ case GS_OPENED:
+ if (IsGarageEmpty())
+ m_eGarageState = GS_CLOSING;
+ break;
+ case GS_CLOSING:
+ m_fDoorPos = max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep());
+ if (m_fDoorPos == 0.0f) {
+ m_eGarageState = GS_FULLYCLOSED;
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f);
+ }
+ if (!IsGarageEmpty())
+ m_eGarageState = GS_OPENING;
+ break;
+ case GS_FULLYCLOSED:
+ break;
+ case GS_OPENING:
+ m_fDoorPos = min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep());
+ if (m_fDoorPos == m_fDoorHeight) {
+ m_eGarageState = GS_OPENED;
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f);
+ }
+ UpdateDoorsHeight();
+ break;
+ //case GS_OPENEDCONTAINSCAR:
+ //case GS_CLOSEDCONTAINSCAR:
+ //case GS_AFTERDROPOFF:
+ default:
+ break;
+ }
+ break;
+ case GARAGE_CRUSHER:
+ switch (m_eGarageState) {
+ case GS_OPENED:
+ {
+ int i = CPools::GetVehiclePool()->GetSize() * (CTimer::GetFrameCounter() % CRUSHER_VEHICLE_TEST_SPAN) / CRUSHER_VEHICLE_TEST_SPAN;
+ int end = CPools::GetVehiclePool()->GetSize() * (CTimer::GetFrameCounter() % CRUSHER_VEHICLE_TEST_SPAN + 1) / CRUSHER_VEHICLE_TEST_SPAN;
+ for (; i < end; i++) {
+ CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i);
+ if (!pVehicle)
+ continue;
+ if (pVehicle->IsCar() && IsEntityEntirelyInside3D(pVehicle, 0.0f)) {
+ m_eGarageState = GS_CLOSING;
+ m_pTarget = pVehicle;
+ m_pTarget->RegisterReference((CEntity**)&m_pTarget);
+ }
+ }
+ break;
+ }
+ case GS_CLOSING:
+ if (m_pTarget) {
+ m_fDoorPos = max(0.0f, m_fDoorPos - CRUSHER_CRANE_SPEED * CTimer::GetTimeStep());
+ if (m_fDoorPos < TWOPI / 5) {
+ m_pTarget->bUsesCollision = false;
+ m_pTarget->bAffectedByGravity = false;
+ m_pTarget->SetMoveSpeed(0.0f, 0.0f, 0.0f);
+ }
+ else {
+ m_pTarget->SetMoveSpeed(m_pTarget->GetMoveSpeed() * Pow(0.8f, CTimer::GetTimeStep()));
+ }
+ if (m_fDoorPos == 0.0f) {
+ CGarages::CrushedCarId = CPools::GetVehiclePool()->GetIndex(m_pTarget);
+ float reward = min(CRUSHER_MAX_REWARD, CRUSHER_MIN_REWARD + m_pTarget->pHandling->nMonetaryValue * m_pTarget->m_fHealth * CRUSHER_REWARD_COEFFICIENT);
+ CWorld::Players[CWorld::PlayerInFocus].m_nMoney += reward;
+ DestroyVehicleAndDriverAndPassengers(m_pTarget);
+ ++CStats::CarsCrushed;
+ m_pTarget = nil;
+ m_eGarageState = GS_AFTERDROPOFF;
+ m_nTimeToStartAction = CTimer::GetTimeInMilliseconds() + TIME_TO_CRUSH_CAR;
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f);
+ }
+ }
+ else
+ m_eGarageState = GS_OPENING;
+ UpdateCrusherAngle();
+ break;
+ case GS_AFTERDROPOFF:
+ if (CTimer::GetTimeInMilliseconds() <= m_nTimeToStartAction) {
+ UpdateCrusherShake((myrand() & 0xFF - 128) * 0.0002f, (myrand() & 0xFF - 128) * 0.0002f);
+ }
+ else {
+ UpdateCrusherShake(0.0f, 0.0f);
+ m_eGarageState = GS_OPENING;
+ }
+ break;
+ case GS_OPENING:
+ m_fDoorPos = min(HALFPI, m_fDoorPos + CTimer::GetTimeStep() * CRUSHER_CRANE_SPEED);
+ if (m_fDoorPos == HALFPI) {
+ m_eGarageState = GS_OPENED;
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f);
+ }
+ UpdateCrusherAngle();
+ break;
+ //case GS_FULLYCLOSED:
+ //case GS_CLOSEDCONTAINSCAR:
+ //case GS_OPENEDCONTAINSCAR:
+ default:
+ break;
+ }
+ if (!FindPlayerVehicle() && (CTimer::GetFrameCounter() & 0x1F) == 0x17 && IsEntityEntirelyInside(FindPlayerPed()))
+ FindPlayerPed()->InflictDamage(nil, WEAPONTYPE_RAMMEDBYCAR, 300.0f, PEDPIECE_TORSO, 0);
+ break;
+ case GARAGE_MISSION_KEEPCAR:
+ case GARAGE_MISSION_KEEPCAR_REMAINCLOSED:
+ switch (m_eGarageState) {
+ case GS_OPENED:
+ if (((CVector2D)FindPlayerCoors() - CVector2D(GetGarageCenterX(), GetGarageCenterY())).MagnitudeSqr() > SQR(DISTANCE_TO_CLOSE_MISSION_GARAGE) &&
+ !IsAnyOtherCarTouchingGarage(nil)) {
+ m_eGarageState = GS_CLOSING;
+ m_bClosingWithoutTargetCar = true;
+ }
+ else if (m_pTarget && m_pTarget == FindPlayerVehicle() && IsStaticPlayerCarEntirelyInside() && !IsAnyCarBlockingDoor()) {
+ CPad::GetPad(0)->SetDisablePlayerControls(PLAYERCONTROL_GARAGE);
+ FindPlayerPed()->m_pWanted->m_bIgnoredByCops = true;
+ m_eGarageState = GS_CLOSING;
+ m_bClosingWithoutTargetCar = false;
+ }
+ break;
+ case GS_CLOSING:
+ m_fDoorPos = max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep());
+ if (m_fDoorPos == 0.0f) {
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f);
+ if (m_bClosingWithoutTargetCar)
+ m_eGarageState = GS_FULLYCLOSED;
+ else {
+ if (m_pTarget) {
+ m_eGarageState = GS_CLOSEDCONTAINSCAR;
+ m_nTimeToStartAction = CTimer::GetTimeInMilliseconds() + TIME_TO_PROCESS_KEEPCAR_GARAGE;
+ m_pTarget = nil;
+ }
+ else
+ m_eGarageState = GS_FULLYCLOSED;
+ CPad::GetPad(0)->SetEnablePlayerControls(PLAYERCONTROL_GARAGE);
+ FindPlayerPed()->m_pWanted->m_bIgnoredByCops = false;
+ }
+ }
+ UpdateDoorsHeight();
+ break;
+ case GS_FULLYCLOSED:
+ if (FindPlayerVehicle() == m_pTarget && m_pTarget &&
+ CalcDistToGarageRectangleSquared(
+ FindPlayerVehicle()->GetPosition().x,
+ FindPlayerVehicle()->GetPosition().y
+ ) < SQR(DISTANCE_TO_ACTIVATE_KEEPCAR_GARAGE))
+ m_eGarageState = GS_OPENING;
+ break;
+ case GS_OPENING:
+ m_fDoorPos = min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep());
+ if (m_fDoorPos == m_fDoorHeight) {
+ m_eGarageState = GS_OPENED;
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f);
+ }
+ UpdateDoorsHeight();
+ break;
+ case GS_CLOSEDCONTAINSCAR:
+ if (m_eGarageType == GARAGE_MISSION_KEEPCAR && CTimer::GetTimeInMilliseconds() > m_nTimeToStartAction)
+ m_eGarageState = GS_OPENING;
+ break;
+ //case GS_OPENEDCONTAINSCAR:
+ //case GS_AFTERDROPOFF:
+ default:
+ break;
+ }
+ break;
+ case GARAGE_FOR_SCRIPT_TO_OPEN:
+ switch (m_eGarageState) {
+ case GS_OPENING:
+ m_fDoorPos = min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep());
+ if (m_fDoorPos == m_fDoorHeight) {
+ m_eGarageState = GS_OPENED;
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f);
+ }
+ UpdateDoorsHeight();
+ break;
+ //case GS_OPENED:
+ //case GS_CLOSING:
+ //case GS_FULLYCLOSED:
+ //case GS_OPENEDCONTAINSCAR:
+ //case GS_CLOSEDCONTAINSCAR:
+ //case GS_AFTERDROPOFF:
+ default:
+ break;
+ }
+ break;
+ case GARAGE_FOR_SCRIPT_TO_OPEN_AND_CLOSE:
+ switch (m_eGarageState) {
+ case GS_CLOSING:
+ m_fDoorPos = max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep());
+ if (m_fDoorPos == 0.0f) {
+ m_eGarageState = GS_FULLYCLOSED;
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f);
+ }
+ UpdateDoorsHeight();
+ break;
+ case GS_OPENING:
+ m_fDoorPos = min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep());
+ if (m_fDoorPos == m_fDoorHeight) {
+ m_eGarageState = GS_OPENED;
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f);
+ }
+ UpdateDoorsHeight();
+ break;
+ //case GS_OPENED:
+ //case GS_FULLYCLOSED:
+ //case GS_OPENEDCONTAINSCAR:
+ //case GS_CLOSEDCONTAINSCAR:
+ //case GS_AFTERDROPOFF:
+ default:
+ break;
+ }
+ break;
+ case GARAGE_HIDEOUT_ONE:
+ case GARAGE_HIDEOUT_TWO:
+ case GARAGE_HIDEOUT_THREE:
+ switch (m_eGarageState) {
+ case GS_OPENED:
+ {
+ float distance = CalcDistToGarageRectangleSquared(FindPlayerCoors().x, FindPlayerCoors().y);
+ // Close car doors either if player is far, or if he is in vehicle and garage is full,
+ // or if player is very very far so that we can remove whatever is blocking garage door without him noticing
+ if ((distance > SQR(DISTANCE_TO_CLOSE_HIDEOUT_GARAGE_IN_CAR) ||
+ !FindPlayerVehicle() && distance > SQR(DISTANCE_TO_CLOSE_HIDEOUT_GARAGE_ON_FOOT) &&
+ !IsAnyCarBlockingDoor()))
+ m_eGarageState = GS_CLOSING;
+ else if (FindPlayerVehicle() &&
+ CountCarsWithCenterPointWithinGarage(FindPlayerVehicle()) >=
+ CGarages::FindMaxNumStoredCarsForGarage(m_eGarageType)) {
+ m_eGarageState = GS_CLOSING;
+ }
+ else if (distance > SQR(DISTANCE_TO_FORCE_CLOSE_HIDEOUT_GARAGE)) {
+ m_eGarageState = GS_CLOSING;
+ RemoveCarsBlockingDoorNotInside();
+ }
+ break;
+ }
+ case GS_CLOSING:
+ m_fDoorPos = max(0.0f, m_fDoorPos - HIDEOUT_DOOR_SPEED_COEFFICIENT * (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep());
+ if (!IsPlayerOutsideGarage())
+ m_eGarageState = GS_OPENING;
+ else if (m_fDoorPos == 0.0f) {
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f);
+ m_eGarageState = GS_FULLYCLOSED;
+ switch (m_eGarageType) {
+ case GARAGE_HIDEOUT_ONE: StoreAndRemoveCarsForThisHideout(CGarages::aCarsInSafeHouse1, MAX_STORED_CARS_IN_INDUSTRIAL); break;
+ case GARAGE_HIDEOUT_TWO: StoreAndRemoveCarsForThisHideout(CGarages::aCarsInSafeHouse2, MAX_STORED_CARS_IN_COMMERCIAL); break;
+ case GARAGE_HIDEOUT_THREE: StoreAndRemoveCarsForThisHideout(CGarages::aCarsInSafeHouse3, MAX_STORED_CARS_IN_SUBURBAN); break;
+ }
+ }
+ UpdateDoorsHeight();
+ break;
+ case GS_FULLYCLOSED:
+ {
+ float distance = CalcDistToGarageRectangleSquared(FindPlayerCoors().x, FindPlayerCoors().y);
+ if (distance < SQR(DISTANCE_TO_OPEN_HIDEOUT_GARAGE_ON_FOOT) ||
+ distance < SQR(DISTANCE_TO_OPEN_HIDEOUT_GARAGE_IN_CAR) && FindPlayerVehicle()) {
+ if (FindPlayerVehicle() && CGarages::CountCarsInHideoutGarage(m_eGarageType) >= CGarages::FindMaxNumStoredCarsForGarage(m_eGarageType)) {
+ if (m_pDoor1) {
+ if (((CVector2D)FindPlayerVehicle()->GetPosition() - (CVector2D)m_pDoor1->GetPosition()).MagnitudeSqr() < SQR(DISTANCE_TO_SHOW_HIDEOUT_MESSAGE) &&
+ CTimer::GetTimeInMilliseconds() - CGarages::LastTimeHelpMessage > TIME_BETWEEN_HIDEOUT_MESSAGES) {
+ CHud::SetHelpMessage(TheText.Get("GA_21"), false); // You cannot store any more cars in this garage.
+ CGarages::LastTimeHelpMessage = CTimer::GetTimeInMilliseconds();
+ }
+ }
+ }
+ else {
+#ifdef FIX_BUGS
+ bool bCreatedAllCars = false;
+#else
+ bool bCraetedAllCars;
+#endif
+ switch (m_eGarageType) {
+ case GARAGE_HIDEOUT_ONE: bCreatedAllCars = RestoreCarsForThisHideout(CGarages::aCarsInSafeHouse1); break;
+ case GARAGE_HIDEOUT_TWO: bCreatedAllCars = RestoreCarsForThisHideout(CGarages::aCarsInSafeHouse2); break;
+ case GARAGE_HIDEOUT_THREE: bCreatedAllCars = RestoreCarsForThisHideout(CGarages::aCarsInSafeHouse3); break;
+ }
+ if (bCreatedAllCars)
+ m_eGarageState = GS_OPENING;
+ }
+ }
+ break;
+ }
+ case GS_OPENING:
+ m_fDoorPos = min(m_fDoorHeight, m_fDoorPos + HIDEOUT_DOOR_SPEED_COEFFICIENT * (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep());
+ if (m_fDoorPos == m_fDoorHeight) {
+ m_eGarageState = GS_OPENED;
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f);
+ }
+ UpdateDoorsHeight();
+ break;
+ //case GS_OPENEDCONTAINSCAR:
+ //case GS_CLOSEDCONTAINSCAR:
+ //case GS_AFTERDROPOFF:
+ default:
+ break;
+ }
+ break;
+ case GARAGE_KEEPS_OPENING_FOR_SPECIFIC_CAR:
+ switch (m_eGarageState) {
+ case GS_OPENED:
+ if (((CVector2D)FindPlayerCoors() - CVector2D(GetGarageCenterX(), GetGarageCenterY())).MagnitudeSqr() > SQR(DISTANCE_TO_CLOSE_MISSION_GARAGE)) {
+ if (m_pTarget && IsEntityEntirelyOutside(m_pTarget, 0.0f) && !IsAnyOtherCarTouchingGarage(nil)) {
+ m_eGarageState = GS_CLOSING;
+ m_bClosingWithoutTargetCar = true;
+ }
+ }
+ break;
+ case GS_CLOSING:
+ m_fDoorPos = max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep());
+ if (m_fDoorPos == 0.0f) {
+ m_eGarageState = GS_FULLYCLOSED;
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f);
+ }
+ UpdateDoorsHeight();
+ break;
+ case GS_FULLYCLOSED:
+ if (FindPlayerVehicle() == m_pTarget && m_pTarget &&
+ CalcDistToGarageRectangleSquared(
+ FindPlayerVehicle()->GetPosition().x,
+ FindPlayerVehicle()->GetPosition().y
+ ) < SQR(DISTANCE_TO_ACTIVATE_GARAGE))
+ m_eGarageState = GS_OPENING;
+ break;
+ case GS_OPENING:
+ m_fDoorPos = min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep());
+ if (m_fDoorPos == m_fDoorHeight) {
+ m_eGarageState = GS_OPENED;
+ DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f);
+ }
+ UpdateDoorsHeight();
+ break;
+ //case GS_OPENEDCONTAINSCAR:
+ //case GS_CLOSEDCONTAINSCAR:
+ //case GS_AFTERDROPOFF:
+ default:
+ break;
+ }
+ break;
+ //case GARAGE_COLLECTORSITEMS:
+ //case GARAGE_60SECONDS:
+ default:
+ break;
+ }
+}
+
+bool CGarage::IsStaticPlayerCarEntirelyInside()
+{
+ if (!FindPlayerVehicle())
+ return false;
+ if (!FindPlayerVehicle()->IsCar())
+ return false;
+ if (FindPlayerPed()->GetPedState() != PED_DRIVING)
+ return false;
+ if (FindPlayerPed()->m_objective == OBJECTIVE_LEAVE_VEHICLE)
+ return false;
+ CVehicle* pVehicle = FindPlayerVehicle();
+ if (pVehicle->GetPosition().x < m_fX1 || pVehicle->GetPosition().x > m_fX2 ||
+ pVehicle->GetPosition().y < m_fY1 || pVehicle->GetPosition().y > m_fY2)
+ return false;
+ if (Abs(pVehicle->GetSpeed().x) > 0.01f ||
+ Abs(pVehicle->GetSpeed().y) > 0.01f ||
+ Abs(pVehicle->GetSpeed().z) > 0.01f)
+ return false;
+ if (pVehicle->GetSpeed().MagnitudeSqr() > SQR(0.01f))
+ return false;
+ return IsEntityEntirelyInside3D(pVehicle, 0.0f);
}
-WRAPPER bool CGarages::HasThisCarBeenCollected(int16 garage, uint8 id) { EAXJMP(0x426D50); }
-WRAPPER void CGarages::ChangeGarageType(int16 garage, eGarageType type, int32 mi) { EAXJMP(0x4222A0); }
-WRAPPER bool CGarages::HasResprayHappened(int16 garage) { EAXJMP(0x4274F0); }
-WRAPPER bool CGarages::IsThisCarWithinGarageArea(int16 garage, CEntity* pCar) { EAXJMP(0x427570); }
+bool CGarage::IsEntityEntirelyInside(CEntity * pEntity)
+{
+ if (pEntity->GetPosition().x < m_fX1 || pEntity->GetPosition().x > m_fX2 ||
+ pEntity->GetPosition().y < m_fY1 || pEntity->GetPosition().y > m_fY2)
+ return false;
+ CColModel* pColModel = CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel();
+ for (int i = 0; i < pColModel->numSpheres; i++) {
+ CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center;
+ float radius = pColModel->spheres[i].radius;
+ if (pos.x - radius < m_fX1 || pos.x + radius > m_fX2 ||
+ pos.y - radius < m_fY1 || pos.y + radius > m_fY2)
+ return false;
+ }
+ return true;
+}
-void CGarage::OpenThisGarage()
+bool CGarage::IsEntityEntirelyInside3D(CEntity * pEntity, float fMargin)
{
- if (m_eGarageState == GS_FULLYCLOSED || m_eGarageState == GS_CLOSING || m_eGarageState == GS_CLOSEDCONTAINSCAR)
- m_eGarageState = GS_OPENING;
+ if (pEntity->GetPosition().x < m_fX1 - fMargin || pEntity->GetPosition().x > m_fX2 + fMargin ||
+ pEntity->GetPosition().y < m_fY1 - fMargin || pEntity->GetPosition().y > m_fY2 + fMargin ||
+ pEntity->GetPosition().z < m_fZ1 - fMargin || pEntity->GetPosition().z > m_fZ2 + fMargin)
+ return false;
+ CColModel* pColModel = CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel();
+ for (int i = 0; i < pColModel->numSpheres; i++) {
+ CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center;
+ float radius = pColModel->spheres[i].radius;
+ if (pos.x + radius < m_fX1 - fMargin || pos.x - radius > m_fX2 + fMargin ||
+ pos.y + radius < m_fY1 - fMargin || pos.y - radius > m_fY2 + fMargin ||
+ pos.z + radius < m_fZ1 - fMargin || pos.z - radius > m_fZ2 + fMargin)
+ return false;
+ }
+ return true;
}
-bool CGarages::IsGarageOpen(int16 garage)
+bool CGarage::IsEntityEntirelyOutside(CEntity * pEntity, float fMargin)
{
- return Garages[garage].IsOpen();
+ if (pEntity->GetPosition().x > m_fX1 - fMargin && pEntity->GetPosition().x < m_fX2 + fMargin &&
+ pEntity->GetPosition().y > m_fY1 - fMargin && pEntity->GetPosition().y < m_fY2 + fMargin)
+ return false;
+ CColModel* pColModel = CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel();
+ for (int i = 0; i < pColModel->numSpheres; i++) {
+ CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center;
+ float radius = pColModel->spheres[i].radius;
+ if (pos.x + radius > m_fX1 - fMargin && pos.x - radius < m_fX2 + fMargin &&
+ pos.y + radius > m_fY1 - fMargin && pos.y - radius < m_fY2 + fMargin)
+ return false;
+ }
+ return true;
}
-bool CGarages::IsGarageClosed(int16 garage)
+bool CGarage::IsGarageEmpty()
{
- return Garages[garage].IsClosed();
+ int16 num;
+ CWorld::FindObjectsIntersectingCube(CVector(m_fX1, m_fY1, m_fZ1), CVector(m_fX2, m_fY2, m_fZ2), &num, 2, nil, false, true, true, false, false);
+ return num == 0;
}
-void CGarage::CloseThisGarage()
+bool CGarage::IsPlayerOutsideGarage()
{
- if (m_eGarageState == GS_OPENED || m_eGarageState == GS_OPENING)
- m_eGarageState = GS_CLOSING;
+ if (FindPlayerVehicle())
+ return IsEntityEntirelyOutside(FindPlayerVehicle(), 0.0f);
+ return IsEntityEntirelyOutside(FindPlayerPed(), 0.0f);
}
-void CGarages::SetGarageDoorToRotate(int16 garage)
+bool CGarage::IsEntityTouching3D(CEntity * pEntity)
{
- if (Garages[garage].m_bRotatedDoor)
- return;
- Garages[garage].m_bRotatedDoor = true;
- Garages[garage].m_fDoorHeight /= 2.0f;
- Garages[garage].m_fDoorHeight -= 0.1f;
+ float radius = pEntity->GetBoundRadius();
+ if (pEntity->GetPosition().x - radius < m_fX1 || pEntity->GetPosition().x + radius > m_fX2 ||
+ pEntity->GetPosition().y - radius < m_fY1 || pEntity->GetPosition().y + radius > m_fY2 ||
+ pEntity->GetPosition().z - radius < m_fZ1 || pEntity->GetPosition().z + radius > m_fZ2)
+ return false;
+ CColModel* pColModel = CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel();
+ for (int i = 0; i < pColModel->numSpheres; i++) {
+ CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center;
+ radius = pColModel->spheres[i].radius;
+ if (pos.x + radius > m_fX1 && pos.x - radius < m_fX2 &&
+ pos.y + radius > m_fY1 && pos.y - radius < m_fY2 &&
+ pos.z + radius > m_fZ1 && pos.z - radius < m_fZ2)
+ return false;
+ }
+ return true;
}
-bool CGarages::HasImportExportGarageCollectedThisCar(int16 garage, int8 car)
+bool CGarage::EntityHasASphereWayOutsideGarage(CEntity * pEntity, float fMargin)
{
- return CarTypesCollected[GetCarsCollectedIndexForGarageType(Garages[garage].m_eGarageType)] & (1 << car);
+ CColModel* pColModel = CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel();
+ for (int i = 0; i < pColModel->numSpheres; i++) {
+ CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center;
+ float radius = pColModel->spheres[i].radius;
+ if (pos.x + radius + fMargin < m_fX1 || pos.x - radius - fMargin > m_fX2 ||
+ pos.y + radius + fMargin < m_fY1 || pos.y - radius - fMargin > m_fY2 ||
+ pos.z + radius + fMargin < m_fZ1 || pos.z - radius - fMargin > m_fZ2)
+ return true;
+ }
+ return false;
}
-void CGarages::SetLeaveCameraForThisGarage(int16 garage)
+bool CGarage::IsAnyOtherCarTouchingGarage(CVehicle * pException)
{
- Garages[garage].m_bCameraFollowsPlayer = true;
+ uint32 i = CPools::GetVehiclePool()->GetSize();
+ while (i--) {
+ CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i);
+ if (!pVehicle || pVehicle == pException)
+ continue;
+ if (!IsEntityTouching3D(pVehicle))
+ continue;
+ CColModel* pColModel = CModelInfo::GetModelInfo(pVehicle->GetModelIndex())->GetColModel();
+ for (int i = 0; i < pColModel->numSpheres; i++) {
+ CVector pos = pVehicle->GetMatrix() * pColModel->spheres[i].center;
+ float radius = pColModel->spheres[i].radius;
+ if (pos.x + radius > m_fX1 && pos.x - radius < m_fX2 &&
+ pos.y + radius > m_fY1 && pos.y - radius < m_fY2 &&
+ pos.z + radius > m_fZ1 && pos.z - radius < m_fZ2)
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CGarage::IsAnyOtherPedTouchingGarage(CPed * pException)
+{
+ uint32 i = CPools::GetPedPool()->GetSize();
+ while (i--) {
+ CPed* pPed = CPools::GetPedPool()->GetSlot(i);
+ if (!pPed || pPed == pException)
+ continue;
+ if (!IsEntityTouching3D(pPed))
+ continue;
+ CColModel* pColModel = CModelInfo::GetModelInfo(pPed->GetModelIndex())->GetColModel();
+ for (int i = 0; i < pColModel->numSpheres; i++) {
+ CVector pos = pPed->GetMatrix() * pColModel->spheres[i].center;
+ float radius = pColModel->spheres[i].radius;
+ if (pos.x + radius > m_fX1 && pos.x - radius < m_fX2 &&
+ pos.y + radius > m_fY1 && pos.y - radius < m_fY2 &&
+ pos.z + radius > m_fZ1 && pos.z - radius < m_fZ2)
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CGarage::IsAnyCarBlockingDoor()
+{
+ uint32 i = CPools::GetVehiclePool()->GetSize();
+ while (i--) {
+ CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i);
+ if (!pVehicle)
+ continue;
+ if (!IsEntityTouching3D(pVehicle))
+ continue;
+ CColModel* pColModel = CModelInfo::GetModelInfo(pVehicle->GetModelIndex())->GetColModel();
+ for (int i = 0; i < pColModel->numSpheres; i++) {
+ CVector pos = pVehicle->GetMatrix() * pColModel->spheres[i].center;
+ float radius = pColModel->spheres[i].radius;
+ if (pos.x + radius < m_fX1 || pos.x - radius > m_fX2 ||
+ pos.y + radius < m_fY1 || pos.y - radius > m_fY2 ||
+ pos.z + radius < m_fZ1 || pos.z - radius > m_fZ2)
+ return true;
+ }
+ }
+ return false;
+}
+
+int32 CGarage::CountCarsWithCenterPointWithinGarage(CEntity * pException)
+{
+ int32 total = 0;
+ uint32 i = CPools::GetVehiclePool()->GetSize();
+ while (i--) {
+ CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i);
+ if (!pVehicle || pVehicle == pException)
+ continue;
+ if (pVehicle->GetPosition().x > m_fX1 && pVehicle->GetPosition().x < m_fX2 &&
+ pVehicle->GetPosition().y > m_fY1 && pVehicle->GetPosition().y < m_fY2 &&
+ pVehicle->GetPosition().z > m_fZ1 && pVehicle->GetPosition().z < m_fZ2)
+ total++;
+ }
+ return total;
+}
+
+void CGarage::RemoveCarsBlockingDoorNotInside()
+{
+ uint32 i = CPools::GetVehiclePool()->GetSize();
+ while (i--) {
+ CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i);
+ if (!pVehicle)
+ continue;
+ if (!IsEntityTouching3D(pVehicle))
+ continue;
+ if (pVehicle->GetPosition().x < m_fX1 || pVehicle->GetPosition().x > m_fX2 ||
+ pVehicle->GetPosition().y < m_fY1 || pVehicle->GetPosition().y > m_fY2 ||
+ pVehicle->GetPosition().z < m_fZ1 || pVehicle->GetPosition().z > m_fZ2) {
+ if (pVehicle->bIsLocked && pVehicle->CanBeDeleted()) {
+ CWorld::Remove(pVehicle);
+ delete pVehicle;
+ return; // WHY?
+ }
+ }
+ }
}
-#if 0
-WRAPPER void CGarages::PrintMessages(void) { EAXJMP(0x426310); }
-#else
void CGarages::PrintMessages()
{
if (CTimer::GetTimeInMilliseconds() > MessageStartTime && CTimer::GetTimeInMilliseconds() < MessageEndTime) {
@@ -159,8 +1391,11 @@ void CGarages::PrintMessages()
CFont::SetFontStyle(FONT_BANK);
CFont::SetColor(CRGBA(0, 0, 0, 255));
+#if defined(PS2) || defined (FIX_BUGS)
float y_offset = SCREEN_HEIGHT / 3; // THIS is PS2 calculation
- // y_offset = SCREEN_HEIGHT / 2 - SCREEN_SCALE_Y(84.0f); // This is PC and results in text being written over some HUD elements
+#else
+ float y_offset = SCREEN_HEIGHT / 2 - SCREEN_SCALE_Y(84.0f); // This is PC and results in text being written over some HUD elements
+#endif
if (MessageNumberInString2 < 0) {
if (MessageNumberInString < 0) {
@@ -187,4 +1422,931 @@ void CGarages::PrintMessages()
}
}
}
-#endif \ No newline at end of file
+
+bool CGarages::IsCarSprayable(CVehicle * pVehicle)
+{
+ switch (pVehicle->GetModelIndex()) {
+ case MI_FIRETRUCK:
+ case MI_AMBULAN:
+ case MI_POLICE:
+ case MI_ENFORCER:
+ case MI_BUS:
+ case MI_RHINO:
+ case MI_BARRACKS:
+ case MI_DODO:
+ case MI_COACH:
+ return false;
+ default:
+ break;
+ }
+ return true;
+}
+
+void CGarage::UpdateDoorsHeight()
+{
+ RefreshDoorPointers(false);
+ if (m_pDoor1) {
+ m_pDoor1->GetPosition().z = m_fDoorPos + m_fDoor1Z;
+ if (m_bRotatedDoor)
+ BuildRotatedDoorMatrix(m_pDoor1, m_fDoorPos / m_fDoorHeight);
+ m_pDoor1->GetMatrix().UpdateRW();
+ m_pDoor1->UpdateRwFrame();
+ }
+ if (m_pDoor2) {
+ m_pDoor2->GetPosition().z = m_fDoorPos + m_fDoor2Z;
+ if (m_bRotatedDoor)
+ BuildRotatedDoorMatrix(m_pDoor2, m_fDoorPos / m_fDoorHeight);
+ m_pDoor2->GetMatrix().UpdateRW();
+ m_pDoor2->UpdateRwFrame();
+ }
+}
+
+void CGarage::BuildRotatedDoorMatrix(CEntity * pDoor, float fPosition)
+{
+ float fAngle = -fPosition * HALFPI;
+ CVector up(-Sin(fAngle) * pDoor->GetForward().y, Sin(fAngle) * pDoor->GetForward().z, Cos(fAngle));
+ pDoor->GetRight() = CrossProduct(up, pDoor->GetForward());
+ pDoor->GetUp() = up;
+}
+
+void CGarage::UpdateCrusherAngle()
+{
+ RefreshDoorPointers(false);
+ m_pDoor2->GetMatrix().SetRotateXOnly(TWOPI - m_fDoorPos);
+ m_pDoor2->GetMatrix().UpdateRW();
+ m_pDoor2->UpdateRwFrame();
+}
+
+void CGarage::UpdateCrusherShake(float X, float Y)
+{
+ RefreshDoorPointers(false);
+ m_pDoor1->GetPosition().x += X;
+ m_pDoor1->GetPosition().y += Y;
+ m_pDoor1->GetMatrix().UpdateRW();
+ m_pDoor1->UpdateRwFrame();
+ m_pDoor1->GetPosition().x -= X;
+ m_pDoor1->GetPosition().y -= Y;
+ m_pDoor2->GetPosition().x += X;
+ m_pDoor2->GetPosition().y += Y;
+ m_pDoor2->GetMatrix().UpdateRW();
+ m_pDoor2->UpdateRwFrame();
+ m_pDoor2->GetPosition().x -= X;
+ m_pDoor2->GetPosition().y -= Y;
+}
+
+// This is dumb but there is no way to avoid goto. What was there originally even?
+static bool DoINeedToRefreshPointer(CEntity * pDoor, bool bIsDummy, int8 nIndex)
+{
+ bool bNeedToFindDoorEntities = false;
+ if (pDoor) {
+ if (bIsDummy) {
+ if (CPools::GetDummyPool()->IsFreeSlot(CPools::GetDummyPool()->GetJustIndex((CDummy*)pDoor)))
+ return true;
+ if (nIndex != CPools::GetDummyPool()->GetIndex((CDummy*)pDoor))
+ bNeedToFindDoorEntities = true;
+ if (!CGarages::IsModelIndexADoor(pDoor->GetModelIndex()))
+ return true;
+ }
+ else {
+ if (CPools::GetObjectPool()->IsFreeSlot(CPools::GetObjectPool()->GetJustIndex((CObject*)pDoor)))
+ return true;
+ if (nIndex != CPools::GetObjectPool()->GetIndex((CObject*)pDoor))
+ bNeedToFindDoorEntities = true;
+ if (!CGarages::IsModelIndexADoor(pDoor->GetModelIndex()))
+ return true;
+ }
+ }
+ return bNeedToFindDoorEntities;
+}
+
+void CGarage::RefreshDoorPointers(bool bCreate)
+{
+ bool bNeedToFindDoorEntities = true;
+ if (!bCreate && !m_bRecreateDoorOnNextRefresh)
+ bNeedToFindDoorEntities = false;
+ m_bRecreateDoorOnNextRefresh = false;
+ if (DoINeedToRefreshPointer(m_pDoor1, m_bDoor1IsDummy, m_bDoor1PoolIndex))
+ bNeedToFindDoorEntities = true;
+ if (DoINeedToRefreshPointer(m_pDoor2, m_bDoor2IsDummy, m_bDoor2PoolIndex))
+ bNeedToFindDoorEntities = true;
+ if (bNeedToFindDoorEntities)
+ FindDoorsEntities();
+}
+
+void CGarages::TriggerMessage(const char* text, int16 num1, uint16 time, int16 num2)
+{
+ if (strcmp(text, MessageIDString) == 0 &&
+ CTimer::GetTimeInMilliseconds() >= MessageStartTime &&
+ CTimer::GetTimeInMilliseconds() <= MessageEndTime) {
+ if (CTimer::GetTimeInMilliseconds() - MessageStartTime <= 500)
+ return;
+ MessageStartTime = CTimer::GetTimeInMilliseconds() - 500;
+ MessageEndTime = CTimer::GetTimeInMilliseconds() - 500 + time;
+ }
+ else {
+ strcpy(MessageIDString, text);
+ MessageStartTime = CTimer::GetTimeInMilliseconds();
+ MessageEndTime = CTimer::GetTimeInMilliseconds() + time;
+ }
+ MessageNumberInString = num1;
+ MessageNumberInString2 = num2;
+}
+
+void CGarages::SetTargetCarForMissonGarage(int16 garage, CVehicle * pVehicle)
+{
+ assert(garage >= 0 && garage < NUM_GARAGES);
+ if (pVehicle) {
+ aGarages[garage].m_pTarget = pVehicle;
+ if (aGarages[garage].m_eGarageState == GS_CLOSEDCONTAINSCAR)
+ aGarages[garage].m_eGarageState = GS_FULLYCLOSED;
+ }
+ else
+ aGarages[garage].m_pTarget = nil;
+}
+
+bool CGarages::HasCarBeenDroppedOffYet(int16 garage)
+{
+ return aGarages[garage].m_eGarageState == GS_CLOSEDCONTAINSCAR;
+}
+
+void CGarages::DeActivateGarage(int16 garage)
+{
+ aGarages[garage].m_bDeactivated = true;
+}
+
+void CGarages::ActivateGarage(int16 garage)
+{
+ aGarages[garage].m_bDeactivated = false;
+ if (aGarages[garage].m_eGarageType == GARAGE_FORCARTOCOMEOUTOF && aGarages[garage].m_eGarageState == GS_FULLYCLOSED)
+ aGarages[garage].m_eGarageState = GS_OPENING;
+}
+
+int32 CGarages::QueryCarsCollected(int16 garage)
+{
+ return 0;
+}
+
+bool CGarages::HasImportExportGarageCollectedThisCar(int16 garage, int8 car)
+{
+ return CarTypesCollected[GetCarsCollectedIndexForGarageType(aGarages[garage].m_eGarageType)] & (BIT(car));
+}
+
+bool CGarages::IsGarageOpen(int16 garage)
+{
+ return aGarages[garage].IsOpen();
+}
+
+bool CGarages::IsGarageClosed(int16 garage)
+{
+ return aGarages[garage].IsClosed();
+}
+
+bool CGarages::HasThisCarBeenCollected(int16 garage, uint8 id)
+{
+ return aGarages[garage].m_bCollectedCarsState & BIT(id);
+}
+
+bool CGarage::DoesCraigNeedThisCar(int32 mi)
+{
+ if (mi == MI_CORPSE)
+ mi = MI_MANANA;
+ int ct = CGarages::GetCarsCollectedIndexForGarageType(m_eGarageType);
+ for (int i = 0; i < TOTAL_COLLECTCARS_CARS; i++) {
+ if (mi == gaCarsToCollectInCraigsGarages[ct][i])
+ return (CGarages::CarTypesCollected[ct] & BIT(i)) == 0;
+ }
+ return false;
+}
+
+bool CGarage::HasCraigCollectedThisCar(int32 mi)
+{
+ if (mi == MI_CORPSE)
+ mi = MI_MANANA;
+ int ct = CGarages::GetCarsCollectedIndexForGarageType(m_eGarageType);
+ for (int i = 0; i < TOTAL_COLLECTCARS_CARS; i++) {
+ if (mi == gaCarsToCollectInCraigsGarages[ct][i])
+ return CGarages::CarTypesCollected[ct] & BIT(i);
+ }
+ return false;
+}
+
+bool CGarage::MarkThisCarAsCollectedForCraig(int32 mi)
+{
+ if (mi == MI_CORPSE)
+ mi = MI_MANANA;
+ int ct = CGarages::GetCarsCollectedIndexForGarageType(m_eGarageType);
+ int index;
+ for (index = 0; index < TOTAL_COLLECTCARS_CARS; index++) {
+ if (mi == gaCarsToCollectInCraigsGarages[ct][index])
+ break;
+ }
+ if (index >= TOTAL_COLLECTCARS_CARS)
+ return false;
+ CGarages::CarTypesCollected[ct] |= BIT(index);
+ CWorld::Players[CWorld::PlayerInFocus].m_nMoney += IMPORT_REWARD;
+ for (int i = 0; i < TOTAL_COLLECTCARS_CARS; i++) {
+ if ((CGarages::CarTypesCollected[ct] & BIT(i)) == 0) {
+ CGarages::TriggerMessage("GA_13", -1, 5000, -1); // Delivered like a pro. Complete the list and there'll be a bonus for you.
+ return false;
+ }
+ }
+ CWorld::Players[CWorld::PlayerInFocus].m_nMoney += IMPORT_ALLCARS_REWARD;
+ CGarages::TriggerMessage("GA_14", -1, 5000, -1); // All the cars. NICE! Here's a little something.
+ return true;
+}
+
+void CGarage::OpenThisGarage()
+{
+ if (m_eGarageState == GS_FULLYCLOSED || m_eGarageState == GS_CLOSING || m_eGarageState == GS_CLOSEDCONTAINSCAR)
+ m_eGarageState = GS_OPENING;
+}
+
+void CGarage::CloseThisGarage()
+{
+ if (m_eGarageState == GS_OPENED || m_eGarageState == GS_OPENING)
+ m_eGarageState = GS_CLOSING;
+}
+
+float CGarage::CalcDistToGarageRectangleSquared(float X, float Y)
+{
+ float distX, distY;
+ if (X < m_fX1)
+ distX = m_fX1 - X;
+ else if (X > m_fX2)
+ distX = X - m_fX2;
+ else
+ distX = 0.0f;
+ if (Y < m_fY1)
+ distY = m_fY1 - X;
+ else if (Y > m_fY2)
+ distY = Y - m_fY2;
+ else
+ distY = 0.0f;
+ return SQR(distX) + SQR(distY);
+}
+
+float CGarage::CalcSmallestDistToGarageDoorSquared(float X, float Y)
+{
+ float dist1 = 10000000.0f;
+ float dist2 = 10000000.0f;
+ if (m_pDoor1)
+ dist1 = SQR(m_fDoor1X - X) + SQR(m_fDoor1Y - Y);
+ if (m_pDoor2)
+ dist2 = SQR(m_fDoor2X - X) + SQR(m_fDoor2Y - Y);
+ return min(dist1, dist2);
+}
+
+void CGarage::FindDoorsEntities()
+{
+ m_pDoor1 = false;
+ m_pDoor2 = false;
+ int xstart = max(0, CWorld::GetSectorIndexX(m_fX1));
+ int xend = min(NUMSECTORS_X - 1, CWorld::GetSectorIndexX(m_fX2));
+ int ystart = max(0, CWorld::GetSectorIndexY(m_fY1));
+ int yend = min(NUMSECTORS_Y - 1, CWorld::GetSectorIndexY(m_fY2));
+ assert(xstart <= xend);
+ assert(ystart <= yend);
+
+ CWorld::AdvanceCurrentScanCode();
+
+ for (int y = ystart; y <= yend; y++) {
+ for (int x = xstart; x <= xend; x++) {
+ CSector* s = CWorld::GetSector(x, y);
+ FindDoorsEntitiesSectorList(s->m_lists[ENTITYLIST_OBJECTS], false);
+ FindDoorsEntitiesSectorList(s->m_lists[ENTITYLIST_OBJECTS_OVERLAP], false);
+ FindDoorsEntitiesSectorList(s->m_lists[ENTITYLIST_DUMMIES], true);
+ FindDoorsEntitiesSectorList(s->m_lists[ENTITYLIST_DUMMIES_OVERLAP], true);
+ }
+ }
+ if (!m_pDoor1 || !m_pDoor2)
+ return;
+ if (m_pDoor1->GetModelIndex() == MI_CRUSHERBODY || m_pDoor1->GetModelIndex() == MI_CRUSHERLID)
+ return;
+ CVector2D vecDoor1ToGarage(m_pDoor1->GetPosition().x - GetGarageCenterX(), m_pDoor1->GetPosition().y - GetGarageCenterY());
+ CVector2D vecDoor2ToGarage(m_pDoor2->GetPosition().x - GetGarageCenterX(), m_pDoor2->GetPosition().y - GetGarageCenterY());
+ if (DotProduct2D(vecDoor1ToGarage, vecDoor2ToGarage) > 0.0f) {
+ if (vecDoor1ToGarage.MagnitudeSqr() >= vecDoor2ToGarage.MagnitudeSqr()) {
+ m_pDoor1 = m_pDoor2;
+ m_bDoor1IsDummy = m_bDoor2IsDummy;
+ }
+ m_pDoor2 = nil;
+ m_bDoor2IsDummy = false;
+ }
+}
+
+void CGarage::FindDoorsEntitiesSectorList(CPtrList& list, bool dummy)
+{
+ CPtrNode* node;
+ for (node = list.first; node; node = node->next) {
+ CEntity* pEntity = (CEntity*)node->item;
+ if (pEntity->m_scanCode == CWorld::GetCurrentScanCode())
+ continue;
+ pEntity->m_scanCode = CWorld::GetCurrentScanCode();
+ if (!pEntity || !CGarages::IsModelIndexADoor(pEntity->GetModelIndex()))
+ continue;
+ if (Abs(pEntity->GetPosition().x - GetGarageCenterX()) >= DISTANCE_TO_CONSIDER_DOOR_FOR_GARAGE)
+ continue;
+ if (Abs(pEntity->GetPosition().y - GetGarageCenterY()) >= DISTANCE_TO_CONSIDER_DOOR_FOR_GARAGE)
+ continue;
+ if (pEntity->GetModelIndex() == MI_CRUSHERBODY) {
+ m_pDoor1 = pEntity;
+ m_bDoor1IsDummy = dummy;
+ // very odd pool operations, they could have used GetJustIndex
+ if (dummy)
+ m_bDoor1PoolIndex = (CPools::GetDummyPool()->GetIndex((CDummy*)pEntity)) & 0x7F;
+ else
+ m_bDoor1PoolIndex = (CPools::GetObjectPool()->GetIndex((CObject*)pEntity)) & 0x7F;
+ continue;
+ }
+ if (pEntity->GetModelIndex() == MI_CRUSHERLID) {
+ m_pDoor2 = pEntity;
+ m_bDoor2IsDummy = dummy;
+ if (dummy)
+ m_bDoor2PoolIndex = (CPools::GetDummyPool()->GetIndex((CDummy*)pEntity)) & 0x7F;
+ else
+ m_bDoor2PoolIndex = (CPools::GetObjectPool()->GetIndex((CObject*)pEntity)) & 0x7F;
+ continue;
+ }
+ if (!m_pDoor1) {
+ m_pDoor1 = pEntity;
+ m_bDoor1IsDummy = dummy;
+ if (dummy)
+ m_bDoor1PoolIndex = (CPools::GetDummyPool()->GetIndex((CDummy*)pEntity)) & 0x7F;
+ else
+ m_bDoor1PoolIndex = (CPools::GetObjectPool()->GetIndex((CObject*)pEntity)) & 0x7F;
+ continue;
+ }
+ else {
+ m_pDoor2 = pEntity;
+ m_bDoor2IsDummy = dummy;
+ if (dummy)
+ m_bDoor2PoolIndex = (CPools::GetDummyPool()->GetIndex((CDummy*)pEntity)) & 0x7F;
+ else
+ m_bDoor2PoolIndex = (CPools::GetObjectPool()->GetIndex((CObject*)pEntity)) & 0x7F;
+ }
+ }
+}
+
+bool CGarages::HasResprayHappened(int16 garage)
+{
+ bool result = aGarages[garage].m_bResprayHappened;
+ aGarages[garage].m_bResprayHappened = false;
+ return result;
+}
+
+void CGarages::SetGarageDoorToRotate(int16 garage)
+{
+ if (aGarages[garage].m_bRotatedDoor)
+ return;
+ aGarages[garage].m_bRotatedDoor = true;
+ aGarages[garage].m_fDoorHeight /= 2.0f;
+ aGarages[garage].m_fDoorHeight -= 0.1f;
+}
+
+void CGarages::SetLeaveCameraForThisGarage(int16 garage)
+{
+ aGarages[garage].m_bCameraFollowsPlayer = true;
+}
+
+bool CGarages::IsThisCarWithinGarageArea(int16 garage, CEntity * pCar)
+{
+ return aGarages[garage].IsEntityEntirelyInside3D(pCar, 0.0f);
+}
+
+bool CGarages::HasCarBeenCrushed(int32 handle)
+{
+ return CrushedCarId == handle;
+}
+
+void CStoredCar::StoreCar(CVehicle* pVehicle)
+{
+ m_nModelIndex = pVehicle->GetModelIndex();
+ m_vecPos = pVehicle->GetPosition();
+ m_vecAngle = pVehicle->GetForward();
+ m_nPrimaryColor = pVehicle->m_currentColour1;
+ m_nSecondaryColor = pVehicle->m_currentColour2;
+ m_nRadioStation = pVehicle->m_nRadioStation;
+ m_nVariationA = pVehicle->m_aExtras[0];
+ m_nVariationB = pVehicle->m_aExtras[1];
+ m_bBulletproof = pVehicle->bBulletProof;
+ m_bFireproof = pVehicle->bFireProof;
+ m_bExplosionproof = pVehicle->bExplosionProof;
+ m_bCollisionproof = pVehicle->bCollisionProof;
+ m_bMeleeproof = pVehicle->bMeleeProof;
+ if (pVehicle->IsCar())
+ m_nCarBombType = ((CAutomobile*)pVehicle)->m_bombType;
+}
+
+CVehicle* CStoredCar::RestoreCar()
+{
+ CStreaming::RequestModel(m_nModelIndex, STREAMFLAGS_DEPENDENCY);
+ if (!CStreaming::HasModelLoaded(m_nModelIndex))
+ return nil;
+ CVehicleModelInfo::SetComponentsToUse(m_nVariationA, m_nVariationB);
+#ifdef FIX_BUGS
+ CVehicle* pVehicle;
+ if (CModelInfo::IsBoatModel(m_nModelIndex))
+ pVehicle = new CBoat(m_nModelIndex, RANDOM_VEHICLE);
+ else
+ pVehicle = new CAutomobile(m_nModelIndex, RANDOM_VEHICLE);
+#else
+ CVehicle* pVehicle = new CAutomobile(m_nModelIndex, RANDOM_VEHICLE);
+#endif
+ pVehicle->GetPosition() = m_vecPos;
+ pVehicle->m_status = STATUS_ABANDONED;
+ pVehicle->GetForward() = m_vecAngle;
+ pVehicle->GetRight() = CVector(m_vecAngle.y, -m_vecAngle.x, 0.0f);
+ pVehicle->GetUp() = CVector(0.0f, 0.0f, 1.0f);
+ pVehicle->pDriver = nil;
+ pVehicle->m_currentColour1 = m_nPrimaryColor;
+ pVehicle->m_currentColour2 = m_nSecondaryColor;
+ pVehicle->m_nRadioStation = m_nRadioStation;
+ pVehicle->bFreebies = false;
+#ifdef FIX_BUGS
+ ((CAutomobile*)pVehicle)->m_bombType = m_nCarBombType;
+#endif
+ pVehicle->bHasBeenOwnedByPlayer = true;
+ pVehicle->m_nDoorLock = CARLOCK_UNLOCKED;
+ pVehicle->bBulletProof = m_bBulletproof;
+ pVehicle->bFireProof = m_bFireproof;
+ pVehicle->bExplosionProof = m_bExplosionproof;
+ pVehicle->bCollisionProof = m_bCollisionproof;
+ pVehicle->bMeleeProof = m_bMeleeproof;
+ return pVehicle;
+}
+
+void CGarage::StoreAndRemoveCarsForThisHideout(CStoredCar* aCars, int32 nMax)
+{
+ for (int i = 0; i < NUM_GARAGE_STORED_CARS; i++)
+ aCars[i].Clear();
+ int i = CPools::GetVehiclePool()->GetSize();
+ int index = 0;
+ while (i--) {
+ CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i);
+ if (!pVehicle)
+ continue;
+ if (pVehicle->GetPosition().x > m_fX1 && pVehicle->GetPosition().x < m_fX2 &&
+ pVehicle->GetPosition().y > m_fY1 && pVehicle->GetPosition().y < m_fY2 &&
+ pVehicle->GetPosition().z > m_fZ1 && pVehicle->GetPosition().z < m_fZ2) {
+ if (pVehicle->VehicleCreatedBy != MISSION_VEHICLE) {
+ if (index < max(NUM_GARAGE_STORED_CARS, nMax) && !EntityHasASphereWayOutsideGarage(pVehicle, 1.0f))
+ aCars[index++].StoreCar(pVehicle);
+ CWorld::Players[CWorld::PlayerInFocus].CancelPlayerEnteringCars(pVehicle);
+ CWorld::Remove(pVehicle);
+ delete pVehicle;
+ }
+ }
+ }
+ // why?
+ for (i = index; i < NUM_GARAGE_STORED_CARS; i++)
+ aCars[i].Clear();
+}
+
+bool CGarage::RestoreCarsForThisHideout(CStoredCar* aCars)
+{
+ for (int i = 0; i < NUM_GARAGE_STORED_CARS; i++) {
+ if (aCars[i].HasCar()) {
+ CVehicle* pVehicle = aCars[i].RestoreCar();
+ if (pVehicle) {
+ CWorld::Add(pVehicle);
+ aCars[i].Clear();
+ }
+ }
+ }
+ for (int i = 0; i < NUM_GARAGE_STORED_CARS; i++) {
+ if (aCars[i].HasCar())
+ return false;
+ }
+ return true;
+}
+
+bool CGarages::IsPointInAGarageCameraZone(CVector point)
+{
+ for (int i = 0; i < NUM_GARAGES; i++) {
+ switch (aGarages[i].m_eGarageType) {
+ case GARAGE_NONE:
+ break;
+ case GARAGE_COLLECTCARS_1:
+ case GARAGE_COLLECTCARS_2:
+ case GARAGE_COLLECTCARS_3:
+ if (aGarages[i].m_fX1 - MARGIN_FOR_CAMERA_COLLECTCARS <= point.x &&
+ aGarages[i].m_fX2 + MARGIN_FOR_CAMERA_COLLECTCARS >= point.x &&
+ aGarages[i].m_fY1 - MARGIN_FOR_CAMERA_COLLECTCARS <= point.y &&
+ aGarages[i].m_fY2 + MARGIN_FOR_CAMERA_COLLECTCARS >= point.y)
+ return true;
+ break;
+ default:
+ if (aGarages[i].m_fX1 - MARGIN_FOR_CAMERA_DEFAULT <= point.x &&
+ aGarages[i].m_fX2 + MARGIN_FOR_CAMERA_DEFAULT >= point.x &&
+ aGarages[i].m_fY1 - MARGIN_FOR_CAMERA_DEFAULT <= point.y &&
+ aGarages[i].m_fY2 + MARGIN_FOR_CAMERA_DEFAULT >= point.y)
+ return true;
+ break;
+ }
+ }
+ return false;
+}
+
+bool CGarages::CameraShouldBeOutside()
+{
+ return bCamShouldBeOutisde;
+}
+
+void CGarages::GivePlayerDetonator()
+{
+ FindPlayerPed()->GiveWeapon(WEAPONTYPE_DETONATOR, 1);
+ FindPlayerPed()->GetWeapon(FindPlayerPed()->GetWeaponSlot(WEAPONTYPE_DETONATOR)).m_eWeaponState = WEAPONSTATE_READY;
+}
+
+float CGarages::FindDoorHeightForMI(int32 mi)
+{
+ return CModelInfo::GetModelInfo(mi)->GetColModel()->boundingBox.max.z - CModelInfo::GetModelInfo(mi)->GetColModel()->boundingBox.min.z - 0.1f;
+}
+
+void CGarage::TidyUpGarage()
+{
+ uint32 i = CPools::GetVehiclePool()->GetSize();
+ while (i--) {
+ CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i);
+ if (!pVehicle || !pVehicle->IsCar())
+ continue;
+ if (pVehicle->GetPosition().x > m_fX1 && pVehicle->GetPosition().x < m_fX2 &&
+ pVehicle->GetPosition().y > m_fY1 && pVehicle->GetPosition().y < m_fY2 &&
+ pVehicle->GetPosition().z > m_fZ1 && pVehicle->GetPosition().z < m_fZ2) {
+ if (pVehicle->m_status == STATUS_WRECKED || pVehicle->GetUp().z < 0.5f) {
+ CWorld::Remove(pVehicle);
+ delete pVehicle;
+ }
+ }
+ }
+}
+
+void CGarage::TidyUpGarageClose()
+{
+ uint32 i = CPools::GetVehiclePool()->GetSize();
+ while (i--) {
+ CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i);
+ if (!pVehicle || !pVehicle->IsCar())
+ continue;
+ if (!pVehicle->IsCar() || pVehicle->m_status != STATUS_WRECKED || !IsEntityTouching3D(pVehicle))
+ continue;
+ bool bRemove = false;
+ if (m_eGarageState != GS_FULLYCLOSED) {
+ CColModel* pColModel = CModelInfo::GetModelInfo(pVehicle->GetModelIndex())->GetColModel();
+ for (int i = 0; i < pColModel->numSpheres; i++) {
+ CVector pos = pVehicle->GetMatrix() * pColModel->spheres[i].center;
+ float radius = pColModel->spheres[i].radius;
+ if (pos.x + radius < m_fX1 || pos.x - radius > m_fX2 ||
+ pos.y + radius < m_fY1 || pos.y - radius > m_fY2 ||
+ pos.z + radius < m_fZ1 || pos.z - radius > m_fZ2) {
+ bRemove = true;
+ }
+ }
+ }
+ else
+ bRemove = true;
+ if (bRemove) {
+ // no MISSION_VEHICLE check???
+ CWorld::Remove(pVehicle);
+ delete pVehicle;
+ }
+ }
+}
+
+void CGarages::PlayerArrestedOrDied()
+{
+ static int GarageToBeTidied = 0; // lol
+ for (int i = 0; i < NUM_GARAGES; i++) {
+ if (aGarages[i].m_eGarageType != GARAGE_NONE)
+ aGarages[i].PlayerArrestedOrDied();
+ }
+ MessageEndTime = 0;
+ MessageStartTime = 0;
+}
+
+void CGarage::PlayerArrestedOrDied()
+{
+ switch (m_eGarageType) {
+ case GARAGE_MISSION:
+ case GARAGE_COLLECTORSITEMS:
+ case GARAGE_COLLECTSPECIFICCARS:
+ case GARAGE_COLLECTCARS_1:
+ case GARAGE_COLLECTCARS_2:
+ case GARAGE_COLLECTCARS_3:
+ case GARAGE_FORCARTOCOMEOUTOF:
+ case GARAGE_60SECONDS:
+ case GARAGE_MISSION_KEEPCAR:
+ case GARAGE_FOR_SCRIPT_TO_OPEN:
+ case GARAGE_HIDEOUT_ONE:
+ case GARAGE_HIDEOUT_TWO:
+ case GARAGE_HIDEOUT_THREE:
+ case GARAGE_FOR_SCRIPT_TO_OPEN_AND_CLOSE:
+ case GARAGE_KEEPS_OPENING_FOR_SPECIFIC_CAR:
+ case GARAGE_MISSION_KEEPCAR_REMAINCLOSED:
+ switch (m_eGarageState) {
+ case GS_OPENED:
+ case GS_CLOSING:
+ case GS_OPENING:
+ m_eGarageState = GS_CLOSING;
+ break;
+ default:
+ break;
+ }
+ break;
+ case GARAGE_BOMBSHOP1:
+ case GARAGE_BOMBSHOP2:
+ case GARAGE_BOMBSHOP3:
+ case GARAGE_RESPRAY:
+ case GARAGE_CRUSHER:
+ switch (m_eGarageState) {
+ case GS_FULLYCLOSED:
+ case GS_CLOSING:
+ case GS_OPENING:
+ m_eGarageState = GS_OPENING;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void CGarage::CenterCarInGarage(CVehicle* pVehicle)
+{
+ if (IsAnyOtherCarTouchingGarage(FindPlayerVehicle()))
+ return;
+ if (IsAnyOtherPedTouchingGarage(FindPlayerPed()))
+ return;
+ CVector pos = pVehicle->GetPosition();
+ float garageX = GetGarageCenterX();
+ float garageY = GetGarageCenterY();
+ float offsetX = garageX - pos.x;
+ float offsetY = garageY - pos.y;
+ float offsetZ = pos.z - pos.z;
+ float distance = CVector(offsetX, offsetY, offsetZ).Magnitude();
+ if (distance < RESPRAY_CENTERING_COEFFICIENT) {
+ pVehicle->GetPosition().x = GetGarageCenterX();
+ pVehicle->GetPosition().y = GetGarageCenterY();
+ }
+ else {
+ pVehicle->GetPosition().x += offsetX * RESPRAY_CENTERING_COEFFICIENT / distance;
+ pVehicle->GetPosition().y += offsetY * RESPRAY_CENTERING_COEFFICIENT / distance;
+ }
+ if (!IsEntityEntirelyInside3D(pVehicle, 0.1f))
+ pVehicle->GetPosition() = pos;
+}
+
+void CGarages::CloseHideOutGaragesBeforeSave()
+{
+ for (int i = 0; i < NUM_GARAGES; i++) {
+ if (aGarages[i].m_eGarageType != GARAGE_HIDEOUT_ONE &&
+ aGarages[i].m_eGarageType != GARAGE_HIDEOUT_TWO &&
+ aGarages[i].m_eGarageType != GARAGE_HIDEOUT_THREE)
+ continue;
+ if (aGarages[i].m_eGarageState != GS_FULLYCLOSED &&
+ aGarages[i].m_eGarageType != GARAGE_HIDEOUT_ONE || !aGarages[i].IsAnyCarBlockingDoor()) {
+ aGarages[i].m_eGarageState = GS_FULLYCLOSED;
+ switch (aGarages[i].m_eGarageType) {
+ case GARAGE_HIDEOUT_ONE:
+ aGarages[i].StoreAndRemoveCarsForThisHideout(aCarsInSafeHouse1, NUM_GARAGE_STORED_CARS);
+ aGarages[i].RemoveCarsBlockingDoorNotInside();
+ break;
+ case GARAGE_HIDEOUT_TWO:
+ aGarages[i].StoreAndRemoveCarsForThisHideout(aCarsInSafeHouse2, NUM_GARAGE_STORED_CARS);
+ aGarages[i].RemoveCarsBlockingDoorNotInside();
+ break;
+ case GARAGE_HIDEOUT_THREE:
+ aGarages[i].StoreAndRemoveCarsForThisHideout(aCarsInSafeHouse3, NUM_GARAGE_STORED_CARS);
+ aGarages[i].RemoveCarsBlockingDoorNotInside();
+ break;
+ default:
+ break;
+ }
+ }
+ aGarages[i].m_fDoorPos = 0.0f;
+ aGarages[i].UpdateDoorsHeight();
+ }
+}
+
+int32 CGarages::CountCarsInHideoutGarage(eGarageType type)
+{
+ int32 total = 0;
+ for (int i = 0; i < NUM_GARAGE_STORED_CARS; i++) {
+ switch (type) {
+ case GARAGE_HIDEOUT_ONE:
+ total += (aCarsInSafeHouse1[i].HasCar());
+ break;
+ case GARAGE_HIDEOUT_TWO:
+ total += (aCarsInSafeHouse2[i].HasCar());
+ break;
+ case GARAGE_HIDEOUT_THREE:
+ total += (aCarsInSafeHouse3[i].HasCar());
+ break;
+ }
+ }
+ return total;
+}
+
+int32 CGarages::FindMaxNumStoredCarsForGarage(eGarageType type)
+{
+ switch (type) {
+ case GARAGE_HIDEOUT_ONE:
+ return LIMIT_CARS_IN_INDUSTRIAL;
+ case GARAGE_HIDEOUT_TWO:
+ return LIMIT_CARS_IN_COMMERCIAL;
+ case GARAGE_HIDEOUT_THREE:
+ return LIMIT_CARS_IN_SUBURBAN;
+ }
+ return 0;
+}
+
+bool CGarages::IsPointWithinHideOutGarage(CVector& point)
+{
+ for (int i = 0; i < NUM_GARAGES; i++) {
+ switch (aGarages[i].m_eGarageType) {
+ case GARAGE_HIDEOUT_ONE:
+ case GARAGE_HIDEOUT_TWO:
+ case GARAGE_HIDEOUT_THREE:
+ if (point.x > aGarages[i].m_fX1 && point.x < aGarages[i].m_fX2 &&
+ point.y > aGarages[i].m_fY1 && point.y < aGarages[i].m_fY2 &&
+ point.z > aGarages[i].m_fZ1 && point.z < aGarages[i].m_fZ2)
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CGarages::IsPointWithinAnyGarage(CVector& point)
+{
+ for (int i = 0; i < NUM_GARAGES; i++) {
+ switch (aGarages[i].m_eGarageType) {
+ case GARAGE_NONE:
+ continue;
+ default:
+ if (point.x > aGarages[i].m_fX1 && point.x < aGarages[i].m_fX2 &&
+ point.y > aGarages[i].m_fY1 && point.y < aGarages[i].m_fY2 &&
+ point.z > aGarages[i].m_fZ1 && point.z < aGarages[i].m_fZ2)
+ return true;
+ }
+ }
+ return false;
+}
+
+void CGarages::SetAllDoorsBackToOriginalHeight()
+{
+ for (int i = 0; i < NUM_GARAGES; i++) {
+ switch (aGarages[i].m_eGarageType) {
+ case GARAGE_NONE:
+ continue;
+ default:
+ aGarages[i].RefreshDoorPointers(true);
+ if (aGarages[i].m_pDoor1) {
+ aGarages[i].m_pDoor1->GetPosition().z = aGarages[i].m_fDoor1Z;
+ if (aGarages[i].m_pDoor1->IsObject())
+ ((CObject*)aGarages[i].m_pDoor1)->m_objectMatrix.GetPosition().z = aGarages[i].m_fDoor1Z;
+ if (aGarages[i].m_bRotatedDoor)
+ aGarages[i].BuildRotatedDoorMatrix(aGarages[i].m_pDoor1, 0.0f);
+ aGarages[i].m_pDoor1->GetMatrix().UpdateRW();
+ aGarages[i].m_pDoor1->UpdateRwFrame();
+ }
+ if (aGarages[i].m_pDoor2) {
+ aGarages[i].m_pDoor2->GetPosition().z = aGarages[i].m_fDoor2Z;
+ if (aGarages[i].m_pDoor2->IsObject())
+ ((CObject*)aGarages[i].m_pDoor2)->m_objectMatrix.GetPosition().z = aGarages[i].m_fDoor2Z;
+ if (aGarages[i].m_bRotatedDoor)
+ aGarages[i].BuildRotatedDoorMatrix(aGarages[i].m_pDoor2, 0.0f);
+ aGarages[i].m_pDoor2->GetMatrix().UpdateRW();
+ aGarages[i].m_pDoor2->UpdateRwFrame();
+ }
+ }
+ }
+}
+
+void CGarages::Save(uint8 * buf, uint32 * size)
+{
+#ifdef FIX_GARAGE_SIZE
+ *size = (6 * sizeof(uint32) + TOTAL_COLLECTCARS_GARAGES * sizeof(*CarTypesCollected) + sizeof(uint32) + 3 * NUM_GARAGE_STORED_CARS * sizeof(CStoredCar) + NUM_GARAGES * sizeof(CGarage));
+#else
+ * size = 5484;
+#endif
+ CloseHideOutGaragesBeforeSave();
+ WriteSaveBuf(buf, NumGarages);
+ WriteSaveBuf(buf, (uint32)BombsAreFree);
+ WriteSaveBuf(buf, (uint32)RespraysAreFree);
+ WriteSaveBuf(buf, CarsCollected);
+ WriteSaveBuf(buf, BankVansCollected);
+ WriteSaveBuf(buf, PoliceCarsCollected);
+ for (int i = 0; i < TOTAL_COLLECTCARS_GARAGES; i++)
+ WriteSaveBuf(buf, CarTypesCollected[i]);
+ WriteSaveBuf(buf, LastTimeHelpMessage);
+ for (int i = 0; i < NUM_GARAGE_STORED_CARS; i++) {
+ WriteSaveBuf(buf, aCarsInSafeHouse1[i]);
+ WriteSaveBuf(buf, aCarsInSafeHouse2[i]);
+ WriteSaveBuf(buf, aCarsInSafeHouse3[i]);
+ }
+ for (int i = 0; i < NUM_GARAGES; i++)
+ WriteSaveBuf(buf, aGarages[i]);
+}
+
+CStoredCar::CStoredCar(const CStoredCar & other)
+{
+ m_nModelIndex = other.m_nModelIndex;
+ m_vecPos = other.m_vecPos;
+ m_vecAngle = other.m_vecAngle;
+ m_bBulletproof = other.m_bBulletproof;
+ m_bFireproof = other.m_bFireproof;
+ m_bExplosionproof = other.m_bExplosionproof;
+ m_bCollisionproof = other.m_bCollisionproof;
+ m_bMeleeproof = other.m_bMeleeproof;
+ m_nPrimaryColor = other.m_nPrimaryColor;
+ m_nSecondaryColor = other.m_nSecondaryColor;
+ m_nRadioStation = other.m_nRadioStation;
+ m_nVariationA = other.m_nVariationA;
+ m_nVariationB = other.m_nVariationB;
+ m_nCarBombType = other.m_nCarBombType;
+}
+
+void CGarages::Load(uint8* buf, uint32 size)
+{
+#ifdef FIX_GARAGE_SIZE
+ assert(size == (6 * sizeof(uint32) + TOTAL_COLLECTCARS_GARAGES * sizeof(*CarTypesCollected) + sizeof(uint32) + 3 * NUM_GARAGE_STORED_CARS * sizeof(CStoredCar) + NUM_GARAGES * sizeof(CGarage));
+#else
+ assert(size == 5484);
+#endif
+ CloseHideOutGaragesBeforeSave();
+ NumGarages = ReadSaveBuf<uint32>(buf);
+ BombsAreFree = ReadSaveBuf<uint32>(buf);
+ RespraysAreFree = ReadSaveBuf<uint32>(buf);
+ CarsCollected = ReadSaveBuf<int32>(buf);
+ BankVansCollected = ReadSaveBuf<int32>(buf);
+ PoliceCarsCollected = ReadSaveBuf<int32>(buf);
+ for (int i = 0; i < TOTAL_COLLECTCARS_GARAGES; i++)
+ CarTypesCollected[i] = ReadSaveBuf<uint32>(buf);
+ LastTimeHelpMessage = ReadSaveBuf<uint32>(buf);
+ for (int i = 0; i < NUM_GARAGE_STORED_CARS; i++) {
+ aCarsInSafeHouse1[i] = ReadSaveBuf<CStoredCar>(buf);
+ aCarsInSafeHouse2[i] = ReadSaveBuf<CStoredCar>(buf);
+ aCarsInSafeHouse3[i] = ReadSaveBuf<CStoredCar>(buf);
+ }
+ for (int i = 0; i < NUM_GARAGES; i++) {
+ aGarages[i] = ReadSaveBuf<CGarage>(buf);
+ aGarages[i].m_pDoor1 = nil;
+ aGarages[i].m_pDoor2 = nil;
+ aGarages[i].m_pTarget = nil;
+ aGarages[i].field_96 = nil;
+ aGarages[i].m_bRecreateDoorOnNextRefresh = true;
+ aGarages[i].RefreshDoorPointers(true);
+ if (aGarages[i].m_eGarageType == GARAGE_CRUSHER)
+ aGarages[i].UpdateCrusherAngle();
+ else
+ aGarages[i].UpdateDoorsHeight();
+ }
+}
+
+bool
+CGarages::IsModelIndexADoor(uint32 id)
+{
+ return id == MI_GARAGEDOOR1 ||
+ id == MI_GARAGEDOOR2 ||
+ id == MI_GARAGEDOOR3 ||
+ id == MI_GARAGEDOOR4 ||
+ id == MI_GARAGEDOOR5 ||
+ id == MI_GARAGEDOOR6 ||
+ id == MI_GARAGEDOOR7 ||
+ id == MI_GARAGEDOOR9 ||
+ id == MI_GARAGEDOOR10 ||
+ id == MI_GARAGEDOOR11 ||
+ id == MI_GARAGEDOOR12 ||
+ id == MI_GARAGEDOOR13 ||
+ id == MI_GARAGEDOOR14 ||
+ id == MI_GARAGEDOOR15 ||
+ id == MI_GARAGEDOOR16 ||
+ id == MI_GARAGEDOOR17 ||
+ id == MI_GARAGEDOOR18 ||
+ id == MI_GARAGEDOOR19 ||
+ id == MI_GARAGEDOOR20 ||
+ id == MI_GARAGEDOOR21 ||
+ id == MI_GARAGEDOOR22 ||
+ id == MI_GARAGEDOOR23 ||
+ id == MI_GARAGEDOOR24 ||
+ id == MI_GARAGEDOOR25 ||
+ id == MI_GARAGEDOOR26 ||
+ id == MI_GARAGEDOOR27 ||
+ id == MI_GARAGEDOOR28 ||
+ id == MI_GARAGEDOOR29 ||
+ id == MI_GARAGEDOOR30 ||
+ id == MI_GARAGEDOOR31 ||
+ id == MI_GARAGEDOOR32 ||
+ id == MI_CRUSHERBODY ||
+ id == MI_CRUSHERLID;
+}
+
+
+STARTPATCHES
+ InjectHook(0x426B20, CGarages::TriggerMessage, PATCH_JUMP); // CCrane::Update, CCrane::FindCarInSectorList
+ InjectHook(0x427AB0, CGarages::IsPointInAGarageCameraZone, PATCH_JUMP); // CCamera::CamControl
+ InjectHook(0x427BC0, CGarages::CameraShouldBeOutside, PATCH_JUMP); // CCamera::CamControl
+ InjectHook(0x428940, CGarages::Load, PATCH_JUMP); // GenericLoad
+ENDPATCHES \ No newline at end of file
diff --git a/src/control/Garages.h b/src/control/Garages.h
index 5e106ade..e3864a48 100644
--- a/src/control/Garages.h
+++ b/src/control/Garages.h
@@ -1,9 +1,11 @@
#pragma once
#include "Automobile.h"
#include "audio_enums.h"
+#include "Camera.h"
#include "config.h"
class CVehicle;
+class CCamera;
enum eGarageState : int8
{
@@ -44,7 +46,8 @@ enum eGarageType : int8
enum
{
- TOTAL_COLLECTCARS_GARAGES = GARAGE_COLLECTCARS_3 - GARAGE_COLLECTCARS_1 + 1
+ TOTAL_COLLECTCARS_GARAGES = GARAGE_COLLECTCARS_3 - GARAGE_COLLECTCARS_1 + 1,
+ TOTAL_COLLECTCARS_CARS = 16
};
class CStoredCar
@@ -63,34 +66,43 @@ class CStoredCar
int8 m_nVariationA;
int8 m_nVariationB;
int8 m_nCarBombType;
+public:
+ void Init() { m_nModelIndex = 0; }
+ void Clear() { m_nModelIndex = 0; }
+ bool HasCar() { return m_nModelIndex != 0; }
+ CStoredCar(const CStoredCar& other);
+ void StoreCar(CVehicle*);
+ CVehicle* RestoreCar();
};
static_assert(sizeof(CStoredCar) == 0x28, "CStoredCar");
+#define SWITCH_GARAGE_DISTANCE_CLOSE 40.0f
+
class CGarage
{
-public:
eGarageType m_eGarageType;
eGarageState m_eGarageState;
- char field_2;
- char m_bClosingWithoutTargetCar;
- char m_bDeactivated;
- char m_bResprayHappened;
- char field_6;
- char field_7;
+ bool field_2; // unused
+ bool m_bClosingWithoutTargetCar;
+ bool m_bDeactivated;
+ bool m_bResprayHappened;
int m_nTargetModelIndex;
CEntity *m_pDoor1;
CEntity *m_pDoor2;
- char m_bDoor1PoolIndex;
- char m_bDoor2PoolIndex;
- char m_bIsDoor1Object;
- char m_bIsDoor2Object;
- char field_24;
- char m_bRotatedDoor;
- char m_bCameraFollowsPlayer;
- char field_27;
- CVector m_vecInf;
- CVector m_vecSup;
+ uint8 m_bDoor1PoolIndex;
+ uint8 m_bDoor2PoolIndex;
+ bool m_bDoor1IsDummy;
+ bool m_bDoor2IsDummy;
+ bool m_bRecreateDoorOnNextRefresh;
+ bool m_bRotatedDoor;
+ bool m_bCameraFollowsPlayer;
+ float m_fX1;
+ float m_fX2;
+ float m_fY1;
+ float m_fY2;
+ float m_fZ1;
+ float m_fZ2;
float m_fDoorPos;
float m_fDoorHeight;
float m_fDoor1X;
@@ -99,26 +111,74 @@ public:
float m_fDoor2Y;
float m_fDoor1Z;
float m_fDoor2Z;
- int m_nDoorOpenTime;
- char m_bCollectedCarsState;
- char field_89;
- char field_90;
- char field_91;
+ uint32 m_nTimeToStartAction;
+ uint8 m_bCollectedCarsState;
CVehicle *m_pTarget;
- int field_96;
- CStoredCar m_sStoredCar;
+ void* field_96; // unused
+ CStoredCar m_sStoredCar; // not needed
void OpenThisGarage();
void CloseThisGarage();
bool IsOpen() { return m_eGarageState == GS_OPENED || m_eGarageState == GS_OPENEDCONTAINSCAR; }
bool IsClosed() { return m_eGarageState == GS_FULLYCLOSED; }
+ bool IsUsed() { return m_eGarageType != GARAGE_NONE; }
+ void Update();
+ float GetGarageCenterX() { return (m_fX1 + m_fX2) / 2; }
+ float GetGarageCenterY() { return (m_fY1 + m_fY2) / 2; }
+ bool IsFar()
+ {
+#ifdef FIX_BUGS
+ return Abs(TheCamera.GetPosition().x - GetGarageCenterX()) > SWITCH_GARAGE_DISTANCE_CLOSE ||
+ Abs(TheCamera.GetPosition().y - GetGarageCenterY()) > SWITCH_GARAGE_DISTANCE_CLOSE;
+#else
+ return Abs(TheCamera.GetPosition().x - m_fX1) > SWITCH_GARAGE_DISTANCE_CLOSE ||
+ Abs(TheCamera.GetPosition().y - m_fY1) > SWITCH_GARAGE_DISTANCE_CLOSE;
+#endif
+ }
+ void TidyUpGarageClose();
+ void TidyUpGarage();
+ void RefreshDoorPointers(bool);
+ void UpdateCrusherAngle();
+ void UpdateDoorsHeight();
+ bool IsEntityEntirelyInside3D(CEntity*, float);
+ bool IsEntityEntirelyOutside(CEntity*, float);
+ bool IsEntityEntirelyInside(CEntity*);
+ float CalcDistToGarageRectangleSquared(float, float);
+ float CalcSmallestDistToGarageDoorSquared(float, float);
+ bool IsAnyOtherCarTouchingGarage(CVehicle* pException);
+ bool IsStaticPlayerCarEntirelyInside();
+ bool IsPlayerOutsideGarage();
+ bool IsAnyCarBlockingDoor();
+ void CenterCarInGarage(CVehicle*);
+ bool DoesCraigNeedThisCar(int32);
+ bool MarkThisCarAsCollectedForCraig(int32);
+ bool HasCraigCollectedThisCar(int32);
+ bool IsGarageEmpty();
+ void UpdateCrusherShake(float, float);
+ int32 CountCarsWithCenterPointWithinGarage(CEntity* pException);
+ void RemoveCarsBlockingDoorNotInside();
+ void StoreAndRemoveCarsForThisHideout(CStoredCar*, int32);
+ bool RestoreCarsForThisHideout(CStoredCar*);
+ bool IsEntityTouching3D(CEntity*);
+ bool EntityHasASphereWayOutsideGarage(CEntity*, float);
+ bool IsAnyOtherPedTouchingGarage(CPed* pException);
+ void BuildRotatedDoorMatrix(CEntity*, float);
+ void FindDoorsEntities();
+ void FindDoorsEntitiesSectorList(CPtrList&, bool);
+ void PlayerArrestedOrDied();
+
+ friend class CGarages;
+ friend class cAudioManager;
+ friend class CCamera;
};
static_assert(sizeof(CGarage) == 140, "CGarage");
class CGarages
{
-public:
+ enum {
+ MESSAGE_LENGTH = 8
+ };
static int32 &BankVansCollected;
static bool &BombsAreFree;
static bool &RespraysAreFree;
@@ -127,7 +187,7 @@ public:
static int32 &CrushedCarId;
static uint32 &LastTimeHelpMessage;
static int32 &MessageNumberInString;
- static const char *MessageIDString;
+ static char(&MessageIDString)[MESSAGE_LENGTH];
static int32 &MessageNumberInString2;
static uint32 &MessageStartTime;
static uint32 &MessageEndTime;
@@ -135,36 +195,62 @@ public:
static bool &PlayerInGarage;
static int32 &PoliceCarsCollected;
static uint32 &GarageToBeTidied;
- static CGarage(&Garages)[NUM_GARAGES];
+ static CGarage(&aGarages)[NUM_GARAGES];
+ static CStoredCar(&aCarsInSafeHouse1)[NUM_GARAGE_STORED_CARS];
+ static CStoredCar(&aCarsInSafeHouse2)[NUM_GARAGE_STORED_CARS];
+ static CStoredCar(&aCarsInSafeHouse3)[NUM_GARAGE_STORED_CARS];
+ static int32 &AudioEntity;
+ static bool &bCamShouldBeOutisde;
public:
- static bool IsModelIndexADoor(uint32 id);
- static void TriggerMessage(const char *text, int16, uint16 time, int16);
- static void PrintMessages(void);
- static bool HasCarBeenCrushed(int32);
- static bool IsPointWithinHideOutGarage(CVector&);
- static bool IsPointWithinAnyGarage(CVector&);
- static void PlayerArrestedOrDied();
static void Init(void);
+#ifndef PS2
+ static void Shutdown(void);
+#endif
static void Update(void);
- static void Load(uint8 *buf, uint32 size);
- static void Save(uint8 *buf, uint32 *size);
- static int16 AddOne(float, float, float, float, float, float, uint8, uint32);
+
+ static int16 AddOne(float X1, float Y1, float Z1, float X2, float Y2, float Z2, eGarageType type, int32 targetId);
+ static void ChangeGarageType(int16, eGarageType, int32);
+ static void PrintMessages(void);
+ static void TriggerMessage(const char* text, int16, uint16 time, int16);
static void SetTargetCarForMissonGarage(int16, CVehicle*);
static bool HasCarBeenDroppedOffYet(int16);
- static void ActivateGarage(int16);
static void DeActivateGarage(int16);
+ static void ActivateGarage(int16);
static int32 QueryCarsCollected(int16);
- static bool HasThisCarBeenCollected(int16, uint8);
- static void ChangeGarageType(int16, eGarageType, int32);
- static bool HasResprayHappened(int16);
- static void GivePlayerDetonator();
+ static bool HasImportExportGarageCollectedThisCar(int16, int8);
static bool IsGarageOpen(int16);
static bool IsGarageClosed(int16);
+ static bool HasThisCarBeenCollected(int16, uint8);
+ static void OpenGarage(int16 garage) { aGarages[garage].OpenThisGarage(); }
+ static void CloseGarage(int16 garage) { aGarages[garage].CloseThisGarage(); }
+ static bool HasResprayHappened(int16);
static void SetGarageDoorToRotate(int16);
- static bool HasImportExportGarageCollectedThisCar(int16, int8);
static void SetLeaveCameraForThisGarage(int16);
static bool IsThisCarWithinGarageArea(int16, CEntity*);
+ static bool HasCarBeenCrushed(int32);
+ static bool IsPointInAGarageCameraZone(CVector);
+ static bool CameraShouldBeOutside(void);
+ static void GivePlayerDetonator(void);
+ static void PlayerArrestedOrDied(void);
+ static bool IsPointWithinHideOutGarage(CVector&);
+ static bool IsPointWithinAnyGarage(CVector&);
+ static void SetAllDoorsBackToOriginalHeight(void);
+ static void Save(uint8* buf, uint32* size);
+ static void Load(uint8* buf, uint32 size);
+ static bool IsModelIndexADoor(uint32 id);
+ static void SetFreeBombs(bool bValue) { BombsAreFree = bValue; }
+ static void SetFreeResprays(bool bValue) { RespraysAreFree = bValue; }
+
+private:
+ static bool IsCarSprayable(CVehicle*);
+ static float FindDoorHeightForMI(int32);
+ static void CloseHideOutGaragesBeforeSave(void);
+ static int32 CountCarsInHideoutGarage(eGarageType);
+ static int32 FindMaxNumStoredCarsForGarage(eGarageType);
+ static int32 GetBombTypeForGarageType(eGarageType type) { return type - GARAGE_BOMBSHOP1 + 1; }
+ static int32 GetCarsCollectedIndexForGarageType(eGarageType type) { return type - GARAGE_COLLECTCARS_1; }
- static int GetCarsCollectedIndexForGarageType(eGarageType type) { return type - GARAGE_COLLECTCARS_1; }
+ friend class cAudioManager;
+ friend class CGarage;
};
diff --git a/src/control/PathFind.cpp b/src/control/PathFind.cpp
index daa27e57..608a209a 100644
--- a/src/control/PathFind.cpp
+++ b/src/control/PathFind.cpp
@@ -11,19 +11,10 @@ CPathFind &ThePaths = *(CPathFind*)0x8F6754;
WRAPPER bool CPedPath::CalcPedRoute(uint8, CVector, CVector, CVector*, int16*, int16) { EAXJMP(0x42E680); }
-enum
-{
- NodeTypeExtern = 1,
- NodeTypeIntern = 2,
-
- ObjectFlag1 = 1,
- ObjectEastWest = 2,
-
- MAX_DIST = INT16_MAX-1
-};
+#define MAX_DIST INT16_MAX-1
// object flags:
-// 1
+// 1 UseInRoadBlock
// 2 east/west road(?)
CPathInfoForObject *&InfoForTileCars = *(CPathInfoForObject**)0x8F1A8C;
@@ -218,14 +209,14 @@ CPathFind::PreparePathData(void)
if(numIntern == 1 && numExtern == 2){
if(numLanes < 4){
if((i & 7) == 4){ // WHAT?
- m_objectFlags[i] |= ObjectFlag1;
+ m_objectFlags[i] |= UseInRoadBlock;
if(maxX > maxY)
m_objectFlags[i] |= ObjectEastWest;
else
m_objectFlags[i] &= ~ObjectEastWest;
}
}else{
- m_objectFlags[i] |= ObjectFlag1;
+ m_objectFlags[i] |= UseInRoadBlock;
if(maxX > maxY)
m_objectFlags[i] |= ObjectEastWest;
else
diff --git a/src/control/PathFind.h b/src/control/PathFind.h
index d42b8bb3..c51cb7c7 100644
--- a/src/control/PathFind.h
+++ b/src/control/PathFind.h
@@ -11,6 +11,15 @@ public:
enum
{
+ NodeTypeExtern = 1,
+ NodeTypeIntern = 2,
+
+ UseInRoadBlock = 1,
+ ObjectEastWest = 2,
+};
+
+enum
+{
PATH_CAR = 0,
PATH_PED = 1,
};
diff --git a/src/control/Phones.cpp b/src/control/Phones.cpp
index f3b3a8db..276f02b9 100644
--- a/src/control/Phones.cpp
+++ b/src/control/Phones.cpp
@@ -11,6 +11,7 @@
#include "General.h"
#include "AudioScriptObject.h"
#include "RpAnimBlend.h"
+#include "AnimBlendAssociation.h"
CPhoneInfo &gPhoneInfo = *(CPhoneInfo*)0x732A20;
diff --git a/src/control/Pickups.cpp b/src/control/Pickups.cpp
index 53da89f4..3e3c2a48 100644
--- a/src/control/Pickups.cpp
+++ b/src/control/Pickups.cpp
@@ -15,8 +15,14 @@
#include "Pad.h"
#include "Pickups.h"
#include "PlayerPed.h"
+#include "Wanted.h"
+#include "DMAudio.h"
+#include "Fire.h"
#include "PointLights.h"
#include "Pools.h"
+#ifdef FIX_BUGS
+#include "Replay.h"
+#endif
#include "Script.h"
#include "Shadows.h"
#include "SpecialFX.h"
@@ -639,32 +645,26 @@ CPickups::AddToCollectedPickupsArray(int32 index)
void
CPickups::Update()
{
-#ifndef FIX_BUGS
- // BUG: this code can only reach 318 out of 320 pickups
+#ifdef FIX_BUGS // RIP speedrunning (solution from SA)
+ if (CReplay::IsPlayingBack())
+ return;
+#endif
#define PICKUPS_FRAME_SPAN (6)
-#define PICKUPS_PER_FRAME (NUMGENERALPICKUPS/PICKUPS_FRAME_SPAN)
-
- for (uint32 i = PICKUPS_PER_FRAME * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN); i < PICKUPS_PER_FRAME * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN + 1); i++) {
- if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].Update(FindPlayerPed(), FindPlayerVehicle(), CWorld::PlayerInFocus)) {
- AddToCollectedPickupsArray(i);
- }
- }
-
- for (uint32 i = NUMGENERALPICKUPS; i < NUMPICKUPS; i++) {
+#ifdef FIX_BUGS
+ for (uint32 i = NUMGENERALPICKUPS * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN) / PICKUPS_FRAME_SPAN; i < NUMGENERALPICKUPS * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN + 1) / PICKUPS_FRAME_SPAN; i++) {
+#else // BUG: this code can only reach 318 out of 320 pickups
+ for (uint32 i = NUMGENERALPICKUPS / PICKUPS_FRAME_SPAN * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN); i < NUMGENERALPICKUPS / PICKUPS_FRAME_SPAN * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN + 1); i++) {
+#endif
if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].Update(FindPlayerPed(), FindPlayerVehicle(), CWorld::PlayerInFocus)) {
AddToCollectedPickupsArray(i);
}
}
-
#undef PICKUPS_FRAME_SPAN
-#undef PICKUPS_PER_FRAME
-#else
- for (uint32 i = 0; i < NUMPICKUPS; i++) {
+ for (uint32 i = NUMGENERALPICKUPS; i < NUMPICKUPS; i++) {
if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].Update(FindPlayerPed(), FindPlayerVehicle(), CWorld::PlayerInFocus)) {
AddToCollectedPickupsArray(i);
}
}
-#endif
}
void
diff --git a/src/control/Remote.cpp b/src/control/Remote.cpp
index e3891502..f7d12702 100644
--- a/src/control/Remote.cpp
+++ b/src/control/Remote.cpp
@@ -35,7 +35,7 @@ CRemote::GivePlayerRemoteControlledCar(float x, float y, float z, float rot, uin
CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle = car;
CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle->RegisterReference((CEntity**)&CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle);
- TheCamera.TakeControl(car, CCam::MODE_BEHINDCAR, INTERPOLATION, CAM_CONTROLLER_1);
+ TheCamera.TakeControl(car, CCam::MODE_BEHINDCAR, INTERPOLATION, CAMCONTROL_SCRIPT);
}
void
diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp
index a68dd5e7..2e325249 100644
--- a/src/control/Replay.cpp
+++ b/src/control/Replay.cpp
@@ -5,6 +5,7 @@
#include "SpecialFX.h"
#include "CarCtrl.h"
#include "CivilianPed.h"
+#include "Wanted.h"
#include "Clock.h"
#include "DMAudio.h"
#include "Draw.h"
@@ -22,6 +23,8 @@
#include "Pools.h"
#include "Population.h"
#include "Replay.h"
+#include "References.h"
+#include "Pools.h"
#include "RpAnimBlend.h"
#include "RwHelper.h"
#include "CutsceneMgr.h"
@@ -33,6 +36,8 @@
#include "Zones.h"
#include "Font.h"
#include "Text.h"
+#include "Camera.h"
+#include "Radar.h"
uint8 &CReplay::Mode = *(uint8*)0x95CD5B;
CAddressInReplayBuffer &CReplay::Record = *(CAddressInReplayBuffer*)0x942F7C;
@@ -108,9 +113,6 @@ static void(*CBArray_RE3[])(CAnimBlendAssociation*, void*) =
&CPed::PedLandCB, &FinishFuckUCB, &CPed::RestoreHeadingRateCB, &CPed::PedSetQuickDraggedOutCarPositionCB, &CPed::PedSetDraggedOutCarPositionCB
};
-#if 0
-WRAPPER uint8 FindCBFunctionID(void(*f)(CAnimBlendAssociation*, void*)) { EAXJMP(0x584E70); }
-#else
static uint8 FindCBFunctionID(void(*f)(CAnimBlendAssociation*, void*))
{
for (int i = 0; i < sizeof(CBArray) / sizeof(*CBArray); i++){
@@ -123,16 +125,12 @@ static uint8 FindCBFunctionID(void(*f)(CAnimBlendAssociation*, void*))
}
return 0;
}
-#endif
static void(*FindCBFunction(uint8 id))(CAnimBlendAssociation*, void*)
{
return CBArray_RE3[id];
}
-#if 0
-WRAPPER static void ApplyPanelDamageToCar(uint32, CAutomobile*, bool) { EAXJMP(0x584EA0); }
-#else
static void ApplyPanelDamageToCar(uint32 panels, CAutomobile* vehicle, bool flying)
{
if(vehicle->Damage.GetPanelStatus(VEHPANEL_FRONT_LEFT) != CDamageManager::GetPanelStatus(panels, VEHPANEL_FRONT_LEFT)){
@@ -164,7 +162,6 @@ static void ApplyPanelDamageToCar(uint32 panels, CAutomobile* vehicle, bool flyi
vehicle->SetPanelDamage(CAR_BUMP_REAR, VEHBUMPER_REAR, flying);
}
}
-#endif
void PrintElementsInPtrList(void)
{
@@ -257,9 +254,6 @@ void CReplay::Update(void)
}
}
-#if 0
-WRAPPER void CReplay::RecordThisFrame(void) { EAXJMP(0x5932B0); }
-#else
void CReplay::RecordThisFrame(void)
{
#ifdef FIX_REPLAY_BUGS
@@ -372,11 +366,7 @@ void CReplay::RecordThisFrame(void)
MarkEverythingAsNew();
#endif
}
-#endif
-#if 0
-WRAPPER void CReplay::StorePedUpdate(CPed *ped, int id) { EAXJMP(0x5935B0); }
-#else
void CReplay::StorePedUpdate(CPed *ped, int id)
{
tPedUpdatePacket* pp = (tPedUpdatePacket*)&Record.m_pBase[Record.m_nOffset];
@@ -394,11 +384,7 @@ void CReplay::StorePedUpdate(CPed *ped, int id)
StorePedAnimation(ped, &pp->anim_state);
Record.m_nOffset += sizeof(tPedUpdatePacket);
}
-#endif
-#if 0
-WRAPPER void CReplay::StorePedAnimation(CPed *ped, CStoredAnimationState *state) { EAXJMP(0x593670); }
-#else
void CReplay::StorePedAnimation(CPed *ped, CStoredAnimationState *state)
{
CAnimBlendAssociation* second;
@@ -437,11 +423,7 @@ void CReplay::StorePedAnimation(CPed *ped, CStoredAnimationState *state)
state->partBlendAmount = 0;
}
}
-#endif
-#if 0
-WRAPPER void CReplay::StoreDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state) { EAXJMP(0x593BB0); }
-#else
void CReplay::StoreDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state)
{
for (int i = 0; i < NUM_MAIN_ANIMS_IN_REPLAY; i++){
@@ -498,10 +480,7 @@ void CReplay::StoreDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState
}
}
}
-#endif
-#if 0
-WRAPPER void CReplay::ProcessPedUpdate(CPed *ped, float interpolation, CAddressInReplayBuffer *buffer) { EAXJMP(0x594050); }
-#else
+
void CReplay::ProcessPedUpdate(CPed *ped, float interpolation, CAddressInReplayBuffer *buffer)
{
tPedUpdatePacket *pp = (tPedUpdatePacket*)&buffer->m_pBase[buffer->m_nOffset];
@@ -538,11 +517,7 @@ void CReplay::ProcessPedUpdate(CPed *ped, float interpolation, CAddressInReplayB
CWorld::Add(ped);
buffer->m_nOffset += sizeof(tPedUpdatePacket);
}
-#endif
-#if 0
-WRAPPER void CReplay::RetrievePedAnimation(CPed *ped, CStoredAnimationState *state) { EAXJMP(0x5942A0); }
-#else
void CReplay::RetrievePedAnimation(CPed *ped, CStoredAnimationState *state)
{
CAnimBlendAssociation* anim1 = CAnimManager::BlendAnimation(
@@ -580,11 +555,7 @@ void CReplay::RetrievePedAnimation(CPed *ped, CStoredAnimationState *state)
}
}
}
-#endif
-#if 0
-WRAPPER void CReplay::RetrieveDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state) { EAXJMP(0x5944B0); }
-#else
void CReplay::RetrieveDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state)
{
#ifdef FIX_REPLAY_BUGS
@@ -653,11 +624,7 @@ void CReplay::RetrieveDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationSt
anim->SetDeleteCallback(FindCBFunction(callback & 0x7F), ped);
}
}
-#endif
-#if 0
-WRAPPER void CReplay::PlaybackThisFrame(void) { EAXJMP(0x5946B0); }
-#else
void CReplay::PlaybackThisFrame(void)
{
static int FrameSloMo = 0;
@@ -682,7 +649,6 @@ void CReplay::PlaybackThisFrame(void)
DMAudio.SetEffectsFadeVol(0);
DMAudio.SetMusicFadeVol(0);
}
-#endif
// next two functions are only found in mobile version
// most likely they were optimized out for being unused
@@ -707,9 +673,6 @@ bool CReplay::FastForwardToTime(uint32 start)
return true;
}
-#if 0
-WRAPPER void CReplay::StoreCarUpdate(CVehicle *vehicle, int id) { EAXJMP(0x5947F0); }
-#else
void CReplay::StoreCarUpdate(CVehicle *vehicle, int id)
{
tVehicleUpdatePacket* vp = (tVehicleUpdatePacket*)&Record.m_pBase[Record.m_nOffset];
@@ -745,11 +708,7 @@ void CReplay::StoreCarUpdate(CVehicle *vehicle, int id)
}
Record.m_nOffset += sizeof(tVehicleUpdatePacket);
}
-#endif
-#if 0
-WRAPPER void CReplay::ProcessCarUpdate(CVehicle *vehicle, float interpolation, CAddressInReplayBuffer *buffer) { EAXJMP(0x594D10); }
-#else
void CReplay::ProcessCarUpdate(CVehicle *vehicle, float interpolation, CAddressInReplayBuffer *buffer)
{
tVehicleUpdatePacket* vp = (tVehicleUpdatePacket*)&buffer->m_pBase[buffer->m_nOffset];
@@ -819,11 +778,7 @@ void CReplay::ProcessCarUpdate(CVehicle *vehicle, float interpolation, CAddressI
((CBoat*)vehicle)->m_bIsAnchored = false;
}
}
-#endif
-#if 0
-WRAPPER bool CReplay::PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, float interpolation, uint32 *pTimer) { EAXJMP(0x595240); }
-#else
bool CReplay::PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, float interpolation, uint32 *pTimer){
/* Mistake. Not even sure what this is even doing here...
* PlayerWanted is a backup to restore at the end of replay.
@@ -1023,10 +978,7 @@ bool CReplay::PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, flo
ProcessReplayCamera();
return false;
}
-#endif
-#if 0
-WRAPPER void CReplay::FinishPlayback(void) { EAXJMP(0x595B20); }
-#else
+
void CReplay::FinishPlayback(void)
{
if (Mode != MODE_PLAYBACK)
@@ -1048,11 +1000,7 @@ void CReplay::FinishPlayback(void)
DMAudio.SetEffectsFadeVol(127);
DMAudio.SetMusicFadeVol(127);
}
-#endif
-#if 0
-WRAPPER void CReplay::EmptyReplayBuffer(void) { EAXJMP(0x595BD0); }
-#else
void CReplay::EmptyReplayBuffer(void)
{
if (Mode == MODE_PLAYBACK)
@@ -1067,11 +1015,7 @@ void CReplay::EmptyReplayBuffer(void)
Record.m_pBase[Record.m_nOffset] = 0;
MarkEverythingAsNew();
}
-#endif
-#if 0
-WRAPPER void CReplay::ProcessReplayCamera(void) { EAXJMP(0x595C40); }
-#else
void CReplay::ProcessReplayCamera(void)
{
switch (CameraMode) {
@@ -1115,11 +1059,7 @@ void CReplay::ProcessReplayCamera(void)
RwMatrixUpdate(RwFrameGetMatrix(RwCameraGetFrame(TheCamera.m_pRwCamera)));
RwFrameUpdateObjects(RwCameraGetFrame(TheCamera.m_pRwCamera));
}
-#endif
-#if 0
-WRAPPER void CReplay::TriggerPlayback(uint8 cam_mode, float cam_x, float cam_y, float cam_z, bool load_scene) { EAXJMP(0x596030); }
-#else
void CReplay::TriggerPlayback(uint8 cam_mode, float cam_x, float cam_y, float cam_z, bool load_scene)
{
if (Mode != MODE_RECORD)
@@ -1169,11 +1109,7 @@ void CReplay::TriggerPlayback(uint8 cam_mode, float cam_x, float cam_y, float ca
if (cam_mode == REPLAYCAMMODE_ASSTORED)
TheCamera.CarZoomIndicator = 5.0f;
}
-#endif
-#if 0
-WRAPPER void CReplay::StoreStuffInMem(void) { EAXJMP(0x5961F0); }
-#else
void CReplay::StoreStuffInMem(void)
{
CPools::GetVehiclePool()->Store(pBuf0, pBuf1);
@@ -1218,11 +1154,7 @@ void CReplay::StoreStuffInMem(void)
StoreDetailedPedAnimation(ped, &pPedAnims[i]);
}
}
-#endif
-#if 0
-WRAPPER void CReplay::RestoreStuffFromMem(void) { EAXJMP(0x5966E0); }
-#else
void CReplay::RestoreStuffFromMem(void)
{
CPools::GetVehiclePool()->CopyBack(pBuf0, pBuf1);
@@ -1383,11 +1315,7 @@ void CReplay::RestoreStuffFromMem(void)
DMAudio.SetRadioInCar(OldRadioStation);
DMAudio.ChangeMusicMode(MUSICMODE_GAME);
}
-#endif
-#if 0
-WRAPPER void CReplay::EmptyPedsAndVehiclePools(void) { EAXJMP(0x5970E0); }
-#else
void CReplay::EmptyPedsAndVehiclePools(void)
{
int i = CPools::GetVehiclePool()->GetSize();
@@ -1407,11 +1335,7 @@ void CReplay::EmptyPedsAndVehiclePools(void)
delete p;
}
}
-#endif
-#if 0
-WRAPPER void CReplay::EmptyAllPools(void) { EAXJMP(0x5971B0); }
-#else
void CReplay::EmptyAllPools(void)
{
EmptyPedsAndVehiclePools();
@@ -1432,11 +1356,7 @@ void CReplay::EmptyAllPools(void)
delete d;
}
}
-#endif
-#if 0
-WRAPPER void CReplay::MarkEverythingAsNew(void) { EAXJMP(0x597280); }
-#else
void CReplay::MarkEverythingAsNew(void)
{
int i = CPools::GetVehiclePool()->GetSize();
@@ -1454,11 +1374,7 @@ void CReplay::MarkEverythingAsNew(void)
p->bHasAlreadyBeenRecorded = false;
}
}
-#endif
-#if 0
-WRAPPER void CReplay::SaveReplayToHD(void) { EAXJMP(0x597330); }
-#else
void CReplay::SaveReplayToHD(void)
{
CFileMgr::SetDirMyDocuments();
@@ -1489,11 +1405,7 @@ void CReplay::SaveReplayToHD(void)
CFileMgr::CloseFile(fw);
CFileMgr::SetDir("");
}
-#endif
-#if 0
-WRAPPER void PlayReplayFromHD(void) { EAXJMP(0x597420); }
-#else
void PlayReplayFromHD(void)
{
CFileMgr::SetDirMyDocuments();
@@ -1525,11 +1437,7 @@ void PlayReplayFromHD(void)
CReplay::bAllowLookAroundCam = true;
CReplay::StreamAllNecessaryCarsAndPeds();
}
-#endif
-#if 0
-WRAPPER void CReplay::StreamAllNecessaryCarsAndPeds(void) { EAXJMP(0x597560); }
-#else
void CReplay::StreamAllNecessaryCarsAndPeds(void)
{
for (int slot = 0; slot < NUM_REPLAYBUFFERS; slot++) {
@@ -1550,11 +1458,7 @@ void CReplay::StreamAllNecessaryCarsAndPeds(void)
}
CStreaming::LoadAllRequestedModels(false);
}
-#endif
-#if 0
-WRAPPER void CReplay::FindFirstFocusCoordinate(CVector *coord) { EAXJMP(0x5975E0); }
-#else
void CReplay::FindFirstFocusCoordinate(CVector *coord)
{
*coord = CVector(0.0f, 0.0f, 0.0f);
@@ -1569,11 +1473,7 @@ void CReplay::FindFirstFocusCoordinate(CVector *coord)
}
}
}
-#endif
-#if 0
-WRAPPER bool CReplay::ShouldStandardCameraBeProcessed(void) { EAXJMP(0x597680); }
-#else
bool CReplay::ShouldStandardCameraBeProcessed(void)
{
if (Mode != MODE_PLAYBACK)
@@ -1582,11 +1482,7 @@ bool CReplay::ShouldStandardCameraBeProcessed(void)
return false;
return FindPlayerVehicle() != nil;
}
-#endif
-#if 0
-WRAPPER void CReplay::ProcessLookAroundCam(void) { EAXJMP(0x5976C0); }
-#else
void CReplay::ProcessLookAroundCam(void)
{
if (!bAllowLookAroundCam)
@@ -1642,11 +1538,7 @@ void CReplay::ProcessLookAroundCam(void)
RwMatrixUpdate(RwFrameGetMatrix(RwCameraGetFrame(TheCamera.m_pRwCamera)));
RwFrameUpdateObjects(RwCameraGetFrame(TheCamera.m_pRwCamera));
}
-#endif
-#if 0
-WRAPPER size_t CReplay::FindSizeOfPacket(uint8 type) { EAXJMP(0x597CC0); }
-#else
size_t CReplay::FindSizeOfPacket(uint8 type)
{
switch (type) {
@@ -1664,11 +1556,7 @@ size_t CReplay::FindSizeOfPacket(uint8 type)
}
return 0;
}
-#endif
-#if 0
-WRAPPER void CReplay::Display(void) { EAXJMP(0x595EE0); }
-#else
void CReplay::Display()
{
static int TimeCount = 0;
@@ -1686,7 +1574,6 @@ void CReplay::Display()
if (Mode == MODE_PLAYBACK)
CFont::PrintString(SCREEN_SCALE_X(63.5f), SCREEN_SCALE_Y(30.0f), TheText.Get("REPLAY"));
}
-#endif
STARTPATCHES
InjectHook(0x592FE0, &CReplay::Init, PATCH_JUMP);
diff --git a/src/control/Replay.h b/src/control/Replay.h
index cc652a11..56de52a3 100644
--- a/src/control/Replay.h
+++ b/src/control/Replay.h
@@ -1,14 +1,7 @@
#pragma once
-#include "Camera.h"
-#include "Ped.h"
#include "Pools.h"
-#include "Radar.h"
-#include "References.h"
-#include "Vehicle.h"
-#include "Wanted.h"
#include "World.h"
-#include "common.h"
#ifdef FIX_BUGS
#ifndef DONT_FIX_REPLAY_BUGS
@@ -16,6 +9,9 @@
#endif
#endif
+class CVehicle;
+struct CReference;
+
struct CAddressInReplayBuffer
{
uint32 m_nOffset;
diff --git a/src/control/RoadBlocks.cpp b/src/control/RoadBlocks.cpp
index ed092391..e39fe481 100644
--- a/src/control/RoadBlocks.cpp
+++ b/src/control/RoadBlocks.cpp
@@ -1,7 +1,37 @@
#include "common.h"
#include "patcher.h"
#include "RoadBlocks.h"
+#include "PathFind.h"
+
+int16 &CRoadBlocks::NumRoadBlocks = *(int16*)0x95CC34;
+int16 (&CRoadBlocks::RoadBlockObjects)[NUMROADBLOCKS] = *(int16(*)[NUMROADBLOCKS]) * (uintptr*)0x72B3A8;
+bool (&CRoadBlocks::InOrOut)[NUMROADBLOCKS] = *(bool(*)[NUMROADBLOCKS]) * (uintptr*)0x733810;
-WRAPPER void CRoadBlocks::Init(void) { EAXJMP(0x436F50); }
WRAPPER void CRoadBlocks::GenerateRoadBlockCopsForCar(CVehicle*, int32, int16) { EAXJMP(0x4376A0); }
-WRAPPER void CRoadBlocks::GenerateRoadBlocks(void) { EAXJMP(0x436FA0); } \ No newline at end of file
+WRAPPER void CRoadBlocks::GenerateRoadBlocks(void) { EAXJMP(0x436FA0); }
+
+void
+CRoadBlocks::Init(void)
+{
+ NumRoadBlocks = 0;
+ for (int objId = 0; objId < ThePaths.m_numMapObjects; objId++) {
+ if (ThePaths.m_objectFlags[objId] & UseInRoadBlock) {
+ if (NumRoadBlocks < 600) {
+ InOrOut[NumRoadBlocks] = true;
+ RoadBlockObjects[NumRoadBlocks] = objId;
+ NumRoadBlocks++;
+ } else {
+#ifndef MASTER
+ printf("Not enough room for the potential roadblocks\n");
+#endif
+ // FIX: Don't iterate loop after NUMROADBLOCKS
+ return;
+ }
+ }
+ }
+
+}
+
+STARTPATCHES
+ InjectHook(0x436F50, &CRoadBlocks::Init, PATCH_JUMP);
+ENDPATCHES \ No newline at end of file
diff --git a/src/control/RoadBlocks.h b/src/control/RoadBlocks.h
index b1bb3589..3f5868e7 100644
--- a/src/control/RoadBlocks.h
+++ b/src/control/RoadBlocks.h
@@ -6,6 +6,10 @@ class CVehicle;
class CRoadBlocks
{
public:
+ static int16 (&NumRoadBlocks);
+ static int16 (&RoadBlockObjects)[NUMROADBLOCKS];
+ static bool (&InOrOut)[NUMROADBLOCKS];
+
static void Init(void);
static void GenerateRoadBlockCopsForCar(CVehicle*, int32, int16);
static void GenerateRoadBlocks(void);
diff --git a/src/control/SceneEdit.cpp b/src/control/SceneEdit.cpp
index 28b4ea6c..3e55d431 100644
--- a/src/control/SceneEdit.cpp
+++ b/src/control/SceneEdit.cpp
@@ -2,5 +2,11 @@
#include "patcher.h"
#include "SceneEdit.h"
+bool &CSceneEdit::m_bEditOn = *(bool*)0x95CD77;
+int32 &CSceneEdit::m_bCameraFollowActor = *(int*)0x940590;
+bool &CSceneEdit::m_bRecording = *(bool*)0x95CD1F;
+CVector &CSceneEdit::m_vecCurrentPosition = *(CVector*)0x943064;
+CVector &CSceneEdit::m_vecCamHeading = *(CVector*)0x942F8C;
+
WRAPPER void CSceneEdit::Update(void) { EAXJMP(0x585570); }
WRAPPER void CSceneEdit::Init(void) { EAXJMP(0x585170); }
diff --git a/src/control/SceneEdit.h b/src/control/SceneEdit.h
index e9209b90..0de72c19 100644
--- a/src/control/SceneEdit.h
+++ b/src/control/SceneEdit.h
@@ -3,6 +3,12 @@
class CSceneEdit
{
public:
+ static bool &m_bEditOn;
+ static int32 &m_bCameraFollowActor;
+ static bool &m_bRecording;
+ static CVector &m_vecCurrentPosition;
+ static CVector &m_vecCamHeading;
+
static void Update(void);
static void Init(void);
};
diff --git a/src/control/Script.cpp b/src/control/Script.cpp
index 4aeacf3f..f96ec060 100644
--- a/src/control/Script.cpp
+++ b/src/control/Script.cpp
@@ -1,3 +1,4 @@
+#define WITHWINDOWS // for our script loading hack
#include "common.h"
#include "patcher.h"
@@ -52,6 +53,8 @@
#include "Restart.h"
#include "Replay.h"
#include "RpAnimBlend.h"
+#include "AnimBlendAssociation.h"
+#include "Fire.h"
#include "Rubbish.h"
#include "Shadows.h"
#include "SpecialFX.h"
@@ -64,6 +67,7 @@
#include "Weather.h"
#include "World.h"
#include "Zones.h"
+#include "Radar.h"
#define PICKUP_PLACEMENT_OFFSET 0.5f
#define PED_FIND_Z_OFFSET 5.0f
@@ -2838,9 +2842,6 @@ int8 CRunningScript::ProcessCommands200To299(int32 command)
return -1;
}
-#if 0
-WRAPPER int8 CRunningScript::ProcessCommand300To399(int32 command) { EAXJMP(0x43ED30); }
-#else
int8 CRunningScript::ProcessCommands300To399(int32 command)
{
switch (command) {
@@ -3072,7 +3073,7 @@ int8 CRunningScript::ProcessCommands300To399(int32 command)
{
CollectParameters(&m_nIp, 3);
// ScriptParams[0] is unused.
- TheCamera.TakeControl(nil, ScriptParams[1], ScriptParams[2], CAM_CONTROLLER_1);
+ TheCamera.TakeControl(nil, ScriptParams[1], ScriptParams[2], CAMCONTROL_SCRIPT);
return 0;
}
case COMMAND_POINT_CAMERA_AT_CAR:
@@ -3080,7 +3081,7 @@ int8 CRunningScript::ProcessCommands300To399(int32 command)
CollectParameters(&m_nIp, 3);
CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
assert(pVehicle);
- TheCamera.TakeControl(pVehicle, ScriptParams[1], ScriptParams[2], CAM_CONTROLLER_1);
+ TheCamera.TakeControl(pVehicle, ScriptParams[1], ScriptParams[2], CAMCONTROL_SCRIPT);
return 0;
}
case COMMAND_POINT_CAMERA_AT_CHAR:
@@ -3088,7 +3089,7 @@ int8 CRunningScript::ProcessCommands300To399(int32 command)
CollectParameters(&m_nIp, 3);
CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]);
assert(pPed);
- TheCamera.TakeControl(pPed, ScriptParams[1], ScriptParams[2], CAM_CONTROLLER_1);
+ TheCamera.TakeControl(pPed, ScriptParams[1], ScriptParams[2], CAMCONTROL_SCRIPT);
return 0;
}
case COMMAND_RESTORE_CAMERA:
@@ -3139,7 +3140,7 @@ int8 CRunningScript::ProcessCommands300To399(int32 command)
CVector pos = *(CVector*)&ScriptParams[0];
if (pos.z <= MAP_Z_LOW_LIMIT)
pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y);
- TheCamera.TakeControlNoEntity(pos, ScriptParams[3], CAM_CONTROLLER_1);
+ TheCamera.TakeControlNoEntity(pos, ScriptParams[3], CAMCONTROL_SCRIPT);
return 0;
}
case COMMAND_ADD_BLIP_FOR_CAR_OLD:
@@ -3572,11 +3573,7 @@ int8 CRunningScript::ProcessCommands300To399(int32 command)
}
return -1;
}
-#endif
-#if 0
-WRAPPER int8 CRunningScript::ProcessCommands400To499(int32 command) { EAXJMP(0x440CB0); }
-#else
int8 CRunningScript::ProcessCommands400To499(int32 command)
{
switch (command) {
@@ -4366,11 +4363,7 @@ int8 CRunningScript::ProcessCommands400To499(int32 command)
}
return -1;
}
-#endif
-#if 0
-WRAPPER int8 CRunningScript::ProcessCommands500To599(int32 command) { EAXJMP(0x4429C0); }
-#else
int8 CRunningScript::ProcessCommands500To599(int32 command)
{
switch (command) {
@@ -4629,7 +4622,7 @@ int8 CRunningScript::ProcessCommands500To599(int32 command)
infZ = *(float*)&ScriptParams[5];
supZ = *(float*)&ScriptParams[2];
}
- ScriptParams[0] = CGarages::AddOne(infX, infY, infZ, supX, supY, supZ, ScriptParams[6], 0);
+ ScriptParams[0] = CGarages::AddOne(infX, infY, infZ, supX, supY, supZ, (eGarageType)ScriptParams[6], 0);
StoreParameters(&m_nIp, 1);
return 0;
}
@@ -4654,7 +4647,7 @@ int8 CRunningScript::ProcessCommands500To599(int32 command)
infZ = *(float*)&ScriptParams[5];
supZ = *(float*)&ScriptParams[2];
}
- ScriptParams[0] = CGarages::AddOne(infX, infY, infZ, supX, supY, supZ, ScriptParams[6], ScriptParams[7]);
+ ScriptParams[0] = CGarages::AddOne(infX, infY, infZ, supX, supY, supZ, (eGarageType)ScriptParams[6], ScriptParams[7]);
StoreParameters(&m_nIp, 1);
return 0;
}
@@ -4678,7 +4671,7 @@ int8 CRunningScript::ProcessCommands500To599(int32 command)
return 0;
case COMMAND_SET_FREE_BOMBS:
CollectParameters(&m_nIp, 1);
- CGarages::BombsAreFree = (ScriptParams[0] != 0);
+ CGarages::SetFreeBombs(ScriptParams[0] != 0);
return 0;
#ifdef GTA_PS2
case COMMAND_SET_POWERPOINT:
@@ -5197,11 +5190,7 @@ int8 CRunningScript::ProcessCommands500To599(int32 command)
}
return -1;
}
-#endif
-#if 0
-WRAPPER int8 CRunningScript::ProcessCommands600To699(int32 command) { EAXJMP(0x444B20); }
-#else
int8 CRunningScript::ProcessCommands600To699(int32 command)
{
switch (command){
@@ -5555,11 +5544,7 @@ int8 CRunningScript::ProcessCommands600To699(int32 command)
}
return -1;
}
-#endif
-#if 0
-WRAPPER int8 CRunningScript::ProcessCommands700To799(int32 command) { EAXJMP(0x4458A0); }
-#else
int8 CRunningScript::ProcessCommands700To799(int32 command)
{
switch (command){
@@ -6425,11 +6410,6 @@ int8 CRunningScript::ProcessCommands700To799(int32 command)
}
return -1;
}
-#endif
-
-#if 0
-WRAPPER int8 CRunningScript::ProcessCommands800To899(int32 command) { EAXJMP(0x448240); }
-#else
int8 CRunningScript::ProcessCommands800To899(int32 command)
{
CMatrix tmp_matrix;
@@ -6682,7 +6662,7 @@ int8 CRunningScript::ProcessCommands800To899(int32 command)
}
case COMMAND_SET_FREE_RESPRAYS:
CollectParameters(&m_nIp, 1);
- CGarages::RespraysAreFree = (ScriptParams[0] != 0);
+ CGarages::SetFreeResprays(ScriptParams[0] != 0);
return 0;
case COMMAND_SET_PLAYER_VISIBLE:
{
@@ -7130,13 +7110,13 @@ int8 CRunningScript::ProcessCommands800To899(int32 command)
case COMMAND_OPEN_GARAGE:
{
CollectParameters(&m_nIp, 1);
- CGarages::Garages[ScriptParams[0]].OpenThisGarage();
+ CGarages::OpenGarage(ScriptParams[0]);
return 0;
}
case COMMAND_CLOSE_GARAGE:
{
CollectParameters(&m_nIp, 1);
- CGarages::Garages[ScriptParams[0]].CloseThisGarage();
+ CGarages::CloseGarage(ScriptParams[1]);
return 0;
}
case COMMAND_WARP_CHAR_FROM_CAR_TO_COORD:
@@ -7511,11 +7491,7 @@ int8 CRunningScript::ProcessCommands800To899(int32 command)
}
return -1;
}
-#endif
-#if 0
-WRAPPER int8 CRunningScript::ProcessCommands900To999(int32 command) { EAXJMP(0x44CB80); }
-#else
int8 CRunningScript::ProcessCommands900To999(int32 command)
{
char str[52];
@@ -8416,7 +8392,6 @@ int8 CRunningScript::ProcessCommands900To999(int32 command)
}
return -1;
}
-#endif
int8 CRunningScript::ProcessCommands1000To1099(int32 command)
{
@@ -9815,7 +9790,7 @@ void CTheScripts::UndoBuildingSwaps()
}
}
-void CTheScripts::UndoEntityVisibilitySettings()
+void CTheScripts::UndoEntityInvisibilitySettings()
{
for (int i = 0; i < MAX_NUM_INVISIBILITY_SETTINGS; i++) {
if (InvisibilitySettingArray[i]) {
@@ -11653,7 +11628,7 @@ InjectHook(0x439040, &CTheScripts::Process, PATCH_JUMP);
InjectHook(0x439400, &CTheScripts::StartTestScript, PATCH_JUMP);
InjectHook(0x439410, &CTheScripts::IsPlayerOnAMission, PATCH_JUMP);
InjectHook(0x44FD10, &CTheScripts::UndoBuildingSwaps, PATCH_JUMP);
-InjectHook(0x44FD60, &CTheScripts::UndoEntityVisibilitySettings, PATCH_JUMP);
+InjectHook(0x44FD60, &CTheScripts::UndoEntityInvisibilitySettings, PATCH_JUMP);
InjectHook(0x4534E0, &CTheScripts::ScriptDebugLine3D, PATCH_JUMP);
InjectHook(0x453550, &CTheScripts::RenderTheScriptDebugLines, PATCH_JUMP);
InjectHook(0x4535E0, &CTheScripts::SaveAllScripts, PATCH_JUMP);
diff --git a/src/control/Script.h b/src/control/Script.h
index b6844b6c..fbcdce48 100644
--- a/src/control/Script.h
+++ b/src/control/Script.h
@@ -281,7 +281,7 @@ public:
static void ClearSpaceForMissionEntity(const CVector&, CEntity*);
static void UndoBuildingSwaps();
- static void UndoEntityVisibilitySettings();
+ static void UndoEntityInvisibilitySettings();
static void ScriptDebugLine3D(float x1, float y1, float z1, float x2, float y2, float z2, uint32 col, uint32 col2);
static void RenderTheScriptDebugLines();
diff --git a/src/core/AnimViewer.cpp b/src/core/AnimViewer.cpp
index a2d7b94a..1086db20 100644
--- a/src/core/AnimViewer.cpp
+++ b/src/core/AnimViewer.cpp
@@ -33,6 +33,7 @@
#include "Clock.h"
#include "Timecycle.h"
#include "RpAnimBlend.h"
+#include "AnimBlendAssociation.h"
#include "Shadows.h"
#include "Radar.h"
#include "Hud.h"
@@ -207,6 +208,7 @@ PlayAnimation(RpClump *clump, AssocGroupId animGroup, AnimationId anim)
animAssoc->SetRun();
}
+extern void (*DebugMenuProcess)(void);
void
CAnimViewer::Update(void)
{
@@ -246,6 +248,9 @@ CAnimViewer::Update(void)
}
CPad::UpdatePads();
CPad* pad = CPad::GetPad(0);
+
+ DebugMenuProcess();
+
CStreaming::UpdateForAnimViewer();
CStreaming::RequestModel(modelId, 0);
if (CStreaming::HasModelLoaded(modelId)) {
@@ -289,7 +294,7 @@ CAnimViewer::Update(void)
}
newEntity->GetPosition() = CVector(0.0f, 0.0f, 0.0f);
CWorld::Add(newEntity);
- TheCamera.TakeControl(pTarget, CCam::MODE_MODELVIEW, JUMP_CUT, CAM_CONTROLLER_1);
+ TheCamera.TakeControl(pTarget, CCam::MODE_MODELVIEW, JUMP_CUT, CAMCONTROL_SCRIPT);
}
if (pTarget->m_type == ENTITY_TYPE_VEHICLE || pTarget->m_type == ENTITY_TYPE_PED || pTarget->m_type == ENTITY_TYPE_OBJECT) {
((CPhysical*)pTarget)->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp
new file mode 100644
index 00000000..5b7a53e9
--- /dev/null
+++ b/src/core/Cam.cpp
@@ -0,0 +1,5292 @@
+#include "common.h"
+#include "patcher.h"
+#include "main.h"
+#include "Draw.h"
+#include "World.h"
+#include "Vehicle.h"
+#include "Automobile.h"
+#include "Ped.h"
+#include "PlayerPed.h"
+#include "CopPed.h"
+#include "RpAnimBlend.h"
+#include "ControllerConfig.h"
+#include "Pad.h"
+#include "Frontend.h"
+#include "General.h"
+#include "Renderer.h"
+#include "Shadows.h"
+#include "Hud.h"
+#include "ZoneCull.h"
+#include "SurfaceTable.h"
+#include "WaterLevel.h"
+#include "MBlur.h"
+#include "SceneEdit.h"
+#include "Debug.h"
+#include "Camera.h"
+#include "DMAudio.h"
+
+const float DefaultFOV = 70.0f; // beta: 80.0f
+
+bool PrintDebugCode = false;
+int16 &DebugCamMode = *(int16*)0x95CCF2;
+
+#ifdef FREE_CAM
+bool CCamera::bFreeCam = false;
+int nPreviousMode = -1;
+#endif
+
+void
+CCam::Init(void)
+{
+ Mode = MODE_FOLLOWPED;
+ Front = CVector(0.0f, 0.0f, -1.0f);
+ Up = CVector(0.0f, 0.0f, 1.0f);
+ Rotating = 0;
+ m_iDoCollisionChecksOnFrameNum = 1;
+ m_iDoCollisionCheckEveryNumOfFrames = 9;
+ m_iFrameNumWereAt = 0;
+ m_bCollisionChecksOn = 1;
+ m_fRealGroundDist = 0.0f;
+ BetaSpeed = 0.0f;
+ AlphaSpeed = 0.0f;
+ DistanceSpeed = 0.0f;
+ f_max_role_angle = DEGTORAD(5.0f);
+ Distance = 30.0f;
+ DistanceSpeed = 0.0f;
+ m_pLastCarEntered = 0;
+ m_pLastPedLookedAt = 0;
+ ResetStatics = 1;
+ Beta = 0.0f;
+ m_bFixingBeta = 0;
+ CA_MIN_DISTANCE = 0.0f;
+ CA_MAX_DISTANCE = 0.0f;
+ LookingBehind = 0;
+ LookingLeft = 0;
+ LookingRight = 0;
+ m_fPlayerInFrontSyphonAngleOffSet = DEGTORAD(20.0f);
+ m_fSyphonModeTargetZOffSet = 0.5f;
+ m_fRadiusForDead = 1.5f;
+ DirectionWasLooking = LOOKING_FORWARD;
+ LookBehindCamWasInFront = 0;
+ f_Roll = 0.0f;
+ f_rollSpeed = 0.0f;
+ m_fCloseInPedHeightOffset = 0.0f;
+ m_fCloseInPedHeightOffsetSpeed = 0.0f;
+ m_fCloseInCarHeightOffset = 0.0f;
+ m_fCloseInCarHeightOffsetSpeed = 0.0f;
+ m_fPedBetweenCameraHeightOffset = 0.0f;
+ m_fTargetBeta = 0.0f;
+ m_fBufferedTargetBeta = 0.0f;
+ m_fBufferedTargetOrientation = 0.0f;
+ m_fBufferedTargetOrientationSpeed = 0.0f;
+ m_fDimensionOfHighestNearCar = 0.0f;
+ m_fRoadOffSet = 0.0f;
+}
+
+void
+CCam::Process(void)
+{
+ CVector CameraTarget;
+ float TargetSpeedVar = 0.0f;
+ float TargetOrientation = 0.0f;
+
+ if(CamTargetEntity == nil)
+ CamTargetEntity = TheCamera.pTargetEntity;
+
+ m_iFrameNumWereAt++;
+ if(m_iFrameNumWereAt > m_iDoCollisionCheckEveryNumOfFrames)
+ m_iFrameNumWereAt = 1;
+ m_bCollisionChecksOn = m_iFrameNumWereAt == m_iDoCollisionChecksOnFrameNum;
+
+ if(m_bCamLookingAtVector){
+ CameraTarget = m_cvecCamFixedModeVector;
+ }else if(CamTargetEntity->IsVehicle()){
+ CameraTarget = CamTargetEntity->GetPosition();
+
+ if(CamTargetEntity->GetForward().x == 0.0f && CamTargetEntity->GetForward().y == 0.0f)
+ TargetOrientation = 0.0f;
+ else
+ TargetOrientation = CGeneral::GetATanOfXY(CamTargetEntity->GetForward().x, CamTargetEntity->GetForward().y);
+
+ CVector Fwd(0.0f, 0.0f, 0.0f);
+ Fwd.x = CamTargetEntity->GetForward().x;
+ Fwd.y = CamTargetEntity->GetForward().y;
+ Fwd.Normalise();
+ // Game normalizes again here manually. useless, so skipped
+
+ float FwdSpeedX = ((CVehicle*)CamTargetEntity)->GetMoveSpeed().x * Fwd.x;
+ float FwdSpeedY = ((CVehicle*)CamTargetEntity)->GetMoveSpeed().y * Fwd.y;
+ if(FwdSpeedX + FwdSpeedY > 0.0f)
+ TargetSpeedVar = min(Sqrt(SQR(FwdSpeedX) + SQR(FwdSpeedY))/0.9f, 1.0f);
+ else
+ TargetSpeedVar = -min(Sqrt(SQR(FwdSpeedX) + SQR(FwdSpeedY))/1.8f, 0.5f);
+ SpeedVar = 0.895f*SpeedVar + 0.105*TargetSpeedVar;
+ }else{
+ CameraTarget = CamTargetEntity->GetPosition();
+
+ if(CamTargetEntity->GetForward().x == 0.0f && CamTargetEntity->GetForward().y == 0.0f)
+ TargetOrientation = 0.0f;
+ else
+ TargetOrientation = CGeneral::GetATanOfXY(CamTargetEntity->GetForward().x, CamTargetEntity->GetForward().y);
+ TargetSpeedVar = 0.0f;
+ SpeedVar = 0.0f;
+ }
+
+ switch(Mode){
+ case MODE_TOPDOWN:
+ case MODE_GTACLASSIC:
+ Process_TopDown(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ case MODE_BEHINDCAR:
+ Process_BehindCar(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ case MODE_FOLLOWPED:
+ if(CCamera::m_bUseMouse3rdPerson)
+ Process_FollowPedWithMouse(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ else
+#ifdef FREE_CAM
+ if(CCamera::bFreeCam)
+ Process_FollowPed_Rotation(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ else
+#endif
+ Process_FollowPed(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+// case MODE_AIMING:
+ case MODE_DEBUG:
+ Process_Debug(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ case MODE_SNIPER:
+ Process_Sniper(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ case MODE_ROCKETLAUNCHER:
+ Process_Rocket(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ case MODE_MODELVIEW:
+ Process_ModelView(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+// case MODE_BILL:
+ case MODE_SYPHON:
+ Process_Syphon(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ case MODE_CIRCLE:
+ Process_Circle(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+// case MODE_CHEESYZOOM:
+ case MODE_WHEELCAM:
+ Process_WheelCam(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ case MODE_FIXED:
+ Process_Fixed(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ case MODE_1STPERSON:
+ Process_1stPerson(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ case MODE_FLYBY:
+ Process_FlyBy(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ case MODE_CAM_ON_A_STRING:
+#ifdef FREE_CAM
+ if(CCamera::bFreeCam)
+ Process_FollowCar_SA(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ else
+#endif
+ Process_Cam_On_A_String(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ case MODE_REACTION:
+ Process_ReactionCam(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ case MODE_FOLLOW_PED_WITH_BIND:
+ Process_FollowPed_WithBinding(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ case MODE_CHRIS:
+ Process_Chris_With_Binding_PlusRotation(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ case MODE_BEHINDBOAT:
+#ifdef FREE_CAM
+ if (CCamera::bFreeCam)
+ Process_FollowCar_SA(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ else
+#endif
+ Process_BehindBoat(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ case MODE_PLAYER_FALLEN_WATER:
+ Process_Player_Fallen_Water(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+// case MODE_CAM_ON_TRAIN_ROOF:
+// case MODE_CAM_RUNNING_SIDE_TRAIN:
+// case MODE_BLOOD_ON_THE_TRACKS:
+// case MODE_IM_THE_PASSENGER_WOOWOO:
+ case MODE_SYPHON_CRIM_IN_FRONT:
+ Process_Syphon_Crim_In_Front(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ case MODE_PED_DEAD_BABY:
+ ProcessPedsDeadBaby();
+ break;
+// case MODE_PILLOWS_PAPS:
+// case MODE_LOOK_AT_CARS:
+ case MODE_ARRESTCAM_ONE:
+ ProcessArrestCamOne();
+ break;
+ case MODE_ARRESTCAM_TWO:
+ ProcessArrestCamTwo();
+ break;
+ case MODE_M16_1STPERSON:
+ case MODE_HELICANNON_1STPERSON: // miami
+ Process_M16_1stPerson(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ case MODE_SPECIAL_FIXED_FOR_SYPHON:
+ Process_SpecialFixedForSyphon(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ case MODE_FIGHT_CAM:
+ Process_Fight_Cam(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ case MODE_TOP_DOWN_PED:
+ Process_TopDownPed(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ case MODE_SNIPER_RUNABOUT:
+ case MODE_ROCKETLAUNCHER_RUNABOUT:
+ case MODE_1STPERSON_RUNABOUT:
+ case MODE_M16_1STPERSON_RUNABOUT:
+ case MODE_FIGHT_CAM_RUNABOUT:
+ Process_1rstPersonPedOnPC(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ case MODE_EDITOR:
+ Process_Editor(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+ break;
+ default:
+ Source = CVector(0.0f, 0.0f, 0.0f);
+ Front = CVector(0.0f, 1.0f, 0.0f);
+ Up = CVector(0.0f, 0.0f, 1.0f);
+ }
+
+#ifdef FREE_CAM
+ nPreviousMode = Mode;
+#endif
+ CVector TargetToCam = Source - m_cvecTargetCoorsForFudgeInter;
+ float DistOnGround = TargetToCam.Magnitude2D();
+ m_fTrueBeta = CGeneral::GetATanOfXY(TargetToCam.x, TargetToCam.y);
+ m_fTrueAlpha = CGeneral::GetATanOfXY(TargetToCam.z, DistOnGround);
+ if(TheCamera.m_uiTransitionState == 0)
+ KeepTrackOfTheSpeed(Source, m_cvecTargetCoorsForFudgeInter, Up, m_fTrueAlpha, m_fTrueBeta, FOV);
+
+ // Look Behind, Left, Right
+ LookingBehind = false;
+ LookingLeft = false;
+ LookingRight = false;
+ SourceBeforeLookBehind = Source;
+ if(&TheCamera.Cams[TheCamera.ActiveCam] == this){
+ if((Mode == MODE_CAM_ON_A_STRING || Mode == MODE_1STPERSON || Mode == MODE_BEHINDBOAT) &&
+ CamTargetEntity->IsVehicle()){
+ if(CPad::GetPad(0)->GetLookBehindForCar()){
+ LookBehind();
+ if(DirectionWasLooking != LOOKING_BEHIND)
+ TheCamera.m_bJust_Switched = true;
+ DirectionWasLooking = LOOKING_BEHIND;
+ }else if(CPad::GetPad(0)->GetLookLeft()){
+ LookLeft();
+ if(DirectionWasLooking != LOOKING_LEFT)
+ TheCamera.m_bJust_Switched = true;
+ DirectionWasLooking = LOOKING_LEFT;
+ }else if(CPad::GetPad(0)->GetLookRight()){
+ LookRight();
+ if(DirectionWasLooking != LOOKING_RIGHT)
+ TheCamera.m_bJust_Switched = true;
+ DirectionWasLooking = LOOKING_RIGHT;
+ }else{
+ if(DirectionWasLooking != LOOKING_FORWARD)
+ TheCamera.m_bJust_Switched = true;
+ DirectionWasLooking = LOOKING_FORWARD;
+ }
+ }
+ if(Mode == MODE_FOLLOWPED && CamTargetEntity->IsPed()){
+ if(CPad::GetPad(0)->GetLookBehindForPed()){
+ LookBehind();
+ if(DirectionWasLooking != LOOKING_BEHIND)
+ TheCamera.m_bJust_Switched = true;
+ DirectionWasLooking = LOOKING_BEHIND;
+ }else
+ DirectionWasLooking = LOOKING_FORWARD;
+ }
+ }
+
+ if(Mode == MODE_SNIPER || Mode == MODE_ROCKETLAUNCHER || Mode == MODE_M16_1STPERSON ||
+ Mode == MODE_1STPERSON || Mode == MODE_HELICANNON_1STPERSON || GetWeaponFirstPersonOn())
+ ClipIfPedInFrontOfPlayer();
+}
+
+// MaxSpeed is a limit of how fast the value is allowed to change. 1.0 = to Target in up to 1ms
+// Acceleration is how fast the speed will change to MaxSpeed. 1.0 = to MaxSpeed in 1ms
+void
+WellBufferMe(float Target, float *CurrentValue, float *CurrentSpeed, float MaxSpeed, float Acceleration, bool IsAngle)
+{
+ float Delta = Target - *CurrentValue;
+
+ if(IsAngle){
+ while(Delta >= PI) Delta -= 2*PI;
+ while(Delta < -PI) Delta += 2*PI;
+ }
+
+ float TargetSpeed = Delta * MaxSpeed;
+ // Add or subtract absolute depending on sign, genius!
+// if(TargetSpeed - *CurrentSpeed > 0.0f)
+// *CurrentSpeed += Acceleration * Abs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep();
+// else
+// *CurrentSpeed -= Acceleration * Abs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep();
+ // this is simpler:
+ *CurrentSpeed += Acceleration * (TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep();
+
+ // Clamp speed if we overshot
+ if(TargetSpeed < 0.0f && *CurrentSpeed < TargetSpeed)
+ *CurrentSpeed = TargetSpeed;
+ else if(TargetSpeed > 0.0f && *CurrentSpeed > TargetSpeed)
+ *CurrentSpeed = TargetSpeed;
+
+ *CurrentValue += *CurrentSpeed * min(10.0f, CTimer::GetTimeStep());
+}
+
+void
+MakeAngleLessThan180(float &Angle)
+{
+ while(Angle >= PI) Angle -= 2*PI;
+ while(Angle < -PI) Angle += 2*PI;
+}
+
+void
+CCam::ProcessSpecialHeightRoutines(void)
+{
+ int i = 0;
+ bool StandingOnBoat = false;
+ static bool PreviouslyFailedRoadHeightCheck = false;
+ CVector CamToTarget, CamToPed;
+ float DistOnGround, BetaAngle;
+ CPed *Player;
+ int ClosestPed = 0;
+ bool FoundPed = false;
+ float ClosestPedDist, PedZDist;
+ CColPoint colPoint;
+
+ CamToTarget = TheCamera.pTargetEntity->GetPosition() - TheCamera.GetGameCamPosition();
+ DistOnGround = CamToTarget.Magnitude2D();
+ BetaAngle = CGeneral::GetATanOfXY(CamToTarget.x, CamToTarget.y);
+ m_bTheHeightFixerVehicleIsATrain = false;
+ ClosestPedDist = 0.0f;
+ // CGeneral::GetATanOfXY(TheCamera.GetForward().x, TheCamera.GetForward().y);
+ Player = CWorld::Players[CWorld::PlayerInFocus].m_pPed;
+
+ if(DistOnGround > 10.0f)
+ DistOnGround = 10.0f;
+
+ if(CamTargetEntity && CamTargetEntity->IsPed()){
+ if(FindPlayerPed()->m_pCurSurface && FindPlayerPed()->m_pCurSurface->IsVehicle() &&
+ ((CVehicle*)FindPlayerPed()->m_pCurSurface)->IsBoat())
+ StandingOnBoat = true;
+
+ // Move up the camera if there is a ped close to it
+ if(Mode == MODE_FOLLOWPED || Mode == MODE_FIGHT_CAM){
+ // Find ped closest to camera
+ while(i < Player->m_numNearPeds){
+ if(Player->m_nearPeds[i] && Player->m_nearPeds[i]->GetPedState() != PED_DEAD){
+ CamToPed = Player->m_nearPeds[i]->GetPosition() - TheCamera.GetGameCamPosition();
+ if(FoundPed){
+ if(CamToPed.Magnitude2D() < ClosestPedDist){
+ ClosestPed = i;
+ ClosestPedDist = CamToPed.Magnitude2D();
+ }
+ }else{
+ FoundPed = true;
+ ClosestPed = i;
+ ClosestPedDist = CamToPed.Magnitude2D();
+ }
+ }
+ i++;
+ }
+
+ if(FoundPed){
+ float Offset = 0.0f;
+ CPed *Ped = Player->m_nearPeds[ClosestPed];
+ CamToPed = Ped->GetPosition() - TheCamera.GetGameCamPosition();
+ PedZDist = 0.0f;
+ float dist = CamToPed.Magnitude2D(); // should be same as ClosestPedDist
+ if(dist < 2.1f){
+ // Ped is close to camera, move up
+
+ // Z Distance between player and close ped
+ PedZDist = 0.0f;
+ if(Ped->bIsStanding)
+ PedZDist = Ped->GetPosition().z - Player->GetPosition().z;
+ // Ignore if too distant
+ if(PedZDist > 1.2f || PedZDist < -1.2f)
+ PedZDist = 0.0f;
+
+ float DistScale = (2.1f - dist)/2.1f;
+ if(Mode == MODE_FOLLOWPED){
+ if(TheCamera.PedZoomIndicator == CAM_ZOOM_1)
+ Offset = 0.45*DistScale + PedZDist;
+ if(TheCamera.PedZoomIndicator == CAM_ZOOM_2)
+ Offset = 0.35*DistScale + PedZDist;
+ if(TheCamera.PedZoomIndicator == CAM_ZOOM_3)
+ Offset = 0.25*DistScale + PedZDist;
+ if(Abs(CGeneral::GetRadianAngleBetweenPoints(CamToPed.x, CamToPed.y, CamToTarget.x, CamToTarget.y)) > HALFPI)
+ Offset += 0.3f;
+ m_fPedBetweenCameraHeightOffset = Offset + 1.3f;
+ PedZDist = 0.0f;
+ }else if(Mode == MODE_FIGHT_CAM)
+ m_fPedBetweenCameraHeightOffset = PedZDist + 1.3f + 0.5f;
+ }else
+ m_fPedBetweenCameraHeightOffset = 0.0f;
+ }else{
+ PedZDist = 0.0f;
+ m_fPedBetweenCameraHeightOffset = 0.0f;
+ }
+ }else
+ PedZDist = 0.0f;
+
+
+ // Move camera up for vehicles in the way
+ if(m_bCollisionChecksOn && (Mode == MODE_FOLLOWPED || Mode == MODE_FIGHT_CAM)){
+ bool FoundCar = false;
+ CEntity *vehicle = nil;
+ float TestDist = DistOnGround + 1.25f;
+ float HighestCar = 0.0f;
+ CVector TestBase = CamTargetEntity->GetPosition();
+ CVector TestPoint;
+ TestBase.z -= 0.15f;
+
+ TestPoint = TestBase - TestDist * CVector(Cos(BetaAngle), Sin(BetaAngle), 0.0f);
+ if(CWorld::ProcessLineOfSight(CamTargetEntity->GetPosition(), TestPoint, colPoint, vehicle, false, true, false, false, false, false) &&
+ vehicle->IsVehicle()){
+ float height = vehicle->GetColModel()->boundingBox.GetSize().z;
+ FoundCar = true;
+ HighestCar = height;
+ if(((CVehicle*)vehicle)->IsTrain())
+ m_bTheHeightFixerVehicleIsATrain = true;
+ }
+
+ TestPoint = TestBase - TestDist * CVector(Cos(BetaAngle+DEGTORAD(28.0f)), Sin(BetaAngle+DEGTORAD(28.0f)), 0.0f);
+ if(CWorld::ProcessLineOfSight(CamTargetEntity->GetPosition(), TestPoint, colPoint, vehicle, false, true, false, false, false, false) &&
+ vehicle->IsVehicle()){
+ float height = vehicle->GetColModel()->boundingBox.GetSize().z;
+ if(FoundCar){
+ HighestCar = max(HighestCar, height);
+ }else{
+ FoundCar = true;
+ HighestCar = height;
+ }
+ if(((CVehicle*)vehicle)->IsTrain())
+ m_bTheHeightFixerVehicleIsATrain = true;
+ }
+
+ TestPoint = TestBase - TestDist * CVector(Cos(BetaAngle-DEGTORAD(28.0f)), Sin(BetaAngle-DEGTORAD(28.0f)), 0.0f);
+ if(CWorld::ProcessLineOfSight(CamTargetEntity->GetPosition(), TestPoint, colPoint, vehicle, false, true, false, false, false, false) &&
+ vehicle->IsVehicle()){
+ float height = vehicle->GetColModel()->boundingBox.GetSize().z;
+ if(FoundCar){
+ HighestCar = max(HighestCar, height);
+ }else{
+ FoundCar = true;
+ HighestCar = height;
+ }
+ if(((CVehicle*)vehicle)->IsTrain())
+ m_bTheHeightFixerVehicleIsATrain = true;
+ }
+
+ if(FoundCar){
+ m_fDimensionOfHighestNearCar = HighestCar + 0.1f;
+ if(Mode == MODE_FIGHT_CAM)
+ m_fDimensionOfHighestNearCar += 0.75f;
+ }else
+ m_fDimensionOfHighestNearCar = 0.0f;
+ }
+
+ // Move up for road
+ if(Mode == MODE_FOLLOWPED || Mode == MODE_FIGHT_CAM ||
+ Mode == MODE_SYPHON || Mode == MODE_SYPHON_CRIM_IN_FRONT || Mode == MODE_SPECIAL_FIXED_FOR_SYPHON){
+ bool Inside = false;
+ bool OnRoad = false;
+
+ switch(((CPhysical*)CamTargetEntity)->m_nSurfaceTouched)
+ case SURFACE_GRASS:
+ case SURFACE_DIRT:
+ case SURFACE_DIRTTRACK:
+ case SURFACE_STEEL:
+ case SURFACE_TIRE:
+ case SURFACE_STONE:
+ OnRoad = true;
+
+ if(CCullZones::PlayerNoRain())
+ Inside = true;
+
+ if((m_bCollisionChecksOn || PreviouslyFailedRoadHeightCheck || OnRoad) &&
+ m_fCloseInPedHeightOffset < 0.0001f && !Inside){
+ CVector TestPoint;
+ CEntity *road;
+ float GroundZ = 0.0f;
+ bool FoundGround = false;
+ float RoofZ = 0.0f;
+ bool FoundRoof = false;
+ static float MinHeightAboveRoad = 0.9f;
+
+ TestPoint = CamTargetEntity->GetPosition() - DistOnGround * CVector(Cos(BetaAngle), Sin(BetaAngle), 0.0f);
+ m_fRoadOffSet = 0.0f;
+
+ if(CWorld::ProcessVerticalLine(TestPoint, -1000.0f, colPoint, road, true, false, false, false, false, false, nil)){
+ FoundGround = true;
+ GroundZ = colPoint.point.z;
+ }
+ // Move up if too close to ground
+ if(FoundGround){
+ if(TestPoint.z - GroundZ < MinHeightAboveRoad){
+ m_fRoadOffSet = GroundZ + MinHeightAboveRoad - TestPoint.z;
+ PreviouslyFailedRoadHeightCheck = true;
+ }else{
+ if(m_bCollisionChecksOn)
+ PreviouslyFailedRoadHeightCheck = false;
+ else
+ m_fRoadOffSet = 0.0f;
+ }
+ }else{
+ if(CWorld::ProcessVerticalLine(TestPoint, 1000.0f, colPoint, road, true, false, false, false, false, false, nil)){
+ FoundRoof = true;
+ RoofZ = colPoint.point.z;
+ }
+ if(FoundRoof){
+ if(TestPoint.z - RoofZ < MinHeightAboveRoad){
+ m_fRoadOffSet = RoofZ + MinHeightAboveRoad - TestPoint.z;
+ PreviouslyFailedRoadHeightCheck = true;
+ }else{
+ if(m_bCollisionChecksOn)
+ PreviouslyFailedRoadHeightCheck = false;
+ else
+ m_fRoadOffSet = 0.0f;
+ }
+ }
+ }
+ }
+ }
+
+ if(PreviouslyFailedRoadHeightCheck && m_fCloseInPedHeightOffset < 0.0001f){
+ if(colPoint.surfaceB != SURFACE_TARMAC &&
+ colPoint.surfaceB != SURFACE_GRASS &&
+ colPoint.surfaceB != SURFACE_DIRT &&
+ colPoint.surfaceB != SURFACE_DIRTTRACK &&
+ colPoint.surfaceB != SURFACE_STONE){
+ if(m_fRoadOffSet > 1.4f)
+ m_fRoadOffSet = 1.4f;
+ }else{
+ if(Mode == MODE_FOLLOWPED){
+ if(TheCamera.PedZoomIndicator == CAM_ZOOM_1)
+ m_fRoadOffSet += 0.2f;
+ if(TheCamera.PedZoomIndicator == CAM_ZOOM_2)
+ m_fRoadOffSet += 0.5f;
+ if(TheCamera.PedZoomIndicator == CAM_ZOOM_3)
+ m_fRoadOffSet += 0.95f;
+ }
+ }
+ }
+ }
+
+ if(StandingOnBoat){
+ m_fRoadOffSet = 0.0f;
+ m_fDimensionOfHighestNearCar = 1.0f;
+ m_fPedBetweenCameraHeightOffset = 0.0f;
+ }
+}
+
+void
+CCam::GetVectorsReadyForRW(void)
+{
+ CVector right;
+ Up = CVector(0.0f, 0.0f, 1.0f);
+ Front.Normalise();
+ if(Front.x == 0.0f && Front.y == 0.0f){
+ Front.x = 0.0001f;
+ Front.y = 0.0001f;
+ }
+ right = CrossProduct(Front, Up);
+ right.Normalise();
+ Up = CrossProduct(right, Front);
+}
+
+void
+CCam::LookBehind(void)
+{
+ float Dist, DeltaBeta, TargetOrientation, Angle;
+ CVector TargetCoors, TargetFwd, TestCoors;
+ CColPoint colPoint;
+ CEntity *entity;
+
+ TargetCoors = CamTargetEntity->GetPosition();
+ Front = CamTargetEntity->GetPosition() - Source;
+
+ if((Mode == MODE_CAM_ON_A_STRING || Mode == MODE_BEHINDBOAT) && CamTargetEntity->IsVehicle()){
+ LookingBehind = true;
+ Dist = Mode == MODE_CAM_ON_A_STRING ? CA_MAX_DISTANCE : 15.5f;
+ TargetFwd = CamTargetEntity->GetForward();
+ TargetFwd.Normalise();
+ TargetOrientation = CGeneral::GetATanOfXY(TargetFwd.x, TargetFwd.y);
+ DeltaBeta = TargetOrientation - Beta;
+ while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
+ while(DeltaBeta < -PI) DeltaBeta += 2*PI;
+ if(DirectionWasLooking != LOOKING_BEHIND)
+ LookBehindCamWasInFront = DeltaBeta <= -HALFPI || DeltaBeta >= HALFPI;
+ if(LookBehindCamWasInFront)
+ TargetOrientation += PI;
+ Source.x = Dist*Cos(TargetOrientation) + TargetCoors.x;
+ Source.y = Dist*Sin(TargetOrientation) + TargetCoors.y;
+ Source.z -= 1.0f;
+ if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, true, false, false, true, false, true, true)){
+ RwCameraSetNearClipPlane(Scene.camera, DEFAULT_NEAR);
+ Source = colPoint.point;
+ }
+ Source.z += 1.0f;
+ Front = CamTargetEntity->GetPosition() - Source;
+ GetVectorsReadyForRW();
+ }
+ if(Mode == MODE_1STPERSON && CamTargetEntity->IsVehicle()){
+ LookingBehind = true;
+ RwCameraSetNearClipPlane(Scene.camera, 0.25f);
+ Front = CamTargetEntity->GetForward();
+ Front.Normalise();
+ if(((CVehicle*)CamTargetEntity)->IsBoat())
+ Source.z -= 0.5f;
+ Source += 0.25f*Front;
+ Front = -Front;
+#ifdef FIX_BUGS
+ // not sure if this is a bug...
+ GetVectorsReadyForRW();
+#endif
+ }
+ if(CamTargetEntity->IsPed()){
+ Angle = CGeneral::GetATanOfXY(Source.x - TargetCoors.x, Source.y - TargetCoors.y) + PI;
+ Source.x = 4.5f*Cos(Angle) + TargetCoors.x;
+ Source.y = 4.5f*Sin(Angle) + TargetCoors.y;
+ Source.z = 1.15f + TargetCoors.z;
+ TestCoors = TargetCoors;
+ TestCoors.z = Source.z;
+ if(CWorld::ProcessLineOfSight(TestCoors, Source, colPoint, entity, true, true, false, true, false, true, true)){
+ Source.x = colPoint.point.x;
+ Source.y = colPoint.point.y;
+ if((TargetCoors - Source).Magnitude2D() < 1.15f)
+ RwCameraSetNearClipPlane(Scene.camera, 0.05f);
+ }
+ Front = TargetCoors - Source;
+ GetVectorsReadyForRW();
+ }
+}
+
+void
+CCam::LookLeft(void)
+{
+ float Dist, TargetOrientation;
+ CVector TargetCoors, TargetFwd;
+ CColPoint colPoint;
+ CEntity *entity;
+
+ if((Mode == MODE_CAM_ON_A_STRING || Mode == MODE_BEHINDBOAT) && CamTargetEntity->IsVehicle()){
+ LookingLeft = true;
+ TargetCoors = CamTargetEntity->GetPosition();
+ Front = CamTargetEntity->GetPosition() - Source;
+ Dist = Mode == MODE_CAM_ON_A_STRING ? CA_MAX_DISTANCE : 9.0f;
+ TargetFwd = CamTargetEntity->GetForward();
+ TargetFwd.Normalise();
+ TargetOrientation = CGeneral::GetATanOfXY(TargetFwd.x, TargetFwd.y);
+ Source.x = Dist*Cos(TargetOrientation - HALFPI) + TargetCoors.x;
+ Source.y = Dist*Sin(TargetOrientation - HALFPI) + TargetCoors.y;
+ Source.z -= 1.0f;
+ if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, true, false, false, true, false, true, true)){
+ RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+ Source = colPoint.point;
+ }
+ Source.z += 1.0f;
+ Front = CamTargetEntity->GetPosition() - Source;
+ Front.z += 1.1f;
+ if(Mode == MODE_BEHINDBOAT)
+ Front.z += 1.2f;
+ GetVectorsReadyForRW();
+ }
+ if(Mode == MODE_1STPERSON && CamTargetEntity->IsVehicle()){
+ LookingLeft = true;
+ RwCameraSetNearClipPlane(Scene.camera, 0.25f);
+ if(((CVehicle*)CamTargetEntity)->IsBoat())
+ Source.z -= 0.5f;
+
+ Up = CamTargetEntity->GetUp();
+ Up.Normalise();
+ Front = CamTargetEntity->GetForward();
+ Front.Normalise();
+ Front = -CrossProduct(Front, Up);
+ Front.Normalise();
+#ifdef FIX_BUGS
+ // not sure if this is a bug...
+ GetVectorsReadyForRW();
+#endif
+ }
+}
+
+void
+CCam::LookRight(void)
+{
+ float Dist, TargetOrientation;
+ CVector TargetCoors, TargetFwd;
+ CColPoint colPoint;
+ CEntity *entity;
+
+ if((Mode == MODE_CAM_ON_A_STRING || Mode == MODE_BEHINDBOAT) && CamTargetEntity->IsVehicle()){
+ LookingRight = true;
+ TargetCoors = CamTargetEntity->GetPosition();
+ Front = CamTargetEntity->GetPosition() - Source;
+ Dist = Mode == MODE_CAM_ON_A_STRING ? CA_MAX_DISTANCE : 9.0f;
+ TargetFwd = CamTargetEntity->GetForward();
+ TargetFwd.Normalise();
+ TargetOrientation = CGeneral::GetATanOfXY(TargetFwd.x, TargetFwd.y);
+ Source.x = Dist*Cos(TargetOrientation + HALFPI) + TargetCoors.x;
+ Source.y = Dist*Sin(TargetOrientation + HALFPI) + TargetCoors.y;
+ Source.z -= 1.0f;
+ if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, true, false, false, true, false, true, true)){
+ RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+ Source = colPoint.point;
+ }
+ Source.z += 1.0f;
+ Front = CamTargetEntity->GetPosition() - Source;
+ Front.z += 1.1f;
+ if(Mode == MODE_BEHINDBOAT)
+ Front.z += 1.2f;
+ GetVectorsReadyForRW();
+ }
+ if(Mode == MODE_1STPERSON && CamTargetEntity->IsVehicle()){
+ LookingRight = true;
+ RwCameraSetNearClipPlane(Scene.camera, 0.25f);
+ if(((CVehicle*)CamTargetEntity)->IsBoat())
+ Source.z -= 0.5f;
+
+ Up = CamTargetEntity->GetUp();
+ Up.Normalise();
+ Front = CamTargetEntity->GetForward();
+ Front.Normalise();
+ Front = CrossProduct(Front, Up);
+ Front.Normalise();
+#ifdef FIX_BUGS
+ // not sure if this is a bug...
+ GetVectorsReadyForRW();
+#endif
+ }
+}
+
+void
+CCam::ClipIfPedInFrontOfPlayer(void)
+{
+ float FwdAngle, PedAngle, DeltaAngle, fDist, Near;
+ CVector vDist;
+ CPed *Player;
+ bool found = false;
+ int ped = 0;
+
+ // unused: TheCamera.pTargetEntity->GetPosition() - TheCamera.GetGameCamPosition();
+
+ FwdAngle = CGeneral::GetATanOfXY(TheCamera.GetForward().x, TheCamera.GetForward().y);
+ Player = CWorld::Players[CWorld::PlayerInFocus].m_pPed;
+ while(ped < Player->m_numNearPeds && !found)
+ if(Player->m_nearPeds[ped] && Player->m_nearPeds[ped]->GetPedState() != PED_DEAD)
+ found = true;
+ else
+ ped++;
+ if(found){
+ vDist = Player->m_nearPeds[ped]->GetPosition() - TheCamera.GetGameCamPosition();
+ PedAngle = CGeneral::GetATanOfXY(vDist.x, vDist.y);
+ DeltaAngle = FwdAngle - PedAngle;
+ while(DeltaAngle >= PI) DeltaAngle -= 2*PI;
+ while(DeltaAngle < -PI) DeltaAngle += 2*PI;
+ if(Abs(DeltaAngle) < HALFPI){
+ fDist = Sqrt(SQR(vDist.x) + SQR(vDist.y));
+ if(fDist < 1.25f){
+ Near = DEFAULT_NEAR - (1.25f - fDist);
+ if(Near < 0.05f)
+ Near = 0.05f;
+ RwCameraSetNearClipPlane(Scene.camera, Near);
+ }
+ }
+ }
+}
+
+void
+CCam::KeepTrackOfTheSpeed(const CVector &source, const CVector &target, const CVector &up, const float &alpha, const float &beta, const float &fov)
+{
+ static CVector PreviousSource = source;
+ static CVector PreviousTarget = target;
+ static CVector PreviousUp = up;
+ static float PreviousBeta = beta;
+ static float PreviousAlpha = alpha;
+ static float PreviousFov = fov;
+
+ if(TheCamera.m_bJust_Switched){
+ PreviousSource = source;
+ PreviousTarget = target;
+ PreviousUp = up;
+ }
+
+ m_cvecSourceSpeedOverOneFrame = PreviousSource - source;
+ m_cvecTargetSpeedOverOneFrame = PreviousTarget - target;
+ m_cvecUpOverOneFrame = PreviousUp - up;
+ m_fFovSpeedOverOneFrame = fov - PreviousFov;
+ m_fBetaSpeedOverOneFrame = beta - PreviousBeta;
+ MakeAngleLessThan180(m_fBetaSpeedOverOneFrame);
+ m_fAlphaSpeedOverOneFrame = alpha - PreviousAlpha;
+ MakeAngleLessThan180(m_fAlphaSpeedOverOneFrame);
+
+ PreviousSource = source;
+ PreviousTarget = target;
+ PreviousUp = up;
+ PreviousBeta = beta;
+ PreviousAlpha = alpha;
+ PreviousFov = fov;
+}
+
+bool
+CCam::Using3rdPersonMouseCam(void)
+{
+ return CCamera::m_bUseMouse3rdPerson &&
+ (Mode == MODE_FOLLOWPED ||
+ TheCamera.m_bPlayerIsInGarage &&
+ FindPlayerPed() && FindPlayerPed()->m_nPedState != PED_DRIVING &&
+ Mode != MODE_TOPDOWN && this->CamTargetEntity == FindPlayerPed());
+}
+
+bool
+CCam::GetWeaponFirstPersonOn(void)
+{
+ CEntity *target = this->CamTargetEntity;
+ if (target && target->IsPed())
+ return ((CPed*)target)->GetWeapon()->m_bAddRotOffset;
+
+ return false;
+}
+
+bool
+CCam::IsTargetInWater(const CVector &CamCoors)
+{
+ if(CamTargetEntity == nil)
+ return false;
+ if(CamTargetEntity->IsPed()){
+ if(!((CPed*)CamTargetEntity)->bIsInWater)
+ return false;
+ if(!((CPed*)CamTargetEntity)->bIsStanding)
+ return true;
+ return false;
+ }
+ return ((CPhysical*)CamTargetEntity)->bIsInWater;
+}
+
+void
+CCam::PrintMode(void)
+{
+ // Doesn't do anything
+ char buf[256];
+
+ if(PrintDebugCode){
+ sprintf(buf, " ");
+ sprintf(buf, " ");
+ sprintf(buf, " ");
+
+ static char *modes[] = { "None",
+ "Top Down", "GTA Classic", "Behind Car", "Follow Ped",
+ "Aiming", "Debug", "Sniper", "Rocket", "Model Viewer", "Bill",
+ "Syphon", "Circle", "Cheesy Zoom", "Wheel", "Fixed",
+ "1st Person", "Fly by", "on a String", "Reaction",
+ "Follow Ped with Bind", "Chris", "Behind Boat",
+ "Player fallen in Water", "Train Roof", "Train Side",
+ "Blood on the tracks", "Passenger", "Syphon Crim in Front",
+ "Dead Baby", "Pillow Paps", "Look at Cars", "Arrest One",
+ "Arrest Two", "M16", "Special fixed for Syphon", "Fight",
+ "Top Down Ped",
+ "Sniper run about", "Rocket run about",
+ "1st Person run about", "M16 run about", "Fight run about",
+ "Editor"
+ };
+ sprintf(buf, "Cam: %s", modes[TheCamera.Cams[TheCamera.ActiveCam].Mode]);
+ CDebug::PrintAt(buf, 2, 5);
+ }
+
+ if(DebugCamMode != MODE_NONE){
+ switch(Mode){
+ case MODE_FOLLOWPED:
+ sprintf(buf, "Debug:- Cam Choice1. No Locking, used as game default");
+ break;
+ case MODE_REACTION:
+ sprintf(buf, "Debug:- Cam Choice2. Reaction Cam On A String ");
+ sprintf(buf, " Uses Locking Button LeftShoulder 1. "); // lie
+ break;
+ case MODE_FOLLOW_PED_WITH_BIND:
+ sprintf(buf, "Debug:- Cam Choice3. Game ReactionCam with Locking ");
+ sprintf(buf, " Uses Locking Button LeftShoulder 1. ");
+ break;
+ case MODE_CHRIS:
+ sprintf(buf, "Debug:- Cam Choice4. Chris's idea. ");
+ sprintf(buf, " Uses Locking Button LeftShoulder 1. ");
+ sprintf(buf, " Also control the camera using the right analogue stick.");
+ break;
+ }
+ }
+}
+
+// This code is really bad. wtf R*?
+CVector
+CCam::DoAverageOnVector(const CVector &vec)
+{
+ int i;
+ CVector Average = { 0.0f, 0.0f, 0.0f };
+
+ if(ResetStatics){
+ m_iRunningVectorArrayPos = 0;
+ m_iRunningVectorCounter = 1;
+ }
+
+ // TODO: make this work with NUMBER_OF_VECTORS_FOR_AVERAGE != 2
+ if(m_iRunningVectorCounter == 3){
+ m_arrPreviousVectors[0] = m_arrPreviousVectors[1];
+ m_arrPreviousVectors[1] = vec;
+ }else
+ m_arrPreviousVectors[m_iRunningVectorArrayPos] = vec;
+
+ for(i = 0; i <= m_iRunningVectorArrayPos; i++)
+ Average += m_arrPreviousVectors[i];
+ Average /= i;
+
+ m_iRunningVectorArrayPos++;
+ m_iRunningVectorCounter++;
+ if(m_iRunningVectorArrayPos >= NUMBER_OF_VECTORS_FOR_AVERAGE)
+ m_iRunningVectorArrayPos = NUMBER_OF_VECTORS_FOR_AVERAGE-1;
+ if(m_iRunningVectorCounter > NUMBER_OF_VECTORS_FOR_AVERAGE+1)
+ m_iRunningVectorCounter = NUMBER_OF_VECTORS_FOR_AVERAGE+1;
+
+ return Average;
+}
+
+// Rotate Beta in direction opposite of BetaOffset in 5 deg. steps.
+// Return the first angle for which Beta + BetaOffset + Angle has a clear view.
+// i.e. BetaOffset is a safe zone so that Beta + Angle is really clear.
+// If BetaOffset == 0, try both directions.
+float
+CCam::GetPedBetaAngleForClearView(const CVector &Target, float Dist, float BetaOffset, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies)
+{
+ CColPoint point;
+ CEntity *ent = nil;
+ CVector ToSource;
+ float a;
+
+ // This would be so much nicer if we just got the step variable before the loop...R*
+
+ for(a = 0.0f; a <= PI; a += DEGTORAD(5.0f)){
+ if(BetaOffset <= 0.0f){
+ ToSource = CVector(Cos(Beta + BetaOffset + a), Sin(Beta + BetaOffset + a), 0.0f)*Dist;
+ if(!CWorld::ProcessLineOfSight(Target, Target + ToSource,
+ point, ent, checkBuildings, checkVehicles, checkPeds,
+ checkObjects, checkDummies, true, true))
+ return a;
+ }
+ if(BetaOffset >= 0.0f){
+ ToSource = CVector(Cos(Beta + BetaOffset - a), Sin(Beta + BetaOffset - a), 0.0f)*Dist;
+ if(!CWorld::ProcessLineOfSight(Target, Target + ToSource,
+ point, ent, checkBuildings, checkVehicles, checkPeds,
+ checkObjects, checkDummies, true, true))
+ return -a;
+ }
+ }
+ return 0.0f;
+}
+
+static float DefaultAcceleration = 0.045f;
+static float DefaultMaxStep = 0.15f;
+
+void
+CCam::Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+ const float GroundDist = 1.85f;
+
+ CVector TargetCoors, Dist, IdealSource;
+ float Length = 0.0f;
+ float LateralLeft = 0.0f;
+ float LateralRight = 0.0f;
+ float Center = 0.0f;
+ static bool PreviouslyObscured;
+ static bool PickedASide;
+ static float FixedTargetOrientation = 0.0f;
+ float AngleToGoTo = 0.0f;
+ float BetaOffsetAvoidBuildings = 0.45f; // ~25 deg
+ float BetaOffsetGoingBehind = 0.45f;
+ bool GoingBehind = false;
+ bool Obscured = false;
+ bool BuildingCheckObscured = false;
+ bool HackPlayerOnStoppingTrain = false;
+ static int TimeIndicatedWantedToGoDown = 0;
+ static bool StartedCountingForGoDown = false;
+ float DeltaBeta;
+
+ m_bFixingBeta = false;
+ bBelowMinDist = false;
+ bBehindPlayerDesired = false;
+
+#ifdef FIX_BUGS
+ if(!CamTargetEntity->IsPed())
+ return;
+#endif
+ assert(CamTargetEntity->IsPed());
+
+ // CenterDist should be > LateralDist because we don't have an angle for safety in this case
+ float CenterDist, LateralDist;
+ float AngleToGoToSpeed;
+ if(m_fCloseInPedHeightOffset > 0.00001f){
+ LateralDist = 0.55f;
+ CenterDist = 1.25f;
+ BetaOffsetAvoidBuildings = 0.9f; // ~50 deg
+ BetaOffsetGoingBehind = 0.9f;
+ AngleToGoToSpeed = 0.88254666f;
+ }else{
+ LateralDist = 0.8f;
+ CenterDist = 1.35f;
+ if(TheCamera.PedZoomIndicator == CAM_ZOOM_1 || TheCamera.PedZoomIndicator == CAM_ZOOM_TOPDOWN){
+ LateralDist = 1.25f;
+ CenterDist = 1.6f;
+ }
+ AngleToGoToSpeed = 0.43254671f;
+ }
+
+ FOV = DefaultFOV;
+
+ if(ResetStatics){
+ Rotating = false;
+ m_bCollisionChecksOn = true;
+ FixedTargetOrientation = 0.0f;
+ PreviouslyObscured = false;
+ PickedASide = false;
+ StartedCountingForGoDown = false;
+ AngleToGoTo = 0.0f;
+ // unused LastAngleWithNoPickedASide
+ }
+
+
+ TargetCoors = CameraTarget;
+ IdealSource = Source;
+ TargetCoors.z += m_fSyphonModeTargetZOffSet;
+
+ TargetCoors = DoAverageOnVector(TargetCoors);
+ TargetCoors.z += m_fRoadOffSet;
+
+ Dist.x = IdealSource.x - TargetCoors.x;
+ Dist.y = IdealSource.y - TargetCoors.y;
+ Length = Dist.Magnitude2D();
+
+ // Cam on a string. With a fixed distance. Zoom in/out is done later.
+ if(Length != 0.0f)
+ IdealSource = TargetCoors + CVector(Dist.x, Dist.y, 0.0f)/Length * GroundDist;
+ else
+ IdealSource = TargetCoors + CVector(1.0f, 1.0f, 0.0f);
+
+ if(TheCamera.m_bUseTransitionBeta && ResetStatics){
+ CVector VecDistance;
+ IdealSource.x = TargetCoors.x + GroundDist*Cos(m_fTransitionBeta);
+ IdealSource.y = TargetCoors.y + GroundDist*Sin(m_fTransitionBeta);
+ Beta = CGeneral::GetATanOfXY(IdealSource.x - TargetCoors.x, IdealSource.y - TargetCoors.y);
+ }else
+ Beta = CGeneral::GetATanOfXY(Source.x - TargetCoors.x, Source.y - TargetCoors.y);
+
+ if(TheCamera.m_bCamDirectlyBehind){
+ m_bCollisionChecksOn = true;
+ Beta = TargetOrientation + PI;
+ }
+
+ if(FindPlayerVehicle())
+ if(FindPlayerVehicle()->m_vehType == VEHICLE_TYPE_TRAIN)
+ HackPlayerOnStoppingTrain = true;
+
+ if(TheCamera.m_bCamDirectlyInFront){
+ m_bCollisionChecksOn = true;
+ Beta = TargetOrientation;
+ }
+
+ while(Beta >= PI) Beta -= 2.0f * PI;
+ while(Beta < -PI) Beta += 2.0f * PI;
+
+ // BUG? is this ever used?
+ // The values seem to be roughly m_fPedZoomValueSmooth + 1.85
+ if(ResetStatics){
+ if(TheCamera.PedZoomIndicator == CAM_ZOOM_1) m_fRealGroundDist = 2.090556f;
+ if(TheCamera.PedZoomIndicator == CAM_ZOOM_2) m_fRealGroundDist = 3.34973f;
+ if(TheCamera.PedZoomIndicator == CAM_ZOOM_3) m_fRealGroundDist = 4.704914f;
+ if(TheCamera.PedZoomIndicator == CAM_ZOOM_TOPDOWN) m_fRealGroundDist = 2.090556f;
+ }
+ // And what is this? It's only used for collision and rotation it seems
+ float RealGroundDist;
+ if(TheCamera.PedZoomIndicator == CAM_ZOOM_1) RealGroundDist = 2.090556f;
+ if(TheCamera.PedZoomIndicator == CAM_ZOOM_2) RealGroundDist = 3.34973f;
+ if(TheCamera.PedZoomIndicator == CAM_ZOOM_3) RealGroundDist = 4.704914f;
+ if(TheCamera.PedZoomIndicator == CAM_ZOOM_TOPDOWN) RealGroundDist = 2.090556f;
+ if(m_fCloseInPedHeightOffset > 0.00001f)
+ RealGroundDist = 1.7016f;
+
+
+ bool Shooting = false;
+ CPed *ped = (CPed*)CamTargetEntity;
+ if(ped->GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED)
+ if(CPad::GetPad(0)->GetWeapon())
+ Shooting = true;
+ if(ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_DETONATOR ||
+ ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT)
+ Shooting = false;
+
+
+ if(m_fCloseInPedHeightOffset > 0.00001f)
+ TargetCoors.z -= m_fRoadOffSet;
+
+ // Figure out if and where we want to rotate
+
+ if(CPad::GetPad(0)->ForceCameraBehindPlayer() || Shooting){
+
+ // Center cam behind player
+
+ GoingBehind = true;
+ m_bCollisionChecksOn = true;
+ float OriginalBeta = Beta;
+ // Set Beta behind player
+ Beta = TargetOrientation + PI;
+ TargetCoors.z -= 0.1f;
+
+ AngleToGoTo = GetPedBetaAngleForClearView(TargetCoors, CenterDist * RealGroundDist, 0.0f, true, false, false, true, false);
+ if(AngleToGoTo != 0.0f){
+ if(AngleToGoTo < 0.0f)
+ AngleToGoTo -= AngleToGoToSpeed;
+ else
+ AngleToGoTo += AngleToGoToSpeed;
+ }else{
+ float LateralLeft = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, BetaOffsetGoingBehind, true, false, false, true, false);
+ float LateralRight = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, -BetaOffsetGoingBehind, true, false, false, true, false);
+ if(LateralLeft == 0.0f && LateralRight != 0.0f)
+ AngleToGoTo += LateralRight;
+ else if(LateralLeft != 0.0f && LateralRight == 0.0f)
+ AngleToGoTo += LateralLeft;
+ }
+
+ TargetCoors.z += 0.1f;
+ Beta = OriginalBeta;
+
+ if(PickedASide){
+ if(AngleToGoTo == 0.0f)
+ FixedTargetOrientation = TargetOrientation + PI;
+ Rotating = true;
+ }else{
+ FixedTargetOrientation = TargetOrientation + PI + AngleToGoTo;
+ Rotating = true;
+ PickedASide = true;
+ }
+ }else{
+
+ // Rotate cam to avoid clipping into buildings
+
+ TargetCoors.z -= 0.1f;
+
+ Center = GetPedBetaAngleForClearView(TargetCoors, CenterDist * RealGroundDist, 0.0f, true, false, false, true, false);
+ if(m_bCollisionChecksOn || PreviouslyObscured || Center != 0.0f || m_fCloseInPedHeightOffset > 0.00001f){
+ if(Center != 0.0f){
+ AngleToGoTo = Center;
+ }else{
+ LateralLeft = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, BetaOffsetAvoidBuildings, true, false, false, true, false);
+ LateralRight = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, -BetaOffsetAvoidBuildings, true, false, false, true, false);
+ if(LateralLeft == 0.0f && LateralRight != 0.0f){
+ AngleToGoTo += LateralRight;
+ if(m_fCloseInPedHeightOffset > 0.0f)
+ RwCameraSetNearClipPlane(Scene.camera, 0.7f);
+ }else if(LateralLeft != 0.0f && LateralRight == 0.0f){
+ AngleToGoTo += LateralLeft;
+ if(m_fCloseInPedHeightOffset > 0.0f)
+ RwCameraSetNearClipPlane(Scene.camera, 0.7f);
+ }
+ }
+ if(LateralLeft != 0.0f || LateralRight != 0.0f || Center != 0.0f)
+ BuildingCheckObscured = true;
+ }
+
+ TargetCoors.z += 0.1f;
+ }
+
+ if(m_fCloseInPedHeightOffset > 0.00001f)
+ TargetCoors.z += m_fRoadOffSet;
+
+
+ // Have to fix to avoid collision
+
+ if(AngleToGoTo != 0.0f){
+ Obscured = true;
+ Rotating = true;
+ if(CPad::GetPad(0)->ForceCameraBehindPlayer() || Shooting){
+ if(!PickedASide)
+ FixedTargetOrientation = Beta + AngleToGoTo; // can this even happen?
+ }else
+ FixedTargetOrientation = Beta + AngleToGoTo;
+
+ // This calculation is only really used to figure out how fast to rotate out of collision
+
+ m_fAmountFractionObscured = 1.0f;
+ CVector PlayerPos = FindPlayerPed()->GetPosition();
+ float RotationDist = (AngleToGoTo == Center ? CenterDist : LateralDist) * RealGroundDist;
+ // What's going on here? - AngleToGoTo?
+ CVector RotatedSource = PlayerPos + CVector(Cos(Beta - AngleToGoTo), Sin(Beta - AngleToGoTo), 0.0f) * RotationDist;
+
+ CColPoint colpoint;
+ CEntity *entity;
+ if(CWorld::ProcessLineOfSight(PlayerPos, RotatedSource, colpoint, entity, true, false, false, true, false, false, false)){
+ if((PlayerPos - RotatedSource).Magnitude() != 0.0f)
+ m_fAmountFractionObscured = (PlayerPos - colpoint.point).Magnitude() / (PlayerPos - RotatedSource).Magnitude();
+ else
+ m_fAmountFractionObscured = 1.0f;
+ }
+ }
+ if(m_fAmountFractionObscured < 0.0f) m_fAmountFractionObscured = 0.0f;
+ if(m_fAmountFractionObscured > 1.0f) m_fAmountFractionObscured = 1.0f;
+
+
+
+ // Figure out speed values for Beta rotation
+
+ float Acceleration, MaxSpeed;
+ static float AccelerationMult = 0.35f;
+ static float MaxSpeedMult = 0.85f;
+ static float AccelerationMultClose = 0.7f;
+ static float MaxSpeedMultClose = 1.6f;
+ float BaseAcceleration = 0.025f;
+ float BaseMaxSpeed = 0.09f;
+ if(m_fCloseInPedHeightOffset > 0.00001f){
+ if(AngleToGoTo == 0.0f){
+ BaseAcceleration = 0.022f;
+ BaseMaxSpeed = 0.04f;
+ }else{
+ BaseAcceleration = DefaultAcceleration;
+ BaseMaxSpeed = DefaultMaxStep;
+ }
+ }
+ if(AngleToGoTo == 0.0f){
+ Acceleration = BaseAcceleration;
+ MaxSpeed = BaseMaxSpeed;
+ }else if(CPad::GetPad(0)->ForceCameraBehindPlayer() && !Shooting){
+ Acceleration = 0.051f;
+ MaxSpeed = 0.18f;
+ }else if(m_fCloseInPedHeightOffset > 0.00001f){
+ Acceleration = BaseAcceleration + AccelerationMultClose*sq(m_fAmountFractionObscured - 1.05f);
+ MaxSpeed = BaseMaxSpeed + MaxSpeedMultClose*sq(m_fAmountFractionObscured - 1.05f);
+ }else{
+ Acceleration = DefaultAcceleration + AccelerationMult*sq(m_fAmountFractionObscured - 1.05f);
+ MaxSpeed = DefaultMaxStep + MaxSpeedMult*sq(m_fAmountFractionObscured - 1.05f);
+ }
+ static float AccelerationLimit = 0.3f;
+ static float MaxSpeedLimit = 0.65f;
+ if(Acceleration > AccelerationLimit) Acceleration = AccelerationLimit;
+ if(MaxSpeed > MaxSpeedLimit) MaxSpeed = MaxSpeedLimit;
+
+
+ int MoveState = ((CPed*)CamTargetEntity)->m_nMoveState;
+ if(MoveState != PEDMOVE_NONE && MoveState != PEDMOVE_STILL &&
+ !CPad::GetPad(0)->ForceCameraBehindPlayer() && !Obscured && !Shooting){
+ Rotating = false;
+ BetaSpeed = 0.0f;
+ }
+
+ // Now do the Beta rotation
+
+ float RotDistance = (IdealSource - TargetCoors).Magnitude2D();
+ m_fDistanceBeforeChanges = RotDistance;
+
+ if(Rotating){
+ m_bFixingBeta = true;
+
+ while(FixedTargetOrientation >= PI) FixedTargetOrientation -= 2*PI;
+ while(FixedTargetOrientation < -PI) FixedTargetOrientation += 2*PI;
+
+ while(Beta >= PI) Beta -= 2*PI;
+ while(Beta < -PI) Beta += 2*PI;
+
+
+/*
+ // This is inlined WellBufferMe
+ DeltaBeta = FixedTargetOrientation - Beta;
+ while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
+ while(DeltaBeta < -PI) DeltaBeta += 2*PI;
+
+ float ReqSpeed = DeltaBeta * MaxSpeed;
+ // Add or subtract absolute depending on sign, genius!
+ if(ReqSpeed - BetaSpeed > 0.0f)
+ BetaSpeed += SpeedStep * Abs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep();
+ else
+ BetaSpeed -= SpeedStep * Abs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep();
+ // this would be simpler:
+ // BetaSpeed += SpeedStep * (ReqSpeed - BetaSpeed) * CTimer::ms_fTimeStep;
+
+ if(ReqSpeed < 0.0f && BetaSpeed < ReqSpeed)
+ BetaSpeed = ReqSpeed;
+ else if(ReqSpeed > 0.0f && BetaSpeed > ReqSpeed)
+ BetaSpeed = ReqSpeed;
+
+ Beta += BetaSpeed * min(10.0f, CTimer::GetTimeStep());
+*/
+ WellBufferMe(FixedTargetOrientation, &Beta, &BetaSpeed, MaxSpeed, Acceleration, true);
+
+ if(ResetStatics){
+ Beta = FixedTargetOrientation;
+ BetaSpeed = 0.0f;
+ }
+
+ Source.x = TargetCoors.x + RotDistance * Cos(Beta);
+ Source.y = TargetCoors.y + RotDistance * Sin(Beta);
+
+ // Check if we can stop rotating
+ DeltaBeta = FixedTargetOrientation - Beta;
+ while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
+ while(DeltaBeta < -PI) DeltaBeta += 2*PI;
+ if(Abs(DeltaBeta) < DEGTORAD(1.0f) && !bBehindPlayerDesired){
+ // Stop rotation
+ PickedASide = false;
+ Rotating = false;
+ BetaSpeed = 0.0f;
+ }
+ }
+
+
+ if(TheCamera.m_bCamDirectlyBehind || TheCamera.m_bCamDirectlyInFront ||
+ HackPlayerOnStoppingTrain || Rotating){
+ if(TheCamera.m_bCamDirectlyBehind){
+ Beta = TargetOrientation + PI;
+ Source.x = TargetCoors.x + RotDistance * Cos(Beta);
+ Source.y = TargetCoors.y + RotDistance * Sin(Beta);
+ }
+ if(TheCamera.m_bCamDirectlyInFront){
+ Beta = TargetOrientation;
+ Source.x = TargetCoors.x + RotDistance * Cos(Beta);
+ Source.y = TargetCoors.y + RotDistance * Sin(Beta);
+ }
+ if(HackPlayerOnStoppingTrain){
+ Beta = TargetOrientation + PI;
+ Source.x = TargetCoors.x + RotDistance * Cos(Beta);
+ Source.y = TargetCoors.y + RotDistance * Sin(Beta);
+ m_fDimensionOfHighestNearCar = 0.0f;
+ m_fCamBufferedHeight = 0.0f;
+ m_fCamBufferedHeightSpeed = 0.0f;
+ }
+ // Beta and Source already set in the rotation code
+ }else{
+ Source = IdealSource;
+ BetaSpeed = 0.0f;
+ }
+
+ // Subtract m_fRoadOffSet from both?
+ TargetCoors.z -= m_fRoadOffSet;
+ Source.z = IdealSource.z - m_fRoadOffSet;
+
+ // Apply zoom now
+ // m_fPedZoomValueSmooth makes the cam go down the further out it is
+ // 0.25 -> 0.20 for nearest dist
+ // 1.50 -> -0.05 for mid dist
+ // 2.90 -> -0.33 for far dist
+ Source.z += (2.5f - TheCamera.m_fPedZoomValueSmooth)*0.2f - 0.25f;
+ // Zoom out camera
+ Front = TargetCoors - Source;
+ Front.Normalise();
+ Source -= Front * TheCamera.m_fPedZoomValueSmooth;
+ // and then we move up again
+ // -0.375
+ // 0.25
+ // 0.95
+ Source.z += (TheCamera.m_fPedZoomValueSmooth - 1.0f)*0.5f + m_fCloseInPedHeightOffset;
+
+
+ // Process height offset to avoid peds and cars
+
+ float TargetZOffSet = m_fRoadOffSet + m_fDimensionOfHighestNearCar;
+ TargetZOffSet = max(TargetZOffSet, m_fPedBetweenCameraHeightOffset);
+ float TargetHeight = CameraTarget.z + TargetZOffSet - Source.z;
+
+ if(TargetHeight > m_fCamBufferedHeight){
+ // Have to go up
+ if(TargetZOffSet == m_fPedBetweenCameraHeightOffset && TargetZOffSet > m_fCamBufferedHeight)
+ WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.04f, false);
+ else if(TargetZOffSet == m_fRoadOffSet && TargetZOffSet > m_fCamBufferedHeight){
+ // TODO: figure this out
+ bool foo = false;
+ switch(((CPhysical*)CamTargetEntity)->m_nSurfaceTouched)
+ case SURFACE_GRASS:
+ case SURFACE_DIRT:
+ case SURFACE_PAVEMENT:
+ case SURFACE_STEEL:
+ case SURFACE_TIRE:
+ case SURFACE_STONE:
+ foo = true;
+ if(foo)
+ WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.4f, 0.05f, false);
+ else
+ WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.025f, false);
+ }else
+ WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.025f, false);
+ StartedCountingForGoDown = false;
+ }else{
+ // Have to go down
+ if(StartedCountingForGoDown){
+ if(CTimer::GetTimeInMilliseconds() != TimeIndicatedWantedToGoDown){
+ if(TargetHeight > 0.0f)
+ WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.01f, false);
+ else
+ WellBufferMe(0.0f, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.01f, false);
+ }
+ }else{
+ StartedCountingForGoDown = true;
+ TimeIndicatedWantedToGoDown = CTimer::GetTimeInMilliseconds();
+ }
+ }
+
+ Source.z += m_fCamBufferedHeight;
+
+
+ // Clip Source if necessary
+
+ bool ClipSource = m_fCloseInPedHeightOffset > 0.00001f && m_fCamBufferedHeight > 0.001f;
+ if(GoingBehind || ResetStatics || ClipSource){
+ CColPoint colpoint;
+ CEntity *entity;
+ if(CWorld::ProcessLineOfSight(TargetCoors, Source, colpoint, entity, true, false, false, true, false, true, true)){
+ Source = colpoint.point;
+ if((TargetCoors - Source).Magnitude2D() < 1.0f)
+ RwCameraSetNearClipPlane(Scene.camera, 0.05f);
+ }
+ }
+
+ TargetCoors.z += min(1.0f, m_fCamBufferedHeight/2.0f);
+ m_cvecTargetCoorsForFudgeInter = TargetCoors;
+
+ Front = TargetCoors - Source;
+ m_fRealGroundDist = Front.Magnitude2D();
+ m_fMinDistAwayFromCamWhenInterPolating = m_fRealGroundDist;
+ Front.Normalise();
+ GetVectorsReadyForRW();
+ TheCamera.m_bCamDirectlyBehind = false;
+ TheCamera.m_bCamDirectlyInFront = false;
+ PreviouslyObscured = BuildingCheckObscured;
+
+ ResetStatics = false;
+}
+
+static float fBaseDist = 1.7f;
+static float fAngleDist = 2.0f;
+static float fFalloff = 3.0f;
+static float fStickSens = 0.01f;
+static float fTweakFOV = 1.05f;
+static float fTranslateCamUp = 0.8f;
+static int16 nFadeControlThreshhold = 45;
+static float fDefaultAlphaOrient = -0.22f;
+
+void
+CCam::Process_FollowPedWithMouse(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+ FOV = DefaultFOV;
+
+ if(!CamTargetEntity->IsPed())
+ return;
+
+ CVector TargetCoors;
+ float CamDist;
+ CColPoint colPoint;
+ CEntity *entity;
+
+ if(ResetStatics){
+ Rotating = false;
+ m_bCollisionChecksOn = true;
+ CPad::GetPad(0)->ClearMouseHistory();
+ ResetStatics = false;
+ }
+
+ bool OnTrain = FindPlayerVehicle() && FindPlayerVehicle()->IsTrain();
+
+ // Look around
+ bool UseMouse = false;
+ float MouseX = CPad::GetPad(0)->GetMouseX();
+ float MouseY = CPad::GetPad(0)->GetMouseY();
+ float LookLeftRight, LookUpDown;
+ if((MouseX != 0.0f || MouseY != 0.0f) && !CPad::GetPad(0)->ArePlayerControlsDisabled()){
+ UseMouse = true;
+ LookLeftRight = -2.5f*MouseX;
+ LookUpDown = 4.0f*MouseY;
+ }else{
+ LookLeftRight = -CPad::GetPad(0)->LookAroundLeftRight();
+ LookUpDown = CPad::GetPad(0)->LookAroundUpDown();
+ }
+ float AlphaOffset, BetaOffset;
+ if(UseMouse){
+ BetaOffset = LookLeftRight * TheCamera.m_fMouseAccelHorzntl * FOV/80.0f;
+ AlphaOffset = LookUpDown * TheCamera.m_fMouseAccelVertical * FOV/80.0f;
+ }else{
+ BetaOffset = LookLeftRight * fStickSens * (0.5f/7.0f) * FOV/80.0f * CTimer::GetTimeStep();
+ AlphaOffset = LookUpDown * fStickSens * (0.3f/7.0f) * FOV/80.0f * CTimer::GetTimeStep();
+ }
+
+ if(TheCamera.GetFading() && TheCamera.GetFadingDirection() == FADE_IN && nFadeControlThreshhold < CDraw::FadeValue ||
+ CDraw::FadeValue > 200){
+ if(Alpha < fDefaultAlphaOrient-0.05f)
+ AlphaOffset = 0.05f;
+ else if(Alpha < fDefaultAlphaOrient)
+ AlphaOffset = fDefaultAlphaOrient - Alpha;
+ else if(Alpha > fDefaultAlphaOrient+0.05f)
+ AlphaOffset = -0.05f;
+ else if(Alpha > fDefaultAlphaOrient)
+ AlphaOffset = fDefaultAlphaOrient - Alpha;
+ else
+ AlphaOffset = 0.0f;
+ }
+
+ Alpha += AlphaOffset;
+ Beta += BetaOffset;
+ while(Beta >= PI) Beta -= 2*PI;
+ while(Beta < -PI) Beta += 2*PI;
+ if(Alpha > DEGTORAD(45.0f)) Alpha = DEGTORAD(45.0f);
+ if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f);
+
+ TargetCoors = CameraTarget;
+ TargetCoors.z += fTranslateCamUp;
+ TargetCoors = DoAverageOnVector(TargetCoors);
+
+ // SA code
+#ifdef FREE_CAM
+ if((CCamera::bFreeCam && Alpha > 0.0f) || (!CCamera::bFreeCam && Alpha > fBaseDist))
+#else
+ if(Alpha > fBaseDist) // comparing an angle against a distance?
+#endif
+ CamDist = fBaseDist + Cos(min(Alpha*fFalloff, HALFPI))*fAngleDist;
+ else
+ CamDist = fBaseDist + Cos(Alpha)*fAngleDist;
+
+ if(TheCamera.m_bUseTransitionBeta)
+ Beta = CGeneral::GetATanOfXY(-Cos(m_fTransitionBeta), -Sin(m_fTransitionBeta));
+
+ if(TheCamera.m_bCamDirectlyBehind)
+ Beta = TheCamera.m_PedOrientForBehindOrInFront;
+ if(TheCamera.m_bCamDirectlyInFront)
+ Beta = TheCamera.m_PedOrientForBehindOrInFront + PI;
+ if(OnTrain)
+ Beta = TargetOrientation;
+
+ Front.x = Cos(Alpha) * Cos(Beta);
+ Front.y = Cos(Alpha) * Sin(Beta);
+ Front.z = Sin(Alpha);
+ Source = TargetCoors - Front*CamDist;
+ m_cvecTargetCoorsForFudgeInter = TargetCoors;
+
+ // Clip Source and fix near clip
+ CWorld::pIgnoreEntity = CamTargetEntity;
+ entity = nil;
+ if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, true, true, true, true, false, false, true)){
+ float PedColDist = (TargetCoors - colPoint.point).Magnitude();
+ float ColCamDist = CamDist - PedColDist;
+ if(entity->IsPed() && ColCamDist > 1.0f){
+ // Ped in the way but not clipping through
+ if(CWorld::ProcessLineOfSight(colPoint.point, Source, colPoint, entity, true, true, true, true, false, false, true)){
+ PedColDist = (TargetCoors - colPoint.point).Magnitude();
+ Source = colPoint.point;
+ if(PedColDist < DEFAULT_NEAR + 0.3f)
+ RwCameraSetNearClipPlane(Scene.camera, max(PedColDist-0.3f, 0.05f));
+ }else{
+ RwCameraSetNearClipPlane(Scene.camera, min(ColCamDist-0.35f, DEFAULT_NEAR));
+ }
+ }else{
+ Source = colPoint.point;
+ if(PedColDist < DEFAULT_NEAR + 0.3f)
+ RwCameraSetNearClipPlane(Scene.camera, max(PedColDist-0.3f, 0.05f));
+ }
+ }
+ CWorld::pIgnoreEntity = nil;
+
+ float ViewPlaneHeight = Tan(DEGTORAD(FOV) / 2.0f);
+ float ViewPlaneWidth = ViewPlaneHeight * CDraw::FindAspectRatio() * fTweakFOV;
+ float Near = RwCameraGetNearClipPlane(Scene.camera);
+ float radius = ViewPlaneWidth*Near;
+ entity = CWorld::TestSphereAgainstWorld(Source + Front*Near, radius, nil, true, true, false, true, false, false);
+ int i = 0;
+ while(entity){
+ CVector CamToCol = gaTempSphereColPoints[0].point - Source;
+ float frontDist = DotProduct(CamToCol, Front);
+ float dist = (CamToCol - Front*frontDist).Magnitude() / ViewPlaneWidth;
+
+ // Try to decrease near clip
+ dist = max(min(Near, dist), 0.1f);
+ if(dist < Near)
+ RwCameraSetNearClipPlane(Scene.camera, dist);
+
+ // Move forward a bit
+ if(dist == 0.1f)
+ Source += (TargetCoors - Source)*0.3f;
+
+#ifndef FIX_BUGS
+ // this is totally wrong...
+ radius = Tan(FOV / 2.0f) * Near;
+#endif
+ // Keep testing
+ entity = CWorld::TestSphereAgainstWorld(Source + Front*Near, radius, nil, true, true, false, true, false, false);
+
+ i++;
+ if(i > 5)
+ entity = nil;
+ }
+
+ if(CamTargetEntity->m_rwObject){
+ // what's going on here?
+ if(RpAnimBlendClumpGetAssociation(CamTargetEntity->GetClump(), ANIM_WEAPON_PUMP) ||
+ RpAnimBlendClumpGetAssociation(CamTargetEntity->GetClump(), ANIM_WEAPON_THROW) ||
+ RpAnimBlendClumpGetAssociation(CamTargetEntity->GetClump(), ANIM_WEAPON_THROWU) ||
+ RpAnimBlendClumpGetAssociation(CamTargetEntity->GetClump(), ANIM_WEAPON_START_THROW)){
+ CPed *player = FindPlayerPed();
+ float PlayerDist = (Source - player->GetPosition()).Magnitude();
+ if(PlayerDist < 2.75f)
+ Near = PlayerDist/2.75f * DEFAULT_NEAR - 0.3f;
+ RwCameraSetNearClipPlane(Scene.camera, max(Near, 0.1f));
+ }
+ }
+
+ TheCamera.m_bCamDirectlyInFront = false;
+ TheCamera.m_bCamDirectlyBehind = false;
+
+ GetVectorsReadyForRW();
+
+ if(((CPed*)CamTargetEntity)->CanStrafeOrMouseControl() && CDraw::FadeValue < 250 &&
+ (TheCamera.GetFadingDirection() != FADE_OUT || CDraw::FadeValue <= 100)){
+ float Heading = Front.Heading();
+ ((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Heading;
+ ((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Heading;
+ TheCamera.pTargetEntity->SetHeading(Heading);
+ TheCamera.pTargetEntity->GetMatrix().UpdateRW();
+ }
+}
+
+void
+CCam::Process_BehindCar(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+ FOV = DefaultFOV;
+
+ if(!CamTargetEntity->IsVehicle())
+ return;
+
+ CVector TargetCoors = CameraTarget;
+ TargetCoors.z -= 0.2f;
+ CA_MAX_DISTANCE = 9.95f;
+ CA_MIN_DISTANCE = 8.5f;
+
+ CVector Dist = Source - TargetCoors;
+ float Length = Dist.Magnitude2D();
+ m_fDistanceBeforeChanges = Length;
+ if(Length < 0.002f)
+ Length = 0.002f;
+ Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y);
+ if(Length > CA_MAX_DISTANCE){
+ Source.x = TargetCoors.x + Dist.x/Length * CA_MAX_DISTANCE;
+ Source.y = TargetCoors.y + Dist.y/Length * CA_MAX_DISTANCE;
+ }else if(Length < CA_MIN_DISTANCE){
+ Source.x = TargetCoors.x + Dist.x/Length * CA_MIN_DISTANCE;
+ Source.y = TargetCoors.y + Dist.y/Length * CA_MIN_DISTANCE;
+ }
+ TargetCoors.z += 0.8f;
+
+ WorkOutCamHeightWeeCar(TargetCoors, TargetOrientation);
+ RotCamIfInFrontCar(TargetCoors, TargetOrientation);
+ FixCamIfObscured(TargetCoors, 1.2f, TargetOrientation);
+
+ Front = TargetCoors - Source;
+ m_cvecTargetCoorsForFudgeInter = TargetCoors;
+ ResetStatics = false;
+ GetVectorsReadyForRW();
+}
+
+void
+CCam::WorkOutCamHeightWeeCar(CVector &TargetCoors, float TargetOrientation)
+{
+ CColPoint colpoint;
+ CEntity *ent;
+ float TargetZOffSet = 0.0f;
+ static bool PreviouslyFailedRoadHeightCheck = false;
+ static float RoadHeightFix = 0.0f;
+ static float RoadHeightFixSpeed = 0.0f;
+
+ if(ResetStatics){
+ RoadHeightFix = 0.0f;
+ RoadHeightFixSpeed = 0.0f;
+ Alpha = DEGTORAD(25.0f);
+ AlphaSpeed = 0.0f;
+ }
+ float AlphaTarget = DEGTORAD(25.0f);
+ if(CCullZones::CamNoRain() || CCullZones::PlayerNoRain())
+ AlphaTarget = DEGTORAD(14.0f);
+ WellBufferMe(AlphaTarget, &Alpha, &AlphaSpeed, 0.1f, 0.05f, true);
+ Source.z = TargetCoors.z + CA_MAX_DISTANCE*Sin(Alpha);
+
+ if(FindPlayerVehicle()){
+ m_fRoadOffSet = 0.0f;
+ bool FoundRoad = false;
+ bool FoundRoof = false;
+ float RoadZ = 0.0f;
+ float RoofZ = 0.0f;
+
+ if(CWorld::ProcessVerticalLine(Source, -1000.0f, colpoint, ent, true, false, false, false, false, false, nil) &&
+ ent->IsBuilding()){
+ FoundRoad = true;
+ RoadZ = colpoint.point.z;
+ }
+
+ if(FoundRoad){
+ if(Source.z - RoadZ < 0.9f){
+ PreviouslyFailedRoadHeightCheck = true;
+ TargetZOffSet = RoadZ + 0.9f - Source.z;
+ }else{
+ if(m_bCollisionChecksOn)
+ PreviouslyFailedRoadHeightCheck = false;
+ else
+ TargetZOffSet = 0.0f;
+ }
+ }else{
+ if(CWorld::ProcessVerticalLine(Source, 1000.0f, colpoint, ent, true, false, false, false, false, false, nil) &&
+ ent->IsBuilding()){
+ FoundRoof = true;
+ RoofZ = colpoint.point.z;
+ }
+ if(FoundRoof){
+ if(Source.z - RoofZ < 0.9f){
+ PreviouslyFailedRoadHeightCheck = true;
+ TargetZOffSet = RoofZ + 0.9f - Source.z;
+ }else{
+ if(m_bCollisionChecksOn)
+ PreviouslyFailedRoadHeightCheck = false;
+ else
+ TargetZOffSet = 0.0f;
+ }
+ }
+ }
+ }
+
+ if(TargetZOffSet > RoadHeightFix)
+ RoadHeightFix = TargetZOffSet;
+ else
+ WellBufferMe(TargetZOffSet, &RoadHeightFix, &RoadHeightFixSpeed, 0.27f, 0.1f, false);
+
+ if((colpoint.surfaceB == SURFACE_DEFAULT || colpoint.surfaceB >= SURFACE_METAL6) &&
+ colpoint.surfaceB != SURFACE_STEEL && colpoint.surfaceB != SURFACE_STONE &&
+ RoadHeightFix > 1.4f)
+ RoadHeightFix = 1.4f;
+
+ Source.z += RoadHeightFix;
+}
+
+void
+CCam::WorkOutCamHeight(const CVector &TargetCoors, float TargetOrientation, float TargetHeight)
+{
+ static float LastTargetAlphaWithCollisionOn = 0.0f;
+ static float LastTopAlphaSpeed = 0.0f;
+ static float LastAlphaSpeedStep = 0.0f;
+ static bool PreviousNearCheckNearClipSmall = false;
+
+ bool CamClear = true;
+ float ModeAlpha = 0.0f;
+
+ if(ResetStatics){
+ LastTargetAlphaWithCollisionOn = 0.0f;
+ LastTopAlphaSpeed = 0.0f;
+ LastAlphaSpeedStep = 0.0f;
+ PreviousNearCheckNearClipSmall = false;
+ }
+
+ float TopAlphaSpeed = 0.15f;
+ float AlphaSpeedStep = 0.015f;
+
+ float zoomvalue = TheCamera.CarZoomValueSmooth;
+ if(zoomvalue < 0.1f)
+ zoomvalue = 0.1f;
+ if(TheCamera.CarZoomIndicator == CAM_ZOOM_1)
+ ModeAlpha = CGeneral::GetATanOfXY(23.0f, zoomvalue); // near
+ else if(TheCamera.CarZoomIndicator == CAM_ZOOM_2)
+ ModeAlpha = CGeneral::GetATanOfXY(10.8f, zoomvalue); // mid
+ else if(TheCamera.CarZoomIndicator == CAM_ZOOM_3)
+ ModeAlpha = CGeneral::GetATanOfXY(7.0f, zoomvalue); // far
+
+
+ float Length = (Source - TargetCoors).Magnitude2D();
+ if(m_bCollisionChecksOn){ // there's another variable (on PC) but it's uninitialised
+ CVector Forward = CamTargetEntity->GetForward();
+ float CarAlpha = CGeneral::GetATanOfXY(Forward.Magnitude2D(), Forward.z);
+ // this shouldn't be necessary....
+ while(CarAlpha >= PI) CarAlpha -= 2*PI;
+ while(CarAlpha < -PI) CarAlpha += 2*PI;
+
+ while(Beta >= PI) Beta -= 2*PI;
+ while(Beta < -PI) Beta += 2*PI;
+
+ float deltaBeta = Beta - TargetOrientation;
+ while(deltaBeta >= PI) deltaBeta -= 2*PI;
+ while(deltaBeta < -PI) deltaBeta += 2*PI;
+
+ float BehindCarNess = Cos(deltaBeta); // 1 if behind car, 0 if side, -1 if in front
+ CarAlpha = -CarAlpha * BehindCarNess;
+ if(CarAlpha < -0.01f)
+ CarAlpha = -0.01f;
+
+ float DeltaAlpha = CarAlpha - Alpha;
+ while(DeltaAlpha >= PI) DeltaAlpha -= 2*PI;
+ while(DeltaAlpha < -PI) DeltaAlpha += 2*PI;
+ // What's this?? wouldn't it make more sense to clamp?
+ float AngleLimit = DEGTORAD(1.8f);
+ if(DeltaAlpha < -AngleLimit)
+ DeltaAlpha += AngleLimit;
+ else if(DeltaAlpha > AngleLimit)
+ DeltaAlpha -= AngleLimit;
+ else
+ DeltaAlpha = 0.0f;
+
+ // Now the collision
+
+ float TargetAlpha = 0.0f;
+ bool FoundRoofCenter = false;
+ bool FoundRoofSide1 = false;
+ bool FoundRoofSide2 = false;
+ bool FoundCamRoof = false;
+ bool FoundCamGround = false;
+ float CamRoof = 0.0f;
+ float CarBottom = TargetCoors.z - TargetHeight/2.0f;
+
+ // Check car center
+ float CarRoof = CWorld::FindRoofZFor3DCoord(TargetCoors.x, TargetCoors.y, CarBottom, &FoundRoofCenter);
+
+ // Check sides of the car
+ Forward = CamTargetEntity->GetForward(); // we actually still have that...
+ Forward.Normalise(); // shouldn't be necessary
+ float CarSideAngle = CGeneral::GetATanOfXY(Forward.x, Forward.y) + PI/2.0f;
+ float SideX = 2.5f * Cos(CarSideAngle);
+ float SideY = 2.5f * Sin(CarSideAngle);
+ CWorld::FindRoofZFor3DCoord(TargetCoors.x + SideX, TargetCoors.y + SideY, CarBottom, &FoundRoofSide1);
+ CWorld::FindRoofZFor3DCoord(TargetCoors.x - SideX, TargetCoors.y - SideY, CarBottom, &FoundRoofSide2);
+
+ // Now find out at what height we'd like to place the camera
+ float CamGround = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, TargetCoors.z + Length*Sin(Alpha + ModeAlpha) + m_fCloseInCarHeightOffset, &FoundCamGround);
+ float CamTargetZ = 0.0f;
+ if(FoundCamGround){
+ // This is the normal case
+ CamRoof = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, CamGround + TargetHeight, &FoundCamRoof);
+ CamTargetZ = CamGround + TargetHeight*1.5f + 0.1f;
+ }else{
+ FoundCamRoof = false;
+ CamTargetZ = TargetCoors.z;
+ }
+
+ if(FoundRoofCenter && !FoundCamRoof && (FoundRoofSide1 || FoundRoofSide2)){
+ // Car is under something but camera isn't
+ // This seems weird...
+ TargetAlpha = CGeneral::GetATanOfXY(CA_MAX_DISTANCE, CarRoof - CamTargetZ - 1.5f);
+ CamClear = false;
+ }
+ if(FoundCamRoof){
+ // Camera is under something
+ float roof = FoundRoofCenter ? min(CamRoof, CarRoof) : CamRoof;
+ // Same weirdness again?
+ TargetAlpha = CGeneral::GetATanOfXY(CA_MAX_DISTANCE, roof - CamTargetZ - 1.5f);
+ CamClear = false;
+ }
+ while(TargetAlpha >= PI) TargetAlpha -= 2*PI;
+ while(TargetAlpha < -PI) TargetAlpha += 2*PI;
+ if(TargetAlpha < DEGTORAD(-7.0f))
+ TargetAlpha = DEGTORAD(-7.0f);
+
+ // huh?
+ if(TargetAlpha > ModeAlpha)
+ CamClear = true;
+ // Camera is contrained by collision in some way
+ PreviousNearCheckNearClipSmall = false;
+ if(!CamClear){
+ PreviousNearCheckNearClipSmall = true;
+ RwCameraSetNearClipPlane(Scene.camera, DEFAULT_NEAR);
+
+ DeltaAlpha = TargetAlpha - (Alpha + ModeAlpha);
+ while(DeltaAlpha >= PI) DeltaAlpha -= 2*PI;
+ while(DeltaAlpha < -PI) DeltaAlpha += 2*PI;
+
+ TopAlphaSpeed = 0.3f;
+ AlphaSpeedStep = 0.03f;
+ }
+
+ // Now do things if CamClear...but what is that anyway?
+ float CamZ = TargetCoors.z + Length*Sin(Alpha + DeltaAlpha + ModeAlpha) + m_fCloseInCarHeightOffset;
+ bool FoundGround, FoundRoof;
+ float CamGround2 = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, CamZ, &FoundGround);
+ if(FoundGround){
+ if(CamClear)
+ if(CamZ - CamGround2 < 1.5f){
+ PreviousNearCheckNearClipSmall = true;
+ RwCameraSetNearClipPlane(Scene.camera, DEFAULT_NEAR);
+
+ float a;
+ if(Length == 0.0f || CamGround2 + 1.5f - TargetCoors.z == 0.0f)
+ a = Alpha;
+ else
+ a = CGeneral::GetATanOfXY(Length, CamGround2 + 1.5f - TargetCoors.z);
+ while(a > PI) a -= 2*PI;
+ while(a < -PI) a += 2*PI;
+ DeltaAlpha = a - Alpha;
+ }
+ }else{
+ if(CamClear){
+ float CamRoof2 = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, CamZ, &FoundRoof);
+ if(FoundRoof && CamZ - CamRoof2 < 1.5f){
+ PreviousNearCheckNearClipSmall = true;
+ RwCameraSetNearClipPlane(Scene.camera, DEFAULT_NEAR);
+
+ if(CamRoof2 > TargetCoors.z + 3.5f)
+ CamRoof2 = TargetCoors.z + 3.5f;
+
+ float a;
+ if(Length == 0.0f || CamRoof2 + 1.5f - TargetCoors.z == 0.0f)
+ a = Alpha;
+ else
+ a = CGeneral::GetATanOfXY(Length, CamRoof2 + 1.5f - TargetCoors.z);
+ while(a > PI) a -= 2*PI;
+ while(a < -PI) a += 2*PI;
+ DeltaAlpha = a - Alpha;
+ }
+ }
+ }
+
+ LastTargetAlphaWithCollisionOn = DeltaAlpha + Alpha;
+ LastTopAlphaSpeed = TopAlphaSpeed;
+ LastAlphaSpeedStep = AlphaSpeedStep;
+ }else{
+ if(PreviousNearCheckNearClipSmall)
+ RwCameraSetNearClipPlane(Scene.camera, DEFAULT_NEAR);
+ }
+
+ WellBufferMe(LastTargetAlphaWithCollisionOn, &Alpha, &AlphaSpeed, LastTopAlphaSpeed, LastAlphaSpeedStep, true);
+
+ Source.z = TargetCoors.z + Sin(Alpha + ModeAlpha)*Length + m_fCloseInCarHeightOffset;
+}
+
+// Rotate cam behind the car when the car is moving forward
+bool
+CCam::RotCamIfInFrontCar(CVector &TargetCoors, float TargetOrientation)
+{
+ bool MovingForward = false;
+ CPhysical *phys = (CPhysical*)CamTargetEntity;
+
+ float ForwardSpeed = DotProduct(phys->GetForward(), phys->GetSpeed(CVector(0.0f, 0.0f, 0.0f)));
+ if(ForwardSpeed > 0.02f)
+ MovingForward = true;
+
+ float Dist = (Source - TargetCoors).Magnitude2D();
+
+ float DeltaBeta = TargetOrientation - Beta;
+ while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
+ while(DeltaBeta < -PI) DeltaBeta += 2*PI;
+
+ if(Abs(DeltaBeta) > DEGTORAD(20.0f) && MovingForward && TheCamera.m_uiTransitionState == 0)
+ m_bFixingBeta = true;
+
+ CPad *pad = CPad::GetPad(0);
+ if(!(pad->GetLookBehindForCar() || pad->GetLookBehindForPed() || pad->GetLookLeft() || pad->GetLookRight()))
+ if(DirectionWasLooking != LOOKING_FORWARD)
+ TheCamera.m_bCamDirectlyBehind = true;
+
+ if(!m_bFixingBeta && !TheCamera.m_bUseTransitionBeta && !TheCamera.m_bCamDirectlyBehind && !TheCamera.m_bCamDirectlyInFront)
+ return false;
+
+ bool SetBeta = false;
+ if(TheCamera.m_bCamDirectlyBehind || TheCamera.m_bCamDirectlyInFront || TheCamera.m_bUseTransitionBeta)
+ if(&TheCamera.Cams[TheCamera.ActiveCam] == this)
+ SetBeta = true;
+
+ if(m_bFixingBeta || SetBeta){
+ WellBufferMe(TargetOrientation, &Beta, &BetaSpeed, 0.15f, 0.007f, true);
+
+ if(TheCamera.m_bCamDirectlyBehind && &TheCamera.Cams[TheCamera.ActiveCam] == this)
+ Beta = TargetOrientation;
+ if(TheCamera.m_bCamDirectlyInFront && &TheCamera.Cams[TheCamera.ActiveCam] == this)
+ Beta = TargetOrientation + PI;
+ if(TheCamera.m_bUseTransitionBeta && &TheCamera.Cams[TheCamera.ActiveCam] == this)
+ Beta = m_fTransitionBeta;
+
+ Source.x = TargetCoors.x - Cos(Beta)*Dist;
+ Source.y = TargetCoors.y - Sin(Beta)*Dist;
+
+ // Check if we're done
+ DeltaBeta = TargetOrientation - Beta;
+ while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
+ while(DeltaBeta < -PI) DeltaBeta += 2*PI;
+ if(Abs(DeltaBeta) < DEGTORAD(2.0f))
+ m_bFixingBeta = false;
+ }
+ TheCamera.m_bCamDirectlyBehind = false;
+ TheCamera.m_bCamDirectlyInFront = false;
+ return true;
+}
+
+// Move the cam to avoid clipping through buildings
+bool
+CCam::FixCamIfObscured(CVector &TargetCoors, float TargetHeight, float TargetOrientation)
+{
+ CVector Target = TargetCoors;
+ bool UseEntityPos = false;
+ CVector EntityPos;
+ static CColPoint colPoint;
+ static bool LastObscured = false;
+
+ if(Mode == MODE_BEHINDCAR)
+ Target.z += TargetHeight/2.0f;
+ if(Mode == MODE_CAM_ON_A_STRING){
+ UseEntityPos = true;
+ Target.z += TargetHeight/2.0f;
+ EntityPos = CamTargetEntity->GetPosition();
+ }
+
+ CVector TempSource = Source;
+
+ bool Obscured1 = false;
+ bool Obscured2 = false;
+ bool Fix1 = false;
+ float Dist1 = 0.0f;
+ float Dist2 = 0.0f;
+ CEntity *ent;
+ if(m_bCollisionChecksOn || LastObscured){
+ Obscured1 = CWorld::ProcessLineOfSight(Target, TempSource, colPoint, ent, true, false, false, true, false, true, true);
+ if(Obscured1){
+ Dist1 = (Target - colPoint.point).Magnitude2D();
+ Fix1 = true;
+ if(UseEntityPos)
+ Obscured1 = CWorld::ProcessLineOfSight(EntityPos, TempSource, colPoint, ent, true, false, false, true, false, true, true);
+ }else if(m_bFixingBeta){
+ float d = (TempSource - Target).Magnitude();
+ TempSource.x = Target.x - d*Cos(TargetOrientation);
+ TempSource.y = Target.y - d*Sin(TargetOrientation);
+
+ // same check again
+ Obscured2 = CWorld::ProcessLineOfSight(Target, TempSource, colPoint, ent, true, false, false, true, false, true, true);
+ if(Obscured2){
+ Dist2 = (Target - colPoint.point).Magnitude2D();
+ if(UseEntityPos)
+ Obscured2 = CWorld::ProcessLineOfSight(EntityPos, TempSource, colPoint, ent, true, false, false, true, false, true, true);
+ }
+ }
+ LastObscured = Obscured1 || Obscured2;
+ }
+
+ // nothing to do
+ if(!LastObscured)
+ return false;
+
+ if(Fix1){
+ Source.x = Target.x - Cos(Beta)*Dist1;
+ Source.y = Target.y - Sin(Beta)*Dist1;
+ if(Mode == MODE_BEHINDCAR)
+ Source = colPoint.point;
+ }else{
+ WellBufferMe(Dist2, &m_fDistanceBeforeChanges, &DistanceSpeed, 0.2f, 0.025f, false);
+ Source.x = Target.x - Cos(Beta)*m_fDistanceBeforeChanges;
+ Source.y = Target.y - Sin(Beta)*m_fDistanceBeforeChanges;
+ }
+
+ if(ResetStatics){
+ m_fDistanceBeforeChanges = (Source - Target).Magnitude2D();
+ DistanceSpeed = 0.0f;
+ Source.x = colPoint.point.x;
+ Source.y = colPoint.point.y;
+ }
+ return true;
+}
+
+void
+CCam::Process_Cam_On_A_String(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+ if(!CamTargetEntity->IsVehicle())
+ return;
+
+ FOV = DefaultFOV;
+
+ if(ResetStatics){
+ AlphaSpeed = 0.0f;
+ if(TheCamera.m_bIdleOn)
+ TheCamera.m_uiTimeWeEnteredIdle = CTimer::GetTimeInMilliseconds();
+ }
+
+ CBaseModelInfo *mi = CModelInfo::GetModelInfo(CamTargetEntity->GetModelIndex());
+ CVector Dimensions = mi->GetColModel()->boundingBox.max - mi->GetColModel()->boundingBox.min;
+ float BaseDist = Dimensions.Magnitude2D();
+
+ CVector TargetCoors = CameraTarget;
+ TargetCoors.z += Dimensions.z - 0.1f; // final
+ Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y);
+ while(Alpha >= PI) Alpha -= 2*PI;
+ while(Alpha < -PI) Alpha += 2*PI;
+ while(Beta >= PI) Beta -= 2*PI;
+ while(Beta < -PI) Beta += 2*PI;
+
+ m_fDistanceBeforeChanges = (Source - TargetCoors).Magnitude2D();
+
+ Cam_On_A_String_Unobscured(TargetCoors, BaseDist);
+ WorkOutCamHeight(TargetCoors, TargetOrientation, Dimensions.z);
+ RotCamIfInFrontCar(TargetCoors, TargetOrientation);
+ FixCamIfObscured(TargetCoors, Dimensions.z, TargetOrientation);
+ FixCamWhenObscuredByVehicle(TargetCoors);
+
+ m_cvecTargetCoorsForFudgeInter = TargetCoors;
+ Front = TargetCoors - Source;
+ Front.Normalise();
+ GetVectorsReadyForRW();
+ ResetStatics = false;
+}
+
+// Basic Cam on a string algorithm
+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);
+
+ CVector Dist = Source - TargetCoors;
+
+ if(ResetStatics)
+ Source = TargetCoors + Dist*(CA_MAX_DISTANCE + 1.0f);
+
+ float Length = Dist.Magnitude2D();
+ if(Length < 0.001f){
+ // This probably shouldn't happen. reset view
+ CVector Forward = CamTargetEntity->GetForward();
+ Forward.z = 0.0f;
+ Forward.Normalise();
+ Source = TargetCoors - Forward*CA_MAX_DISTANCE;
+ Dist = Source - TargetCoors;
+ Length = Dist.Magnitude2D();
+ }
+
+ if(Length > CA_MAX_DISTANCE){
+ Source.x = TargetCoors.x + Dist.x/Length * CA_MAX_DISTANCE;
+ Source.y = TargetCoors.y + Dist.y/Length * CA_MAX_DISTANCE;
+ }else if(Length < CA_MIN_DISTANCE){
+ Source.x = TargetCoors.x + Dist.x/Length * CA_MIN_DISTANCE;
+ Source.y = TargetCoors.y + Dist.y/Length * CA_MIN_DISTANCE;
+ }
+}
+
+void
+CCam::FixCamWhenObscuredByVehicle(const CVector &TargetCoors)
+{
+ // BUG? is this never reset
+ static float HeightFixerCarsObscuring = 0.0f;
+ static float HeightFixerCarsObscuringSpeed = 0.0f;
+ CColPoint colPoint;
+ CEntity *entity;
+
+ float HeightTarget = 0.0f;
+ if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, false, true, false, false, false, false, false)){
+ CBaseModelInfo *mi = CModelInfo::GetModelInfo(entity->GetModelIndex());
+ HeightTarget = mi->GetColModel()->boundingBox.max.z + 1.0f + TargetCoors.z - Source.z;
+ if(HeightTarget < 0.0f)
+ HeightTarget = 0.0f;
+ }
+ WellBufferMe(HeightTarget, &HeightFixerCarsObscuring, &HeightFixerCarsObscuringSpeed, 0.2f, 0.025f, false);
+ Source.z += HeightFixerCarsObscuring;
+}
+
+void
+CCam::Process_TopDown(const CVector &CameraTarget, float TargetOrientation, float SpeedVar, float TargetSpeedVar)
+{
+ FOV = DefaultFOV;
+
+ if(!CamTargetEntity->IsVehicle())
+ return;
+
+ float Dist;
+ float HeightTarget = 0.0f;
+ static float AdjustHeightTargetMoveBuffer = 0.0f;
+ static float AdjustHeightTargetMoveSpeed = 0.0f;
+ static float NearClipDistance = 1.5f;
+ const float FarClipDistance = 200.0f;
+ CVector TargetFront, Target;
+ CVector TestSource, TestTarget;
+ CColPoint colPoint;
+ CEntity *entity;
+
+ TargetFront = CameraTarget;
+ TargetFront.x += 18.0f*CamTargetEntity->GetForward().x*SpeedVar;
+ TargetFront.y += 18.0f*CamTargetEntity->GetForward().y*SpeedVar;
+
+ if(ResetStatics){
+ AdjustHeightTargetMoveBuffer = 0.0f;
+ AdjustHeightTargetMoveSpeed = 0.0f;
+ }
+
+ float f = Pow(0.8f, 4.0f);
+ Target = f*CameraTarget + (1.0f-f)*TargetFront;
+ if(Mode == MODE_GTACLASSIC)
+ SpeedVar = TargetSpeedVar;
+ Source = Target + CVector(0.0f, 0.0f, (40.0f*SpeedVar + 30.0f)*0.8f);
+ // What is this? looks horrible
+ if(Mode == MODE_GTACLASSIC)
+ Source.x += (uint8)(100.0f*CameraTarget.x)/500.0f;
+
+ TestSource = Source;
+ TestTarget = TestSource;
+ TestTarget.z = Target.z;
+ if(CWorld::ProcessLineOfSight(TestTarget, TestSource, colPoint, entity, true, false, false, false, false, false, false)){
+ if(Source.z < colPoint.point.z+3.0f)
+ HeightTarget = colPoint.point.z+3.0f - Source.z;
+ }else{
+ TestSource = Source;
+ TestTarget = TestSource;
+ TestTarget.z += 10.0f;
+ if(CWorld::ProcessLineOfSight(TestTarget, TestSource, colPoint, entity, true, false, false, false, false, false, false))
+ if(Source.z < colPoint.point.z+3.0f)
+ HeightTarget = colPoint.point.z+3.0f - Source.z;
+ }
+ WellBufferMe(HeightTarget, &AdjustHeightTargetMoveBuffer, &AdjustHeightTargetMoveSpeed, 0.2f, 0.02f, false);
+ Source.z += AdjustHeightTargetMoveBuffer;
+
+ if(RwCameraGetFarClipPlane(Scene.camera) > FarClipDistance)
+ RwCameraSetFarClipPlane(Scene.camera, FarClipDistance);
+ RwCameraSetNearClipPlane(Scene.camera, NearClipDistance);
+
+ Front = CVector(-0.01f, -0.01f, -1.0f); // look down
+ Front.Normalise();
+ Dist = (Source - CameraTarget).Magnitude();
+ m_cvecTargetCoorsForFudgeInter = Dist*Front + Source;
+ Up = CVector(0.0f, 1.0f, 0.0f);
+
+ ResetStatics = false;
+}
+
+void
+CCam::AvoidWallsTopDownPed(const CVector &TargetCoors, const CVector &Offset, float *Adjuster, float *AdjusterSpeed, float yDistLimit)
+{
+ float Target = 0.0f;
+ float MaxSpeed = 0.13f;
+ float Acceleration = 0.015f;
+ float SpeedMult;
+ float dy;
+ CVector TestPoint2;
+ CVector TestPoint1;
+ CColPoint colPoint;
+ CEntity *entity;
+
+ TestPoint2 = TargetCoors + Offset;
+ TestPoint1 = TargetCoors;
+ TestPoint1.z = TestPoint2.z;
+ if(CWorld::ProcessLineOfSight(TestPoint1, TestPoint2, colPoint, entity, true, false, false, false, false, false, false)){
+ // What is this even?
+ dy = TestPoint1.y - colPoint.point.y;
+ if(dy > yDistLimit)
+ dy = yDistLimit;
+ SpeedMult = yDistLimit - Abs(dy/yDistLimit);
+
+ Target = 2.5f;
+ MaxSpeed += SpeedMult*0.3f;
+ Acceleration += SpeedMult*0.03f;
+ }
+ WellBufferMe(Target, Adjuster, AdjusterSpeed, MaxSpeed, Acceleration, false);
+}
+
+void
+CCam::Process_TopDownPed(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+ if(!CamTargetEntity->IsPed())
+ return;
+
+ float Dist;
+ float HeightTarget;
+ static int NumPedPosCountsSoFar = 0;
+ static float PedAverageSpeed = 0.0f;
+ static float AdjustHeightTargetMoveBuffer = 0.0f;
+ static float AdjustHeightTargetMoveSpeed = 0.0f;
+ static float PedSpeedSoFar = 0.0f;
+ static float FarClipDistance = 200.0f;
+ static float NearClipDistance = 1.5f;
+ static float TargetAdjusterForSouth = 0.0f;
+ static float TargetAdjusterSpeedForSouth = 0.0f;
+ static float TargetAdjusterForNorth = 0.0f;
+ static float TargetAdjusterSpeedForNorth = 0.0f;
+ static float TargetAdjusterForEast = 0.0f;
+ static float TargetAdjusterSpeedForEast = 0.0f;
+ static float TargetAdjusterForWest = 0.0f;
+ static float TargetAdjusterSpeedForWest = 0.0f;
+ static CVector PreviousPlayerMoveSpeedVec;
+ CVector TargetCoors, PlayerMoveSpeed;
+ CVector TestSource, TestTarget;
+ CColPoint colPoint;
+ CEntity *entity;
+
+ FOV = DefaultFOV;
+ TargetCoors = CameraTarget;
+ PlayerMoveSpeed = ((CPed*)CamTargetEntity)->GetMoveSpeed();
+
+ if(ResetStatics){
+ PreviousPlayerMoveSpeedVec = PlayerMoveSpeed;
+ AdjustHeightTargetMoveBuffer = 0.0f;
+ AdjustHeightTargetMoveSpeed = 0.0f;
+ NumPedPosCountsSoFar = 0;
+ PedSpeedSoFar = 0.0f;
+ PedAverageSpeed = 0.0f;
+ TargetAdjusterForWest = 0.0f;
+ TargetAdjusterSpeedForWest = 0.0f;
+ TargetAdjusterForEast = 0.0f;
+ TargetAdjusterSpeedForEast = 0.0f;
+ TargetAdjusterForNorth = 0.0f;
+ TargetAdjusterSpeedForNorth = 0.0f;
+ TargetAdjusterForSouth = 0.0f;
+ TargetAdjusterSpeedForSouth = 0.0f;
+ }
+
+ if(RwCameraGetFarClipPlane(Scene.camera) > FarClipDistance)
+ RwCameraSetFarClipPlane(Scene.camera, FarClipDistance);
+ RwCameraSetNearClipPlane(Scene.camera, NearClipDistance);
+
+ // Average ped speed
+ NumPedPosCountsSoFar++;
+ PedSpeedSoFar += PlayerMoveSpeed.Magnitude();
+ if(NumPedPosCountsSoFar == 5){
+ PedAverageSpeed = 0.4f*PedAverageSpeed + 0.6*(PedSpeedSoFar/5.0f);
+ NumPedPosCountsSoFar = 0;
+ PedSpeedSoFar = 0.0f;
+ }
+ PreviousPlayerMoveSpeedVec = PlayerMoveSpeed;
+
+ // Zoom out depending on speed
+ if(PedAverageSpeed > 0.01f && PedAverageSpeed <= 0.04f)
+ HeightTarget = 2.5f;
+ else if(PedAverageSpeed > 0.04f && PedAverageSpeed <= 0.145f)
+ HeightTarget = 4.5f;
+ else if(PedAverageSpeed > 0.145f)
+ HeightTarget = 7.0f;
+ else
+ HeightTarget = 0.0f;
+
+ // Zoom out if locked on target is far away
+ if(FindPlayerPed()->m_pPointGunAt){
+ Dist = (FindPlayerPed()->m_pPointGunAt->GetPosition() - CameraTarget).Magnitude2D();
+ if(Dist > 6.0f)
+ HeightTarget = max(HeightTarget, Dist/22.0f*37.0f);
+ }
+
+ Source = TargetCoors + CVector(0.0f, -1.0f, 9.0f);
+
+ // Collision checks
+ entity = nil;
+ TestSource = TargetCoors + CVector(0.0f, -1.0f, 9.0f);
+ TestTarget = TestSource;
+ TestTarget.z = TargetCoors.z;
+ if(CWorld::ProcessLineOfSight(TestTarget, TestSource, colPoint, entity, true, false, false, false, false, false, false)){
+ if(TargetCoors.z+9.0f+HeightTarget < colPoint.point.z+3.0f)
+ HeightTarget = colPoint.point.z+3.0f - (TargetCoors.z+9.0f);
+ }else{
+ TestSource = TargetCoors + CVector(0.0f, -1.0f, 9.0f);
+ TestTarget = TestSource;
+ TestSource.z += HeightTarget;
+ TestTarget.z = TestSource.z + 10.0f;
+ if(CWorld::ProcessLineOfSight(TestTarget, TestSource, colPoint, entity, true, false, false, false, false, false, false)){
+ if(TargetCoors.z+9.0f+HeightTarget < colPoint.point.z+3.0f)
+ HeightTarget = colPoint.point.z+3.0f - (TargetCoors.z+9.0f);
+ }
+ }
+
+ WellBufferMe(HeightTarget, &AdjustHeightTargetMoveBuffer, &AdjustHeightTargetMoveSpeed, 0.3f, 0.03f, false);
+ Source.z += AdjustHeightTargetMoveBuffer;
+
+ // Wall checks
+ AvoidWallsTopDownPed(TargetCoors, CVector(0.0f, -3.0f, 3.0f), &TargetAdjusterForSouth, &TargetAdjusterSpeedForSouth, 1.0f);
+ Source.y += TargetAdjusterForSouth;
+ AvoidWallsTopDownPed(TargetCoors, CVector(0.0f, 3.0f, 3.0f), &TargetAdjusterForNorth, &TargetAdjusterSpeedForNorth, 1.0f);
+ Source.y -= TargetAdjusterForNorth;
+ // BUG: east and west flipped
+ AvoidWallsTopDownPed(TargetCoors, CVector(3.0f, 0.0f, 3.0f), &TargetAdjusterForWest, &TargetAdjusterSpeedForWest, 1.0f);
+ Source.x -= TargetAdjusterForWest;
+ AvoidWallsTopDownPed(TargetCoors, CVector(-3.0f, 0.0f, 3.0f), &TargetAdjusterForEast, &TargetAdjusterSpeedForEast, 1.0f);
+ Source.x += TargetAdjusterForEast;
+
+ TargetCoors.y = Source.y + 1.0f;
+ TargetCoors.y += TargetAdjusterForSouth;
+ TargetCoors.x += TargetAdjusterForEast;
+ TargetCoors.x -= TargetAdjusterForWest;
+
+ Front = TargetCoors - Source;
+ Front.Normalise();
+#ifdef FIX_BUGS
+ if(Front.x == 0.0f && Front.y == 0.0f)
+ Front.y = 0.0001f;
+#else
+ // someone used = instead of == in the above check by accident
+ Front.x = 0.0f;
+#endif
+ m_cvecTargetCoorsForFudgeInter = TargetCoors;
+ Up = CrossProduct(Front, CVector(-1.0f, 0.0f, 0.0f));
+ Up.Normalise();
+
+ ResetStatics = false;
+}
+
+// Identical to M16
+void
+CCam::Process_Rocket(const CVector &CameraTarget, float, float, float)
+{
+ if(!CamTargetEntity->IsPed())
+ return;
+
+ static bool FailedTestTwelveFramesAgo = false;
+ RwV3d HeadPos;
+ CVector TargetCoors;
+
+ FOV = DefaultFOV;
+ TargetCoors = CameraTarget;
+
+ if(ResetStatics){
+ Beta = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI;
+ Alpha = 0.0f;
+ m_fInitialPlayerOrientation = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI;
+ FailedTestTwelveFramesAgo = false;
+ // static DPadVertical unused
+ // static DPadHorizontal unused
+ m_bCollisionChecksOn = true;
+ ResetStatics = false;
+ }
+
+ ((CPed*)CamTargetEntity)->m_pedIK.GetComponentPosition(&HeadPos, PED_HEAD);
+ Source = HeadPos;
+ Source.z += 0.1f;
+ Source.x -= 0.19f*Cos(m_fInitialPlayerOrientation);
+ Source.y -= 0.19f*Sin(m_fInitialPlayerOrientation);
+
+ // Look around
+ bool UseMouse = false;
+ float MouseX = CPad::GetPad(0)->GetMouseX();
+ float MouseY = CPad::GetPad(0)->GetMouseY();
+ float LookLeftRight, LookUpDown;
+ if(MouseX != 0.0f || MouseY != 0.0f){
+ UseMouse = true;
+ LookLeftRight = -3.0f*MouseX;
+ LookUpDown = 4.0f*MouseY;
+ }else{
+ LookLeftRight = -CPad::GetPad(0)->SniperModeLookLeftRight();
+ LookUpDown = CPad::GetPad(0)->SniperModeLookUpDown();
+ }
+ if(UseMouse){
+ Beta += TheCamera.m_fMouseAccelHorzntl * LookLeftRight * FOV/80.0f;
+ Alpha += TheCamera.m_fMouseAccelVertical * LookUpDown * FOV/80.0f;
+ }else{
+ float xdir = LookLeftRight < 0.0f ? -1.0f : 1.0f;
+ float ydir = LookUpDown < 0.0f ? -1.0f : 1.0f;
+ Beta += SQR(LookLeftRight/100.0f)*xdir/17.5 * FOV/80.0f * CTimer::GetTimeStep();
+ Alpha += SQR(LookUpDown/150.0f)*ydir/14.0f * FOV/80.0f * CTimer::GetTimeStep();
+ }
+ while(Beta >= PI) Beta -= 2*PI;
+ while(Beta < -PI) Beta += 2*PI;
+ if(Alpha > DEGTORAD(60.0f)) Alpha = DEGTORAD(60.0f);
+ if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f);
+
+ TargetCoors.x = 3.0f * Cos(Alpha) * Cos(Beta) + Source.x;
+ TargetCoors.y = 3.0f * Cos(Alpha) * Sin(Beta) + Source.y;
+ TargetCoors.z = 3.0f * Sin(Alpha) + Source.z;
+ Front = TargetCoors - Source;
+ Front.Normalise();
+ Source += Front*0.4f;
+
+ if(m_bCollisionChecksOn){
+ if(!CWorld::GetIsLineOfSightClear(TargetCoors, Source, true, true, false, true, false, true, true)){
+ RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+ FailedTestTwelveFramesAgo = true;
+ }else{
+ CVector TestPoint;
+ TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta + DEGTORAD(35.0f)) + Source.x;
+ TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta + DEGTORAD(35.0f)) + Source.y;
+ TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z;
+ if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){
+ RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+ FailedTestTwelveFramesAgo = true;
+ }else{
+ TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta - DEGTORAD(35.0f)) + Source.x;
+ TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta - DEGTORAD(35.0f)) + Source.y;
+ TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z;
+ if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){
+ RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+ FailedTestTwelveFramesAgo = true;
+ }else
+ FailedTestTwelveFramesAgo = false;
+ }
+ }
+ }
+
+ if(FailedTestTwelveFramesAgo)
+ RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+ Source -= Front*0.4f;
+
+ GetVectorsReadyForRW();
+ float Rotation = CGeneral::GetATanOfXY(Front.x, Front.y) - HALFPI;
+ ((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Rotation;
+ ((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Rotation;
+}
+
+// Identical to Rocket
+void
+CCam::Process_M16_1stPerson(const CVector &CameraTarget, float, float, float)
+{
+ if(!CamTargetEntity->IsPed())
+ return;
+
+ static bool FailedTestTwelveFramesAgo = false;
+ RwV3d HeadPos;
+ CVector TargetCoors;
+
+ FOV = DefaultFOV;
+ TargetCoors = CameraTarget;
+
+ if(ResetStatics){
+ Beta = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI;
+ Alpha = 0.0f;
+ m_fInitialPlayerOrientation = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI;
+ FailedTestTwelveFramesAgo = false;
+ // static DPadVertical unused
+ // static DPadHorizontal unused
+ m_bCollisionChecksOn = true;
+ ResetStatics = false;
+ }
+
+ ((CPed*)CamTargetEntity)->m_pedIK.GetComponentPosition(&HeadPos, PED_HEAD);
+ Source = HeadPos;
+ Source.z += 0.1f;
+ Source.x -= 0.19f*Cos(m_fInitialPlayerOrientation);
+ Source.y -= 0.19f*Sin(m_fInitialPlayerOrientation);
+
+ // Look around
+ bool UseMouse = false;
+ float MouseX = CPad::GetPad(0)->GetMouseX();
+ float MouseY = CPad::GetPad(0)->GetMouseY();
+ float LookLeftRight, LookUpDown;
+ if(MouseX != 0.0f || MouseY != 0.0f){
+ UseMouse = true;
+ LookLeftRight = -3.0f*MouseX;
+ LookUpDown = 4.0f*MouseY;
+ }else{
+ LookLeftRight = -CPad::GetPad(0)->SniperModeLookLeftRight();
+ LookUpDown = CPad::GetPad(0)->SniperModeLookUpDown();
+ }
+ if(UseMouse){
+ Beta += TheCamera.m_fMouseAccelHorzntl * LookLeftRight * FOV/80.0f;
+ Alpha += TheCamera.m_fMouseAccelVertical * LookUpDown * FOV/80.0f;
+ }else{
+ float xdir = LookLeftRight < 0.0f ? -1.0f : 1.0f;
+ float ydir = LookUpDown < 0.0f ? -1.0f : 1.0f;
+ Beta += SQR(LookLeftRight/100.0f)*xdir/17.5 * FOV/80.0f * CTimer::GetTimeStep();
+ Alpha += SQR(LookUpDown/150.0f)*ydir/14.0f * FOV/80.0f * CTimer::GetTimeStep();
+ }
+ while(Beta >= PI) Beta -= 2*PI;
+ while(Beta < -PI) Beta += 2*PI;
+ if(Alpha > DEGTORAD(60.0f)) Alpha = DEGTORAD(60.0f);
+ if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f);
+
+ TargetCoors.x = 3.0f * Cos(Alpha) * Cos(Beta) + Source.x;
+ TargetCoors.y = 3.0f * Cos(Alpha) * Sin(Beta) + Source.y;
+ TargetCoors.z = 3.0f * Sin(Alpha) + Source.z;
+ Front = TargetCoors - Source;
+ Front.Normalise();
+ Source += Front*0.4f;
+
+ if(m_bCollisionChecksOn){
+ if(!CWorld::GetIsLineOfSightClear(TargetCoors, Source, true, true, false, true, false, true, true)){
+ RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+ FailedTestTwelveFramesAgo = true;
+ }else{
+ CVector TestPoint;
+ TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta + DEGTORAD(35.0f)) + Source.x;
+ TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta + DEGTORAD(35.0f)) + Source.y;
+ TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z;
+ if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){
+ RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+ FailedTestTwelveFramesAgo = true;
+ }else{
+ TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta - DEGTORAD(35.0f)) + Source.x;
+ TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta - DEGTORAD(35.0f)) + Source.y;
+ TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z;
+ if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){
+ RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+ FailedTestTwelveFramesAgo = true;
+ }else
+ FailedTestTwelveFramesAgo = false;
+ }
+ }
+ }
+
+ if(FailedTestTwelveFramesAgo)
+ RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+ Source -= Front*0.4f;
+
+ GetVectorsReadyForRW();
+ float Rotation = CGeneral::GetATanOfXY(Front.x, Front.y) - HALFPI;
+ ((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Rotation;
+ ((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Rotation;
+}
+
+void
+CCam::Process_1stPerson(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+ static float DontLookThroughWorldFixer = 0.0f;
+ CVector TargetCoors;
+
+ FOV = DefaultFOV;
+ TargetCoors = CameraTarget;
+ if(CamTargetEntity->m_rwObject == nil)
+ return;
+
+ if(ResetStatics){
+ Beta = TargetOrientation;
+ Alpha = 0.0f;
+ m_fInitialPlayerOrientation = TargetOrientation;
+ if(CamTargetEntity->IsPed()){
+ Beta = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI;
+ Alpha = 0.0f;
+ m_fInitialPlayerOrientation = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI;
+ }
+ DontLookThroughWorldFixer = 0.0f;
+ }
+
+ if(CamTargetEntity->IsPed()){
+ static bool FailedTestTwelveFramesAgo = false;
+ RwV3d HeadPos;
+
+ TargetCoors = CameraTarget;
+
+ if(ResetStatics){
+ Beta = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI;
+ Alpha = 0.0f;
+ m_fInitialPlayerOrientation = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI;
+ FailedTestTwelveFramesAgo = false;
+ // static DPadVertical unused
+ // static DPadHorizontal unused
+ m_bCollisionChecksOn = true;
+ ResetStatics = false;
+ }
+
+ ((CPed*)CamTargetEntity)->m_pedIK.GetComponentPosition(&HeadPos, PED_HEAD);
+ Source = HeadPos;
+ Source.z += 0.1f;
+ Source.x -= 0.19f*Cos(m_fInitialPlayerOrientation);
+ Source.y -= 0.19f*Sin(m_fInitialPlayerOrientation);
+
+ float LookLeftRight, LookUpDown;
+ LookLeftRight = -CPad::GetPad(0)->LookAroundLeftRight();
+ LookUpDown = CPad::GetPad(0)->LookAroundUpDown();
+ float xdir = LookLeftRight < 0.0f ? -1.0f : 1.0f;
+ float ydir = LookUpDown < 0.0f ? -1.0f : 1.0f;
+ Beta += SQR(LookLeftRight/100.0f)*xdir/17.5 * FOV/80.0f * CTimer::GetTimeStep();
+ Alpha += SQR(LookUpDown/150.0f)*ydir/14.0f * FOV/80.0f * CTimer::GetTimeStep();
+ while(Beta >= PI) Beta -= 2*PI;
+ while(Beta < -PI) Beta += 2*PI;
+ if(Alpha > DEGTORAD(60.0f)) Alpha = DEGTORAD(60.0f);
+ if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f);
+
+ TargetCoors.x = 3.0f * Cos(Alpha) * Cos(Beta) + Source.x;
+ TargetCoors.y = 3.0f * Cos(Alpha) * Sin(Beta) + Source.y;
+ TargetCoors.z = 3.0f * Sin(Alpha) + Source.z;
+ Front = TargetCoors - Source;
+ Front.Normalise();
+ Source += Front*0.4f;
+
+ if(m_bCollisionChecksOn){
+ if(!CWorld::GetIsLineOfSightClear(TargetCoors, Source, true, true, false, true, false, true, true)){
+ RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+ FailedTestTwelveFramesAgo = true;
+ }else{
+ CVector TestPoint;
+ TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta + DEGTORAD(35.0f)) + Source.x;
+ TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta + DEGTORAD(35.0f)) + Source.y;
+ TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z;
+ if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){
+ RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+ FailedTestTwelveFramesAgo = true;
+ }else{
+ TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta - DEGTORAD(35.0f)) + Source.x;
+ TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta - DEGTORAD(35.0f)) + Source.y;
+ TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z;
+ if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){
+ RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+ FailedTestTwelveFramesAgo = true;
+ }else
+ FailedTestTwelveFramesAgo = false;
+ }
+ }
+ }
+
+ if(FailedTestTwelveFramesAgo)
+ RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+ Source -= Front*0.4f;
+
+ GetVectorsReadyForRW();
+ float Rotation = CGeneral::GetATanOfXY(Front.x, Front.y) - HALFPI;
+ ((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Rotation;
+ ((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Rotation;
+ }else{
+ assert(CamTargetEntity->IsVehicle());
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(CamTargetEntity->GetModelIndex());
+ CVector CamPos = mi->m_vehicleType == VEHICLE_TYPE_BOAT ? mi->m_positions[BOAT_POS_FRONTSEAT] : mi->m_positions[CAR_POS_FRONTSEAT];
+ CamPos.x = 0.0f;
+ CamPos.y += -0.08f;
+ CamPos.z += 0.62f;
+ FOV = 60.0f;
+ Source = Multiply3x3(CamTargetEntity->GetMatrix(), CamPos);
+ Source += CamTargetEntity->GetPosition();
+ if(((CVehicle*)CamTargetEntity)->IsBoat())
+ Source.z += 0.5f;
+
+ if(((CVehicle*)CamTargetEntity)->IsUpsideDown()){
+ if(DontLookThroughWorldFixer < 0.5f)
+ DontLookThroughWorldFixer += 0.03f;
+ else
+ DontLookThroughWorldFixer = 0.5f;
+ }else{
+ if(DontLookThroughWorldFixer < 0.0f)
+#ifdef FIX_BUGS
+ DontLookThroughWorldFixer += 0.03f;
+#else
+ DontLookThroughWorldFixer -= 0.03f;
+#endif
+ else
+ DontLookThroughWorldFixer = 0.0f;
+ }
+ Source.z += DontLookThroughWorldFixer;
+ Front = CamTargetEntity->GetForward();
+ Front.Normalise();
+ Up = CamTargetEntity->GetUp();
+ Up.Normalise();
+ CVector Right = CrossProduct(Front, Up);
+ Right.Normalise();
+ Up = CrossProduct(Right, Front);
+ Up.Normalise();
+ }
+
+ ResetStatics = false;
+}
+
+static CVector vecHeadCamOffset(0.06f, 0.05f, 0.0f);
+
+void
+CCam::Process_1rstPersonPedOnPC(const CVector&, float TargetOrientation, float, float)
+{
+ // static int DontLookThroughWorldFixer = 0; // unused
+ static CVector InitialHeadPos;
+
+ if(Mode != MODE_SNIPER_RUNABOUT)
+ FOV = DefaultFOV;
+ TheCamera.m_1rstPersonRunCloseToAWall = false;
+ if(CamTargetEntity->m_rwObject == nil)
+ return;
+
+ if(CamTargetEntity->IsPed()){
+ // static bool FailedTestTwelveFramesAgo = false; // unused
+ RwV3d HeadPos = vecHeadCamOffset;
+ CVector TargetCoors;
+
+ // needs fix for SKINNING
+ RwFrame *frm = ((CPed*)CamTargetEntity)->GetNodeFrame(PED_HEAD);
+ while(frm){
+ RwV3dTransformPoints(&HeadPos, &HeadPos, 1, RwFrameGetMatrix(frm));
+ frm = RwFrameGetParent(frm);
+ if(frm == RpClumpGetFrame(CamTargetEntity->GetClump()))
+ frm = nil;
+ }
+
+ if(ResetStatics){
+ Beta = TargetOrientation;
+ Alpha = 0.0f;
+ m_fInitialPlayerOrientation = TargetOrientation;
+ if(CamTargetEntity->IsPed()){ // useless check
+ Beta = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI;
+ Alpha = 0.0f;
+ m_fInitialPlayerOrientation = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI;
+ // FailedTestTwelveFramesAgo = false;
+ m_bCollisionChecksOn = true;
+ }
+ // DontLookThroughWorldFixer = false;
+ m_vecBufferedPlayerBodyOffset = HeadPos;
+ InitialHeadPos = HeadPos;
+ }
+
+ m_vecBufferedPlayerBodyOffset.y = HeadPos.y;
+
+ if(TheCamera.m_bHeadBob){
+ m_vecBufferedPlayerBodyOffset.x =
+ TheCamera.m_fGaitSwayBuffer * m_vecBufferedPlayerBodyOffset.x +
+ (1.0f-TheCamera.m_fGaitSwayBuffer) * HeadPos.x;
+ m_vecBufferedPlayerBodyOffset.z =
+ TheCamera.m_fGaitSwayBuffer * m_vecBufferedPlayerBodyOffset.z +
+ (1.0f-TheCamera.m_fGaitSwayBuffer) * HeadPos.z;
+ HeadPos = RwV3d(CamTargetEntity->GetMatrix() * m_vecBufferedPlayerBodyOffset);
+ }else{
+ float HeadDelta = (HeadPos - InitialHeadPos).Magnitude2D();
+ CVector Fwd = CamTargetEntity->GetForward();
+ Fwd.z = 0.0f;
+ Fwd.Normalise();
+ HeadPos = RwV3d(HeadDelta*1.23f*Fwd + CamTargetEntity->GetPosition());
+ HeadPos.z += 0.59f;
+ }
+ Source = HeadPos;
+
+ // unused:
+ // ((CPed*)CamTargetEntity)->m_pedIK.GetComponentPosition(&MidPos, PED_MID);
+ // Source - MidPos;
+
+ // Look around
+ bool UseMouse = false;
+ float MouseX = CPad::GetPad(0)->GetMouseX();
+ float MouseY = CPad::GetPad(0)->GetMouseY();
+ float LookLeftRight, LookUpDown;
+ if(MouseX != 0.0f || MouseY != 0.0f){
+ UseMouse = true;
+ LookLeftRight = -3.0f*MouseX;
+ LookUpDown = 4.0f*MouseY;
+ }else{
+ LookLeftRight = -CPad::GetPad(0)->LookAroundLeftRight();
+ LookUpDown = CPad::GetPad(0)->LookAroundUpDown();
+ }
+ if(UseMouse){
+ Beta += TheCamera.m_fMouseAccelHorzntl * LookLeftRight * FOV/80.0f;
+ Alpha += TheCamera.m_fMouseAccelVertical * LookUpDown * FOV/80.0f;
+ }else{
+ float xdir = LookLeftRight < 0.0f ? -1.0f : 1.0f;
+ float ydir = LookUpDown < 0.0f ? -1.0f : 1.0f;
+ Beta += SQR(LookLeftRight/100.0f)*xdir/17.5 * FOV/80.0f * CTimer::GetTimeStep();
+ Alpha += SQR(LookUpDown/150.0f)*ydir/14.0f * FOV/80.0f * CTimer::GetTimeStep();
+ }
+ while(Beta >= PI) Beta -= 2*PI;
+ while(Beta < -PI) Beta += 2*PI;
+ if(Alpha > DEGTORAD(60.0f)) Alpha = DEGTORAD(60.0f);
+ if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f);
+
+ TargetCoors.x = 3.0f * Cos(Alpha) * Cos(Beta) + Source.x;
+ TargetCoors.y = 3.0f * Cos(Alpha) * Sin(Beta) + Source.y;
+ TargetCoors.z = 3.0f * Sin(Alpha) + Source.z;
+ Front = TargetCoors - Source;
+ Front.Normalise();
+ Source += Front*0.4f;
+
+ TheCamera.m_AlphaForPlayerAnim1rstPerson = Alpha;
+
+ GetVectorsReadyForRW();
+
+ float Heading = Front.Heading();
+ ((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Heading;
+ ((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Heading;
+ TheCamera.pTargetEntity->SetHeading(Heading);
+ TheCamera.pTargetEntity->GetMatrix().UpdateRW();
+
+ if(Mode == MODE_SNIPER_RUNABOUT){
+ // no mouse wheel FOV buffering here like in normal sniper mode
+ if(CPad::GetPad(0)->SniperZoomIn() || CPad::GetPad(0)->SniperZoomOut()){
+ if(CPad::GetPad(0)->SniperZoomOut())
+ FOV *= (255.0f*CTimer::GetTimeStep() + 10000.0f) / 10000.0f;
+ else
+ FOV /= (255.0f*CTimer::GetTimeStep() + 10000.0f) / 10000.0f;
+ }
+
+ TheCamera.SetMotionBlur(180, 255, 180, 120, MBLUR_SNIPER);
+
+ if(FOV > DefaultFOV)
+ FOV = DefaultFOV;
+ if(FOV < 15.0f)
+ FOV = 15.0f;
+ }
+ }
+
+ ResetStatics = false;
+ RwCameraSetNearClipPlane(Scene.camera, 0.05f);
+}
+
+void
+CCam::Process_Sniper(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+ if(CamTargetEntity->m_rwObject == nil)
+ return;
+
+#ifdef FIX_BUGS
+ if(!CamTargetEntity->IsPed())
+ return;
+#endif
+
+ static bool FailedTestTwelveFramesAgo = false;
+ RwV3d HeadPos;
+ CVector TargetCoors;
+ TargetCoors = CameraTarget;
+
+ static float TargetFOV = 0.0f;
+
+ if(ResetStatics){
+ Beta = TargetOrientation;
+ Alpha = 0.0f;
+ m_fInitialPlayerOrientation = TargetOrientation;
+ FailedTestTwelveFramesAgo = false;
+ // static DPadVertical unused
+ // static DPadHorizontal unused
+ m_bCollisionChecksOn = true;
+ FOVSpeed = 0.0f;
+ TargetFOV = FOV;
+ ResetStatics = false;
+ }
+
+ ((CPed*)CamTargetEntity)->m_pedIK.GetComponentPosition(&HeadPos, PED_HEAD);
+ Source = HeadPos;
+ Source.z += 0.1f;
+ Source.x -= 0.19f*Cos(m_fInitialPlayerOrientation);
+ Source.y -= 0.19f*Sin(m_fInitialPlayerOrientation);
+
+ // Look around
+ bool UseMouse = false;
+ float MouseX = CPad::GetPad(0)->GetMouseX();
+ float MouseY = CPad::GetPad(0)->GetMouseY();
+ float LookLeftRight, LookUpDown;
+ if(MouseX != 0.0f || MouseY != 0.0f){
+ UseMouse = true;
+ LookLeftRight = -3.0f*MouseX;
+ LookUpDown = 4.0f*MouseY;
+ }else{
+ LookLeftRight = -CPad::GetPad(0)->SniperModeLookLeftRight();
+ LookUpDown = CPad::GetPad(0)->SniperModeLookUpDown();
+ }
+ if(UseMouse){
+ Beta += TheCamera.m_fMouseAccelHorzntl * LookLeftRight * FOV/80.0f;
+ Alpha += TheCamera.m_fMouseAccelVertical * LookUpDown * FOV/80.0f;
+ }else{
+ float xdir = LookLeftRight < 0.0f ? -1.0f : 1.0f;
+ float ydir = LookUpDown < 0.0f ? -1.0f : 1.0f;
+ Beta += SQR(LookLeftRight/100.0f)*xdir/17.5 * FOV/80.0f * CTimer::GetTimeStep();
+ Alpha += SQR(LookUpDown/150.0f)*ydir/14.0f * FOV/80.0f * CTimer::GetTimeStep();
+ }
+ while(Beta >= PI) Beta -= 2*PI;
+ while(Beta < -PI) Beta += 2*PI;
+ if(Alpha > DEGTORAD(60.0f)) Alpha = DEGTORAD(60.0f);
+ if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f);
+
+ TargetCoors.x = 3.0f * Cos(Alpha) * Cos(Beta) + Source.x;
+ TargetCoors.y = 3.0f * Cos(Alpha) * Sin(Beta) + Source.y;
+ TargetCoors.z = 3.0f * Sin(Alpha) + Source.z;
+
+ UseMouse = false;
+ int ZoomInButton = ControlsManager.GetMouseButtonAssociatedWithAction(PED_SNIPER_ZOOM_IN);
+ int ZoomOutButton = ControlsManager.GetMouseButtonAssociatedWithAction(PED_SNIPER_ZOOM_OUT);
+ // TODO: enum? this should be mouse wheel up and down
+ if(ZoomInButton == 4 || ZoomInButton == 5 || ZoomOutButton == 4 || ZoomOutButton == 5){
+ if(CPad::GetPad(0)->GetMouseWheelUp() || CPad::GetPad(0)->GetMouseWheelDown()){
+ if(CPad::GetPad(0)->SniperZoomIn()){
+ TargetFOV = FOV - 10.0f;
+ UseMouse = true;
+ }
+ if(CPad::GetPad(0)->SniperZoomOut()){
+ TargetFOV = FOV + 10.0f;
+ UseMouse = true;
+ }
+ }
+ }
+ if((CPad::GetPad(0)->SniperZoomIn() || CPad::GetPad(0)->SniperZoomOut()) && !UseMouse){
+ if(CPad::GetPad(0)->SniperZoomOut()){
+ FOV *= (255.0f*CTimer::GetTimeStep() + 10000.0f) / 10000.0f;
+ TargetFOV = FOV;
+ FOVSpeed = 0.0f;
+ }else{
+ FOV /= (255.0f*CTimer::GetTimeStep() + 10000.0f) / 10000.0f;
+ TargetFOV = FOV;
+ FOVSpeed = 0.0f;
+ }
+ }else{
+ if(Abs(TargetFOV - FOV) > 0.5f)
+ WellBufferMe(TargetFOV, &FOV, &FOVSpeed, 0.5f, 0.25f, false);
+ else
+ FOVSpeed = 0.0f;
+ }
+
+ TheCamera.SetMotionBlur(180, 255, 180, 120, MBLUR_SNIPER);
+
+ if(FOV > DefaultFOV)
+ FOV = DefaultFOV;
+ if(FOV < 15.0f)
+ FOV = 15.0f;
+
+ Front = TargetCoors - Source;
+ Front.Normalise();
+ Source += Front*0.4f;
+
+ if(m_bCollisionChecksOn){
+ if(!CWorld::GetIsLineOfSightClear(TargetCoors, Source, true, true, false, true, false, true, true)){
+ RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+ FailedTestTwelveFramesAgo = true;
+ }else{
+ CVector TestPoint;
+ TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta + DEGTORAD(35.0f)) + Source.x;
+ TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta + DEGTORAD(35.0f)) + Source.y;
+ TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z;
+ if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){
+ RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+ FailedTestTwelveFramesAgo = true;
+ }else{
+ TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta - DEGTORAD(35.0f)) + Source.x;
+ TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta - DEGTORAD(35.0f)) + Source.y;
+ TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z;
+ if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){
+ RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+ FailedTestTwelveFramesAgo = true;
+ }else
+ FailedTestTwelveFramesAgo = false;
+ }
+ }
+ }
+
+ if(FailedTestTwelveFramesAgo)
+ RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+ Source -= Front*0.4f;
+
+ GetVectorsReadyForRW();
+ float Rotation = CGeneral::GetATanOfXY(Front.x, Front.y) - HALFPI;
+ ((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Rotation;
+ ((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Rotation;
+}
+
+void
+CCam::Process_Syphon(const CVector &CameraTarget, float, float, float)
+{
+ FOV = DefaultFOV;
+
+ if(!CamTargetEntity->IsPed())
+ return;
+
+ static bool CameraObscured = false;
+ // unused FailedClippingTestPrevously
+ static float BetaOffset = DEGTORAD(18.0f);
+ // unused AngleToGoTo
+ // unused AngleToGoToSpeed
+ // unused DistBetweenPedAndPlayerPreviouslyOn
+ static float HeightDown = -0.5f;
+ static float PreviousDistForInter;
+ CVector TargetCoors;
+ CVector2D vDist;
+ float fDist, fAimingDist;
+ float TargetAlpha;
+ CColPoint colPoint;
+ CEntity *entity;
+
+ TargetCoors = CameraTarget;
+
+ if(TheCamera.Cams[TheCamera.ActiveCam].Mode != MODE_SYPHON)
+ return;
+
+ vDist = Source - TargetCoors;
+ fDist = vDist.Magnitude();
+ if(fDist == 0.0f)
+ Source = TargetCoors + CVector(1.0f, 1.0f, 0.0f);
+ else
+ Source = TargetCoors + CVector(vDist.x/fDist * 1.7f, vDist.y/fDist * 1.7f, 0.0f);
+ if(fDist > 1.7f)
+ fDist = 1.7f;
+
+ Beta = CGeneral::GetATanOfXY(Source.x - TargetCoors.x, Source.y - TargetCoors.y);
+ while(Beta >= PI) Beta -= 2*PI;
+ while(Beta < -PI) Beta += 2*PI;
+
+ float NewBeta = CGeneral::GetATanOfXY(TheCamera.m_cvecAimingTargetCoors.x - TargetCoors.x, TheCamera.m_cvecAimingTargetCoors.y - TargetCoors.y) + PI;
+ if(ResetStatics){
+ CameraObscured = false;
+ float TestBeta1 = NewBeta - BetaOffset - Beta;
+ float TestBeta2 = NewBeta + BetaOffset - Beta;
+ MakeAngleLessThan180(TestBeta1);
+ MakeAngleLessThan180(TestBeta2);
+ if(Abs(TestBeta1) < Abs(TestBeta2))
+ BetaOffset = -BetaOffset;
+ // some unuseds
+ ResetStatics = false;
+ }
+ Beta = NewBeta + BetaOffset;
+ Source = TargetCoors;
+ Source.x += 1.7f*Cos(Beta);
+ Source.y += 1.7f*Sin(Beta);
+ TargetCoors.z += m_fSyphonModeTargetZOffSet;
+ fAimingDist = (TheCamera.m_cvecAimingTargetCoors - TargetCoors).Magnitude2D();
+ if(fAimingDist < 6.5f)
+ fAimingDist = 6.5f;
+ TargetAlpha = CGeneral::GetATanOfXY(fAimingDist, TheCamera.m_cvecAimingTargetCoors.z - TargetCoors.z);
+ while(TargetAlpha >= PI) TargetAlpha -= 2*PI;
+ while(TargetAlpha < -PI) TargetAlpha += 2*PI;
+
+ // inlined
+ WellBufferMe(-TargetAlpha, &Alpha, &AlphaSpeed, 0.07f, 0.015f, true);
+
+ Source.z += fDist*Sin(Alpha) + fDist*0.2f;
+ if(Source.z < TargetCoors.z + HeightDown)
+ Source.z = TargetCoors.z + HeightDown;
+
+ CameraObscured = CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, true, false, false, true, false, true, true);
+ // PreviousDistForInter unused
+ if(CameraObscured){
+ PreviousDistForInter = (TargetCoors - colPoint.point).Magnitude2D();
+ Source = colPoint.point;
+ }else
+ PreviousDistForInter = 1.7f;
+
+ m_cvecTargetCoorsForFudgeInter = TargetCoors;
+ Front = TargetCoors - Source;
+ m_fMinDistAwayFromCamWhenInterPolating = Front.Magnitude2D();
+ if(m_fMinDistAwayFromCamWhenInterPolating < 1.1f)
+ RwCameraSetNearClipPlane(Scene.camera, max(m_fMinDistAwayFromCamWhenInterPolating - 0.35f, 0.05f));
+ Front.Normalise();
+ GetVectorsReadyForRW();
+}
+
+void
+CCam::Process_Syphon_Crim_In_Front(const CVector &CameraTarget, float, float, float)
+{
+ FOV = DefaultFOV;
+
+ if(!CamTargetEntity->IsPed())
+ return;
+
+ CVector TargetCoors = CameraTarget;
+ CVector vDist;
+ float fDist, TargetDist;
+ float zOffset;
+ float AimingAngle;
+ CColPoint colPoint;
+ CEntity *entity;
+
+ TargetDist = TheCamera.m_fPedZoomValueSmooth * 0.5f + 4.0f;
+ vDist = Source - TargetCoors;
+ fDist = vDist.Magnitude2D();
+ zOffset = TargetDist - 2.65f;
+ if(zOffset < 0.0f)
+ zOffset = 0.0f;
+ if(zOffset == 0.0f)
+ Source = TargetCoors + CVector(1.0f, 1.0f, zOffset);
+ else
+ Source = TargetCoors + CVector(vDist.x/fDist*TargetDist, vDist.y/fDist*TargetDist, zOffset);
+
+ AimingAngle = CGeneral::GetATanOfXY(TheCamera.m_cvecAimingTargetCoors.x - TargetCoors.x, TheCamera.m_cvecAimingTargetCoors.y - TargetCoors.y);
+ while(AimingAngle >= PI) AimingAngle -= 2*PI;
+ while(AimingAngle < -PI) AimingAngle += 2*PI;
+
+ if(TheCamera.PlayerWeaponMode.Mode == MODE_SYPHON)
+ Beta = AimingAngle + m_fPlayerInFrontSyphonAngleOffSet;
+
+ Source.x = TargetCoors.x;
+ Source.y = TargetCoors.y;
+ Source.x += Cos(Beta) * TargetDist;
+ Source.y += Sin(Beta) * TargetDist;
+
+ if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, true, false, false, true, false, true, true)){
+ Beta = CGeneral::GetATanOfXY(Source.x - TargetCoors.x, Source.y - TargetCoors.y);
+ fDist = (TargetCoors - colPoint.point).Magnitude2D();
+ Source.x = TargetCoors.x;
+ Source.y = TargetCoors.y;
+ Source.x += Cos(Beta) * fDist;
+ Source.y += Sin(Beta) * fDist;
+ }
+
+ TargetCoors = CameraTarget;
+ TargetCoors.z += m_fSyphonModeTargetZOffSet;
+ m_cvecTargetCoorsForFudgeInter = TargetCoors;
+ Front = TargetCoors - Source;
+ GetVectorsReadyForRW();
+}
+
+void
+CCam::Process_BehindBoat(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+ if(!CamTargetEntity->IsVehicle()){
+ ResetStatics = false;
+ return;
+ }
+
+ CVector TargetCoors = CameraTarget;
+ float DeltaBeta = 0.0f;
+ static CColPoint colPoint;
+ CEntity *entity;
+ static float TargetWhenChecksWereOn = 0.0f;
+ static float CenterObscuredWhenChecksWereOn = 0.0f;
+ static float WaterZAddition = 2.75f;
+ float WaterLevel = 0.0f;
+ float s, c;
+
+ Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y);
+ FOV = DefaultFOV;
+
+ if(ResetStatics){
+ CenterObscuredWhenChecksWereOn = 0.0f;
+ TargetWhenChecksWereOn = 0.0f;
+ Beta = TargetOrientation + PI;
+ }
+
+ CWaterLevel::GetWaterLevelNoWaves(TargetCoors.x, TargetCoors.y, TargetCoors.z, &WaterLevel);
+ WaterLevel += WaterZAddition;
+ static float FixerForGoingBelowGround = 0.4f;
+ if(-FixerForGoingBelowGround < TargetCoors.z-WaterLevel)
+ WaterLevel += TargetCoors.z-WaterLevel - FixerForGoingBelowGround;
+
+ bool Obscured;
+ if(m_bCollisionChecksOn || ResetStatics){
+ CVector TestPoint;
+ // Weird calculations here, also casting bool to float...
+ c = Cos(TargetOrientation);
+ s = Sin(TargetOrientation);
+ TestPoint = TheCamera.CarZoomValueSmooth * CVector(-c, -s, 0.0f) +
+ (TheCamera.CarZoomValueSmooth+7.0f) * CVector(-c, -s, 0.0f) +
+ TargetCoors;
+ TestPoint.z = WaterLevel + TheCamera.CarZoomValueSmooth;
+ float Test1 = CWorld::GetIsLineOfSightClear(TestPoint, TargetCoors, true, false, false, true, false, true, true);
+
+ c = Cos(TargetOrientation + 0.8f);
+ s = Sin(TargetOrientation + DEGTORAD(40.0f));
+ TestPoint = TheCamera.CarZoomValueSmooth * CVector(-c, -s, 0.0f) +
+ (TheCamera.CarZoomValueSmooth+7.0f) * CVector(-c, -s, 0.0f) +
+ TargetCoors;
+ TestPoint.z = WaterLevel + TheCamera.CarZoomValueSmooth;
+ float Test2 = CWorld::GetIsLineOfSightClear(TestPoint, TargetCoors, true, false, false, true, false, true, true);
+
+ c = Cos(TargetOrientation - 0.8);
+ s = Sin(TargetOrientation - DEGTORAD(40.0f));
+ TestPoint = TheCamera.CarZoomValueSmooth * CVector(-c, -s, 0.0f) +
+ (TheCamera.CarZoomValueSmooth+7.0f) * CVector(-c, -s, 0.0f) +
+ TargetCoors;
+ TestPoint.z = WaterLevel + TheCamera.CarZoomValueSmooth;
+ float Test3 = CWorld::GetIsLineOfSightClear(TestPoint, TargetCoors, true, false, false, true, false, true, true);
+
+ if(Test2 == 0.0f){
+ DeltaBeta = TargetOrientation - Beta - DEGTORAD(40.0f);
+ if(ResetStatics)
+ Beta = TargetOrientation - DEGTORAD(40.0f);
+ }else if(Test3 == 0.0f){
+ DeltaBeta = TargetOrientation - Beta + DEGTORAD(40.0f);
+ if(ResetStatics)
+ Beta = TargetOrientation + DEGTORAD(40.0f);
+ }else if(Test1 == 0.0f){
+ DeltaBeta = 0.0f;
+ }else if(Test2 != 0.0f && Test3 != 0.0f && Test1 != 0.0f){
+ if(ResetStatics)
+ Beta = TargetOrientation;
+ DeltaBeta = TargetOrientation - Beta;
+ }
+
+ c = Cos(Beta);
+ s = Sin(Beta);
+ TestPoint.x = TheCamera.CarZoomValueSmooth * -c +
+ (TheCamera.CarZoomValueSmooth + 7.0f) * -c +
+ TargetCoors.x;
+ TestPoint.y = TheCamera.CarZoomValueSmooth * -s +
+ (TheCamera.CarZoomValueSmooth + 7.0f) * -s +
+ TargetCoors.y;
+ TestPoint.z = WaterLevel + TheCamera.CarZoomValueSmooth;
+ Obscured = CWorld::ProcessLineOfSight(TestPoint, TargetCoors, colPoint, entity, true, false, false, true, false, true, true);
+ CenterObscuredWhenChecksWereOn = Obscured;
+
+ // now DeltaBeta == TargetWhenChecksWereOn - Beta, which we need for WellBufferMe below
+ TargetWhenChecksWereOn = DeltaBeta + Beta;
+ }else{
+ // DeltaBeta = TargetWhenChecksWereOn - Beta; // unneeded since we don't inline WellBufferMe
+ Obscured = CenterObscuredWhenChecksWereOn != 0.0f;
+ }
+
+ if(Obscured){
+ CWorld::ProcessLineOfSight(Source, TargetCoors, colPoint, entity, true, false, false, true, false, true, true);
+ Source = colPoint.point;
+ }else{
+ // inlined
+ WellBufferMe(TargetWhenChecksWereOn, &Beta, &BetaSpeed, 0.07f, 0.015f, true);
+
+ s = Sin(Beta);
+ c = Cos(Beta);
+ Source = TheCamera.CarZoomValueSmooth * CVector(-c, -s, 0.0f) +
+ (TheCamera.CarZoomValueSmooth+7.0f) * CVector(-c, -s, 0.0f) +
+ TargetCoors;
+ Source.z = WaterLevel + TheCamera.CarZoomValueSmooth;
+ }
+
+ if(TheCamera.CarZoomValueSmooth < 0.05f){
+ static float AmountUp = 2.2f;
+ TargetCoors.z += AmountUp * (0.0f - TheCamera.CarZoomValueSmooth);
+ }
+ TargetCoors.z += TheCamera.CarZoomValueSmooth + 0.5f;
+ m_cvecTargetCoorsForFudgeInter = TargetCoors;
+ Front = TargetCoors - Source;
+ GetVectorsReadyForRW();
+ ResetStatics = false;
+}
+
+void
+CCam::Process_Fight_Cam(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+ if(!CamTargetEntity->IsPed())
+ return;
+
+ FOV = DefaultFOV;
+ float BetaLeft, BetaRight, DeltaBetaLeft, DeltaBetaRight;
+ float BetaFix;
+ float Dist;
+ float BetaMaxSpeed = 0.015f;
+ float BetaAcceleration = 0.007f;
+ static bool PreviouslyFailedBuildingChecks = false;
+ float TargetCamHeight;
+ CVector TargetCoors;
+
+ m_fMinDistAwayFromCamWhenInterPolating = 4.0f;
+ Front = Source - CameraTarget;
+ Beta = CGeneral::GetATanOfXY(Front.x, Front.y);
+ while(TargetOrientation >= PI) TargetOrientation -= 2*PI;
+ while(TargetOrientation < -PI) TargetOrientation += 2*PI;
+ while(Beta >= PI) Beta -= 2*PI;
+ while(Beta < -PI) Beta += 2*PI;
+
+ // Figure out Beta
+ BetaLeft = TargetOrientation - HALFPI;
+ BetaRight = TargetOrientation + HALFPI;
+ DeltaBetaLeft = Beta - BetaLeft;
+ DeltaBetaRight = Beta - BetaRight;
+ while(DeltaBetaLeft >= PI) DeltaBetaLeft -= 2*PI;
+ while(DeltaBetaLeft < -PI) DeltaBetaLeft += 2*PI;
+ while(DeltaBetaRight >= PI) DeltaBetaRight -= 2*PI;
+ while(DeltaBetaRight < -PI) DeltaBetaRight += 2*PI;
+
+ if(ResetStatics){
+ if(Abs(DeltaBetaLeft) < Abs(DeltaBetaRight))
+ m_fTargetBeta = DeltaBetaLeft;
+ else
+ m_fTargetBeta = DeltaBetaRight;
+ m_fBufferedTargetOrientation = TargetOrientation;
+ m_fBufferedTargetOrientationSpeed = 0.0f;
+ m_bCollisionChecksOn = true;
+ BetaSpeed = 0.0f;
+ }else if(CPad::GetPad(0)->WeaponJustDown()){
+ if(Abs(DeltaBetaLeft) < Abs(DeltaBetaRight))
+ m_fTargetBeta = DeltaBetaLeft;
+ else
+ m_fTargetBeta = DeltaBetaRight;
+ }
+
+ // Check collisions
+ BetaFix = 0.0f;
+ Dist = Front.Magnitude2D();
+ if(m_bCollisionChecksOn || PreviouslyFailedBuildingChecks){
+ BetaFix = GetPedBetaAngleForClearView(CameraTarget, Dist+0.25f, 0.0f, true, false, false, true, false);
+ if(BetaFix == 0.0f){
+ BetaFix = GetPedBetaAngleForClearView(CameraTarget, Dist+0.5f, DEGTORAD(24.0f), true, false, false, true, false);
+ if(BetaFix == 0.0f)
+ BetaFix = GetPedBetaAngleForClearView(CameraTarget, Dist+0.5f, -DEGTORAD(24.0f), true, false, false, true, false);
+ }
+ }
+ if(BetaFix != 0.0f){
+ BetaMaxSpeed = 0.1f;
+ PreviouslyFailedBuildingChecks = true;
+ BetaAcceleration = 0.025f;
+ m_fTargetBeta = Beta + BetaFix;
+ }
+ WellBufferMe(m_fTargetBeta, &Beta, &BetaSpeed, BetaMaxSpeed, BetaAcceleration, true);
+
+ Source = CameraTarget + 4.0f*CVector(Cos(Beta), Sin(Beta), 0.0f);
+ Source.z -= 0.5f;
+
+ WellBufferMe(TargetOrientation, &m_fBufferedTargetOrientation, &m_fBufferedTargetOrientationSpeed, 0.07f, 0.004f, true);
+ TargetCoors = CameraTarget + 0.5f*CVector(Cos(m_fBufferedTargetOrientation), Sin(m_fBufferedTargetOrientation), 0.0f);
+
+ TargetCamHeight = CameraTarget.z - Source.z + max(m_fPedBetweenCameraHeightOffset, m_fRoadOffSet + m_fDimensionOfHighestNearCar) - 0.5f;
+ if(TargetCamHeight > m_fCamBufferedHeight)
+ WellBufferMe(TargetCamHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.15f, 0.04f, false);
+ else
+ WellBufferMe(0.0f, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.08f, 0.0175f, false);
+ Source.z += m_fCamBufferedHeight;
+
+ m_cvecTargetCoorsForFudgeInter = TargetCoors;
+ Front = TargetCoors - Source;
+ Front.Normalise();
+ GetVectorsReadyForRW();
+
+ ResetStatics = false;
+}
+
+/*
+// Spline format is this, but game doesn't seem to use any kind of struct:
+struct Spline
+{
+ float numFrames;
+ struct {
+ float time;
+ float f[3]; // CVector for Vector spline
+ } frames[1]; // numFrames
+};
+*/
+
+// These two functions are pretty ugly
+
+#define MS(t) (uint32)((t)*1000.0f)
+
+void
+FindSplinePathPositionFloat(float *out, float *spline, uint32 time, uint32 &marker)
+{
+ // marker is at time
+ uint32 numFrames = spline[0];
+ uint32 timeDelta = MS(spline[marker] - spline[marker-4]);
+ uint32 endTime = MS(spline[4*(numFrames-1) + 1]);
+ if(time < endTime){
+ bool canAdvance = true;
+ if((marker-1)/4 > numFrames){
+ canAdvance = false;
+ marker = 4*(numFrames-1) + 1;
+ }
+ // skipping over small time deltas apparently?
+ while(timeDelta <= 75 && canAdvance){
+ marker += 4;
+ if((marker-1)/4 > numFrames){
+ canAdvance = false;
+ marker = 4*(numFrames-1) + 1;
+ }
+ timeDelta = (spline[marker] - spline[marker-4]) * 1000.0f;
+ }
+ }
+ float a = ((float)time - (float)MS(spline[marker-4])) / (float)MS(spline[marker] - spline[marker-4]);
+ a = clamp(a, 0.0f, 1.0f);
+ float b = 1.0f - a;
+ *out = b*b*b * spline[marker-3] +
+ 3.0f*a*b*b * spline[marker-1] +
+ 3.0f*a*a*b * spline[marker+2] +
+ a*a*a * spline[marker+1];
+}
+
+void
+FindSplinePathPositionVector(CVector *out, float *spline, uint32 time, uint32 &marker)
+{
+ // marker is at time
+ uint32 numFrames = spline[0];
+ uint32 timeDelta = MS(spline[marker] - spline[marker-10]);
+ uint32 endTime = MS(spline[10*(numFrames-1) + 1]);
+ if(time < endTime){
+ bool canAdvance = true;
+ if((marker-1)/10 > numFrames){
+ canAdvance = false;
+ marker = 10*(numFrames-1) + 1;
+ }
+ // skipping over small time deltas apparently?
+ while(timeDelta <= 75 && canAdvance){
+ marker += 10;
+ if((marker-1)/10 > numFrames){
+ canAdvance = false;
+ marker = 10*(numFrames-1) + 1;
+ }
+ timeDelta = (spline[marker] - spline[marker-10]) * 1000.0f;
+ }
+ }
+
+ if((marker-1)/10 > numFrames){
+ printf("Arraymarker %i \n", marker);
+ printf("Path zero %i \n", numFrames);
+ }
+
+ float a = ((float)time - (float)MS(spline[marker-10])) / (float)MS(spline[marker] - spline[marker-10]);
+ a = clamp(a, 0.0f, 1.0f);
+ float b = 1.0f - a;
+ out->x =
+ b*b*b * spline[marker-9] +
+ 3.0f*a*b*b * spline[marker-3] +
+ 3.0f*a*a*b * spline[marker+4] +
+ a*a*a * spline[marker+1];
+ out->y =
+ b*b*b * spline[marker-8] +
+ 3.0f*a*b*b * spline[marker-2] +
+ 3.0f*a*a*b * spline[marker+5] +
+ a*a*a * spline[marker+2];
+ out->z =
+ b*b*b * spline[marker-7] +
+ 3.0f*a*b*b * spline[marker-1] +
+ 3.0f*a*a*b * spline[marker+6] +
+ a*a*a * spline[marker+3];
+ *out += TheCamera.m_vecCutSceneOffset;
+}
+
+void
+CCam::Process_FlyBy(const CVector&, float, float, float)
+{
+ float UpAngle = 0.0f;
+ static float FirstFOVValue = 0.0f;
+ static float PsuedoFOV;
+ static uint32 ArrayMarkerFOV;
+ static uint32 ArrayMarkerUp;
+ static uint32 ArrayMarkerSource;
+ static uint32 ArrayMarkerFront;
+
+ if(TheCamera.m_bcutsceneFinished)
+ return;
+
+ Up = CVector(0.0f, 0.0f, 1.0f);
+ if(TheCamera.m_bStartingSpline)
+ m_fTimeElapsedFloat += CTimer::GetTimeStepInMilliseconds();
+ else{
+ m_fTimeElapsedFloat = 0.0f;
+ m_uiFinishTime = MS(TheCamera.m_arrPathArray[2].m_arr_PathData[10*((int)TheCamera.m_arrPathArray[2].m_arr_PathData[0]-1) + 1]);
+ TheCamera.m_bStartingSpline = true;
+ FirstFOVValue = TheCamera.m_arrPathArray[0].m_arr_PathData[2];
+ PsuedoFOV = TheCamera.m_arrPathArray[0].m_arr_PathData[2];
+ ArrayMarkerFOV = 5;
+ ArrayMarkerUp = 5;
+ ArrayMarkerSource = 11;
+ ArrayMarkerFront = 11;
+ }
+
+ float fTime = m_fTimeElapsedFloat;
+ uint32 uiFinishTime = m_uiFinishTime;
+ uint32 uiTime = fTime;
+ if(uiTime < uiFinishTime){
+ TheCamera.m_fPositionAlongSpline = (float) uiTime / uiFinishTime;
+
+ while(uiTime >= (TheCamera.m_arrPathArray[2].m_arr_PathData[ArrayMarkerSource] - TheCamera.m_arrPathArray[2].m_arr_PathData[1])*1000.0f)
+ ArrayMarkerSource += 10;
+ FindSplinePathPositionVector(&Source, TheCamera.m_arrPathArray[2].m_arr_PathData, uiTime, ArrayMarkerSource);
+
+ while(uiTime >= (TheCamera.m_arrPathArray[3].m_arr_PathData[ArrayMarkerFront] - TheCamera.m_arrPathArray[3].m_arr_PathData[1])*1000.0f)
+ ArrayMarkerFront += 10;
+ FindSplinePathPositionVector(&Front, TheCamera.m_arrPathArray[3].m_arr_PathData, uiTime, ArrayMarkerFront);
+
+ while(uiTime >= (TheCamera.m_arrPathArray[1].m_arr_PathData[ArrayMarkerUp] - TheCamera.m_arrPathArray[1].m_arr_PathData[1])*1000.0f)
+ ArrayMarkerUp += 4;
+ FindSplinePathPositionFloat(&UpAngle, TheCamera.m_arrPathArray[1].m_arr_PathData, uiTime, ArrayMarkerUp);
+ UpAngle = DEGTORAD(UpAngle) + HALFPI;
+ Up.x = Cos(UpAngle);
+ Up.z = Sin(UpAngle);
+
+ while(uiTime >= (TheCamera.m_arrPathArray[0].m_arr_PathData[ArrayMarkerFOV] - TheCamera.m_arrPathArray[0].m_arr_PathData[1])*1000.0f)
+ ArrayMarkerFOV += 4;
+ FindSplinePathPositionFloat(&PsuedoFOV, TheCamera.m_arrPathArray[0].m_arr_PathData, uiTime, ArrayMarkerFOV);
+
+ m_cvecTargetCoorsForFudgeInter = Front;
+ Front = Front - Source;
+ Front.Normalise();
+ CVector Left = CrossProduct(Up, Front);
+ Up = CrossProduct(Front, Left);
+ Up.Normalise();
+ FOV = PsuedoFOV;
+ }else{
+ // end
+ ArrayMarkerSource = (TheCamera.m_arrPathArray[2].m_arr_PathData[0] - 1)*10 + 1;
+ ArrayMarkerFront = (TheCamera.m_arrPathArray[3].m_arr_PathData[0] - 1)*10 + 1;
+ ArrayMarkerUp = (TheCamera.m_arrPathArray[1].m_arr_PathData[0] - 1)*4 + 1;
+ ArrayMarkerFOV = (TheCamera.m_arrPathArray[0].m_arr_PathData[0] - 1)*4 + 1;
+
+ FindSplinePathPositionVector(&Source, TheCamera.m_arrPathArray[2].m_arr_PathData, uiTime, ArrayMarkerSource);
+ FindSplinePathPositionVector(&Front, TheCamera.m_arrPathArray[3].m_arr_PathData, uiTime, ArrayMarkerFront);
+ FindSplinePathPositionFloat(&UpAngle, TheCamera.m_arrPathArray[1].m_arr_PathData, uiTime, ArrayMarkerUp);
+ UpAngle = DEGTORAD(UpAngle) + HALFPI;
+ Up.x = Cos(UpAngle);
+ Up.z = Sin(UpAngle);
+ FindSplinePathPositionFloat(&PsuedoFOV, TheCamera.m_arrPathArray[0].m_arr_PathData, uiTime, ArrayMarkerFOV);
+
+ TheCamera.m_fPositionAlongSpline = 1.0f;
+ ArrayMarkerFOV = 0;
+ ArrayMarkerUp = 0;
+ ArrayMarkerSource = 0;
+ ArrayMarkerFront = 0;
+
+ m_cvecTargetCoorsForFudgeInter = Front;
+ Front = Front - Source;
+ Front.Normalise();
+ CVector Left = CrossProduct(Up, Front);
+ Up = CrossProduct(Front, Left);
+ Up.Normalise();
+ FOV = PsuedoFOV;
+ }
+}
+
+void
+CCam::Process_WheelCam(const CVector&, float, float, float)
+{
+ FOV = DefaultFOV;
+
+ if(CamTargetEntity->IsPed()){
+ // what? ped with wheels or what?
+ Source = Multiply3x3(CamTargetEntity->GetMatrix(), CVector(-0.3f, -0.5f, 0.1f));
+ Source += CamTargetEntity->GetPosition();
+ Front = CVector(1.0f, 0.0f, 0.0f);
+ }else{
+ Source = Multiply3x3(CamTargetEntity->GetMatrix(), CVector(-1.4f, -2.3f, 0.3f));
+ Source += CamTargetEntity->GetPosition();
+ Front = CamTargetEntity->GetForward();
+ }
+
+ CVector NewUp(0.0f, 0.0f, 1.0f);
+ CVector Left = CrossProduct(Front, NewUp);
+ Left.Normalise();
+ NewUp = CrossProduct(Left, Front);
+
+ float Roll = Cos((CTimer::GetTimeInMilliseconds()&0x1FFFF)/(float)0x1FFFF * TWOPI);
+ Up = Cos(Roll*0.4f)*NewUp + Sin(Roll*0.4f)*Left;
+}
+
+void
+CCam::Process_Fixed(const CVector &CameraTarget, float, float, float)
+{
+ Source = m_cvecCamFixedModeSource;
+ Front = CameraTarget - Source;
+ m_cvecTargetCoorsForFudgeInter = CameraTarget;
+ GetVectorsReadyForRW();
+
+ Up = CVector(0.0f, 0.0f, 1.0f) + m_cvecCamFixedModeUpOffSet;
+ Up.Normalise();
+ CVector Right = CrossProduct(Front, Up);
+ Right.Normalise();
+ Up = CrossProduct(Right, Front);
+
+ FOV = DefaultFOV;
+ if(TheCamera.m_bUseSpecialFovTrain)
+ FOV = TheCamera.m_fFovForTrain;
+
+ if(CMenuManager::m_ControlMethod == 0 && Using3rdPersonMouseCam()){
+ CPed *player = FindPlayerPed();
+ if(player && player->CanStrafeOrMouseControl()){
+ float Heading = Front.Heading();
+ ((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Heading;
+ ((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Heading;
+ TheCamera.pTargetEntity->SetHeading(Heading);
+ TheCamera.pTargetEntity->GetMatrix().UpdateRW();
+ }
+ }
+}
+
+void
+CCam::Process_Player_Fallen_Water(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+ CColPoint colPoint;
+ CEntity *entity = nil;
+
+ FOV = DefaultFOV;
+ Source = CameraTarget;
+ Source.x += -4.5f*Cos(TargetOrientation);
+ Source.y += -4.5f*Sin(TargetOrientation);
+ Source.z = m_vecLastAboveWaterCamPosition.z + 4.0f;
+
+ m_cvecTargetCoorsForFudgeInter = CameraTarget;
+ Front = CameraTarget - Source;
+ Front.Normalise();
+ if(CWorld::ProcessLineOfSight(CameraTarget, Source, colPoint, entity, true, false, false, true, false, true, true))
+ Source = colPoint.point;
+ GetVectorsReadyForRW();
+ Front = CameraTarget - Source;
+ Front.Normalise();
+}
+
+// unused
+void
+CCam::Process_Circle(const CVector &CameraTarget, float, float, float)
+{
+ FOV = DefaultFOV;
+
+ Front.x = Cos(0.7f) * Cos((CTimer::GetTimeInMilliseconds()&0xFFF)/(float)0xFFF * TWOPI);
+ Front.y = Cos(0.7f) * Sin((CTimer::GetTimeInMilliseconds()&0xFFF)/(float)0xFFF * TWOPI);
+ Front.z = -Sin(0.7f);
+ Source = CameraTarget - 4.0f*Front;
+ Source.z += 1.0f;
+ GetVectorsReadyForRW();
+}
+
+void
+CCam::Process_SpecialFixedForSyphon(const CVector &CameraTarget, float, float, float)
+{
+ Source = m_cvecCamFixedModeSource;
+ m_cvecTargetCoorsForFudgeInter = CameraTarget;
+ m_cvecTargetCoorsForFudgeInter.z += m_fSyphonModeTargetZOffSet;
+ Front = CameraTarget - Source;
+ Front.z += m_fSyphonModeTargetZOffSet;
+
+ GetVectorsReadyForRW();
+
+ Up += m_cvecCamFixedModeUpOffSet;
+ Up.Normalise();
+ CVector Left = CrossProduct(Up, Front);
+ Left.Normalise();
+ Front = CrossProduct(Left, Up);
+ Front.Normalise();
+ FOV = DefaultFOV;
+}
+
+#ifdef IMPROVED_CAMERA
+
+#define KEYJUSTDOWN(k) ControlsManager.GetIsKeyboardKeyJustDown((RsKeyCodes)k)
+#define KEYDOWN(k) ControlsManager.GetIsKeyboardKeyDown((RsKeyCodes)k)
+#define CTRLJUSTDOWN(key) \
+ ((KEYDOWN(rsLCTRL) || KEYDOWN(rsRCTRL)) && KEYJUSTDOWN((RsKeyCodes)key) || \
+ (KEYJUSTDOWN(rsLCTRL) || KEYJUSTDOWN(rsRCTRL)) && KEYDOWN((RsKeyCodes)key))
+#define CTRLDOWN(key) ((KEYDOWN(rsLCTRL) || KEYDOWN(rsRCTRL)) && KEYDOWN((RsKeyCodes)key))
+
+
+void
+CCam::Process_Debug(const CVector&, float, float, float)
+{
+ static float Speed = 0.0f;
+ static float PanSpeedX = 0.0f;
+ static float PanSpeedY = 0.0f;
+ CVector TargetCoors;
+
+ RwCameraSetNearClipPlane(Scene.camera, DEFAULT_NEAR);
+ FOV = DefaultFOV;
+ Alpha += DEGTORAD(CPad::GetPad(1)->GetLeftStickY()) / 50.0f;
+ Beta += DEGTORAD(CPad::GetPad(1)->GetLeftStickX())*1.5f / 19.0f;
+ if(CPad::GetPad(0)->GetLeftMouse()){
+ Alpha += DEGTORAD(CPad::GetPad(0)->GetMouseY()/2.0f);
+ Beta -= DEGTORAD(CPad::GetPad(0)->GetMouseX()/2.0f);
+ }
+
+ TargetCoors.x = Source.x + Cos(Alpha) * Cos(Beta) * 3.0f;
+ TargetCoors.y = Source.y + Cos(Alpha) * Sin(Beta) * 3.0f;
+ TargetCoors.z = Source.z + Sin(Alpha) * 3.0f;
+
+ if(Alpha > DEGTORAD(89.5f)) Alpha = DEGTORAD(89.5f);
+ if(Alpha < DEGTORAD(-89.5f)) Alpha = DEGTORAD(-89.5f);
+
+ if(CPad::GetPad(1)->GetSquare() || KEYDOWN('W'))
+ Speed += 0.1f;
+ else if(CPad::GetPad(1)->GetCross() || KEYDOWN('S'))
+ Speed -= 0.1f;
+ else
+ Speed = 0.0f;
+ if(Speed > 70.0f) Speed = 70.0f;
+ if(Speed < -70.0f) Speed = -70.0f;
+
+
+ if(KEYDOWN(rsRIGHT) || KEYDOWN('D'))
+ PanSpeedX += 0.1f;
+ else if(KEYDOWN(rsLEFT) || KEYDOWN('A'))
+ PanSpeedX -= 0.1f;
+ else
+ PanSpeedX = 0.0f;
+ if(PanSpeedX > 70.0f) PanSpeedX = 70.0f;
+ if(PanSpeedX < -70.0f) PanSpeedX = -70.0f;
+
+
+ if(KEYDOWN(rsUP))
+ PanSpeedY += 0.1f;
+ else if(KEYDOWN(rsDOWN))
+ PanSpeedY -= 0.1f;
+ else
+ PanSpeedY = 0.0f;
+ if(PanSpeedY > 70.0f) PanSpeedY = 70.0f;
+ if(PanSpeedY < -70.0f) PanSpeedY = -70.0f;
+
+
+ Front = TargetCoors - Source;
+ Front.Normalise();
+ Source = Source + Front*Speed;
+
+ Up = CVector{ 0.0f, 0.0f, 1.0f };
+ CVector Right = CrossProduct(Front, Up);
+ Up = CrossProduct(Right, Front);
+ Source = Source + Up*PanSpeedY + Right*PanSpeedX;
+
+ if(Source.z < -450.0f)
+ Source.z = -450.0f;
+
+ if(CPad::GetPad(1)->GetRightShoulder2JustDown() || KEYJUSTDOWN(rsENTER)){
+ if(FindPlayerVehicle())
+ FindPlayerVehicle()->Teleport(Source);
+ else
+ CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetPosition() = Source;
+ }
+
+ // stay inside sectors
+ while(CWorld::GetSectorX(Source.x) > 95.0f)
+ Source.x -= 1.0f;
+ while(CWorld::GetSectorX(Source.x) < 5.0f)
+ Source.x += 1.0f;
+ while(CWorld::GetSectorY(Source.y) > 95.0f)
+ Source.y -= 1.0f;
+ while(CWorld::GetSectorY(Source.y) < 5.0f)
+ Source.y += 1.0f;
+ GetVectorsReadyForRW();
+
+ CPad::GetPad(0)->DisablePlayerControls = PLAYERCONTROL_DISABLED_1;
+
+ if(CPad::GetPad(1)->GetLeftShockJustDown() && gbBigWhiteDebugLightSwitchedOn)
+ CShadows::StoreShadowToBeRendered(SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &Source,
+ 12.0f, 0.0f, 0.0f, -12.0f,
+ 128, 128, 128, 128, 1000.0f, false, 1.0f);
+
+ if(CHud::m_Wants_To_Draw_Hud){
+ char str[256];
+ sprintf(str, "CamX: %f CamY: %f CamZ: %f", Source.x, Source.y, Source.z);
+ sprintf(str, "Frontx: %f, Fronty: %f, Frontz: %f ", Front.x, Front.y, Front.z);
+ sprintf(str, "Look@: %f, Look@: %f, Look@: %f ", Front.x + Source.x, Front.y + Source.y, Front.z + Source.z);
+ }
+}
+#else
+void
+CCam::Process_Debug(const CVector&, float, float, float)
+{
+ static float Speed = 0.0f;
+ CVector TargetCoors;
+
+ RwCameraSetNearClipPlane(Scene.camera, DEFAULT_NEAR);
+ FOV = DefaultFOV;
+ Alpha += DEGTORAD(CPad::GetPad(1)->GetLeftStickY()) / 50.0f;
+ Beta += DEGTORAD(CPad::GetPad(1)->GetLeftStickX())*1.5f / 19.0f;
+
+ TargetCoors.x = Source.x + Cos(Alpha) * Cos(Beta) * 3.0f;
+ TargetCoors.y = Source.y + Cos(Alpha) * Sin(Beta) * 3.0f;
+ TargetCoors.z = Source.z + Sin(Alpha) * 3.0f;
+
+ if(Alpha > DEGTORAD(89.5f)) Alpha = DEGTORAD(89.5f);
+ if(Alpha < DEGTORAD(-89.5f)) Alpha = DEGTORAD(-89.5f);
+
+ if(CPad::GetPad(1)->GetSquare() || CPad::GetPad(1)->GetLeftMouse())
+ Speed += 0.1f;
+ else if(CPad::GetPad(1)->GetCross() || CPad::GetPad(1)->GetRightMouse())
+ Speed -= 0.1f;
+ else
+ Speed = 0.0f;
+ if(Speed > 70.0f) Speed = 70.0f;
+ if(Speed < -70.0f) Speed = -70.0f;
+
+ Front = TargetCoors - Source;
+ Front.Normalise();
+ Source = Source + Front*Speed;
+
+ if(Source.z < -450.0f)
+ Source.z = -450.0f;
+
+ if(CPad::GetPad(1)->GetRightShoulder2JustDown()){
+ if(FindPlayerVehicle())
+ FindPlayerVehicle()->Teleport(Source);
+ else
+ CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetPosition() = Source;
+
+ }
+
+ // stay inside sectors
+ while(CWorld::GetSectorX(Source.x) > 95.0f)
+ Source.x -= 1.0f;
+ while(CWorld::GetSectorX(Source.x) < 5.0f)
+ Source.x += 1.0f;
+ while(CWorld::GetSectorY(Source.y) > 95.0f)
+ Source.y -= 1.0f;
+ while(CWorld::GetSectorY(Source.y) < 5.0f)
+ Source.y += 1.0f;
+ GetVectorsReadyForRW();
+
+ if(CPad::GetPad(1)->GetLeftShockJustDown() && gbBigWhiteDebugLightSwitchedOn)
+ CShadows::StoreShadowToBeRendered(SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &Source,
+ 12.0f, 0.0f, 0.0f, -12.0f,
+ 128, 128, 128, 128, 1000.0f, false, 1.0f);
+
+ if(CHud::m_Wants_To_Draw_Hud){
+ char str[256];
+ sprintf(str, "CamX: %f CamY: %f CamZ: %f", Source.x, Source.y, Source.z);
+ sprintf(str, "Frontx: %f, Fronty: %f, Frontz: %f ", Front.x, Front.y, Front.z);
+ sprintf(str, "Look@: %f, Look@: %f, Look@: %f ", Front.x + Source.x, Front.y + Source.y, Front.z + Source.z);
+ }
+}
+#endif
+
+void
+CCam::Process_Editor(const CVector&, float, float, float)
+{
+ static float Speed = 0.0f;
+ CVector TargetCoors;
+
+ if(ResetStatics){
+ Source = CVector(796.0f, -937.0, 40.0f);
+ CamTargetEntity = nil;
+ }
+ ResetStatics = false;
+
+ RwCameraSetNearClipPlane(Scene.camera, DEFAULT_NEAR);
+ FOV = DefaultFOV;
+ Alpha += DEGTORAD(CPad::GetPad(1)->GetLeftStickY()) / 50.0f;
+ Beta += DEGTORAD(CPad::GetPad(1)->GetLeftStickX())*1.5f / 19.0f;
+
+ if(CamTargetEntity && CSceneEdit::m_bCameraFollowActor){
+ TargetCoors = CamTargetEntity->GetPosition();
+ }else if(CSceneEdit::m_bRecording){
+ TargetCoors.x = Source.x + Cos(Alpha) * Cos(Beta) * 7.0f;
+ TargetCoors.y = Source.y + Cos(Alpha) * Sin(Beta) * 7.0f;
+ TargetCoors.z = Source.z + Sin(Alpha) * 7.0f;
+ }else
+ TargetCoors = CSceneEdit::m_vecCamHeading + Source;
+ CSceneEdit::m_vecCurrentPosition = TargetCoors;
+ CSceneEdit::m_vecCamHeading = TargetCoors - Source;
+
+ if(Alpha > DEGTORAD(89.5f)) Alpha = DEGTORAD(89.5f);
+ if(Alpha < DEGTORAD(-89.5f)) Alpha = DEGTORAD(-89.5f);
+
+ if(CPad::GetPad(1)->GetSquare() || CPad::GetPad(1)->GetLeftMouse())
+ Speed += 0.1f;
+ else if(CPad::GetPad(1)->GetCross() || CPad::GetPad(1)->GetRightMouse())
+ Speed -= 0.1f;
+ else
+ Speed = 0.0f;
+ if(Speed > 70.0f) Speed = 70.0f;
+ if(Speed < -70.0f) Speed = -70.0f;
+
+ Front = TargetCoors - Source;
+ Front.Normalise();
+ Source = Source + Front*Speed;
+
+ if(Source.z < -450.0f)
+ Source.z = -450.0f;
+
+ if(CPad::GetPad(1)->GetRightShoulder2JustDown()){
+ if(FindPlayerVehicle())
+ FindPlayerVehicle()->Teleport(Source);
+ else
+ CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetPosition() = Source;
+
+ }
+
+ // stay inside sectors
+ while(CWorld::GetSectorX(Source.x) > 95.0f)
+ Source.x -= 1.0f;
+ while(CWorld::GetSectorX(Source.x) < 5.0f)
+ Source.x += 1.0f;
+ while(CWorld::GetSectorY(Source.y) > 95.0f)
+ Source.y -= 1.0f;
+ while(CWorld::GetSectorY(Source.y) < 5.0f)
+ Source.y += 1.0f;
+ GetVectorsReadyForRW();
+
+ if(CPad::GetPad(1)->GetLeftShockJustDown() && gbBigWhiteDebugLightSwitchedOn)
+ CShadows::StoreShadowToBeRendered(SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &Source,
+ 12.0f, 0.0f, 0.0f, -12.0f,
+ 128, 128, 128, 128, 1000.0f, false, 1.0f);
+
+ if(CHud::m_Wants_To_Draw_Hud){
+ char str[256];
+ sprintf(str, "CamX: %f CamY: %f CamZ: %f", Source.x, Source.y, Source.z);
+ sprintf(str, "Frontx: %f, Fronty: %f, Frontz: %f ", Front.x, Front.y, Front.z);
+ sprintf(str, "Look@: %f, Look@: %f, Look@: %f ", Front.x + Source.x, Front.y + Source.y, Front.z + Source.z);
+ }
+}
+
+void
+CCam::Process_ModelView(const CVector &CameraTarget, float, float, float)
+{
+ CVector TargetCoors = CameraTarget;
+ float Angle = Atan2(Front.x, Front.y);
+ FOV = DefaultFOV;
+
+ Angle += CPad::GetPad(0)->GetLeftStickX()/1280.0f;
+ if(Distance < 10.0f)
+ Distance += CPad::GetPad(0)->GetLeftStickY()/1000.0f;
+ else
+ Distance += CPad::GetPad(0)->GetLeftStickY() * ((Distance - 10.0f)/20.0f + 1.0f) / 1000.0f;
+ if(Distance < 1.5f)
+ Distance = 1.5f;
+
+ Front.x = Cos(0.3f) * Sin(Angle);
+ Front.y = Cos(0.3f) * Cos(Angle);
+ Front.z = -Sin(0.3f);
+ Source = CameraTarget - Distance*Front;
+
+ GetVectorsReadyForRW();
+}
+
+void
+CCam::ProcessPedsDeadBaby(void)
+{
+ float Distance = 0.0f;
+ static bool SafeToRotate = false;
+ CVector TargetDist, TestPoint;
+
+ FOV = DefaultFOV;
+ TargetDist = Source - CamTargetEntity->GetPosition();
+ Distance = TargetDist.Magnitude();
+ Beta = CGeneral::GetATanOfXY(TargetDist.x, TargetDist.y);
+ while(Beta >= PI) Beta -= 2*PI;
+ while(Beta < -PI) Beta += 2*PI;
+
+ if(ResetStatics){
+ TestPoint = CamTargetEntity->GetPosition() +
+ CVector(4.0f * Cos(Alpha) * Cos(Beta),
+ 4.0f * Cos(Alpha) * Sin(Beta),
+ 4.0f * Sin(Alpha));
+ bool Safe1 = CWorld::GetIsLineOfSightClear(TestPoint, CamTargetEntity->GetPosition(), true, false, false, true, false, true, true);
+
+ TestPoint = CamTargetEntity->GetPosition() +
+ CVector(4.0f * Cos(Alpha) * Cos(Beta + DEGTORAD(120.0f)),
+ 4.0f * Cos(Alpha) * Sin(Beta + DEGTORAD(120.0f)),
+ 4.0f * Sin(Alpha));
+ bool Safe2 = CWorld::GetIsLineOfSightClear(TestPoint, CamTargetEntity->GetPosition(), true, false, false, true, false, true, true);
+
+ TestPoint = CamTargetEntity->GetPosition() +
+ CVector(4.0f * Cos(Alpha) * Cos(Beta - DEGTORAD(120.0f)),
+ 4.0f * Cos(Alpha) * Sin(Beta - DEGTORAD(120.0f)),
+ 4.0f * Sin(Alpha));
+ bool Safe3 = CWorld::GetIsLineOfSightClear(TestPoint, CamTargetEntity->GetPosition(), true, false, false, true, false, true, true);
+
+ SafeToRotate = Safe1 && Safe2 && Safe3;
+
+ ResetStatics = false;
+ }
+
+ if(SafeToRotate)
+ WellBufferMe(Beta + DEGTORAD(175.0f), &Beta, &BetaSpeed, 0.015f, 0.007f, true);
+
+ WellBufferMe(DEGTORAD(89.5f), &Alpha, &AlphaSpeed, 0.015f, 0.07f, true);
+ WellBufferMe(35.0f, &Distance, &DistanceSpeed, 0.006f, 0.007f, false);
+
+ Source = CamTargetEntity->GetPosition() +
+ CVector(Distance * Cos(Alpha) * Cos(Beta),
+ Distance * Cos(Alpha) * Sin(Beta),
+ Distance * Sin(Alpha));
+ m_cvecTargetCoorsForFudgeInter = CamTargetEntity->GetPosition();
+ Front = CamTargetEntity->GetPosition() - Source;
+ Front.Normalise();
+ GetVectorsReadyForRW();
+}
+
+bool
+CCam::ProcessArrestCamOne(void)
+{
+ FOV = 45.0f;
+ if(ResetStatics)
+ return true;
+
+#ifdef FIX_BUGS
+ if(!CamTargetEntity->IsPed())
+ return true;
+#endif
+
+ bool found;
+ float Ground;
+ CVector PlayerCoors = TheCamera.pTargetEntity->GetPosition();
+ CVector CopCoors = ((CPlayerPed*)TheCamera.pTargetEntity)->m_pArrestingCop->GetPosition();
+ Beta = CGeneral::GetATanOfXY(PlayerCoors.x - CopCoors.x, PlayerCoors.y - CopCoors.y);
+
+ Source = PlayerCoors + 9.5f*CVector(Cos(Beta), Sin(Beta), 0.0f);
+ Source.z += 6.0f;
+ Ground = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, Source.z, &found);
+ if(!found){
+ Ground = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, Source.z, &found);
+ if(!found)
+ return false;
+ }
+ Source.z = Ground + 0.25f;
+ if(!CWorld::GetIsLineOfSightClear(Source, CopCoors, true, true, false, true, false, true, true)){
+ Beta += DEGTORAD(115.0f);
+ Source = PlayerCoors + 9.5f*CVector(Cos(Beta), Sin(Beta), 0.0f);
+ Source.z += 6.0f;
+ Ground = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, Source.z, &found);
+ if(!found){
+ Ground = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, Source.z, &found);
+ if(!found)
+ return false;
+ }
+ Source.z = Ground + 0.25f;
+
+ CopCoors.z += 0.35f;
+ Front = CopCoors - Source;
+ if(!CWorld::GetIsLineOfSightClear(Source, CopCoors, true, true, false, true, false, true, true))
+ return false;
+ }
+ CopCoors.z += 0.35f;
+ m_cvecTargetCoorsForFudgeInter = CopCoors;
+ Front = CopCoors - Source;
+ ResetStatics = false;
+ GetVectorsReadyForRW();
+ return true;
+}
+
+bool
+CCam::ProcessArrestCamTwo(void)
+{
+ CPed *player = CWorld::Players[CWorld::PlayerInFocus].m_pPed;
+ if(!ResetStatics)
+ return true;
+ ResetStatics = false;
+
+ CVector TargetCoors, ToCamera;
+ float BetaOffset;
+ float SourceX, SourceY;
+ CCam *ActiveCam = &TheCamera.Cams[TheCamera.ActiveCam];
+ if(&ActiveCam[1] == this){
+ SourceX = TheCamera.Cams[(TheCamera.ActiveCam + 1) % 2].Source.x;
+ SourceY = TheCamera.Cams[(TheCamera.ActiveCam + 1) % 2].Source.y;
+ }else{
+ SourceX = ActiveCam[1].Source.x;
+ SourceY = ActiveCam[1].Source.y;
+ }
+
+ for(int i = 0; i <= 1; i++){
+ int Dir = i == 0 ? 1 : -1;
+
+ TargetCoors = player->GetPosition();
+ Beta = CGeneral::GetATanOfXY(TargetCoors.x-SourceX, TargetCoors.y-SourceY);
+ BetaOffset = DEGTORAD(Dir*80);
+ Source = TargetCoors + 11.5f*CVector(Cos(Beta+BetaOffset), Sin(Beta+BetaOffset), 0.0f);
+
+ ToCamera = Source - TargetCoors;
+ ToCamera.Normalise();
+ TargetCoors.x += 0.4f*ToCamera.x;
+ TargetCoors.y += 0.4f*ToCamera.y;
+ if(CWorld::GetIsLineOfSightClear(Source, TargetCoors, true, true, false, true, false, true, true)){
+ Source.z += 5.5f;
+ TargetCoors += CVector(-0.8f*ToCamera.x, -0.8f*ToCamera.y, 2.2f);
+ m_cvecTargetCoorsForFudgeInter = TargetCoors;
+ Front = TargetCoors - Source;
+ ResetStatics = false;
+ GetVectorsReadyForRW();
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/*
+ * Unused PS2 cams
+ */
+
+void
+CCam::Process_Chris_With_Binding_PlusRotation(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+ static float AngleToBinned = 0.0f;
+ static float StartingAngleLastChange = 0.0f;
+ static float FixedTargetOrientation = 0.0f;
+ static float DeadZoneReachedOnePrevious;
+
+ FOV = DefaultFOV; // missing in game
+
+ bool FixOrientation = true;
+ if(ResetStatics){
+ Rotating = false;
+ DeadZoneReachedOnePrevious = 0.0f;
+ FixedTargetOrientation = 0.0f;
+ ResetStatics = false;
+ }
+
+ CVector TargetCoors = CameraTarget;
+
+ float StickX = CPad::GetPad(0)->GetRightStickX();
+ float StickY = CPad::GetPad(0)->GetRightStickY();
+ float StickAngle;
+ if(StickX != 0.0 || StickY != 0.0f) // BUG: game checks StickX twice
+ StickAngle = CGeneral::GetATanOfXY(StickX, StickY); // result unused?
+ else
+ FixOrientation = false;
+
+ CVector Dist = Source - TargetCoors;
+ Source.z = TargetCoors.z + 0.75f;
+ float Length = Dist.Magnitude2D();
+ if(Length > 2.5f){
+ Source.x = TargetCoors.x + Dist.x/Length * 2.5f;
+ Source.y = TargetCoors.y + Dist.y/Length * 2.5f;
+ }else if(Length < 2.4f){
+ Source.x = TargetCoors.x + Dist.x/Length * 2.4f;
+ Source.y = TargetCoors.y + Dist.y/Length * 2.4f;
+ }
+
+ Beta = CGeneral::GetATanOfXY(Dist.x, Dist.y);
+ if(CPad::GetPad(0)->GetLeftShoulder1()){
+ FixedTargetOrientation = TargetOrientation;
+ Rotating = true;
+ }
+
+ if(FixOrientation){
+ Rotating = true;
+ FixedTargetOrientation = StickX/128.0f + Beta - PI;
+ }
+
+ if(Rotating){
+ Dist = Source - TargetCoors;
+ Length = Dist.Magnitude2D();
+ // inlined
+ WellBufferMe(FixedTargetOrientation+PI, &Beta, &BetaSpeed, 0.1f, 0.06f, true);
+
+ Source.x = TargetCoors.x + Length*Cos(Beta);
+ Source.y = TargetCoors.y + Length*Sin(Beta);
+
+ float DeltaBeta = FixedTargetOrientation+PI - Beta;
+ while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
+ while(DeltaBeta < -PI) DeltaBeta += 2*PI;
+ if(Abs(DeltaBeta) < 0.06f)
+ Rotating = false;
+ }
+
+ Front = TargetCoors - Source;
+ Front.Normalise();
+ CVector Front2 = Front;
+ Front2.Normalise(); // What?
+ // FIX: the meaning of this value must have changed somehow
+ Source -= Front2 * TheCamera.m_fPedZoomValueSmooth*1.5f;
+// Source += Front2 * TheCamera.m_fPedZoomValueSmooth;
+
+ GetVectorsReadyForRW();
+}
+
+void
+CCam::Process_ReactionCam(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+ static float AngleToBinned = 0.0f;
+ static float StartingAngleLastChange = 0.0f;
+ static float FixedTargetOrientation;
+ static float DeadZoneReachedOnePrevious;
+ static uint32 TimeOfLastChange;
+ uint32 Time;
+ bool DontBind = false; // BUG: left uninitialized
+
+ FOV = DefaultFOV; // missing in game
+
+ if(ResetStatics){
+ Rotating = false;
+ DeadZoneReachedOnePrevious = 0.0f;
+ FixedTargetOrientation = 0.0f;
+ ResetStatics = false;
+ DontBind = false;
+ }
+
+ CVector TargetCoors = CameraTarget;
+
+ CVector Dist = Source - TargetCoors;
+ Source.z = TargetCoors.z + 0.75f;
+ float Length = Dist.Magnitude2D();
+ if(Length > 2.5f){
+ Source.x = TargetCoors.x + Dist.x/Length * 2.5f;
+ Source.y = TargetCoors.y + Dist.y/Length * 2.5f;
+ }else if(Length < 2.4f){
+ Source.x = TargetCoors.x + Dist.x/Length * 2.4f;
+ Source.y = TargetCoors.y + Dist.y/Length * 2.4f;
+ }
+
+ Beta = CGeneral::GetATanOfXY(Dist.x, Dist.y);
+
+ float StickX = CPad::GetPad(0)->GetLeftStickX();
+ float StickY = CPad::GetPad(0)->GetLeftStickY();
+ float StickAngle;
+ if(StickX != 0.0 || StickY != 0.0f){
+ StickAngle = CGeneral::GetATanOfXY(StickX, StickY);
+ while(StickAngle >= PI) StickAngle -= 2*PI;
+ while(StickAngle < -PI) StickAngle += 2*PI;
+ }else
+ StickAngle = 1000.0f;
+
+ if(Abs(StickAngle-AngleToBinned) > DEGTORAD(15.0f)){
+ DontBind = true;
+ Time = CTimer::GetTimeInMilliseconds();
+ }
+
+ if(CTimer::GetTimeInMilliseconds()-TimeOfLastChange > 200){
+ if(Abs(HALFPI-StickAngle) > DEGTORAD(50.0f)){
+ FixedTargetOrientation = TargetOrientation;
+ Rotating = true;
+ TimeOfLastChange = CTimer::GetTimeInMilliseconds();
+ }
+ }
+
+ // These two together don't make much sense.
+ // Only prevents rotation for one frame
+ AngleToBinned = StickAngle;
+ if(DontBind)
+ TimeOfLastChange = Time;
+
+ if(Rotating){
+ Dist = Source - TargetCoors;
+ Length = Dist.Magnitude2D();
+ // inlined
+ WellBufferMe(FixedTargetOrientation+PI, &Beta, &BetaSpeed, 0.1f, 0.06f, true);
+
+ Source.x = TargetCoors.x + Length*Cos(Beta);
+ Source.y = TargetCoors.y + Length*Sin(Beta);
+
+ float DeltaBeta = FixedTargetOrientation+PI - Beta;
+ while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
+ while(DeltaBeta < -PI) DeltaBeta += 2*PI;
+ if(Abs(DeltaBeta) < 0.06f)
+ Rotating = false;
+ }
+
+ Front = TargetCoors - Source;
+ Front.Normalise();
+ CVector Front2 = Front;
+ Front2.Normalise(); // What?
+ // FIX: the meaning of this value must have changed somehow
+ Source -= Front2 * TheCamera.m_fPedZoomValueSmooth*1.5f;
+// Source += Front2 * TheCamera.m_fPedZoomValueSmooth;
+
+ GetVectorsReadyForRW();
+}
+
+void
+CCam::Process_FollowPed_WithBinding(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+ static float AngleToBinned = 0.0f;
+ static float StartingAngleLastChange = 0.0f;
+ static float FixedTargetOrientation;
+ static float DeadZoneReachedOnePrevious;
+ static uint32 TimeOfLastChange;
+ uint32 Time;
+ bool DontBind = false;
+
+ FOV = DefaultFOV; // missing in game
+
+ if(ResetStatics){
+ Rotating = false;
+ DeadZoneReachedOnePrevious = 0.0f;
+ FixedTargetOrientation = 0.0f;
+ ResetStatics = false;
+ }
+
+ CVector TargetCoors = CameraTarget;
+
+ CVector Dist = Source - TargetCoors;
+ Source.z = TargetCoors.z + 0.75f;
+ float Length = Dist.Magnitude2D();
+ if(Length > 2.5f){
+ Source.x = TargetCoors.x + Dist.x/Length * 2.5f;
+ Source.y = TargetCoors.y + Dist.y/Length * 2.5f;
+ }else if(Length < 2.4f){
+ Source.x = TargetCoors.x + Dist.x/Length * 2.4f;
+ Source.y = TargetCoors.y + Dist.y/Length * 2.4f;
+ }
+
+ Beta = CGeneral::GetATanOfXY(Dist.x, Dist.y);
+
+ float StickX = CPad::GetPad(0)->GetLeftStickX();
+ float StickY = CPad::GetPad(0)->GetLeftStickY();
+ float StickAngle;
+ if(StickX != 0.0 || StickY != 0.0f){
+ StickAngle = CGeneral::GetATanOfXY(StickX, StickY);
+ while(StickAngle >= PI) StickAngle -= 2*PI;
+ while(StickAngle < -PI) StickAngle += 2*PI;
+ }else
+ StickAngle = 1000.0f;
+
+ if(Abs(StickAngle-AngleToBinned) > DEGTORAD(15.0f)){
+ DontBind = true;
+ Time = CTimer::GetTimeInMilliseconds();
+ }
+
+ if(CTimer::GetTimeInMilliseconds()-TimeOfLastChange > 200){
+ if(Abs(HALFPI-StickAngle) > DEGTORAD(50.0f)){
+ FixedTargetOrientation = TargetOrientation;
+ Rotating = true;
+ TimeOfLastChange = CTimer::GetTimeInMilliseconds();
+ }
+ }
+
+ if(CPad::GetPad(0)->GetLeftShoulder1JustDown()){
+ FixedTargetOrientation = TargetOrientation;
+ Rotating = true;
+ TimeOfLastChange = CTimer::GetTimeInMilliseconds();
+ }
+
+ // These two together don't make much sense.
+ // Only prevents rotation for one frame
+ AngleToBinned = StickAngle;
+ if(DontBind)
+ TimeOfLastChange = Time;
+
+ if(Rotating){
+ Dist = Source - TargetCoors;
+ Length = Dist.Magnitude2D();
+ // inlined
+ WellBufferMe(FixedTargetOrientation+PI, &Beta, &BetaSpeed, 0.1f, 0.06f, true);
+
+ Source.x = TargetCoors.x + Length*Cos(Beta);
+ Source.y = TargetCoors.y + Length*Sin(Beta);
+
+ float DeltaBeta = FixedTargetOrientation+PI - Beta;
+ while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
+ while(DeltaBeta < -PI) DeltaBeta += 2*PI;
+ if(Abs(DeltaBeta) < 0.06f)
+ Rotating = false;
+ }
+
+ Front = TargetCoors - Source;
+ Front.Normalise();
+ CVector Front2 = Front;
+ Front2.Normalise(); // What?
+ // FIX: the meaning of this value must have changed somehow
+ Source -= Front2 * TheCamera.m_fPedZoomValueSmooth*1.5f;
+// Source += Front2 * TheCamera.m_fPedZoomValueSmooth;
+
+ GetVectorsReadyForRW();
+}
+
+#ifdef FREE_CAM
+void
+CCam::Process_FollowPed_Rotation(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+ FOV = DefaultFOV;
+
+ const float MinDist = 2.0f;
+ const float MaxDist = 2.0f + TheCamera.m_fPedZoomValueSmooth;
+ const float BaseOffset = 0.75f; // base height of camera above target
+
+ CVector TargetCoors = CameraTarget;
+
+ TargetCoors.z += m_fSyphonModeTargetZOffSet;
+ TargetCoors = DoAverageOnVector(TargetCoors);
+ TargetCoors.z += BaseOffset; // add offset so alpha evens out to 0
+// TargetCoors.z += m_fRoadOffSet;
+
+ CVector Dist = Source - TargetCoors;
+ CVector ToCam;
+
+ bool Shooting = false;
+ if(((CPed*)CamTargetEntity)->GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED)
+ if(CPad::GetPad(0)->GetWeapon())
+ Shooting = true;
+ if(((CPed*)CamTargetEntity)->GetWeapon()->m_eWeaponType == WEAPONTYPE_DETONATOR ||
+ ((CPed*)CamTargetEntity)->GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT)
+ Shooting = false;
+
+
+ if(ResetStatics){
+ // Coming out of top down here probably
+ // so keep Beta, reset alpha and calculate vectors
+ Beta = CGeneral::GetATanOfXY(Dist.x, Dist.y);
+ Alpha = 0.0f;
+
+ Dist = MaxDist*CVector(Cos(Alpha) * Cos(Beta), Cos(Alpha) * Sin(Beta), Sin(Alpha));
+ Source = TargetCoors + Dist;
+
+ ResetStatics = false;
+ }
+
+ // Drag the camera along at the look-down offset
+ float CamDist = Dist.Magnitude();
+ if(CamDist == 0.0f)
+ Dist = CVector(1.0f, 1.0f, 0.0f);
+ else if(CamDist < MinDist)
+ Dist *= MinDist/CamDist;
+ else if(CamDist > MaxDist)
+ Dist *= MaxDist/CamDist;
+ CamDist = Dist.Magnitude();
+
+ // Beta = 0 is looking east, HALFPI is north, &c.
+ // Alpha positive is looking up
+ float GroundDist = Dist.Magnitude2D();
+ Beta = CGeneral::GetATanOfXY(-Dist.x, -Dist.y);
+ Alpha = CGeneral::GetATanOfXY(GroundDist, -Dist.z);
+ while(Beta >= PI) Beta -= 2.0f*PI;
+ while(Beta < -PI) Beta += 2.0f*PI;
+ while(Alpha >= PI) Alpha -= 2.0f*PI;
+ while(Alpha < -PI) Alpha += 2.0f*PI;
+
+ // Look around
+ bool UseMouse = false;
+ float MouseX = CPad::GetPad(0)->GetMouseX();
+ float MouseY = CPad::GetPad(0)->GetMouseY();
+ float LookLeftRight, LookUpDown;
+/*
+ if((MouseX != 0.0f || MouseY != 0.0f) && !CPad::GetPad(0)->ArePlayerControlsDisabled()){
+ UseMouse = true;
+ LookLeftRight = -2.5f*MouseX;
+ LookUpDown = 4.0f*MouseY;
+ }else
+*/
+ {
+ LookLeftRight = -CPad::GetPad(0)->LookAroundLeftRight();
+ LookUpDown = CPad::GetPad(0)->LookAroundUpDown();
+ }
+ float AlphaOffset, BetaOffset;
+ if(UseMouse){
+ BetaOffset = LookLeftRight * TheCamera.m_fMouseAccelHorzntl * FOV/80.0f;
+ AlphaOffset = LookUpDown * TheCamera.m_fMouseAccelVertical * FOV/80.0f;
+ }else{
+ BetaOffset = LookLeftRight * fStickSens * (0.5f/10.0f) * FOV/80.0f * CTimer::GetTimeStep();
+ AlphaOffset = LookUpDown * fStickSens * (0.3f/10.0f) * FOV/80.0f * CTimer::GetTimeStep();
+ }
+
+ // Stop centering once stick has been touched
+ if(BetaOffset)
+ Rotating = false;
+
+ Beta += BetaOffset;
+ Alpha += AlphaOffset;
+ while(Beta >= PI) Beta -= 2.0f*PI;
+ while(Beta < -PI) Beta += 2.0f*PI;
+ if(Alpha > DEGTORAD(45.0f)) Alpha = DEGTORAD(45.0f);
+ if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f);
+
+
+ float BetaDiff = TargetOrientation+PI - Beta;
+ while(BetaDiff >= PI) BetaDiff -= 2.0f*PI;
+ while(BetaDiff < -PI) BetaDiff += 2.0f*PI;
+ float TargetAlpha = Alpha;
+ // 12deg to account for our little height offset. we're not working on the true alpha here
+ const float AlphaLimitUp = DEGTORAD(15.0f) + DEGTORAD(12.0f);
+ const float AlphaLimitDown = -DEGTORAD(15.0f) + DEGTORAD(12.0f);
+ if(Abs(BetaDiff) < DEGTORAD(25.0f) && ((CPed*)CamTargetEntity)->GetMoveSpeed().Magnitude2D() > 0.01f){
+ // Limit alpha when player is walking towards camera
+ if(TargetAlpha > AlphaLimitUp) TargetAlpha = AlphaLimitUp;
+ if(TargetAlpha < AlphaLimitDown) TargetAlpha = AlphaLimitDown;
+ }
+
+ WellBufferMe(TargetAlpha, &Alpha, &AlphaSpeed, 0.2f, 0.1f, true);
+
+ if(CPad::GetPad(0)->ForceCameraBehindPlayer() || Shooting){
+ m_fTargetBeta = TargetOrientation;
+ Rotating = true;
+ }
+
+ if(Rotating){
+ WellBufferMe(m_fTargetBeta, &Beta, &BetaSpeed, 0.1f, 0.06f, true);
+ float DeltaBeta = m_fTargetBeta - Beta;
+ while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
+ while(DeltaBeta < -PI) DeltaBeta += 2*PI;
+ if(Abs(DeltaBeta) < 0.06f)
+ Rotating = false;
+ }
+
+
+ Front = CVector(Cos(Alpha) * Cos(Beta), Cos(Alpha) * Sin(Beta), Sin(Alpha));
+ Source = TargetCoors - Front*CamDist;
+ TargetCoors.z -= BaseOffset; // now get back to the real target coors again
+
+ m_cvecTargetCoorsForFudgeInter = TargetCoors;
+
+
+ Front = TargetCoors - Source;
+ Front.Normalise();
+
+
+
+ /*
+ * Handle collisions - taken from FollowPedWithMouse
+ */
+
+ CEntity *entity;
+ CColPoint colPoint;
+ // Clip Source and fix near clip
+ CWorld::pIgnoreEntity = CamTargetEntity;
+ entity = nil;
+ if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, true, true, true, true, false, false, true)){
+ float PedColDist = (TargetCoors - colPoint.point).Magnitude();
+ float ColCamDist = CamDist - PedColDist;
+ if(entity->IsPed() && ColCamDist > 1.0f){
+ // Ped in the way but not clipping through
+ if(CWorld::ProcessLineOfSight(colPoint.point, Source, colPoint, entity, true, true, true, true, false, false, true)){
+ PedColDist = (TargetCoors - colPoint.point).Magnitude();
+ Source = colPoint.point;
+ if(PedColDist < DEFAULT_NEAR + 0.3f)
+ RwCameraSetNearClipPlane(Scene.camera, max(PedColDist-0.3f, 0.05f));
+ }else{
+ RwCameraSetNearClipPlane(Scene.camera, min(ColCamDist-0.35f, DEFAULT_NEAR));
+ }
+ }else{
+ Source = colPoint.point;
+ if(PedColDist < DEFAULT_NEAR + 0.3f)
+ RwCameraSetNearClipPlane(Scene.camera, max(PedColDist-0.3f, 0.05f));
+ }
+ }
+ CWorld::pIgnoreEntity = nil;
+
+ float ViewPlaneHeight = Tan(DEGTORAD(FOV) / 2.0f);
+ float ViewPlaneWidth = ViewPlaneHeight * CDraw::FindAspectRatio() * fTweakFOV;
+ float Near = RwCameraGetNearClipPlane(Scene.camera);
+ float radius = ViewPlaneWidth*Near;
+ entity = CWorld::TestSphereAgainstWorld(Source + Front*Near, radius, nil, true, true, false, true, false, false);
+ int i = 0;
+ while(entity){
+ CVector CamToCol = gaTempSphereColPoints[0].point - Source;
+ float frontDist = DotProduct(CamToCol, Front);
+ float dist = (CamToCol - Front*frontDist).Magnitude() / ViewPlaneWidth;
+
+ // Try to decrease near clip
+ dist = max(min(Near, dist), 0.1f);
+ if(dist < Near)
+ RwCameraSetNearClipPlane(Scene.camera, dist);
+
+ // Move forward a bit
+ if(dist == 0.1f)
+ Source += (TargetCoors - Source)*0.3f;
+
+ // Keep testing
+ entity = CWorld::TestSphereAgainstWorld(Source + Front*Near, radius, nil, true, true, false, true, false, false);
+
+ i++;
+ if(i > 5)
+ entity = nil;
+ }
+
+ GetVectorsReadyForRW();
+}
+
+// LCS cam hehe
+void
+CCam::Process_FollowCar_SA(const CVector& CameraTarget, float TargetOrientation, float, float)
+{
+ // Missing things on III CCam
+ static CVector m_aTargetHistoryPosOne;
+ static CVector m_aTargetHistoryPosTwo;
+ static CVector m_aTargetHistoryPosThree;
+ static int m_nCurrentHistoryPoints = 0;
+ static float lastBeta = -9999.0f;
+ static float lastAlpha = -9999.0f;
+ static float stepsLeftToChangeBetaByMouse;
+ static float dontCollideWithCars;
+ static bool alphaCorrected;
+ static float heightIncreaseMult;
+
+ if (!CamTargetEntity->IsVehicle())
+ return;
+
+ CVehicle* car = (CVehicle*)CamTargetEntity;
+ CVector TargetCoors = CameraTarget;
+ uint8 camSetArrPos = 0;
+
+ // We may need those later
+ bool isPlane = car->m_modelIndex == MI_DODO;
+ bool isHeli = false;
+ bool isBike = false;
+ bool isCar = car->IsCar() && !isPlane && !isHeli && !isBike;
+
+ CPad* pad = CPad::GetPad(0);
+
+ // Next direction is non-existent in III
+ uint8 nextDirectionIsForward = !(pad->GetLookBehindForCar() || pad->GetLookBehindForPed() || pad->GetLookLeft() || pad->GetLookRight()) &&
+ DirectionWasLooking == LOOKING_FORWARD;
+
+ if (car->m_modelIndex == MI_FIRETRUCK) {
+ camSetArrPos = 7;
+ } else if (car->m_modelIndex == MI_RCBANDIT) {
+ camSetArrPos = 5;
+ } else if (car->IsBoat()) {
+ camSetArrPos = 4;
+ } else if (isBike) {
+ camSetArrPos = 1;
+ } else if (isPlane) {
+ camSetArrPos = 3;
+ } else if (isHeli) {
+ camSetArrPos = 2;
+ }
+
+ // LCS one but index 1(firetruck) moved to last
+ float CARCAM_SET[][15] = {
+ {1.3f, 1.0f, 0.4f, 10.0f, 15.0f, 0.5f, 1.0f, 1.0f, 0.85f, 0.2f, 0.075f, 0.05f, 0.8f, DEGTORAD(45.0f), DEGTORAD(89.0f)}, // cars
+ {1.1f, 1.0f, 0.1f, 10.0f, 11.0f, 0.5f, 1.0f, 1.0f, 0.85f, 0.2f, 0.075f, 0.05f, 0.75f, DEGTORAD(45.0f), DEGTORAD(89.0f)}, // bike
+ {1.1f, 1.0f, 0.2f, 10.0f, 15.0f, 0.05f, 0.05f, 0.0f, 0.9f, 0.05f, 0.01f, 0.05f, 1.0f, DEGTORAD(10.0f), DEGTORAD(70.0f)}, // heli (SA values)
+ {1.1f, 3.5f, 0.2f, 10.0f, 25.0f, 0.5f, 1.0f, 1.0f, 0.75f, 0.1f, 0.005f, 0.2f, 1.0f, DEGTORAD(89.0f), DEGTORAD(89.0f)}, // plane (SA values)
+ {0.9f, 1.0f, 0.1f, 10.0f, 15.0f, 0.5f, 1.0f, 0.0f, 0.9f, 0.05f, 0.005f, 0.05f, 1.0f, -0.2f, DEGTORAD(70.0f)}, // boat
+ {1.1f, 1.0f, 0.2f, 10.0f, 5.0f, 0.5f, 1.0f, 1.0f, 0.75f, 0.1f, 0.005f, 0.2f, 1.0f, DEGTORAD(45.0f), DEGTORAD(89.0f)}, // rc cars
+ {1.1f, 1.0f, 0.2f, 10.0f, 5.0f, 0.5f, 1.0f, 1.0f, 0.75f, 0.1f, 0.005f, 0.2f, 1.0f, DEGTORAD(20.0f), DEGTORAD(70.0f)}, // rc heli/planes
+ {1.3f, 1.0f, 0.4f, 10.0f, 15.0f, 0.5f, 1.0f, 1.0f, 0.85f, 0.2f, 0.075f, 0.05f, 0.8f, -0.18f, DEGTORAD(40.0f)}, // firetruck...
+ };
+
+ // RC Heli/planes use same alpha values with heli/planes (LCS firetruck will fallback to 0)
+ uint8 alphaArrPos = (camSetArrPos > 4 ? (isPlane ? 3 : (isHeli ? 2 : 0)) : camSetArrPos);
+ float zoomModeAlphaOffset = 0.0f;
+ static float ZmOneAlphaOffsetLCS[] = { 0.12f, 0.08f, 0.15f, 0.08f, 0.08f };
+ static float ZmTwoAlphaOffsetLCS[] = { 0.1f, 0.08f, 0.3f, 0.08f, 0.08f };
+ static float ZmThreeAlphaOffsetLCS[] = { 0.065f, 0.05f, 0.15f, 0.06f, 0.08f };
+
+ if (isHeli && car->m_status == STATUS_PLAYER_REMOTE)
+ zoomModeAlphaOffset = ZmTwoAlphaOffsetLCS[alphaArrPos];
+ else {
+ switch ((int)TheCamera.CarZoomIndicator) {
+ // near
+ case 1:
+ zoomModeAlphaOffset = ZmOneAlphaOffsetLCS[alphaArrPos];
+ break;
+ // mid
+ case 2:
+ zoomModeAlphaOffset = ZmTwoAlphaOffsetLCS[alphaArrPos];
+ break;
+ // far
+ case 3:
+ zoomModeAlphaOffset = ZmThreeAlphaOffsetLCS[alphaArrPos];
+ break;
+ default:
+ break;
+ }
+ }
+
+ CColModel* carCol = (CColModel*)car->GetColModel();
+ float colMaxZ = carCol->boundingBox.max.z; // As opposed to LCS and SA, VC does this: carCol->boundingBox.max.z - carCol->boundingBox.min.z;
+ float approxCarLength = 2.0f * Abs(carCol->boundingBox.min.y); // SA taxi min.y = -2.95, max.z = 0.883502f
+
+ float newDistance = TheCamera.CarZoomValueSmooth + CARCAM_SET[camSetArrPos][1] + approxCarLength;
+
+ float minDistForThisCar = approxCarLength * CARCAM_SET[camSetArrPos][3];
+
+ if (!isHeli || car->m_status == STATUS_PLAYER_REMOTE) {
+ float radiusToStayOutside = colMaxZ * CARCAM_SET[camSetArrPos][0] - CARCAM_SET[camSetArrPos][2];
+ if (radiusToStayOutside > 0.0f) {
+ TargetCoors.z += radiusToStayOutside;
+ newDistance += radiusToStayOutside;
+ zoomModeAlphaOffset += 0.3f / newDistance * radiusToStayOutside;
+ }
+ } else {
+ // 0.6f = fTestShiftHeliCamTarget
+ TargetCoors.x += 0.6f * car->GetUp().x * colMaxZ;
+ TargetCoors.y += 0.6f * car->GetUp().y * colMaxZ;
+ TargetCoors.z += 0.6f * car->GetUp().z * colMaxZ;
+ }
+
+ float minDistForVehType = CARCAM_SET[camSetArrPos][4];
+
+ if ((int)TheCamera.CarZoomIndicator == 1 && (camSetArrPos < 2 || camSetArrPos == 7)) {
+ minDistForVehType = minDistForVehType * 0.65f;
+ }
+
+ float nextDistance = max(newDistance, minDistForVehType);
+
+ CA_MAX_DISTANCE = newDistance;
+ CA_MIN_DISTANCE = 3.5f;
+
+ if (ResetStatics) {
+ FOV = DefaultFOV;
+
+ // GTA 3 has this in veh. camera
+ if (TheCamera.m_bIdleOn)
+ TheCamera.m_uiTimeWeEnteredIdle = CTimer::GetTimeInMilliseconds();
+ } else {
+ if (isCar || isBike) {
+ // 0.4f: CAR_FOV_START_SPEED
+ if (DotProduct(car->GetForward(), car->m_vecMoveSpeed) > 0.4f)
+ FOV += (DotProduct(car->GetForward(), car->m_vecMoveSpeed) - 0.4f) * CTimer::GetTimeStep();
+ }
+
+ if (FOV > DefaultFOV)
+ // 0.98f: CAR_FOV_FADE_MULT
+ FOV = pow(0.98f, CTimer::GetTimeStep()) * (FOV - DefaultFOV) + DefaultFOV;
+
+ if (FOV <= DefaultFOV + 30.0f) {
+ if (FOV < DefaultFOV)
+ FOV = DefaultFOV;
+ } else
+ FOV = DefaultFOV + 30.0f;
+ }
+
+ // WORKAROUND: I still don't know how looking behind works (m_bCamDirectlyInFront is unused in III, they seem to use m_bUseTransitionBeta)
+ if (pad->GetLookBehindForCar())
+ if (DirectionWasLooking == LOOKING_FORWARD || !LookingBehind)
+ TheCamera.m_bCamDirectlyInFront = true;
+
+ // Taken from RotCamIfInFrontCar, because we don't call it anymore
+ if (!(pad->GetLookBehindForCar() || pad->GetLookBehindForPed() || pad->GetLookLeft() || pad->GetLookRight()))
+ if (DirectionWasLooking != LOOKING_FORWARD)
+ TheCamera.m_bCamDirectlyBehind = true;
+
+ // Called when we just entered the car, just started to look behind or returned back from looking left, right or behind
+ if (ResetStatics || TheCamera.m_bCamDirectlyBehind || TheCamera.m_bCamDirectlyInFront) {
+ ResetStatics = false;
+ Rotating = false;
+ m_bCollisionChecksOn = true;
+ // TheCamera.m_bResetOldMatrix = 1;
+
+ // Garage exit cam is not working well in III...
+ // if (!TheCamera.m_bJustCameOutOfGarage) // && !sthForScript)
+ // {
+ Alpha = 0.0f;
+ Beta = car->GetForward().Heading() - HALFPI;
+ if (TheCamera.m_bCamDirectlyInFront) {
+ Beta += PI;
+ }
+ // }
+
+ BetaSpeed = 0.0;
+ AlphaSpeed = 0.0;
+ Distance = 1000.0;
+
+ Front.x = -(cos(Beta) * cos(Alpha));
+ Front.y = -(sin(Beta) * cos(Alpha));
+ Front.z = sin(Alpha);
+
+ m_aTargetHistoryPosOne = TargetCoors - nextDistance * Front;
+
+ m_aTargetHistoryPosTwo = TargetCoors - newDistance * Front;
+
+ m_nCurrentHistoryPoints = 0;
+ if (!TheCamera.m_bJustCameOutOfGarage) // && !sthForScript)
+ Alpha = -zoomModeAlphaOffset;
+ }
+
+ Front = TargetCoors - m_aTargetHistoryPosOne;
+ Front.Normalise();
+
+ // Code that makes cam rotate around the car
+ float camRightHeading = Front.Heading() - HALFPI;
+ if (camRightHeading < -PI)
+ camRightHeading = camRightHeading + TWOPI;
+
+ float velocityRightHeading;
+ if (car->m_vecMoveSpeed.Magnitude2D() <= 0.02f)
+ velocityRightHeading = camRightHeading;
+ else
+ velocityRightHeading = car->m_vecMoveSpeed.Heading() - HALFPI;
+
+ if (velocityRightHeading < camRightHeading - PI)
+ velocityRightHeading = velocityRightHeading + TWOPI;
+ else if (velocityRightHeading > camRightHeading + PI)
+ velocityRightHeading = velocityRightHeading - TWOPI;
+
+ float betaChangeMult1 = CTimer::GetTimeStep() * CARCAM_SET[camSetArrPos][10];
+ float betaChangeLimit = CTimer::GetTimeStep() * CARCAM_SET[camSetArrPos][11];
+
+ float betaChangeMult2 = (car->m_vecMoveSpeed - DotProduct(car->m_vecMoveSpeed, Front) * Front).Magnitude();
+
+ float betaChange = min(1.0f, betaChangeMult1 * betaChangeMult2) * (velocityRightHeading - camRightHeading);
+ if (betaChange <= betaChangeLimit) {
+ if (betaChange < -betaChangeLimit)
+ betaChange = -betaChangeLimit;
+ } else {
+ betaChange = betaChangeLimit;
+ }
+ float targetBeta = camRightHeading + betaChange;
+
+ if (targetBeta < Beta - HALFPI)
+ targetBeta += TWOPI;
+ else if (targetBeta > Beta + PI)
+ targetBeta -= TWOPI;
+
+ float carPosChange = (TargetCoors - m_aTargetHistoryPosTwo).Magnitude();
+ if (carPosChange < newDistance && newDistance > minDistForThisCar) {
+ newDistance = max(minDistForThisCar, carPosChange);
+ }
+ float maxAlphaAllowed = CARCAM_SET[camSetArrPos][13];
+
+ // Originally this is to prevent camera enter into car while we're stopping, but what about moving???
+ // This is also original LCS and SA bug, or some attempt to fix lag. We'll never know
+
+ // if (car->m_vecMoveSpeed.MagnitudeSqr() < sq(0.2f))
+ if (car->m_modelIndex != MI_FIRETRUCK) {
+ // if (!isBike || GetMysteriousWheelRelatedThingBike(car) > 3)
+ // if (!isHeli && (!isPlane || car->GetWheelsOnGround())) {
+
+ CVector left = CrossProduct(car->GetForward(), CVector(0.0f, 0.0f, 1.0f));
+ left.Normalise();
+ CVector up = CrossProduct(left, car->GetForward());
+ up.Normalise();
+ float lookingUp = DotProduct(up, Front);
+ if (lookingUp > 0.0f) {
+ float v88 = Asin(Abs(Sin(Beta - (car->GetForward().Heading() - HALFPI))));
+ float v200;
+ if (v88 <= Atan2(carCol->boundingBox.max.x, -carCol->boundingBox.min.y)) {
+ v200 = (1.5f - carCol->boundingBox.min.y) / Cos(v88);
+ } else {
+ float a6g = 1.2f + carCol->boundingBox.max.x;
+ v200 = a6g / Cos(max(0.0f, HALFPI - v88));
+ }
+ maxAlphaAllowed = Cos(Beta - (car->GetForward().Heading() - HALFPI)) * Atan2(car->GetForward().z, car->GetForward().Magnitude2D())
+ + Atan2(TargetCoors.z - car->GetPosition().z + car->GetHeightAboveRoad(), v200 * 1.2f);
+
+ if (isCar && ((CAutomobile*)car)->m_nWheelsOnGround > 1 && Abs(DotProduct(car->m_vecTurnSpeed, car->GetForward())) < 0.05f) {
+ maxAlphaAllowed += Cos(Beta - (car->GetForward().Heading() - HALFPI) + HALFPI) * Atan2(car->GetRight().z, car->GetRight().Magnitude2D());
+ }
+ }
+ }
+
+ float targetAlpha = Asin(clamp(Front.z, -1.0f, 1.0f)) - zoomModeAlphaOffset;
+ if (targetAlpha <= maxAlphaAllowed) {
+ if (targetAlpha < -CARCAM_SET[camSetArrPos][14])
+ targetAlpha = -CARCAM_SET[camSetArrPos][14];
+ } else {
+ targetAlpha = maxAlphaAllowed;
+ }
+ float maxAlphaBlendAmount = CTimer::GetTimeStep() * CARCAM_SET[camSetArrPos][6];
+ float targetAlphaBlendAmount = (1.0f - pow(CARCAM_SET[camSetArrPos][5], CTimer::GetTimeStep())) * (targetAlpha - Alpha);
+ if (targetAlphaBlendAmount <= maxAlphaBlendAmount) {
+ if (targetAlphaBlendAmount < -maxAlphaBlendAmount)
+ targetAlphaBlendAmount = -maxAlphaBlendAmount;
+ } else {
+ targetAlphaBlendAmount = maxAlphaBlendAmount;
+ }
+
+ // Using GetCarGun(LR/UD) will give us same unprocessed RightStick value as SA
+ float stickX = -(pad->GetCarGunLeftRight());
+ float stickY = pad->GetCarGunUpDown();
+
+ // In SA this checks for m_bUseMouse3rdPerson so num2/num8 do not move camera when Keyboard & Mouse controls are used.
+ if (CCamera::m_bUseMouse3rdPerson)
+ stickY = 0.0f;
+
+ float xMovement = Abs(stickX) * (FOV / 80.0f * 5.f / 70.f) * stickX * 0.007f * 0.007f;
+ float yMovement = Abs(stickY) * (FOV / 80.0f * 3.f / 70.f) * stickY * 0.007f * 0.007f;
+
+ bool correctAlpha = true;
+ // if (SA checks if we aren't in work car, why?) {
+ if (!isCar || car->m_modelIndex != MI_YARDIE) {
+ correctAlpha = false;
+ }
+ else {
+ xMovement = 0.0f;
+ yMovement = 0.0f;
+ }
+ // } else
+ // yMovement = 0.0;
+
+ if (!nextDirectionIsForward) {
+ yMovement = 0.0;
+ xMovement = 0.0;
+ }
+
+ if (camSetArrPos == 0 || camSetArrPos == 7) {
+ // This is not working on cars as SA
+ // Because III/VC doesn't have any buttons tied to LeftStick if you're not in Classic Configuration, using Dodo or using GInput/Pad, so :shrug:
+ if (Abs(pad->GetSteeringUpDown()) > 120.0f) {
+ if (car->pDriver && car->pDriver->m_objective != OBJECTIVE_LEAVE_VEHICLE) {
+ yMovement += Abs(pad->GetSteeringUpDown()) * (FOV / 80.0f * 3.f / 70.f) * pad->GetSteeringUpDown() * 0.007f * 0.007f * 0.5;
+ }
+ }
+ }
+
+ if (yMovement > 0.0)
+ yMovement = yMovement * 0.5;
+
+ bool mouseChangesBeta = false;
+
+ // FIX: Disable mouse movement in drive-by, it's buggy. Original SA bug.
+ if (/*bFreeMouseCam &&*/ CCamera::m_bUseMouse3rdPerson && !pad->ArePlayerControlsDisabled() && nextDirectionIsForward) {
+ float mouseY = pad->GetMouseY() * 2.0f;
+ float mouseX = pad->GetMouseX() * -2.0f;
+
+ // If you want an ability to toggle free cam while steering with mouse, you can add an OR after DisableMouseSteering.
+ // There was a pad->NewState.m_bVehicleMouseLook in SA, which doesn't exists in III.
+
+ if ((mouseX != 0.0 || mouseY != 0.0) && (CVehicle::m_bDisableMouseSteering)) {
+ yMovement = mouseY * FOV / 80.0f * TheCamera.m_fMouseAccelHorzntl; // Same as SA, horizontal sensitivity.
+ BetaSpeed = 0.0;
+ AlphaSpeed = 0.0;
+ xMovement = mouseX * FOV / 80.0f * TheCamera.m_fMouseAccelHorzntl;
+ targetAlpha = Alpha;
+ stepsLeftToChangeBetaByMouse = 1.0f * 50.0f;
+ mouseChangesBeta = true;
+ } else if (stepsLeftToChangeBetaByMouse > 0.0f) {
+ // Finish rotation by decreasing speed when we stopped moving mouse
+ BetaSpeed = 0.0;
+ AlphaSpeed = 0.0;
+ yMovement = 0.0;
+ xMovement = 0.0;
+ targetAlpha = Alpha;
+ stepsLeftToChangeBetaByMouse = max(0.0f, stepsLeftToChangeBetaByMouse - CTimer::GetTimeStep());
+ mouseChangesBeta = true;
+ }
+ }
+
+ if (correctAlpha) {
+ if (nPreviousMode != MODE_CAM_ON_A_STRING)
+ alphaCorrected = false;
+
+ if (!alphaCorrected && Abs(zoomModeAlphaOffset + Alpha) > 0.05f) {
+ yMovement = (-zoomModeAlphaOffset - Alpha) * 0.05f;
+ } else
+ alphaCorrected = true;
+ }
+ float alphaSpeedFromStickY = yMovement * CARCAM_SET[camSetArrPos][12];
+ float betaSpeedFromStickX = xMovement * CARCAM_SET[camSetArrPos][12];
+
+ float newAngleSpeedMaxBlendAmount = CARCAM_SET[camSetArrPos][9];
+ float angleChangeStep = pow(CARCAM_SET[camSetArrPos][8], CTimer::GetTimeStep());
+ float targetBetaWithStickBlendAmount = betaSpeedFromStickX + (targetBeta - Beta) / max(CTimer::GetTimeStep(), 1.0f);
+
+ if (targetBetaWithStickBlendAmount < -newAngleSpeedMaxBlendAmount)
+ targetBetaWithStickBlendAmount = -newAngleSpeedMaxBlendAmount;
+ else if (targetBetaWithStickBlendAmount > newAngleSpeedMaxBlendAmount)
+ targetBetaWithStickBlendAmount = newAngleSpeedMaxBlendAmount;
+
+ float angleChangeStepLeft = 1.0f - angleChangeStep;
+ BetaSpeed = targetBetaWithStickBlendAmount * angleChangeStepLeft + angleChangeStep * BetaSpeed;
+ if (Abs(BetaSpeed) < 0.0001f)
+ BetaSpeed = 0.0f;
+
+ float betaChangePerFrame;
+ if (mouseChangesBeta)
+ betaChangePerFrame = betaSpeedFromStickX;
+ else
+ betaChangePerFrame = CTimer::GetTimeStep() * BetaSpeed;
+ Beta = betaChangePerFrame + Beta;
+
+ if (TheCamera.m_bJustCameOutOfGarage) {
+ float invHeading = Atan2(Front.y, Front.x);
+ if (invHeading < 0.0f)
+ invHeading += TWOPI;
+
+ Beta = invHeading + PI;
+ }
+
+ Beta = CGeneral::LimitRadianAngle(Beta);
+ if (Beta < 0.0f)
+ Beta += TWOPI;
+
+ if ((camSetArrPos <= 1 || camSetArrPos == 7) && targetAlpha < Alpha && carPosChange >= newDistance) {
+ if (isCar && ((CAutomobile*)car)->m_nWheelsOnGround > 1)
+ // || isBike && GetMysteriousWheelRelatedThingBike(car) > 1)
+ alphaSpeedFromStickY += (targetAlpha - Alpha) * 0.075f;
+ }
+
+ AlphaSpeed = angleChangeStepLeft * alphaSpeedFromStickY + angleChangeStep * AlphaSpeed;
+ float maxAlphaSpeed = newAngleSpeedMaxBlendAmount;
+ if (alphaSpeedFromStickY > 0.0f)
+ maxAlphaSpeed = maxAlphaSpeed * 0.5;
+
+ if (AlphaSpeed <= maxAlphaSpeed) {
+ float minAlphaSpeed = -maxAlphaSpeed;
+ if (AlphaSpeed < minAlphaSpeed)
+ AlphaSpeed = minAlphaSpeed;
+ } else {
+ AlphaSpeed = maxAlphaSpeed;
+ }
+
+ if (Abs(AlphaSpeed) < 0.0001f)
+ AlphaSpeed = 0.0f;
+
+ float alphaWithSpeedAccounted;
+ if (mouseChangesBeta) {
+ alphaWithSpeedAccounted = alphaSpeedFromStickY + targetAlpha;
+ Alpha += alphaSpeedFromStickY;
+ } else {
+ alphaWithSpeedAccounted = CTimer::GetTimeStep() * AlphaSpeed + targetAlpha;
+ Alpha += targetAlphaBlendAmount;
+ }
+
+ if (Alpha <= maxAlphaAllowed) {
+ float minAlphaAllowed = -CARCAM_SET[camSetArrPos][14];
+ if (minAlphaAllowed > Alpha) {
+ Alpha = minAlphaAllowed;
+ AlphaSpeed = 0.0f;
+ }
+ } else {
+ Alpha = maxAlphaAllowed;
+ AlphaSpeed = 0.0f;
+ }
+
+ // Prevent unsignificant angle changes
+ if (Abs(lastAlpha - Alpha) < 0.0001f)
+ Alpha = lastAlpha;
+
+ lastAlpha = Alpha;
+
+ if (Abs(lastBeta - Beta) < 0.0001f)
+ Beta = lastBeta;
+
+ lastBeta = Beta;
+
+ Front.x = -(cos(Beta) * cos(Alpha));
+ Front.y = -(sin(Beta) * cos(Alpha));
+ Front.z = sin(Alpha);
+ GetVectorsReadyForRW();
+ TheCamera.m_bCamDirectlyBehind = false;
+ TheCamera.m_bCamDirectlyInFront = false;
+
+ Source = TargetCoors - newDistance * Front;
+
+ m_cvecTargetCoorsForFudgeInter = TargetCoors;
+ m_aTargetHistoryPosThree = m_aTargetHistoryPosOne;
+ float nextAlpha = alphaWithSpeedAccounted + zoomModeAlphaOffset;
+ float nextFrontX = -(cos(Beta) * cos(nextAlpha));
+ float nextFrontY = -(sin(Beta) * cos(nextAlpha));
+ float nextFrontZ = sin(nextAlpha);
+
+ m_aTargetHistoryPosOne.x = TargetCoors.x - nextFrontX * nextDistance;
+ m_aTargetHistoryPosOne.y = TargetCoors.y - nextFrontY * nextDistance;
+ m_aTargetHistoryPosOne.z = TargetCoors.z - nextFrontZ * nextDistance;
+
+ m_aTargetHistoryPosTwo.x = TargetCoors.x - nextFrontX * newDistance;
+ m_aTargetHistoryPosTwo.y = TargetCoors.y - nextFrontY * newDistance;
+ m_aTargetHistoryPosTwo.z = TargetCoors.z - nextFrontZ * newDistance;
+
+ // SA calls SetColVarsVehicle in here
+ if (nextDirectionIsForward) {
+
+ // This is new in LCS!
+ float timestepFactor = Pow(0.99f, CTimer::GetTimeStep());
+ dontCollideWithCars = (timestepFactor * dontCollideWithCars) + ((1.0f - timestepFactor) * car->m_vecMoveSpeed.Magnitude());
+
+ // Move cam if on collision
+ CColPoint foundCol;
+ CEntity* foundEnt;
+ CWorld::pIgnoreEntity = CamTargetEntity;
+ if (CWorld::ProcessLineOfSight(TargetCoors, Source, foundCol, foundEnt, true, dontCollideWithCars < 0.1f, false, true, false, true, false)) {
+ float obstacleTargetDist = (TargetCoors - foundCol.point).Magnitude();
+ float obstacleCamDist = newDistance - obstacleTargetDist;
+ if (!foundEnt->IsPed() || obstacleCamDist <= 1.0f) {
+ Source = foundCol.point;
+ if (obstacleTargetDist < 1.2f) {
+ RwCameraSetNearClipPlane(Scene.camera, max(0.05f, obstacleTargetDist - 0.3f));
+ }
+ } else {
+ if (!CWorld::ProcessLineOfSight(foundCol.point, Source, foundCol, foundEnt, true, dontCollideWithCars < 0.1f, false, true, false, true, false)) {
+ float lessClip = obstacleCamDist - 0.35f;
+ if (lessClip <= DEFAULT_NEAR)
+ RwCameraSetNearClipPlane(Scene.camera, lessClip);
+ else
+ RwCameraSetNearClipPlane(Scene.camera, DEFAULT_NEAR);
+ } else {
+ obstacleTargetDist = (TargetCoors - foundCol.point).Magnitude();
+ Source = foundCol.point;
+ if (obstacleTargetDist < 1.2f) {
+ float lessClip = obstacleTargetDist - 0.3f;
+ if (lessClip >= 0.05f)
+ RwCameraSetNearClipPlane(Scene.camera, lessClip);
+ else
+ RwCameraSetNearClipPlane(Scene.camera, 0.05f);
+ }
+ }
+ }
+ }
+ CWorld::pIgnoreEntity = nil;
+ float nearClip = RwCameraGetNearClipPlane(Scene.camera);
+ float radius = Tan(DEGTORAD(FOV * 0.5f)) * CDraw::GetAspectRatio() * 1.1f;
+
+ // If we're seeing blue hell due to camera intersects some surface, fix it.
+ // SA and LCS have this unrolled.
+ for (int i = 0;
+ i <= 5 && CWorld::TestSphereAgainstWorld((nearClip * Front) + Source, radius * nearClip, nil, true, true, false, true, false, false);
+ i++) {
+
+ CVector surfaceCamDist = gaTempSphereColPoints->point - Source;
+ CVector frontButInvertedIfTouchesSurface = DotProduct(surfaceCamDist, Front) * Front;
+ float newNearClip = (surfaceCamDist - frontButInvertedIfTouchesSurface).Magnitude() / radius;
+
+ if (newNearClip > nearClip)
+ newNearClip = nearClip;
+ if (newNearClip < 0.1f)
+ newNearClip = 0.1f;
+ if (nearClip > newNearClip)
+ RwCameraSetNearClipPlane(Scene.camera, newNearClip);
+
+ if (newNearClip == 0.1f)
+ Source += (TargetCoors - Source) * 0.3f;
+
+ nearClip = RwCameraGetNearClipPlane(Scene.camera);
+ radius = Tan(DEGTORAD(FOV * 0.5f)) * CDraw::GetAspectRatio() * 1.1f;
+ }
+ }
+ TheCamera.m_bCamDirectlyBehind = false;
+ TheCamera.m_bCamDirectlyInFront = false;
+
+ // ------- LCS specific part starts
+
+ if (camSetArrPos == 5 && Source.z < 1.0f) // RC Bandit and Baron
+ Source.z = 1.0f;
+
+ // Obviously some specific place in LC
+ if (Source.x > 11.0f && Source.x < 91.0f) {
+ if (Source.y > -680.0f && Source.y < -600.0f && Source.z < 24.4f)
+ Source.z = 24.4f;
+ }
+
+ // CCam::FixSourceAboveWaterLevel
+ if (CameraTarget.z >= -2.0f) {
+ float level = -6000.0;
+ // +0.5f is needed for III
+ if (CWaterLevel::GetWaterLevelNoWaves(Source.x, Source.y, Source.z, &level)) {
+ if (Source.z < level + 0.5f)
+ Source.z = level + 0.5f;
+ }
+ }
+ Front = TargetCoors - Source;
+
+ // -------- LCS specific part ends
+
+ GetVectorsReadyForRW();
+ // SA
+ // gTargetCoordsForLookingBehind = TargetCoors;
+
+ // SA code from CAutomobile::TankControl/FireTruckControl.
+ if (car->m_modelIndex == MI_RHINO || car->m_modelIndex == MI_FIRETRUCK) {
+
+ float &carGunLR = ((CAutomobile*)car)->m_fCarGunLR;
+ CVector hi = Multiply3x3(Front, car->GetMatrix());
+
+ // III/VC's firetruck turret angle is reversed
+ float angleToFace = (car->m_modelIndex == MI_FIRETRUCK ? -hi.Heading() : hi.Heading());
+
+ if (angleToFace <= carGunLR + PI) {
+ if (angleToFace < carGunLR - PI)
+ angleToFace = angleToFace + TWOPI;
+ } else {
+ angleToFace = angleToFace - TWOPI;
+ }
+
+ float neededTurn = angleToFace - carGunLR;
+ float turnPerFrame = CTimer::GetTimeStep() * (car->m_modelIndex == MI_FIRETRUCK ? 0.05f : 0.015f);
+ if (neededTurn <= turnPerFrame) {
+ if (neededTurn < -turnPerFrame)
+ angleToFace = carGunLR - turnPerFrame;
+ } else {
+ angleToFace = turnPerFrame + carGunLR;
+ }
+
+ if (car->m_modelIndex == MI_RHINO && carGunLR != angleToFace) {
+ DMAudio.PlayOneShot(car->m_audioEntityId, SOUND_CAR_TANK_TURRET_ROTATE, Abs(angleToFace - carGunLR));
+ }
+ carGunLR = angleToFace;
+
+ if (carGunLR < -PI) {
+ carGunLR += TWOPI;
+ } else if (carGunLR > PI) {
+ carGunLR -= TWOPI;
+ }
+
+ // Because firetruk turret also has Y movement
+ if (car->m_modelIndex == MI_FIRETRUCK) {
+ float &carGunUD = ((CAutomobile*)car)->m_fCarGunUD;
+
+ float alphaToFace = Atan2(hi.z, hi.Magnitude2D()) + DEGTORAD(15.0f);
+ float neededAlphaTurn = alphaToFace - carGunUD;
+ float alphaTurnPerFrame = CTimer::GetTimeStep() * 0.02f;
+
+ if (neededAlphaTurn > alphaTurnPerFrame) {
+ neededTurn = alphaTurnPerFrame;
+ carGunUD = neededTurn + carGunUD;
+ } else {
+ if (neededAlphaTurn >= -alphaTurnPerFrame) {
+ carGunUD = alphaToFace;
+ } else {
+ carGunUD = carGunUD - alphaTurnPerFrame;
+ }
+ }
+
+ float turretMinY = -DEGTORAD(20.0f);
+ float turretMaxY = DEGTORAD(20.0f);
+ if (turretMinY <= carGunUD) {
+ if (carGunUD > turretMaxY)
+ carGunUD = turretMaxY;
+ } else {
+ carGunUD = turretMinY;
+ }
+ }
+ }
+}
+#endif
+
+STARTPATCHES
+ InjectHook(0x456F40, WellBufferMe, PATCH_JUMP);
+ InjectHook(0x458410, &CCam::Init, PATCH_JUMP);
+ InjectHook(0x4582F0, &CCam::GetVectorsReadyForRW, PATCH_JUMP);
+ InjectHook(0x457710, &CCam::DoAverageOnVector, PATCH_JUMP);
+ InjectHook(0x458060, &CCam::GetPedBetaAngleForClearView, PATCH_JUMP);
+ InjectHook(0x457210, &CCam::Cam_On_A_String_Unobscured, PATCH_JUMP);
+ InjectHook(0x457A80, &CCam::FixCamWhenObscuredByVehicle, PATCH_JUMP);
+ InjectHook(0x457B90, &CCam::FixCamIfObscured, PATCH_JUMP);
+ InjectHook(0x465DA0, &CCam::RotCamIfInFrontCar, PATCH_JUMP);
+ InjectHook(0x4662D0, &CCam::WorkOutCamHeightWeeCar, PATCH_JUMP);
+ InjectHook(0x466650, &CCam::WorkOutCamHeight, PATCH_JUMP);
+ InjectHook(0x458600, &CCam::LookBehind, PATCH_JUMP);
+ InjectHook(0x458C40, &CCam::LookLeft, PATCH_JUMP);
+ InjectHook(0x458FB0, &CCam::LookRight, PATCH_JUMP);
+ InjectHook(0x4574C0, &CCam::ClipIfPedInFrontOfPlayer, PATCH_JUMP);
+ InjectHook(0x459300, &CCam::KeepTrackOfTheSpeed, PATCH_JUMP);
+ InjectHook(0x458580, &CCam::IsTargetInWater, PATCH_JUMP);
+ InjectHook(0x4570C0, &CCam::AvoidWallsTopDownPed, PATCH_JUMP);
+ InjectHook(0x4595B0, &CCam::PrintMode, PATCH_JUMP);
+
+ InjectHook(0x467400, &CCam::ProcessSpecialHeightRoutines, PATCH_JUMP);
+ InjectHook(0x4596A0, &CCam::Process, PATCH_JUMP);
+ InjectHook(0x45E3A0, &CCam::Process_FollowPed, PATCH_JUMP);
+ InjectHook(0x45FF70, &CCam::Process_FollowPedWithMouse, PATCH_JUMP);
+ InjectHook(0x45BE60, &CCam::Process_BehindCar, PATCH_JUMP);
+ InjectHook(0x45C090, &CCam::Process_Cam_On_A_String, PATCH_JUMP);
+ InjectHook(0x463EB0, &CCam::Process_TopDown, PATCH_JUMP);
+ InjectHook(0x464390, &CCam::Process_TopDownPed, PATCH_JUMP);
+ InjectHook(0x461AF0, &CCam::Process_Rocket, PATCH_JUMP);
+ InjectHook(0x460E00, &CCam::Process_M16_1stPerson, PATCH_JUMP);
+ InjectHook(0x459FA0, &CCam::Process_1stPerson, PATCH_JUMP);
+ InjectHook(0x462420, &CCam::Process_Sniper, PATCH_JUMP);
+ InjectHook(0x463130, &CCam::Process_Syphon, PATCH_JUMP);
+ InjectHook(0x463A70, &CCam::Process_Syphon_Crim_In_Front, PATCH_JUMP);
+ InjectHook(0x45B470, &CCam::Process_BehindBoat, PATCH_JUMP);
+ InjectHook(0x45D2F0, &CCam::Process_Fight_Cam, PATCH_JUMP);
+ InjectHook(0x45DC20, &CCam::Process_FlyBy, PATCH_JUMP);
+ InjectHook(0x464D10, &CCam::Process_WheelCam, PATCH_JUMP);
+ InjectHook(0x45DA20, &CCam::Process_Fixed, PATCH_JUMP);
+ InjectHook(0x461940, &CCam::Process_Player_Fallen_Water, PATCH_JUMP);
+ InjectHook(0x45C400, &CCam::Process_Circle, PATCH_JUMP);
+ InjectHook(0x462FC0, &CCam::Process_SpecialFixedForSyphon, PATCH_JUMP);
+ InjectHook(0x45CCC0, &CCam::Process_Debug, PATCH_JUMP);
+ InjectHook(0x4656C0, &CCam::ProcessPedsDeadBaby, PATCH_JUMP);
+ InjectHook(0x465000, &CCam::ProcessArrestCamOne, PATCH_JUMP);
+ InjectHook(0x4653C0, &CCam::ProcessArrestCamTwo, PATCH_JUMP);
+
+ InjectHook(0x456CE0, &FindSplinePathPositionFloat, PATCH_JUMP);
+ InjectHook(0x4569A0, &FindSplinePathPositionVector, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp
index 75e52c5f..e5bc09c8 100644
--- a/src/core/Camera.cpp
+++ b/src/core/Camera.cpp
@@ -4,1382 +4,3185 @@
#include "Draw.h"
#include "World.h"
#include "Vehicle.h"
+#include "Train.h"
+#include "Automobile.h"
#include "Ped.h"
#include "PlayerPed.h"
+#include "Wanted.h"
#include "Pad.h"
+#include "ControllerConfig.h"
#include "General.h"
#include "ZoneCull.h"
#include "SurfaceTable.h"
+#include "WaterLevel.h"
+#include "World.h"
+#include "Garages.h"
+#include "Replay.h"
+#include "CutsceneMgr.h"
+#include "Renderer.h"
#include "MBlur.h"
+#include "Text.h"
+#include "Hud.h"
+#include "DMAudio.h"
+#include "FileMgr.h"
+#include "Frontend.h"
+#include "SceneEdit.h"
+#include "Pools.h"
+#include "Debug.h"
#include "Camera.h"
-const float DefaultFOV = 70.0f; // beta: 80.0f
+enum
+{
+ // car
+ OBBE_WHEEL,
+ OBBE_1,
+ OBBE_2,
+ OBBE_3,
+ OBBE_1STPERSON, // unused
+ OBBE_5,
+ OBBE_ONSTRING,
+ OBBE_COPCAR,
+ OBBE_COPCAR_WHEEL,
+ // ped
+ OBBE_9,
+ OBBE_10,
+ OBBE_11,
+ OBBE_12,
+ OBBE_13,
+
+ OBBE_INVALID
+};
+
+// abbreviate a few things
+#define PLAYER (CWorld::Players[CWorld::PlayerInFocus].m_pPed)
+// NB: removed explicit TheCamera from all functions
CCamera &TheCamera = *(CCamera*)0x6FACF8;
bool &CCamera::m_bUseMouse3rdPerson = *(bool *)0x5F03D8;
+bool &bDidWeProcessAnyCinemaCam = *(bool*)0x95CD46;
-WRAPPER void CCamera::CamShake(float strength, float x, float y, float z) { EAXJMP(0x46B200); }
-WRAPPER void CCamera::DrawBordersForWideScreen(void) { EAXJMP(0x46B430); }
-WRAPPER void CCamera::CalculateDerivedValues(void) { EAXJMP(0x46EEA0); }
-WRAPPER void CCamera::Restore(void) { EAXJMP(0x46F990); }
-WRAPPER void CamShakeNoPos(CCamera*, float) { EAXJMP(0x46B100); }
-WRAPPER void CCamera::TakeControl(CEntity*, int16, int16, int32) { EAXJMP(0x471500); }
-WRAPPER void CCamera::TakeControlNoEntity(const CVector&, int16, int32) { EAXJMP(0x4715B0); }
-WRAPPER void CCamera::Init(void) { EAXJMP(0x46BAD0); }
-WRAPPER void CCamera::Process(void) { EAXJMP(0x46D3F0); }
-WRAPPER void CCamera::LoadPathSplines(int file) { EAXJMP(0x46D1D0); }
-WRAPPER void CCamera::RestoreWithJumpCut(void) { EAXJMP(0x46FAE0); };
-WRAPPER void CCamera::SetPercentAlongCutScene(float) { EAXJMP(0x46FE20); };
-WRAPPER void CCamera::SetParametersForScriptInterpolation(float, float, int32) { EAXJMP(0x46FDE0); }
+#ifdef IMPROVED_CAMERA
+#define KEYJUSTDOWN(k) ControlsManager.GetIsKeyboardKeyJustDown((RsKeyCodes)k)
+#define KEYDOWN(k) ControlsManager.GetIsKeyboardKeyDown((RsKeyCodes)k)
+#define CTRLJUSTDOWN(key) \
+ ((KEYDOWN(rsLCTRL) || KEYDOWN(rsRCTRL)) && KEYJUSTDOWN((RsKeyCodes)key) || \
+ (KEYJUSTDOWN(rsLCTRL) || KEYJUSTDOWN(rsRCTRL)) && KEYDOWN((RsKeyCodes)key))
+#define CTRLDOWN(key) ((KEYDOWN(rsLCTRL) || KEYDOWN(rsRCTRL)) && KEYDOWN((RsKeyCodes)key))
+#endif
-bool
-CCamera::GetFading()
+void
+CCamera::Init(void)
{
- return m_bFading;
+ memset(this, 0, sizeof(CCamera)); // getting rid of vtable, eh?
+
+ m_pRwCamera = nil;
+ m_1rstPersonRunCloseToAWall = false;
+ m_fPositionAlongSpline = 0.0f;
+ m_bCameraJustRestored = false;
+ Cams[0].Init();
+ Cams[1].Init();
+ Cams[2].Init();
+ Cams[0].Mode = CCam::MODE_FOLLOWPED;
+ Cams[1].Mode = CCam::MODE_FOLLOWPED;
+ unknown = 0;
+ m_bJustJumpedOutOf1stPersonBecauseOfTarget = 0;
+ ClearPlayerWeaponMode();
+ m_bInATunnelAndABigVehicle = false;
+ m_iModeObbeCamIsInForCar = OBBE_INVALID;
+ Cams[0].CamTargetEntity = nil;
+ Cams[1].CamTargetEntity = nil;
+ Cams[2].CamTargetEntity = nil;
+ Cams[0].m_fCamBufferedHeight = 0.0f;
+ Cams[0].m_fCamBufferedHeightSpeed = 0.0f;
+ Cams[1].m_fCamBufferedHeight = 0.0f;
+ Cams[1].m_fCamBufferedHeightSpeed = 0.0f;
+ Cams[0].m_bCamLookingAtVector = false;
+ Cams[1].m_bCamLookingAtVector = false;
+ Cams[2].m_bCamLookingAtVector = false;
+ Cams[0].m_fPlayerVelocity = 0.0f;
+ Cams[1].m_fPlayerVelocity = 0.0f;
+ Cams[2].m_fPlayerVelocity = 0.0f;
+ m_bHeadBob = false;
+ m_fFractionInterToStopMovingTarget = 0.25f;
+ m_fFractionInterToStopCatchUpTarget = 0.75f;
+ m_fGaitSwayBuffer = 0.85f;
+ m_bScriptParametersSetForInterPol = false;
+ m_uiCamShakeStart = 0;
+ m_fCamShakeForce = 0.0f;
+ m_iModeObbeCamIsInForCar = OBBE_INVALID;
+ m_bIgnoreFadingStuffForMusic = false;
+ m_bWaitForInterpolToFinish = false;
+ pToGarageWeAreIn = nil;
+ pToGarageWeAreInForHackAvoidFirstPerson = nil;
+ m_bPlayerIsInGarage = false;
+ m_bJustCameOutOfGarage = false;
+ m_fNearClipScript = DEFAULT_NEAR;
+ m_bUseNearClipScript = false;
+ m_vecDoingSpecialInterPolation = false;
+ m_bAboveGroundTrainNodesLoaded = false;
+ m_bBelowGroundTrainNodesLoaded = false;
+ m_WideScreenOn = false;
+ m_fFOV_Wide_Screen = 0.0f;
+ m_bRestoreByJumpCut = false;
+ CarZoomIndicator = 2.0f;
+ PedZoomIndicator = 2.0f;
+ CarZoomValueSmooth = 0.0f;
+ m_fPedZoomValueSmooth = 0.0f;
+ pTargetEntity = nil;
+ if(FindPlayerVehicle())
+ pTargetEntity = FindPlayerVehicle();
+ else
+ pTargetEntity = CWorld::Players[CWorld::PlayerInFocus].m_pPed;
+ m_bInitialNodeFound = false;
+ m_ScreenReductionPercentage = 0.0f;
+ m_ScreenReductionSpeed = 0.0f;
+ m_WideScreenOn = false;
+ m_bWantsToSwitchWidescreenOff = false;
+ WorldViewerBeingUsed = false;
+ PlayerExhaustion = 1.0f;
+ DebugCamMode = CCam::MODE_NONE;
+ m_PedOrientForBehindOrInFront = 0.0f;
+ if(!FrontEndMenuManager.m_bStartGameLoading){
+ m_bFading = false;
+ CDraw::FadeValue = 0;
+ m_fFLOATingFade = 0.0f;
+ m_bMusicFading = false;
+ m_fTimeToFadeMusic = 0.0f;
+ m_fFLOATingFadeMusic = 0.0f;
+ }
+ m_bMoveCamToAvoidGeom = false;
+ if(FrontEndMenuManager.m_bStartGameLoading)
+ m_bMoveCamToAvoidGeom = true;
+ m_bStartingSpline = false;
+ m_iTypeOfSwitch = INTERPOLATION;
+ m_bUseScriptZoomValuePed = false;
+ m_bUseScriptZoomValueCar = false;
+ m_fPedZoomValueScript = 0.0f;
+ m_fCarZoomValueScript = 0.0f;
+ m_bUseSpecialFovTrain = false;
+ m_fFovForTrain = 70.0f; // or DefaultFOV from Cam.cpp
+ m_iModeToGoTo = CCam::MODE_FOLLOWPED;
+ m_bJust_Switched = false;
+ m_bUseTransitionBeta = false;
+ m_matrix.SetScale(1.0f);
+ m_bTargetJustBeenOnTrain = false;
+ m_bInitialNoNodeStaticsSet = false;
+ m_uiLongestTimeInMill = 5000;
+ m_uiTimeLastChange = 0;
+ m_uiTimeWeEnteredIdle = 0;
+ m_bIdleOn = false;
+ LODDistMultiplier = 1.0f;
+ m_bCamDirectlyBehind = false;
+ m_bCamDirectlyInFront = false;
+ m_motionBlur = 0;
+ m_bGarageFixedCamPositionSet = false;
+ SetMotionBlur(255, 255, 255, 0, 0);
+ m_bCullZoneChecksOn = false;
+ m_bFailedCullZoneTestPreviously = false;
+ m_iCheckCullZoneThisNumFrames = 6;
+ m_iZoneCullFrameNumWereAt = 0;
+ m_CameraAverageSpeed = 0.0f;
+ m_CameraSpeedSoFar = 0.0f;
+ m_PreviousCameraPosition = CVector(0.0f, 0.0f, 0.0f);
+ m_iWorkOutSpeedThisNumFrames = 4;
+ m_iNumFramesSoFar = 0;
+ m_bJustInitalised = true;
+ m_uiTransitionState = 0;
+ m_uiTimeTransitionStart = 0;
+ m_bLookingAtPlayer = true;
+ m_fMouseAccelHorzntl = 0.0025f;
+ m_fMouseAccelVertical = 0.003f;
+ m_f3rdPersonCHairMultX = 0.53f;
+ m_f3rdPersonCHairMultY = 0.4f;
}
-bool
-CCamera::IsSphereVisible(const CVector &center, float radius, const CMatrix *mat)
+void
+CCamera::Process(void)
{
- RwV3d c;
- c = *(RwV3d*)&center;
- RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix);
- if(c.y + radius < CDraw::GetNearClipZ()) return false;
- if(c.y - radius > CDraw::GetFarClipZ()) return false;
- if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > radius) return false;
- if(c.x*m_vecFrustumNormals[1].x + c.y*m_vecFrustumNormals[1].y > radius) return false;
- if(c.y*m_vecFrustumNormals[2].y + c.z*m_vecFrustumNormals[2].z > radius) return false;
- if(c.y*m_vecFrustumNormals[3].y + c.z*m_vecFrustumNormals[3].z > radius) return false;
- return true;
-}
+ // static bool InterpolatorNotInitialised = true; // unused
+ static float PlayerMinDist = 1.6f; // not on PS2
+ static bool WasPreviouslyInterSyhonFollowPed = false; // only written
+ float FOV = 0.0f;
+ float oldBeta, newBeta;
+ float deltaBeta = 0.0f;
+ bool lookLRBVehicle = false;
+ CVector CamFront, CamUp, CamSource, Target;
+
+ m_bJust_Switched = false;
+ m_RealPreviousCameraPosition = GetPosition();
+
+ // Update target entity
+ if(m_bLookingAtPlayer || m_bTargetJustBeenOnTrain || WhoIsInControlOfTheCamera == CAMCONTROL_OBBE)
+ UpdateTargetEntity();
+ if(pTargetEntity == nil)
+ pTargetEntity = FindPlayerPed();
+ if(Cams[ActiveCam].CamTargetEntity == nil)
+ Cams[ActiveCam].CamTargetEntity = pTargetEntity;
+ if(Cams[(ActiveCam+1)%2].CamTargetEntity == nil)
+ Cams[(ActiveCam+1)%2].CamTargetEntity = pTargetEntity;
+
+ CamControl();
+ if(m_bFading)
+ ProcessFade();
+ if(m_bMusicFading)
+ ProcessMusicFade();
+ if(m_WideScreenOn)
+ ProcessWideScreenOn();
+
+#ifdef IMPROVED_CAMERA
+ if(CPad::GetPad(1)->GetCircleJustDown() || CTRLJUSTDOWN('B')){
+#else
+ if(CPad::GetPad(1)->GetCircleJustDown()){
+#endif
+ WorldViewerBeingUsed = !WorldViewerBeingUsed;
+ if(WorldViewerBeingUsed)
+ InitialiseCameraForDebugMode();
+ else
+ CPad::m_bMapPadOneToPadTwo = false;
+ }
-bool
-CCamera::IsSphereVisible(const CVector &center, float radius)
-{
- CMatrix mat = m_cameraMatrix;
- return IsSphereVisible(center, radius, &mat);
-}
+ RwCameraSetNearClipPlane(Scene.camera, DEFAULT_NEAR);
-bool
-CCamera::IsPointVisible(const CVector &center, const CMatrix *mat)
-{
- RwV3d c;
- c = *(RwV3d*)&center;
- RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix);
- if(c.y < CDraw::GetNearClipZ()) return false;
- if(c.y > CDraw::GetFarClipZ()) return false;
- if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > 0.0f) return false;
- if(c.x*m_vecFrustumNormals[1].x + c.y*m_vecFrustumNormals[1].y > 0.0f) return false;
- if(c.y*m_vecFrustumNormals[2].y + c.z*m_vecFrustumNormals[2].z > 0.0f) return false;
- if(c.y*m_vecFrustumNormals[3].y + c.z*m_vecFrustumNormals[3].z > 0.0f) return false;
- return true;
-}
+ if(Cams[ActiveCam].Front.x == 0.0f && Cams[ActiveCam].Front.y == 0.0f)
+ oldBeta = 0.0f;
+ else
+ oldBeta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y);
-bool
-CCamera::IsBoxVisible(RwV3d *box, const CMatrix *mat)
-{
- int i;
- int frustumTests[6] = { 0 };
- RwV3dTransformPoints(box, box, 8, &mat->m_matrix);
+ Cams[ActiveCam].Process();
+ Cams[ActiveCam].ProcessSpecialHeightRoutines();
- for(i = 0; i < 8; i++){
- if(box[i].y < CDraw::GetNearClipZ()) frustumTests[0]++;
- if(box[i].y > CDraw::GetFarClipZ()) frustumTests[1]++;
- if(box[i].x*m_vecFrustumNormals[0].x + box[i].y*m_vecFrustumNormals[0].y > 0.0f) frustumTests[2]++;
- if(box[i].x*m_vecFrustumNormals[1].x + box[i].y*m_vecFrustumNormals[1].y > 0.0f) frustumTests[3]++;
-// Why not test z?
-// if(box[i].y*m_vecFrustumNormals[2].y + box[i].z*m_vecFrustumNormals[2].z > 0.0f) frustumTests[4]++;
-// if(box[i].y*m_vecFrustumNormals[3].y + box[i].z*m_vecFrustumNormals[3].z > 0.0f) frustumTests[5]++;
- }
- for(i = 0; i < 6; i++)
- if(frustumTests[i] == 8)
- return false; // Box is completely outside of one plane
- return true;
-}
+ if(Cams[ActiveCam].Front.x == 0.0f && Cams[ActiveCam].Front.y == 0.0f)
+ newBeta = 0.0f;
+ else
+ newBeta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y);
-int
-CCamera::GetLookDirection(void)
-{
- if(Cams[ActiveCam].Mode == CCam::MODE_CAM_ON_A_STRING ||
- Cams[ActiveCam].Mode == CCam::MODE_1STPERSON ||
- Cams[ActiveCam].Mode == CCam::MODE_BEHINDBOAT ||
- Cams[ActiveCam].Mode == CCam::MODE_FOLLOWPED)
- return Cams[ActiveCam].DirectionWasLooking;
- return LOOKING_FORWARD;;
-}
-bool
-CCamera::GetLookingForwardFirstPerson()
-{
- return Cams[ActiveCam].Mode == CCam::MODE_1STPERSON &&
- Cams[ActiveCam].DirectionWasLooking == LOOKING_FORWARD;
-}
+ // Stop transition when it's done
+ if(m_uiTransitionState != 0){
+/*
+ // PS2:
+ if(!m_bWaitForInterpolToFinish){
+ Cams[(ActiveCam+1)%2].Process();
+ Cams[(ActiveCam+1)%2].ProcessSpecialHeightRoutines();
+ }
+*/
+ // not PS2 (done in CamControl there it seems)
+ if(CTimer::GetTimeInMilliseconds() > m_uiTransitionDuration+m_uiTimeTransitionStart){
+ m_uiTransitionState = 0;
+ m_vecDoingSpecialInterPolation = false;
+ m_bWaitForInterpolToFinish = false;
+ }
+ }
+ if(m_bUseNearClipScript)
+ RwCameraSetNearClipPlane(Scene.camera, m_fNearClipScript);
+
+ deltaBeta = newBeta - oldBeta;
+ while(deltaBeta >= PI) deltaBeta -= 2*PI;
+ while(deltaBeta < -PI) deltaBeta += 2*PI;
+ if(Abs(deltaBeta) > 0.3f)
+ m_bJust_Switched = true;
+
+ // Debug stuff
+ if(!gbModelViewer)
+ Cams[ActiveCam].PrintMode();
+ if(WorldViewerBeingUsed)
+ Cams[2].Process();
+
+ if(Cams[ActiveCam].DirectionWasLooking != LOOKING_FORWARD && pTargetEntity->IsVehicle())
+ lookLRBVehicle = true;
+
+ if(m_uiTransitionState != 0 && !lookLRBVehicle){
+ // Process transition
+ // different on PS2
+
+ uint32 currentTime = CTimer::GetTimeInMilliseconds() - m_uiTimeTransitionStart;
+ if(currentTime >= m_uiTransitionDuration)
+ currentTime = m_uiTransitionDuration;
+ float fractionInter = (float) currentTime / m_uiTransitionDuration;
+
+ if(fractionInter <= m_fFractionInterToStopMovingTarget){
+ float inter;
+ if(m_fFractionInterToStopMovingTarget == 0.0f)
+ inter = 0.0f;
+ else
+ inter = (m_fFractionInterToStopMovingTarget - fractionInter)/m_fFractionInterToStopMovingTarget;
+ inter = 0.5f - 0.5*Cos(inter*PI); // smooth it
+
+ m_vecSourceWhenInterPol = m_cvecStartingSourceForInterPol + inter*m_cvecSourceSpeedAtStartInter;
+ m_vecTargetWhenInterPol = m_cvecStartingTargetForInterPol + inter*m_cvecTargetSpeedAtStartInter;
+ m_vecUpWhenInterPol = m_cvecStartingUpForInterPol + inter*m_cvecUpSpeedAtStartInter;
+ m_fFOVWhenInterPol = m_fStartingFOVForInterPol + inter*m_fFOVSpeedAtStartInter;
+
+ CamSource = m_vecSourceWhenInterPol;
+
+ if(m_bItsOkToLookJustAtThePlayer){
+ m_vecTargetWhenInterPol.x = FindPlayerPed()->GetPosition().x;
+ m_vecTargetWhenInterPol.y = FindPlayerPed()->GetPosition().y;
+ m_fBetaWhenInterPol = m_fStartingBetaForInterPol + inter*m_fBetaSpeedAtStartInter;
+
+ float dist = (CamSource - m_vecTargetWhenInterPol).Magnitude2D();
+ if(dist < PlayerMinDist){
+ if(dist > 0.0f){
+ CamSource.x = m_vecTargetWhenInterPol.x + PlayerMinDist*Cos(m_fBetaWhenInterPol);
+ CamSource.y = m_vecTargetWhenInterPol.y + PlayerMinDist*Sin(m_fBetaWhenInterPol);
+ }else{
+ // can only be 0.0 now...
+ float beta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y);
+ CamSource.x = m_vecTargetWhenInterPol.x + PlayerMinDist*Cos(beta);
+ CamSource.y = m_vecTargetWhenInterPol.y + PlayerMinDist*Sin(beta);
+ }
+ }else{
+ CamSource.x = m_vecTargetWhenInterPol.x + dist*Cos(m_fBetaWhenInterPol);
+ CamSource.y = m_vecTargetWhenInterPol.y + dist*Sin(m_fBetaWhenInterPol);
+ }
+ }
-WRAPPER void CCamera::Fade(float timeout, int16 direction) { EAXJMP(0x46B3A0); }
-WRAPPER void CCamera::ProcessFade(void) { EAXJMP(0x46F080); }
-WRAPPER void CCamera::ProcessMusicFade(void) { EAXJMP(0x46F1E0); }
+ CamFront = m_vecTargetWhenInterPol - CamSource;
+ StoreValuesDuringInterPol(CamSource, m_vecTargetWhenInterPol, m_vecUpWhenInterPol, m_fFOVWhenInterPol);
+ Target = m_vecTargetWhenInterPol;
+ CamFront.Normalise();
+ if(m_bLookingAtPlayer)
+ CamUp = CVector(0.0f, 0.0f, 1.0f);
+ else
+ CamUp = m_vecUpWhenInterPol;
+ CamUp.Normalise();
-int
-CCamera::GetScreenFadeStatus(void)
-{
- if(m_fFLOATingFade == 0.0f)
- return FADE_0;
- if(m_fFLOATingFade == 255.0f)
- return FADE_2;
- return FADE_1;
-}
+ if(Cams[ActiveCam].Mode == CCam::MODE_TOPDOWN || Cams[ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED){
+ CamFront.Normalise();
+ CamUp = CrossProduct(CamFront, CVector(-1.0f, 0.0f, 0.0f));
+ }else{
+ CamFront.Normalise();
+ CamUp.Normalise();
+ CVector right = CrossProduct(CamFront, CamUp);
+ right.Normalise();
+ CamUp = CrossProduct(right, CamFront);
+ }
+ CamUp.Normalise();
+ FOV = m_fFOVWhenInterPol;
+ }else if(fractionInter > m_fFractionInterToStopMovingTarget && fractionInter <= 1.0f){
+ float inter;
+ if(m_fFractionInterToStopCatchUpTarget == 0.0f)
+ inter = 0.0f;
+ else
+ inter = (fractionInter - m_fFractionInterToStopMovingTarget)/m_fFractionInterToStopCatchUpTarget;
+ inter = 0.5f - 0.5*Cos(inter*PI); // smooth it
+
+ CamSource = m_vecSourceWhenInterPol + inter*(Cams[ActiveCam].Source - m_vecSourceWhenInterPol);
+ FOV = m_fFOVWhenInterPol + inter*(Cams[ActiveCam].FOV - m_fFOVWhenInterPol);
+ Target = m_vecTargetWhenInterPol + inter*(Cams[ActiveCam].m_cvecTargetCoorsForFudgeInter - m_vecTargetWhenInterPol);
+ CamUp = m_vecUpWhenInterPol + inter*(Cams[ActiveCam].Up - m_vecUpWhenInterPol);
+ deltaBeta = Cams[ActiveCam].m_fTrueBeta - m_fBetaWhenInterPol;
+ MakeAngleLessThan180(deltaBeta);
+ float interpBeta = m_fBetaWhenInterPol + inter*deltaBeta;
+
+ if(m_bItsOkToLookJustAtThePlayer){
+ Target.x = FindPlayerPed()->GetPosition().x;
+ Target.y = FindPlayerPed()->GetPosition().y;
+
+ float dist = (CamSource - Target).Magnitude2D();
+ if(dist < PlayerMinDist){
+ if(dist > 0.0f){
+ CamSource.x = Target.x + PlayerMinDist*Cos(interpBeta);
+ CamSource.y = Target.y + PlayerMinDist*Sin(interpBeta);
+ }else{
+ // can only be 0.0 now...
+ float beta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y);
+ CamSource.x = Target.x + PlayerMinDist*Cos(beta);
+ CamSource.y = Target.y + PlayerMinDist*Sin(beta);
+ }
+ }else{
+ CamSource.x = Target.x + dist*Cos(interpBeta);
+ CamSource.y = Target.y + dist*Sin(interpBeta);
+ }
+ }
-void
-CCamera::SetFadeColour(uint8 r, uint8 g, uint8 b)
-{
- m_FadeTargetIsSplashScreen = r == 0 && g == 0 && b == 0;
- CDraw::FadeRed = r;
- CDraw::FadeGreen = g;
- CDraw::FadeBlue = b;
-}
+ CamFront = Target - CamSource;
+ StoreValuesDuringInterPol(CamSource, Target, CamUp, FOV);
+ CamFront.Normalise();
+ if(m_bLookingAtPlayer)
+ CamUp = CVector(0.0f, 0.0f, 1.0f);
-void
-CCamera::SetMotionBlur(int r, int g, int b, int a, int type)
-{
- m_BlurRed = r;
- m_BlurGreen = g;
- m_BlurBlue = b;
- m_motionBlur = a;
- m_BlurType = type;
-}
+ if(Cams[ActiveCam].Mode == CCam::MODE_TOPDOWN || Cams[ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED){
+ CamFront.Normalise();
+ CamUp = CrossProduct(CamFront, CVector(-1.0f, 0.0f, 0.0f));
+ }else{
+ CamFront.Normalise();
+ CamUp.Normalise();
+ CVector right = CrossProduct(CamFront, CamUp);
+ right.Normalise();
+ CamUp = CrossProduct(right, CamFront);
+ }
+ CamUp.Normalise();
+#ifndef FIX_BUGS
+ // BUG: FOV was already interpolated but m_fFOVWhenInterPol was not
+ FOV = m_fFOVWhenInterPol;
+#endif
+ }
-void
-CCamera::SetMotionBlurAlpha(int a)
-{
- m_imotionBlurAddAlpha = a;
-}
+ CVector Dist = CamSource - Target;
+ float DistOnGround = Dist.Magnitude2D();
+ float Alpha = CGeneral::GetATanOfXY(DistOnGround, Dist.z);
+ float Beta = CGeneral::GetATanOfXY(Dist.x, Dist.y);
+ Cams[ActiveCam].KeepTrackOfTheSpeed(CamSource, Target, CamUp, Alpha, Beta, FOV);
+ }else{
+ // No transition, take Cam values directly
+ if(WorldViewerBeingUsed){
+ CamSource = Cams[2].Source;
+ CamFront = Cams[2].Front;
+ CamUp = Cams[2].Up;
+ FOV = Cams[2].FOV;
+ }else{
+ CamSource = Cams[ActiveCam].Source;
+ CamFront = Cams[ActiveCam].Front;
+ CamUp = Cams[ActiveCam].Up;
+ FOV = Cams[ActiveCam].FOV;
+ }
+ WasPreviouslyInterSyhonFollowPed = false; // unused
+ }
-void
-CCamera::SetNearClipScript(float clip)
-{
- m_fNearClipScript = clip;
- m_bUseNearClipScript = true;
-}
+ if(m_uiTransitionState != 0)
+ if(!m_bLookingAtVector && m_bLookingAtPlayer && !CCullZones::CamStairsForPlayer() && !m_bPlayerIsInGarage){
+ CEntity *entity = nil;
+ CColPoint colPoint;
+ if(CWorld::ProcessLineOfSight(pTargetEntity->GetPosition(), CamSource, colPoint, entity, true, false, false, true, false, true, true)){
+ CamSource = colPoint.point;
+ RwCameraSetNearClipPlane(Scene.camera, 0.05f);
+ }
+ }
-void
-CCamera::RenderMotionBlur(void)
-{
- if(m_BlurType == 0)
- return;
+ GetRight() = CrossProduct(CamUp, CamFront); // actually Left
+ GetForward() = CamFront;
+ GetUp() = CamUp;
+ GetPosition() = CamSource;
+
+ // Process Shake
+ float shakeStrength = m_fCamShakeForce - 0.28f*(CTimer::GetTimeInMilliseconds()-m_uiCamShakeStart)/1000.0f;
+ shakeStrength = clamp(shakeStrength, 0.0f, 2.0f);
+ int shakeRand = CGeneral::GetRandomNumber();
+ float shakeOffset = shakeStrength*0.1f;
+ GetPosition().x += shakeOffset*((shakeRand&0xF)-7);
+ GetPosition().y += shakeOffset*(((shakeRand&0xF0)>>4)-7);
+ GetPosition().z += shakeOffset*(((shakeRand&0xF00)>>8)-7);
+
+ if(shakeOffset > 0.0f && m_BlurType != MBLUR_SNIPER)
+ SetMotionBlurAlpha(min((int)(shakeStrength*255.0f) + 25, 150));
+ if(Cams[ActiveCam].Mode == CCam::MODE_1STPERSON && FindPlayerVehicle() && FindPlayerVehicle()->GetUp().z < 0.2f)
+ SetMotionBlur(230, 230, 230, 215, MBLUR_NORMAL);
+
+ CalculateDerivedValues();
+ CDraw::SetFOV(FOV);
+
+ // Set RW camera
+ if(WorldViewerBeingUsed){
+ RwFrame *frame = RwCameraGetFrame(m_pRwCamera);
+ CVector Source = Cams[2].Source;
+ CVector Front = Cams[2].Front;
+ CVector Up = Cams[2].Up;
+
+ GetRight() = CrossProduct(Up, Front);
+ GetForward() = Front;
+ GetUp() = Up;
+ GetPosition() = Source;
+
+ CDraw::SetFOV(Cams[2].FOV);
+ m_vecGameCamPos = Cams[ActiveCam].Source;
+
+ *RwMatrixGetPos(RwFrameGetMatrix(frame)) = (RwV3d)GetPosition();
+ *RwMatrixGetAt(RwFrameGetMatrix(frame)) = (RwV3d)GetForward();
+ *RwMatrixGetUp(RwFrameGetMatrix(frame)) = (RwV3d)GetUp();
+ *RwMatrixGetRight(RwFrameGetMatrix(frame)) = (RwV3d)GetRight();
+ RwMatrixUpdate(RwFrameGetMatrix(frame));
+ RwFrameUpdateObjects(frame);
+ }else{
+ RwFrame *frame = RwCameraGetFrame(m_pRwCamera);
+ m_vecGameCamPos = GetPosition();
+ *RwMatrixGetPos(RwFrameGetMatrix(frame)) = (RwV3d)GetPosition();
+ *RwMatrixGetAt(RwFrameGetMatrix(frame)) = (RwV3d)GetForward();
+ *RwMatrixGetUp(RwFrameGetMatrix(frame)) = (RwV3d)GetUp();
+ *RwMatrixGetRight(RwFrameGetMatrix(frame)) = (RwV3d)GetRight();
+ RwMatrixUpdate(RwFrameGetMatrix(frame));
+ RwFrameUpdateObjects(frame);
+ }
- CMBlur::MotionBlurRender(m_pRwCamera,
- m_BlurRed, m_BlurGreen, m_BlurBlue,
- m_motionBlur, m_BlurType, m_imotionBlurAddAlpha);
-}
+ CDraw::SetNearClipZ(RwCameraGetNearClipPlane(m_pRwCamera));
+ CDraw::SetFarClipZ(RwCameraGetFarClipPlane(m_pRwCamera));
-void
-CCamera::ClearPlayerWeaponMode()
-{
- PlayerWeaponMode.Mode = 0;
- PlayerWeaponMode.MaxZoom = 1;
- PlayerWeaponMode.MinZoom = -1;
- PlayerWeaponMode.Duration = 0.0f;
-}
+ UpdateSoundDistances();
+ if((CTimer::GetFrameCounter()&0xF) == 3)
+ DistanceToWater = CWaterLevel::CalcDistanceToWater(GetPosition().x, GetPosition().y);
-/*
- *
- * CCam
- *
- */
+ // LOD dist
+ if(!CCutsceneMgr::IsRunning() || CCutsceneMgr::UseLodMultiplier())
+ LODDistMultiplier = 70.0f/CDraw::GetFOV() * CDraw::GetAspectRatio()/(4.0f/3.0f);
+ else
+ LODDistMultiplier = 1.0f;
+ GenerationDistMultiplier = LODDistMultiplier;
+ LODDistMultiplier *= CRenderer::ms_lodDistScale;
+
+ // Keep track of speed
+ if(m_bJustInitalised || m_bJust_Switched){
+ m_PreviousCameraPosition = GetPosition();
+ m_bJustInitalised = false;
+ }
+ m_CameraSpeedSoFar += (GetPosition() - m_PreviousCameraPosition).Magnitude();
+ m_iNumFramesSoFar++;
+ if(m_iNumFramesSoFar == m_iWorkOutSpeedThisNumFrames){
+ m_CameraAverageSpeed = m_CameraSpeedSoFar / m_iWorkOutSpeedThisNumFrames;
+ m_CameraSpeedSoFar = 0.0f;
+ m_iNumFramesSoFar = 0;
+ }
+ m_PreviousCameraPosition = GetPosition();
+ // PS2: something doing on with forward vector here
-// MaxSpeed is a limit of how fast the value is allowed to change. 1.0 = to Target in up to 1ms
-// Acceleration is how fast the speed will change to MaxSpeed. 1.0 = to MaxSpeed in 1ms
-void
-WellBufferMe(float Target, float *CurrentValue, float *CurrentSpeed, float MaxSpeed, float Acceleration, bool IsAngle)
-{
- float Delta = Target - *CurrentValue;
+ if(Cams[ActiveCam].DirectionWasLooking != LOOKING_FORWARD && Cams[ActiveCam].Mode != CCam::MODE_TOP_DOWN_PED){
+ Cams[ActiveCam].Source = Cams[ActiveCam].SourceBeforeLookBehind;
+ Orientation += PI;
+ }
- if(IsAngle){
- while(Delta >= PI) Delta -= 2*PI;
- while(Delta < -PI) Delta += 2*PI;
+ if(m_uiTransitionState != 0){
+ int OtherCam = (ActiveCam+1)%2;
+ if(Cams[OtherCam].CamTargetEntity &&
+ pTargetEntity && pTargetEntity->IsPed() &&
+ !Cams[OtherCam].CamTargetEntity->IsVehicle() &&
+ Cams[ActiveCam].Mode != CCam::MODE_TOP_DOWN_PED && Cams[ActiveCam].DirectionWasLooking != LOOKING_FORWARD){
+ Cams[OtherCam].Source = Cams[ActiveCam%2].SourceBeforeLookBehind;
+ Orientation += PI;
+ }
}
- float TargetSpeed = Delta * MaxSpeed;
- // Add or subtract absolute depending on sign, genius!
-// if(TargetSpeed - *CurrentSpeed > 0.0f)
-// *CurrentSpeed += Acceleration * Abs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep();
-// else
-// *CurrentSpeed -= Acceleration * Abs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep();
- // this is simpler:
- *CurrentSpeed += Acceleration * (TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep();
-
- // Clamp speed if we overshot
- if(TargetSpeed < 0.0f && *CurrentSpeed < TargetSpeed)
- *CurrentSpeed = TargetSpeed;
- else if(TargetSpeed > 0.0f && *CurrentSpeed > TargetSpeed)
- *CurrentSpeed = TargetSpeed;
-
- *CurrentValue += *CurrentSpeed * min(10.0f, CTimer::GetTimeStep());
+ m_bCameraJustRestored = false;
}
void
-CCam::GetVectorsReadyForRW(void)
-{
- CVector right;
- Up = CVector(0.0f, 0.0f, 1.0f);
- Front.Normalise();
- if(Front.x == 0.0f && Front.y == 0.0f){
- Front.x = 0.0001f;
- Front.y = 0.0001f;
- }
- right = CrossProduct(Front, Up);
- right.Normalise();
- Up = CrossProduct(right, Front);
-}
-
-// This code is really bad. wtf R*?
-CVector
-CCam::DoAverageOnVector(const CVector &vec)
+CCamera::CamControl(void)
{
- int i;
- CVector Average = { 0.0f, 0.0f, 0.0f };
-
- if(ResetStatics){
- m_iRunningVectorArrayPos = 0;
- m_iRunningVectorCounter = 1;
+ static bool PlaceForFixedWhenSniperFound = false;
+ static int16 ReqMode;
+ bool disableGarageCam = false;
+ bool switchByJumpCut = false;
+ bool stairs = false;
+ bool boatTarget = false;
+ CVector targetPos;
+ CVector garageCenter, garageDoorPos1, garageDoorPos2;
+ CVector garageCenterToDoor, garageCamPos;
+ int whichDoor;
+
+ m_bObbeCinematicPedCamOn = false;
+ m_bObbeCinematicCarCamOn = false;
+ m_bUseTransitionBeta = false;
+ m_bUseSpecialFovTrain = false;
+ m_bJustCameOutOfGarage = false;
+ m_bTargetJustCameOffTrain = false;
+ m_bInATunnelAndABigVehicle = false;
+
+ if(Cams[ActiveCam].CamTargetEntity == nil && pTargetEntity == nil)
+ pTargetEntity = PLAYER;
+
+ m_iZoneCullFrameNumWereAt++;
+ if(m_iZoneCullFrameNumWereAt > m_iCheckCullZoneThisNumFrames)
+ m_iZoneCullFrameNumWereAt = 1;
+ m_bCullZoneChecksOn = m_iZoneCullFrameNumWereAt == m_iCheckCullZoneThisNumFrames;
+ if(m_bCullZoneChecksOn)
+ m_bFailedCullZoneTestPreviously = CCullZones::CamCloseInForPlayer();
+
+ if(m_bLookingAtPlayer){
+ CPad::GetPad(0)->DisablePlayerControls &= ~PLAYERCONTROL_DISABLED_1;
+ FindPlayerPed()->bIsVisible = true;
}
- // TODO: make this work with NUMBER_OF_VECTORS_FOR_AVERAGE != 2
- if(m_iRunningVectorCounter == 3){
- m_arrPreviousVectors[0] = m_arrPreviousVectors[1];
- m_arrPreviousVectors[1] = vec;
- }else
- m_arrPreviousVectors[m_iRunningVectorArrayPos] = vec;
+ if(!CTimer::GetIsPaused()){
+ float CloseInCarHeightTarget = 0.0f;
+ float CloseInPedHeightTarget = 0.0f;
+
+ if(m_bTargetJustBeenOnTrain){
+ // Getting off train
+ if(!pTargetEntity->IsVehicle() || !((CVehicle*)pTargetEntity)->IsTrain()){
+ Restore();
+ m_bTargetJustCameOffTrain = true;
+ m_bTargetJustBeenOnTrain = false;
+ SetWideScreenOff();
+ }
+ }
- for(i = 0; i <= m_iRunningVectorArrayPos; i++)
- Average += m_arrPreviousVectors[i];
- Average /= i;
+ // Vehicle target
+ if(pTargetEntity->IsVehicle()){
+ if(((CVehicle*)pTargetEntity)->IsTrain()){
+ if(!m_bTargetJustBeenOnTrain){
+ m_bInitialNodeFound = false;
+ m_bInitialNoNodeStaticsSet = false;
+ }
+ Process_Train_Camera_Control();
+ }else{
+ if(((CVehicle*)pTargetEntity)->IsBoat())
+ boatTarget = true;
+
+ // Change user selected mode
+ if(CPad::GetPad(0)->CycleCameraModeUpJustDown() && !CReplay::IsPlayingBack() &&
+ (m_bLookingAtPlayer || WhoIsInControlOfTheCamera == CAMCONTROL_OBBE) &&
+ !m_WideScreenOn)
+ CarZoomIndicator -= 1.0f;
+ if(CPad::GetPad(0)->CycleCameraModeDownJustDown() && !CReplay::IsPlayingBack() &&
+ (m_bLookingAtPlayer || WhoIsInControlOfTheCamera == CAMCONTROL_OBBE) &&
+ !m_WideScreenOn)
+ CarZoomIndicator += 1.0f;
+ if(!m_bFailedCullZoneTestPreviously){
+ if(CarZoomIndicator < CAM_ZOOM_1STPRS) CarZoomIndicator = CAM_ZOOM_CINEMATIC;
+ else if(CarZoomIndicator > CAM_ZOOM_CINEMATIC) CarZoomIndicator = CAM_ZOOM_1STPRS;
+ }
- m_iRunningVectorArrayPos++;
- m_iRunningVectorCounter++;
- if(m_iRunningVectorArrayPos >= NUMBER_OF_VECTORS_FOR_AVERAGE)
- m_iRunningVectorArrayPos = NUMBER_OF_VECTORS_FOR_AVERAGE-1;
- if(m_iRunningVectorCounter > NUMBER_OF_VECTORS_FOR_AVERAGE+1)
- m_iRunningVectorCounter = NUMBER_OF_VECTORS_FOR_AVERAGE+1;
+ if(m_bFailedCullZoneTestPreviously)
+ if(CarZoomIndicator != CAM_ZOOM_1STPRS && CarZoomIndicator != CAM_ZOOM_TOPDOWN)
+ ReqMode = CCam::MODE_CAM_ON_A_STRING;
+
+ switch(((CVehicle*)pTargetEntity)->m_vehType){
+ case VEHICLE_TYPE_CAR:
+ case VEHICLE_TYPE_BIKE:
+ if(CGarages::IsPointInAGarageCameraZone(pTargetEntity->GetPosition())){
+ if(!m_bGarageFixedCamPositionSet && m_bLookingAtPlayer ||
+ WhoIsInControlOfTheCamera == CAMCONTROL_OBBE){
+ if(pToGarageWeAreIn){
+ float ground;
+ bool foundGround;
+
+ // This is all very strange....
+ // targetPos = pTargetEntity->GetPosition(); // unused
+ if(pToGarageWeAreIn->m_pDoor1){
+ whichDoor = 1;
+ garageDoorPos1.x = pToGarageWeAreIn->m_fDoor1X;
+ garageDoorPos1.y = pToGarageWeAreIn->m_fDoor1Y;
+ garageDoorPos1.z = 0.0f;
+ // targetPos.z = 0.0f; // unused
+ // (targetPos - doorPos1).Magnitude(); // unused
+ }else if(pToGarageWeAreIn->m_pDoor2){
+ whichDoor = 2;
+#ifdef FIX_BUGS
+ garageDoorPos2.x = pToGarageWeAreIn->m_fDoor2X;
+ garageDoorPos2.y = pToGarageWeAreIn->m_fDoor2Y;
+ garageDoorPos2.z = 0.0f;
+#endif
+ }else{
+ whichDoor = 1;
+ garageDoorPos1.x = pTargetEntity->GetPosition().x;
+ garageDoorPos1.y = pTargetEntity->GetPosition().y;
+#ifdef FIX_BUGS
+ garageDoorPos1.z = 0.0f;
+#else
+ garageDoorPos2.z = 0.0f;
+#endif
+ }
+ garageCenter.x = (pToGarageWeAreIn->m_fX1 + pToGarageWeAreIn->m_fX2)/2.0f;
+ garageCenter.y = (pToGarageWeAreIn->m_fY1 + pToGarageWeAreIn->m_fY2)/2.0f;
+ garageCenter.z = 0.0f;
+ if(whichDoor == 1)
+ garageCenterToDoor = garageDoorPos1 - garageCenter;
+ else
+ garageCenterToDoor = garageDoorPos2 - garageCenter;
+ targetPos = pTargetEntity->GetPosition();
+ ground = CWorld::FindGroundZFor3DCoord(targetPos.x, targetPos.y, targetPos.z, &foundGround);
+ if(!foundGround)
+ ground = targetPos.z - 0.2f;
+ garageCenterToDoor.z = 0.0f;
+ garageCenterToDoor.Normalise();
+ if(whichDoor == 1)
+ garageCamPos = garageDoorPos1 + 13.0f*garageCenterToDoor;
+ else
+ garageCamPos = garageDoorPos2 + 13.0f*garageCenterToDoor;
+ garageCamPos.z = ground + 3.1f;
+ SetCamPositionForFixedMode(garageCamPos, CVector(0.0f, 0.0f, 0.0f));
+ m_bGarageFixedCamPositionSet = true;
+ }
+ }
+
+ if(CGarages::CameraShouldBeOutside() && m_bGarageFixedCamPositionSet &&
+ (m_bLookingAtPlayer || WhoIsInControlOfTheCamera == CAMCONTROL_OBBE)){
+ if(pToGarageWeAreIn){
+ ReqMode = CCam::MODE_FIXED;
+ m_bPlayerIsInGarage = true;
+ }
+ }else{
+ if(m_bPlayerIsInGarage){
+ m_bJustCameOutOfGarage = true;
+ m_bPlayerIsInGarage = false;
+ }
+ ReqMode = CCam::MODE_CAM_ON_A_STRING;
+ }
+ }else{
+ if(m_bPlayerIsInGarage){
+ m_bJustCameOutOfGarage = true;
+ m_bPlayerIsInGarage = false;
+ }
+ m_bGarageFixedCamPositionSet = false;
+ ReqMode = CCam::MODE_CAM_ON_A_STRING;
+ }
+ break;
+ case VEHICLE_TYPE_BOAT:
+ ReqMode = CCam::MODE_BEHINDBOAT;
+ break;
+ }
- return Average;
-}
+ // Car zoom value
+ if(CarZoomIndicator == CAM_ZOOM_1STPRS && !m_bPlayerIsInGarage){
+ CarZoomValue = 0.0f;
+ ReqMode = CCam::MODE_1STPERSON;
+ }else if(CarZoomIndicator == CAM_ZOOM_1)
+ CarZoomValue = 0.05f;
+ else if(CarZoomIndicator == CAM_ZOOM_2)
+ CarZoomValue = 1.9f;
+ else if(CarZoomIndicator == CAM_ZOOM_3)
+ CarZoomValue = 3.9f;
+ if(CarZoomIndicator == CAM_ZOOM_TOPDOWN && !m_bPlayerIsInGarage){
+ CarZoomValue = 1.0f;
+ ReqMode = CCam::MODE_TOPDOWN;
+ }
-// Rotate Beta in direction opposite of BetaOffset in 5 deg. steps.
-// Return the first angle for which Beta + BetaOffset + Angle has a clear view.
-// i.e. BetaOffset is a safe zone so that Beta + Angle is really clear.
-// If BetaOffset == 0, try both directions.
-float
-CCam::GetPedBetaAngleForClearView(const CVector &Target, float Dist, float BetaOffset, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies)
-{
- CColPoint point;
- CEntity *ent = nil;
- CVector ToSource;
- float a;
-
- // This would be so much nicer if we just got the step variable before the loop...R*
-
- for(a = 0.0f; a <= PI; a += DEGTORAD(5.0f)){
- if(BetaOffset <= 0.0f){
- ToSource = CVector(Cos(Beta + BetaOffset + a), Sin(Beta + BetaOffset + a), 0.0f)*Dist;
- if(!CWorld::ProcessLineOfSight(Target, Target + ToSource,
- point, ent, checkBuildings, checkVehicles, checkPeds,
- checkObjects, checkDummies, true, true))
- return a;
- }
- if(BetaOffset >= 0.0f){
- ToSource = CVector(Cos(Beta + BetaOffset - a), Sin(Beta + BetaOffset - a), 0.0f)*Dist;
- if(!CWorld::ProcessLineOfSight(Target, Target + ToSource,
- point, ent, checkBuildings, checkVehicles, checkPeds,
- checkObjects, checkDummies, true, true))
- return -a;
- }
- }
- return 0.0f;
-}
+ // Check if we have to go into first person
+ if(((CVehicle*)pTargetEntity)->IsCar() && !m_bPlayerIsInGarage){
+ if(CCullZones::Cam1stPersonForPlayer() &&
+ pTargetEntity->GetColModel()->boundingBox.GetSize().z >= 3.026f &&
+ pToGarageWeAreInForHackAvoidFirstPerson == nil){
+ ReqMode = CCam::MODE_1STPERSON;
+ m_bInATunnelAndABigVehicle = true;
+ }
+ }
+ if(ReqMode == CCam::MODE_TOPDOWN &&
+ (CCullZones::Cam1stPersonForPlayer() || CCullZones::CamNoRain() || CCullZones::PlayerNoRain()))
+ ReqMode = CCam::MODE_1STPERSON;
+
+ // Smooth zoom value - ugly code
+ if(m_bUseScriptZoomValueCar){
+ if(CarZoomValueSmooth < m_fCarZoomValueScript){
+ CarZoomValueSmooth += 0.12f * CTimer::GetTimeStep();
+ CarZoomValueSmooth = min(CarZoomValueSmooth, m_fCarZoomValueScript);
+ }else{
+ CarZoomValueSmooth -= 0.12f * CTimer::GetTimeStep();
+ CarZoomValueSmooth = max(CarZoomValueSmooth, m_fCarZoomValueScript);
+ }
+ }else if(m_bFailedCullZoneTestPreviously){
+ CloseInCarHeightTarget = 0.65f;
+ if(CarZoomValueSmooth < -0.65f){
+ CarZoomValueSmooth += 0.12f * CTimer::GetTimeStep();
+ CarZoomValueSmooth = min(CarZoomValueSmooth, -0.65f);
+ }else{
+ CarZoomValueSmooth -= 0.12f * CTimer::GetTimeStep();
+ CarZoomValueSmooth = max(CarZoomValueSmooth, -0.65f);
+ }
+ }else{
+ if(CarZoomValueSmooth < CarZoomValue){
+ CarZoomValueSmooth += 0.12f * CTimer::GetTimeStep();
+ CarZoomValueSmooth = min(CarZoomValueSmooth, CarZoomValue);
+ }else{
+ CarZoomValueSmooth -= 0.12f * CTimer::GetTimeStep();
+ CarZoomValueSmooth = max(CarZoomValueSmooth, CarZoomValue);
+ }
+ }
-static float DefaultAcceleration = 0.045f;
-static float DefaultMaxStep = 0.15f;
+ WellBufferMe(CloseInCarHeightTarget, &Cams[ActiveCam].m_fCloseInCarHeightOffset, &Cams[ActiveCam].m_fCloseInCarHeightOffsetSpeed, 0.1f, 0.25f, false);
-void
-CCam::Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, float, float)
-{
- const float GroundDist = 1.85f;
-
- CVector TargetCoors, Dist, IdealSource;
- float Length = 0.0f;
- float LateralLeft = 0.0f;
- float LateralRight = 0.0f;
- float Center = 0.0f;
- static bool PreviouslyObscured;
- static bool PickedASide;
- static float FixedTargetOrientation = 0.0f;
- float AngleToGoTo = 0.0f;
- float BetaOffsetAvoidBuildings = 0.45f; // ~25 deg
- float BetaOffsetGoingBehind = 0.45f;
- bool GoingBehind = false;
- bool Obscured = false;
- bool BuildingCheckObscured = false;
- bool HackPlayerOnStoppingTrain = false;
- static int TimeIndicatedWantedToGoDown = 0;
- static bool StartedCountingForGoDown = false;
- float DeltaBeta;
-
- m_bFixingBeta = false;
- bBelowMinDist = false;
- bBehindPlayerDesired = false;
-
- assert(CamTargetEntity->IsPed());
-
- // CenterDist should be > LateralDist because we don't have an angle for safety in this case
- float CenterDist, LateralDist;
- float AngleToGoToSpeed;
- if(m_fCloseInPedHeightOffsetSpeed > 0.00001f){
- LateralDist = 0.55f;
- CenterDist = 1.25f;
- BetaOffsetAvoidBuildings = 0.9f; // ~50 deg
- BetaOffsetGoingBehind = 0.9f;
- AngleToGoToSpeed = 0.88254666f;
- }else{
- LateralDist = 0.8f;
- CenterDist = 1.35f;
- if(TheCamera.PedZoomIndicator == 1.0f || TheCamera.PedZoomIndicator == 4.0f){
- LateralDist = 1.25f;
- CenterDist = 1.6f;
+ // Fallen into water
+ if(Cams[ActiveCam].IsTargetInWater(Cams[ActiveCam].Source) && !boatTarget &&
+ !Cams[ActiveCam].CamTargetEntity->IsPed())
+ ReqMode = CCam::MODE_PLAYER_FALLEN_WATER;
+ }
}
- AngleToGoToSpeed = 0.43254671f;
- }
- FOV = DefaultFOV;
-
- if(ResetStatics){
- Rotating = false;
- m_bCollisionChecksOn = true;
- FixedTargetOrientation = 0.0f;
- PreviouslyObscured = false;
- PickedASide = false;
- StartedCountingForGoDown = false;
- AngleToGoTo = 0.0f;
- // unused LastAngleWithNoPickedASide
- }
+ // Ped target
+ else if(pTargetEntity->IsPed()){
+ // Change user selected mode
+ if(CPad::GetPad(0)->CycleCameraModeUpJustDown() && !CReplay::IsPlayingBack() &&
+ (m_bLookingAtPlayer || WhoIsInControlOfTheCamera == CAMCONTROL_OBBE) &&
+ !m_WideScreenOn && !m_bFailedCullZoneTestPreviously){
+ if(FrontEndMenuManager.m_ControlMethod == CONTROL_STANDARD){
+ if(PedZoomIndicator == CAM_ZOOM_TOPDOWN)
+ PedZoomIndicator = CAM_ZOOM_1;
+ else
+ PedZoomIndicator = CAM_ZOOM_TOPDOWN;
+ }else
+ PedZoomIndicator -= 1.0f;
+ }
+ if(CPad::GetPad(0)->CycleCameraModeDownJustDown() && !CReplay::IsPlayingBack() &&
+ (m_bLookingAtPlayer || WhoIsInControlOfTheCamera == CAMCONTROL_OBBE) &&
+ !m_WideScreenOn && !m_bFailedCullZoneTestPreviously){
+ if(FrontEndMenuManager.m_ControlMethod == CONTROL_STANDARD){
+ if(PedZoomIndicator == CAM_ZOOM_TOPDOWN)
+ PedZoomIndicator = CAM_ZOOM_1;
+ else
+ PedZoomIndicator = CAM_ZOOM_TOPDOWN;
+ }else
+ PedZoomIndicator += 1.0f;
+ }
+ // disabled obbe's cam here
+ if(PedZoomIndicator < CAM_ZOOM_1) PedZoomIndicator = CAM_ZOOM_TOPDOWN;
+ else if(PedZoomIndicator > CAM_ZOOM_TOPDOWN) PedZoomIndicator = CAM_ZOOM_1;
+
+ ReqMode = CCam::MODE_FOLLOWPED;
+
+ // Check 1st person mode
+ if(m_bLookingAtPlayer && pTargetEntity->IsPed() && !m_WideScreenOn && !Cams[0].Using3rdPersonMouseCam()
+#ifdef FREE_CAM
+ && !CCamera::bFreeCam
+#endif
+ ){
+ // See if we want to enter first person mode
+ if(CPad::GetPad(0)->LookAroundLeftRight() || CPad::GetPad(0)->LookAroundUpDown()){
+ m_uiFirstPersonCamLastInputTime = CTimer::GetTimeInMilliseconds();
+ m_bFirstPersonBeingUsed = true;
+ }else if(m_bFirstPersonBeingUsed){
+ // Or if we want to go back to 3rd person
+ if(CPad::GetPad(0)->GetPedWalkLeftRight() || CPad::GetPad(0)->GetPedWalkUpDown() ||
+ CPad::GetPad(0)->GetSquare() || CPad::GetPad(0)->GetTriangle() ||
+ CPad::GetPad(0)->GetCross() || CPad::GetPad(0)->GetCircle() ||
+ CTimer::GetTimeInMilliseconds() - m_uiFirstPersonCamLastInputTime > 2850.0f)
+ m_bFirstPersonBeingUsed = false;
+ }
+ }else
+ m_bFirstPersonBeingUsed = false;
+
+ if(!FindPlayerPed()->IsPedInControl() || FindPlayerPed()->m_fMoveSpeed > 0.0f)
+ m_bFirstPersonBeingUsed = false;
+ if(m_bFirstPersonBeingUsed){
+ ReqMode = CCam::MODE_1STPERSON;
+ CPad::GetPad(0)->DisablePlayerControls |= PLAYERCONTROL_DISABLED_1;
+ }
+ // Zoom value
+ if(PedZoomIndicator == CAM_ZOOM_1)
+ m_fPedZoomValue = 0.25f;
+ else if(PedZoomIndicator == CAM_ZOOM_2)
+ m_fPedZoomValue = 1.5f;
+ else if(PedZoomIndicator == CAM_ZOOM_3)
+ m_fPedZoomValue = 2.9f;
+
+ // Smooth zoom value - ugly code
+ if(m_bUseScriptZoomValuePed){
+ if(m_fPedZoomValueSmooth < m_fPedZoomValueScript){
+ m_fPedZoomValueSmooth += 0.12f * CTimer::GetTimeStep();
+ m_fPedZoomValueSmooth = min(m_fPedZoomValueSmooth, m_fPedZoomValueScript);
+ }else{
+ m_fPedZoomValueSmooth -= 0.12f * CTimer::GetTimeStep();
+ m_fPedZoomValueSmooth = max(m_fPedZoomValueSmooth, m_fPedZoomValueScript);
+ }
+ }else if(m_bFailedCullZoneTestPreviously){
+ static float PedZoomedInVal = 0.5f;
+ CloseInPedHeightTarget = 0.7f;
+ if(m_fPedZoomValueSmooth < PedZoomedInVal){
+ m_fPedZoomValueSmooth += 0.12f * CTimer::GetTimeStep();
+ m_fPedZoomValueSmooth = min(m_fPedZoomValueSmooth, PedZoomedInVal);
+ }else{
+ m_fPedZoomValueSmooth -= 0.12f * CTimer::GetTimeStep();
+ m_fPedZoomValueSmooth = max(m_fPedZoomValueSmooth, PedZoomedInVal);
+ }
+ }else{
+ if(m_fPedZoomValueSmooth < m_fPedZoomValue){
+ m_fPedZoomValueSmooth += 0.12f * CTimer::GetTimeStep();
+ m_fPedZoomValueSmooth = min(m_fPedZoomValueSmooth, m_fPedZoomValue);
+ }else{
+ m_fPedZoomValueSmooth -= 0.12f * CTimer::GetTimeStep();
+ m_fPedZoomValueSmooth = max(m_fPedZoomValueSmooth, m_fPedZoomValue);
+ }
+ }
- TargetCoors = CameraTarget;
- IdealSource = Source;
- TargetCoors.z += m_fSyphonModeTargetZOffSet;
+ WellBufferMe(CloseInPedHeightTarget, &Cams[ActiveCam].m_fCloseInPedHeightOffset, &Cams[ActiveCam].m_fCloseInPedHeightOffsetSpeed, 0.1f, 0.025f, false);
- CVector TempTargetCoors;
- TempTargetCoors = DoAverageOnVector(TargetCoors);
- TargetCoors = TempTargetCoors;
- // Add this unknown offset, but later it's removed again
- TargetCoors.z += m_fUnknownZOffSet;
+ // Check if entering fight cam
+ if(!m_bFirstPersonBeingUsed){
+ if(FindPlayerPed()->GetPedState() == PED_FIGHT && !m_bUseMouse3rdPerson)
+ ReqMode = CCam::MODE_FIGHT_CAM;
+ if(((CPed*)pTargetEntity)->GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT &&
+ FindPlayerPed()->GetPedState() == PED_ATTACK && !m_bUseMouse3rdPerson)
+ ReqMode = CCam::MODE_FIGHT_CAM;
+ }
- Dist.x = IdealSource.x - TargetCoors.x;
- Dist.y = IdealSource.y - TargetCoors.y;
- Length = Dist.Magnitude2D();
+ // Garage cam
+ if(CCullZones::CamStairsForPlayer() && CCullZones::FindZoneWithStairsAttributeForPlayer())
+ stairs = true;
+ // Some hack for Mr Whoopee in a bomb shop
+ if(Cams[ActiveCam].Using3rdPersonMouseCam() && CCollision::ms_collisionInMemory == LEVEL_COMMERCIAL){
+ if(pTargetEntity->GetPosition().x < 83.0f && pTargetEntity->GetPosition().x > 18.0f &&
+ pTargetEntity->GetPosition().y < -305.0f && pTargetEntity->GetPosition().y > -390.0f)
+ disableGarageCam = true;
+ }
+ if(!disableGarageCam && (CGarages::IsPointInAGarageCameraZone(pTargetEntity->GetPosition()) || stairs)){
+ if(!m_bGarageFixedCamPositionSet && m_bLookingAtPlayer){
+ if(pToGarageWeAreIn || stairs){
+ float ground;
+ bool foundGround;
+
+ if(pToGarageWeAreIn){
+ // targetPos = pTargetEntity->GetPosition(); // unused
+ if(pToGarageWeAreIn->m_pDoor1){
+ whichDoor = 1;
+ garageDoorPos1.x = pToGarageWeAreIn->m_fDoor1X;
+ garageDoorPos1.y = pToGarageWeAreIn->m_fDoor1Y;
+ garageDoorPos1.z = 0.0f;
+ // targetPos.z = 0.0f; // unused
+ // (targetPos - doorPos1).Magnitude(); // unused
+ }else if(pToGarageWeAreIn->m_pDoor2){
+ whichDoor = 2;
+#ifdef FIX_BUGS
+ garageDoorPos2.x = pToGarageWeAreIn->m_fDoor2X;
+ garageDoorPos2.y = pToGarageWeAreIn->m_fDoor2Y;
+ garageDoorPos2.z = 0.0f;
+#endif
+ }else{
+ whichDoor = 1;
+ garageDoorPos1.x = pTargetEntity->GetPosition().x;
+ garageDoorPos1.y = pTargetEntity->GetPosition().y;
+#ifdef FIX_BUGS
+ garageDoorPos1.z = 0.0f;
+#else
+ garageDoorPos2.z = 0.0f;
+#endif
+ }
+ }else{
+ whichDoor = 1;
+ garageDoorPos1 = Cams[ActiveCam].Source;
+ }
+
+ if(pToGarageWeAreIn){
+ garageCenter.x = (pToGarageWeAreIn->m_fX1 + pToGarageWeAreIn->m_fX2)/2.0f;
+ garageCenter.y = (pToGarageWeAreIn->m_fY1 + pToGarageWeAreIn->m_fY2)/2.0f;
+ garageCenter.z = 0.0f;
+ }else{
+ garageDoorPos1.z = 0.0f;
+ if(stairs){
+ CAttributeZone *az = CCullZones::FindZoneWithStairsAttributeForPlayer();
+ garageCenter.x = (az->minx + az->maxx)/2.0f;
+ garageCenter.y = (az->miny + az->maxy)/2.0f;
+ garageCenter.z = 0.0f;
+ }else
+ garageCenter = pTargetEntity->GetPosition();
+ }
+ if(whichDoor == 1)
+ garageCenterToDoor = garageDoorPos1 - garageCenter;
+ else
+ garageCenterToDoor = garageDoorPos2 - garageCenter;
+ targetPos = pTargetEntity->GetPosition();
+ ground = CWorld::FindGroundZFor3DCoord(targetPos.x, targetPos.y, targetPos.z, &foundGround);
+ if(!foundGround)
+ ground = targetPos.z - 0.2f;
+ garageCenterToDoor.z = 0.0f;
+ garageCenterToDoor.Normalise();
+ if(whichDoor == 1){
+ if(pToGarageWeAreIn == nil && stairs)
+ garageCamPos = garageDoorPos1 + 3.75f*garageCenterToDoor;
+ else
+ garageCamPos = garageDoorPos1 + 13.0f*garageCenterToDoor;
+ }else{
+ garageCamPos = garageDoorPos2 + 13.0f*garageCenterToDoor;
+ }
+ if(PedZoomIndicator == CAM_ZOOM_TOPDOWN && !stairs){
+ garageCamPos = garageCenter;
+ garageCamPos.z += FindPlayerPed()->GetPosition().z + 2.1f;
+ if(pToGarageWeAreIn && garageCamPos.z > pToGarageWeAreIn->m_fX2) // What?
+ garageCamPos.z = pToGarageWeAreIn->m_fX2;
+ }else
+ garageCamPos.z = ground + 3.1f;
+ SetCamPositionForFixedMode(garageCamPos, CVector(0.0f, 0.0f, 0.0f));
+ m_bGarageFixedCamPositionSet = true;
+ }
+ }
- // Cam on a string. With a fixed distance. Zoom in/out is done later.
- if(Length != 0.0f)
- IdealSource = TargetCoors + CVector(Dist.x, Dist.y, 0.0f)/Length * GroundDist;
- else
- IdealSource = TargetCoors + CVector(1.0f, 1.0f, 0.0f);
-
- // TODO: what's transition beta?
- if(TheCamera.m_bUseTransitionBeta && ResetStatics){
- CVector VecDistance;
- IdealSource.x = TargetCoors.x + GroundDist*Cos(m_fTransitionBeta);
- IdealSource.y = TargetCoors.y + GroundDist*Sin(m_fTransitionBeta);
- Beta = CGeneral::GetATanOfXY(IdealSource.x - TargetCoors.x, IdealSource.y - TargetCoors.y);
- }else
- Beta = CGeneral::GetATanOfXY(Source.x - TargetCoors.x, Source.y - TargetCoors.y);
+ if((CGarages::CameraShouldBeOutside() || stairs) && m_bLookingAtPlayer && m_bGarageFixedCamPositionSet){
+ if(pToGarageWeAreIn || stairs){
+ ReqMode = CCam::MODE_FIXED;
+ m_bPlayerIsInGarage = true;
+ }
+ }else{
+ if(m_bPlayerIsInGarage){
+ m_bJustCameOutOfGarage = true;
+ m_bPlayerIsInGarage = false;
+ }
+ ReqMode = CCam::MODE_FOLLOWPED;
+ }
+ }else{
+ if(m_bPlayerIsInGarage){
+ m_bJustCameOutOfGarage = true;
+ m_bPlayerIsInGarage = false;
+ }
+ m_bGarageFixedCamPositionSet = false;
+ }
- if(TheCamera.m_bCamDirectlyBehind){
- m_bCollisionChecksOn = true;
- Beta = TargetOrientation + PI;
+ // Fallen into water
+ if(Cams[ActiveCam].IsTargetInWater(Cams[ActiveCam].Source) &&
+ Cams[ActiveCam].CamTargetEntity->IsPed())
+ ReqMode = CCam::MODE_PLAYER_FALLEN_WATER;
+
+ // Set top down
+ if(PedZoomIndicator == CAM_ZOOM_TOPDOWN &&
+ !CCullZones::Cam1stPersonForPlayer() &&
+ !CCullZones::CamNoRain() &&
+ !CCullZones::PlayerNoRain() &&
+ !m_bFirstPersonBeingUsed &&
+ !m_bPlayerIsInGarage)
+ ReqMode = CCam::MODE_TOP_DOWN_PED;
+
+ // Weapon mode
+ if(!CPad::GetPad(0)->GetTarget() && PlayerWeaponMode.Mode != CCam::MODE_HELICANNON_1STPERSON)
+ ClearPlayerWeaponMode();
+ if(m_PlayerMode.Mode != CCam::MODE_NONE)
+ ReqMode = m_PlayerMode.Mode;
+ if(PlayerWeaponMode.Mode != CCam::MODE_NONE && !stairs){
+ if(PlayerWeaponMode.Mode == CCam::MODE_SNIPER ||
+ PlayerWeaponMode.Mode == CCam::MODE_ROCKETLAUNCHER ||
+ PlayerWeaponMode.Mode == CCam::MODE_M16_1STPERSON ||
+ PlayerWeaponMode.Mode == CCam::MODE_HELICANNON_1STPERSON ||
+ Cams[ActiveCam].GetWeaponFirstPersonOn()){
+ // First person weapon mode
+ if(PLAYER->GetPedState() == PED_SEEK_CAR){
+ if(ReqMode == CCam::MODE_TOP_DOWN_PED || Cams[ActiveCam].GetWeaponFirstPersonOn())
+ ReqMode = PlayerWeaponMode.Mode;
+ else
+ ReqMode = CCam::MODE_FOLLOWPED;
+ }else
+ ReqMode = PlayerWeaponMode.Mode;
+ }else if(ReqMode != CCam::MODE_TOP_DOWN_PED){
+ // Syphon mode
+ float playerTargetDist;
+ float deadPedDist = 4.0f;
+ static float alivePedDist = 2.0f; // original name lost
+ float pedDist; // actually only used on dead target
+ bool targetDead = false;
+ float camAngle, targetAngle;
+ CVector playerToTarget = m_cvecAimingTargetCoors - pTargetEntity->GetPosition();
+ CVector playerToCam = Cams[ActiveCam].Source - pTargetEntity->GetPosition();
+
+ if(PedZoomIndicator == CAM_ZOOM_1)
+ deadPedDist = 2.25f;
+ if(FindPlayerPed()->m_pPointGunAt){
+ // BUG: this need not be a ped!
+ if(((CPed*)FindPlayerPed()->m_pPointGunAt)->DyingOrDead()){
+ targetDead = true;
+ pedDist = deadPedDist;
+ }else
+ pedDist = alivePedDist;
+ playerTargetDist = playerToTarget.Magnitude2D();
+ camAngle = CGeneral::GetATanOfXY(playerToCam.x, playerToCam.y);
+ targetAngle = CGeneral::GetATanOfXY(playerToTarget.x, playerToTarget.y);
+ ReqMode = PlayerWeaponMode.Mode;
+
+ // Check whether to start aiming in crim-in-front mode
+ if(Cams[ActiveCam].Mode != CCam::MODE_SYPHON){
+ float angleDiff = camAngle - targetAngle;
+ while(angleDiff >= PI) angleDiff -= 2*PI;
+ while(angleDiff < -PI) angleDiff += 2*PI;
+ if(Abs(angleDiff) < HALFPI && playerTargetDist < 3.5f && playerToTarget.z > -1.0f)
+ ReqMode = CCam::MODE_SYPHON_CRIM_IN_FRONT;
+ }
+
+ // Check whether to go to special fixed mode
+ float fixedModeDist = 0.0f;
+ if((ReqMode == CCam::MODE_SYPHON_CRIM_IN_FRONT || ReqMode == CCam::MODE_SYPHON) &&
+ (m_uiTransitionState == 0 || Cams[ActiveCam].Mode == CCam::MODE_SPECIAL_FIXED_FOR_SYPHON) &&
+ playerTargetDist < pedDist && targetDead){
+ if(ReqMode == CCam::MODE_SYPHON_CRIM_IN_FRONT)
+ fixedModeDist = 5.0f;
+ else
+ fixedModeDist = 3.0f;
+ ReqMode = CCam::MODE_SPECIAL_FIXED_FOR_SYPHON;
+ }
+ if(ReqMode == CCam::MODE_SPECIAL_FIXED_FOR_SYPHON){
+ if(!PlaceForFixedWhenSniperFound){
+ // Find position
+ CEntity *entity;
+ CColPoint colPoint;
+ CVector fixedPos = pTargetEntity->GetPosition();
+ fixedPos.x += fixedModeDist*Cos(camAngle);
+ fixedPos.y += fixedModeDist*Sin(camAngle);
+ fixedPos.z += 1.15f;
+ if(CWorld::ProcessLineOfSight(pTargetEntity->GetPosition(), fixedPos, colPoint, entity, true, false, false, true, false, true, true))
+ SetCamPositionForFixedMode(colPoint.point, CVector(0.0f, 0.0f, 0.0f));
+ else
+ SetCamPositionForFixedMode(fixedPos, CVector(0.0f, 0.0f, 0.0f));
+ PlaceForFixedWhenSniperFound = true;
+ }
+ }else
+ PlaceForFixedWhenSniperFound = false;
+ }
+ }
+ }
+ }
}
- if(FindPlayerVehicle())
- if(FindPlayerVehicle()->m_vehType == VEHICLE_TYPE_TRAIN)
- HackPlayerOnStoppingTrain = true;
+ m_bIdleOn = false;
- if(TheCamera.m_bCamDirectlyInFront){
- m_bCollisionChecksOn = true;
- Beta = TargetOrientation;
- }
+ if(DebugCamMode)
+ ReqMode = DebugCamMode;
- while(Beta >= PI) Beta -= 2.0f * PI;
- while(Beta < -PI) Beta += 2.0f * PI;
- // BUG? is this ever used?
- // The values seem to be roughly m_fPedZoomValueSmooth + 1.85
- if(ResetStatics){
- if(TheCamera.PedZoomIndicator == 1.0f) m_fRealGroundDist = 2.090556f;
- if(TheCamera.PedZoomIndicator == 2.0f) m_fRealGroundDist = 3.34973f;
- if(TheCamera.PedZoomIndicator == 3.0f) m_fRealGroundDist = 4.704914f;
- if(TheCamera.PedZoomIndicator == 4.0f) m_fRealGroundDist = 2.090556f;
+ // Process arrested player
+ static int ThePickedArrestMode;
+ static int LastPedState;
+ bool startArrestCam = false;
+
+ if(LastPedState != PED_ARRESTED && PLAYER->GetPedState() == PED_ARRESTED){
+ if(CarZoomIndicator != CAM_ZOOM_1STPRS && pTargetEntity->IsVehicle())
+ startArrestCam = true;
+ }else
+ startArrestCam = false;
+ LastPedState = PLAYER->GetPedState();
+ if(startArrestCam){
+ if(m_uiTransitionState)
+ ReqMode = Cams[ActiveCam].Mode;
+ else{
+ bool valid;
+ if(pTargetEntity->IsPed()){
+ // How can this happen if arrest cam is only done in cars?
+ Cams[(ActiveCam+1)%2].ResetStatics = true;
+ valid = Cams[(ActiveCam+1)%2].ProcessArrestCamOne();
+ ReqMode = CCam::MODE_ARRESTCAM_ONE;
+ }else{
+ Cams[(ActiveCam+1)%2].ResetStatics = true;
+ valid = Cams[(ActiveCam+1)%2].ProcessArrestCamTwo();
+ ReqMode = CCam::MODE_ARRESTCAM_TWO;
+ }
+ if(!valid)
+ ReqMode = Cams[ActiveCam].Mode;
+ }
}
- // And what is this? It's only used for collision and rotation it seems
- float RealGroundDist;
- if(TheCamera.PedZoomIndicator == 1.0f) RealGroundDist = 2.090556f;
- if(TheCamera.PedZoomIndicator == 2.0f) RealGroundDist = 3.34973f;
- if(TheCamera.PedZoomIndicator == 3.0f) RealGroundDist = 4.704914f;
- if(TheCamera.PedZoomIndicator == 4.0f) RealGroundDist = 2.090556f;
- if(m_fCloseInPedHeightOffset > 0.00001f)
- RealGroundDist = 1.7016f;
-
-
- bool Shooting = false;
- CPed *ped = (CPed*)CamTargetEntity;
- if(ped->GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED)
- if(CPad::GetPad(0)->GetWeapon())
- Shooting = true;
- if(ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_DETONATOR ||
- ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT)
- Shooting = false;
-
-
- if(m_fCloseInPedHeightOffset > 0.00001f)
- TargetCoors.z -= m_fUnknownZOffSet;
-
- // Figure out if and where we want to rotate
-
- if(CPad::GetPad(0)->ForceCameraBehindPlayer() || Shooting){
-
- // Center cam behind player
-
- GoingBehind = true;
- m_bCollisionChecksOn = true;
- float OriginalBeta = Beta;
- // Set Beta behind player
- Beta = TargetOrientation + PI;
- TargetCoors.z -= 0.1f;
-
- AngleToGoTo = GetPedBetaAngleForClearView(TargetCoors, CenterDist * RealGroundDist, 0.0f, true, false, false, true, false);
- if(AngleToGoTo != 0.0f){
- if(AngleToGoTo < 0.0f)
- AngleToGoTo -= AngleToGoToSpeed;
- else
- AngleToGoTo += AngleToGoToSpeed;
- }else{
- float LateralLeft = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, BetaOffsetGoingBehind, true, false, false, true, false);
- float LateralRight = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, -BetaOffsetGoingBehind, true, false, false, true, false);
- if(LateralLeft == 0.0f && LateralRight != 0.0f)
- AngleToGoTo += LateralRight;
- else if(LateralLeft != 0.0f && LateralRight == 0.0f)
- AngleToGoTo += LateralLeft;
+ ThePickedArrestMode = ReqMode;
+ if(PLAYER->GetPedState() == PED_ARRESTED)
+ ReqMode = ThePickedArrestMode; // this is rather useless...
+
+ // Process dead player
+ if(PLAYER->GetPedState() == PED_DEAD){
+ if(Cams[ActiveCam].Mode == CCam::MODE_PED_DEAD_BABY)
+ ReqMode = CCam::MODE_PED_DEAD_BABY;
+ else{
+ bool foundRoof;
+ CVector pos = FindPlayerPed()->GetPosition();
+ CWorld::FindRoofZFor3DCoord(pos.x, pos.y, pos.z, &foundRoof);
+ if(!foundRoof)
+ ReqMode = CCam::MODE_PED_DEAD_BABY;
}
+ }
+
+ // Restore with a jump cut
+ if(m_bRestoreByJumpCut){
+ if(ReqMode != CCam::MODE_FOLLOWPED &&
+ ReqMode != CCam::MODE_M16_1STPERSON &&
+ ReqMode != CCam::MODE_SNIPER &&
+ ReqMode != CCam::MODE_ROCKETLAUNCHER ||
+ !m_bUseMouse3rdPerson)
+ SetCameraDirectlyBehindForFollowPed_CamOnAString();
+
+ ReqMode = m_iModeToGoTo;
+ Cams[ActiveCam].Mode = ReqMode;
+ m_bJust_Switched = true;
+ Cams[ActiveCam].ResetStatics = true;
+ Cams[ActiveCam].m_cvecCamFixedModeVector = m_vecFixedModeVector;
+ Cams[ActiveCam].CamTargetEntity = pTargetEntity;
+ Cams[ActiveCam].m_cvecCamFixedModeSource = m_vecFixedModeSource;
+ Cams[ActiveCam].m_cvecCamFixedModeUpOffSet = m_vecFixedModeUpOffSet;
+ Cams[ActiveCam].m_bCamLookingAtVector = false;
+ Cams[ActiveCam].m_vecLastAboveWaterCamPosition = Cams[(ActiveCam+1)%2].m_vecLastAboveWaterCamPosition;
+ m_bRestoreByJumpCut = false;
+ Cams[ActiveCam].ResetStatics = true;
+ pTargetEntity->RegisterReference(&pTargetEntity);
+ Cams[ActiveCam].CamTargetEntity->RegisterReference(&Cams[ActiveCam].CamTargetEntity);
+ CarZoomValueSmooth = CarZoomValue;
+ m_fPedZoomValueSmooth = m_fPedZoomValue;
+ m_uiTransitionState = 0;
+ m_vecDoingSpecialInterPolation = false;
+ }
- TargetCoors.z += 0.1f;
- Beta = OriginalBeta;
+ if(gbModelViewer)
+ ReqMode = CCam::MODE_MODELVIEW;
- if(PickedASide){
- if(AngleToGoTo == 0.0f)
- FixedTargetOrientation = TargetOrientation + PI;
- Rotating = true;
+ // Turn on Obbe's cam
+ bool canUseObbeCam = true;
+ if(pTargetEntity){
+ if(pTargetEntity->IsVehicle()){
+ if(CarZoomIndicator == CAM_ZOOM_CINEMATIC)
+ m_bObbeCinematicCarCamOn = true;
}else{
- FixedTargetOrientation = TargetOrientation + PI + AngleToGoTo;
- Rotating = true;
- PickedASide = true;
+ if(PedZoomIndicator == CAM_ZOOM_CINEMATIC)
+ m_bObbeCinematicPedCamOn = true;
}
- }else{
+ }
+ if(m_bTargetJustBeenOnTrain ||
+ ReqMode == CCam::MODE_SYPHON || ReqMode == CCam::MODE_SYPHON_CRIM_IN_FRONT || ReqMode == CCam::MODE_SPECIAL_FIXED_FOR_SYPHON ||
+ ReqMode == CCam::MODE_PED_DEAD_BABY || ReqMode == CCam::MODE_ARRESTCAM_ONE || ReqMode == CCam::MODE_ARRESTCAM_TWO ||
+ ReqMode == CCam::MODE_FIGHT_CAM || ReqMode == CCam::MODE_PLAYER_FALLEN_WATER ||
+ ReqMode == CCam::MODE_SNIPER || ReqMode == CCam::MODE_ROCKETLAUNCHER || ReqMode == CCam::MODE_M16_1STPERSON ||
+ ReqMode == CCam::MODE_SNIPER_RUNABOUT || ReqMode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT ||
+ ReqMode == CCam::MODE_1STPERSON_RUNABOUT || ReqMode == CCam::MODE_M16_1STPERSON_RUNABOUT ||
+ ReqMode == CCam::MODE_FIGHT_CAM_RUNABOUT || ReqMode == CCam::MODE_HELICANNON_1STPERSON ||
+ WhoIsInControlOfTheCamera == CAMCONTROL_SCRIPT ||
+ m_bJustCameOutOfGarage || m_bPlayerIsInGarage)
+ canUseObbeCam = false;
+
+ if(m_bObbeCinematicPedCamOn && canUseObbeCam)
+ ProcessObbeCinemaCameraPed();
+ else if(m_bObbeCinematicCarCamOn && canUseObbeCam)
+ ProcessObbeCinemaCameraCar();
+ else{
+ if(m_bPlayerIsInGarage && m_bObbeCinematicCarCamOn)
+ switchByJumpCut = true;
+ canUseObbeCam = false;
+ DontProcessObbeCinemaCamera();
+ }
- // Rotate cam to avoid clipping into buildings
+ // Start the transition or do a jump cut
+ if(m_bLookingAtPlayer){
+ // Going into top down modes normally needs a jump cut (but see below)
+ if(ReqMode == CCam::MODE_TOPDOWN || ReqMode == CCam::MODE_1STPERSON || ReqMode == CCam::MODE_TOP_DOWN_PED){
+ switchByJumpCut = true;
+ }
+ // Going from top down to vehicle
+ else if(ReqMode == CCam::MODE_CAM_ON_A_STRING || ReqMode == CCam::MODE_BEHINDBOAT){
+ if(Cams[ActiveCam].Mode == CCam::MODE_TOPDOWN ||
+ Cams[ActiveCam].Mode == CCam::MODE_1STPERSON ||
+ Cams[ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED)
+ switchByJumpCut = true;
+ }else if(ReqMode == CCam::MODE_FIXED){
+ if(Cams[ActiveCam].Mode == CCam::MODE_TOPDOWN)
+ switchByJumpCut = true;
+ }
- TargetCoors.z -= 0.1f;
+ // Top down modes can interpolate between each other
+ if(ReqMode == CCam::MODE_TOPDOWN){
+ if(Cams[ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED || Cams[ActiveCam].Mode == CCam::MODE_PED_DEAD_BABY)
+ switchByJumpCut = false;
+ }else if(ReqMode == CCam::MODE_TOP_DOWN_PED){
+ if(Cams[ActiveCam].Mode == CCam::MODE_TOPDOWN || Cams[ActiveCam].Mode == CCam::MODE_PED_DEAD_BABY)
+ switchByJumpCut = false;
+ }
- Center = GetPedBetaAngleForClearView(TargetCoors, CenterDist * RealGroundDist, 0.0f, true, false, false, true, false);
- if(m_bCollisionChecksOn || PreviouslyObscured || Center != 0.0f || m_fCloseInPedHeightOffset > 0.00001f){
- if(Center != 0.0f){
- AngleToGoTo = Center;
- }else{
- LateralLeft = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, BetaOffsetAvoidBuildings, true, false, false, true, false);
- LateralRight = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, -BetaOffsetAvoidBuildings, true, false, false, true, false);
- if(LateralLeft == 0.0f && LateralRight != 0.0f){
- AngleToGoTo += LateralRight;
- if(m_fCloseInPedHeightOffset > 0.0f)
- RwCameraSetNearClipPlane(Scene.camera, 0.7f);
- }else if(LateralLeft != 0.0f && LateralRight == 0.0f){
- AngleToGoTo += LateralLeft;
- if(m_fCloseInPedHeightOffset > 0.0f)
- RwCameraSetNearClipPlane(Scene.camera, 0.7f);
+ if(ReqMode == CCam::MODE_1STPERSON || ReqMode == CCam::MODE_M16_1STPERSON ||
+ ReqMode == CCam::MODE_SNIPER || ReqMode == CCam::MODE_ROCKETLAUNCHER ||
+ ReqMode == CCam::MODE_SNIPER_RUNABOUT || ReqMode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT ||
+ ReqMode == CCam::MODE_1STPERSON_RUNABOUT || ReqMode == CCam::MODE_M16_1STPERSON_RUNABOUT ||
+ ReqMode == CCam::MODE_FIGHT_CAM_RUNABOUT ||
+ ReqMode == CCam::MODE_HELICANNON_1STPERSON ||
+ ReqMode == CCam::MODE_ARRESTCAM_ONE || ReqMode == CCam::MODE_ARRESTCAM_TWO){
+ // Going into any 1st person mode is a jump cut
+ if(pTargetEntity->IsPed())
+ switchByJumpCut = true;
+ }else if(ReqMode == CCam::MODE_FIXED && m_bPlayerIsInGarage){
+ // Going from 1st peron mode into garage
+ if(Cams[ActiveCam].Mode == CCam::MODE_SNIPER ||
+ Cams[ActiveCam].Mode == CCam::MODE_HELICANNON_1STPERSON ||
+ Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER ||
+ Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON ||
+ Cams[ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED ||
+ stairs ||
+ Cams[ActiveCam].Mode == CCam::MODE_1STPERSON ||
+ Cams[ActiveCam].Mode == CCam::MODE_SNIPER_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_1STPERSON_RUNABOUT){
+ if(pTargetEntity && pTargetEntity->IsVehicle())
+ switchByJumpCut = true;
+ }
+ }else if(ReqMode == CCam::MODE_FOLLOWPED){
+ if(Cams[ActiveCam].Mode == CCam::MODE_1STPERSON ||
+ Cams[ActiveCam].Mode == CCam::MODE_SNIPER ||
+ Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER ||
+ Cams[ActiveCam].Mode == CCam::MODE_ARRESTCAM_ONE ||
+ Cams[ActiveCam].Mode == CCam::MODE_ARRESTCAM_TWO ||
+ Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON ||
+ Cams[ActiveCam].Mode == CCam::MODE_PED_DEAD_BABY ||
+ Cams[ActiveCam].Mode == CCam::MODE_PILLOWS_PAPS ||
+ Cams[ActiveCam].Mode == CCam::MODE_SNIPER_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_1STPERSON_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_HELICANNON_1STPERSON ||
+ Cams[ActiveCam].Mode == CCam::MODE_TOPDOWN ||
+ Cams[ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED){
+ if(!m_bJustCameOutOfGarage){
+ if(Cams[ActiveCam].Mode == CCam::MODE_1STPERSON ||
+ Cams[ActiveCam].Mode == CCam::MODE_SNIPER ||
+ Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER ||
+ Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON ||
+ Cams[ActiveCam].Mode == CCam::MODE_SNIPER_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_1STPERSON_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_HELICANNON_1STPERSON){
+ float angle = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y) - HALFPI;
+ ((CPed*)pTargetEntity)->m_fRotationCur = angle;
+ ((CPed*)pTargetEntity)->m_fRotationDest = angle;
+ }
+ m_bUseTransitionBeta = true;
+ switchByJumpCut = true;
+ if(Cams[ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED){
+ CVector front = Cams[ActiveCam].Source - FindPlayerPed()->GetPosition();
+ front.z = 0.0f;
+ front.Normalise();
+#ifdef FIX_BUGS
+ // this is almost as bad as the bugged code
+ if(front.x == 0.001f && front.y == 0.001f)
+ front.y = 1.0f;
+#else
+ // someone used = instead of == in the above check by accident
+ front.x = 0.001f;
+ front.y = 1.0f;
+#endif
+ Cams[ActiveCam].m_fTransitionBeta = CGeneral::GetATanOfXY(front.x, front.y);
+ }else
+ Cams[ActiveCam].m_fTransitionBeta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y) + PI;
}
}
- if(LateralLeft != 0.0f || LateralRight != 0.0f || Center != 0.0f)
- BuildingCheckObscured = true;
+ }else if(ReqMode == CCam::MODE_FIGHT_CAM){
+ if(Cams[ActiveCam].Mode == CCam::MODE_1STPERSON)
+ switchByJumpCut = true;
}
- TargetCoors.z += 0.1f;
- }
-
- if(m_fCloseInPedHeightOffset > 0.00001f)
- TargetCoors.z += m_fUnknownZOffSet;
+ if(ReqMode != Cams[ActiveCam].Mode && Cams[ActiveCam].CamTargetEntity == nil)
+ switchByJumpCut = true;
+ if(m_bPlayerIsInGarage && pToGarageWeAreIn){
+ if(pToGarageWeAreIn->m_eGarageType == GARAGE_BOMBSHOP1 ||
+ pToGarageWeAreIn->m_eGarageType == GARAGE_BOMBSHOP2 ||
+ pToGarageWeAreIn->m_eGarageType == GARAGE_BOMBSHOP3){
+ if(pTargetEntity->IsVehicle() && pTargetEntity->GetModelIndex() == MI_MRWHOOP &&
+ ReqMode != Cams[ActiveCam].Mode)
+ switchByJumpCut = true;
+ }
+ }
+ if(CSceneEdit::m_bEditOn)
+ ReqMode = CCam::MODE_EDITOR;
+
+ if((m_uiTransitionState == 0 || switchByJumpCut) && ReqMode != Cams[ActiveCam].Mode){
+ if(switchByJumpCut){
+ if(!m_bPlayerIsInGarage || m_bJustCameOutOfGarage){
+ if(ReqMode != CCam::MODE_FOLLOWPED &&
+ ReqMode != CCam::MODE_M16_1STPERSON &&
+ ReqMode != CCam::MODE_SNIPER &&
+ ReqMode != CCam::MODE_ROCKETLAUNCHER ||
+ !m_bUseMouse3rdPerson)
+ SetCameraDirectlyBehindForFollowPed_CamOnAString();
+ }
+ Cams[ActiveCam].Mode = ReqMode;
+ m_bJust_Switched = true;
+ Cams[ActiveCam].m_cvecCamFixedModeVector = m_vecFixedModeVector;
+ Cams[ActiveCam].CamTargetEntity = pTargetEntity;
+ Cams[ActiveCam].m_cvecCamFixedModeSource = m_vecFixedModeSource;
+ Cams[ActiveCam].m_cvecCamFixedModeUpOffSet = m_vecFixedModeUpOffSet;
+ Cams[ActiveCam].m_bCamLookingAtVector = m_bLookingAtVector;
+ Cams[ActiveCam].m_vecLastAboveWaterCamPosition = Cams[(ActiveCam+1)%2].m_vecLastAboveWaterCamPosition;
+ CarZoomValueSmooth = CarZoomValue;
+ m_fPedZoomValueSmooth = m_fPedZoomValue;
+ m_uiTransitionState = 0;
+ m_vecDoingSpecialInterPolation = false;
+ m_bStartInterScript = false;
+ Cams[ActiveCam].ResetStatics = true;
+
+ pTargetEntity->RegisterReference(&pTargetEntity);
+ Cams[ActiveCam].CamTargetEntity->RegisterReference(&Cams[ActiveCam].CamTargetEntity);
+ }else if(!m_bWaitForInterpolToFinish){
+ StartTransition(ReqMode);
+ pTargetEntity->RegisterReference(&pTargetEntity);
+ Cams[ActiveCam].CamTargetEntity->RegisterReference(&Cams[ActiveCam].CamTargetEntity);
+ }
+ }else if(m_uiTransitionState != 0 && ReqMode != Cams[ActiveCam].Mode){
+ bool startTransition = true;
+
+ if(ReqMode == CCam::MODE_FIGHT_CAM || Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM)
+ startTransition = false;
+ if(ReqMode == CCam::MODE_FOLLOWPED && Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM)
+ startTransition = false;
+
+ if(!m_bWaitForInterpolToFinish && m_bLookingAtPlayer && m_uiTransitionState != 0){
+ CVector playerDist;
+ playerDist.x = FindPlayerPed()->GetPosition().x - GetPosition().x;
+ playerDist.y = FindPlayerPed()->GetPosition().y - GetPosition().y;
+ playerDist.z = FindPlayerPed()->GetPosition().z - GetPosition().z;
+ // if player is too far away, keep interpolating and don't transition
+ if(pTargetEntity && pTargetEntity->IsPed()){
+ if(playerDist.Magnitude() > 17.5f &&
+ (ReqMode == CCam::MODE_SYPHON || ReqMode == CCam::MODE_SYPHON_CRIM_IN_FRONT))
+ m_bWaitForInterpolToFinish = true;
+ }
+ }
+ if(m_bWaitForInterpolToFinish)
+ startTransition = false;
+ if(startTransition){
+ StartTransitionWhenNotFinishedInter(ReqMode);
+ pTargetEntity->RegisterReference(&pTargetEntity);
+ Cams[ActiveCam].CamTargetEntity->RegisterReference(&Cams[ActiveCam].CamTargetEntity);
+ }
+ }else if(ReqMode == CCam::MODE_FIXED && pTargetEntity != Cams[ActiveCam].CamTargetEntity && m_bPlayerIsInGarage){
+ if(m_uiTransitionState != 0)
+ StartTransitionWhenNotFinishedInter(ReqMode);
+ else
+ StartTransition(ReqMode);
+ pTargetEntity->RegisterReference(&pTargetEntity);
+ Cams[ActiveCam].CamTargetEntity->RegisterReference(&Cams[ActiveCam].CamTargetEntity);
+ }
+ }else{
+ // not following player
+ if(m_uiTransitionState == 0 && m_bStartInterScript && m_iTypeOfSwitch == INTERPOLATION){
+ ReqMode = m_iModeToGoTo;
+ StartTransition(ReqMode);
+ pTargetEntity->RegisterReference(&pTargetEntity);
+ Cams[ActiveCam].CamTargetEntity->RegisterReference(&Cams[ActiveCam].CamTargetEntity);
+ }else if(m_uiTransitionState != 0 && m_bStartInterScript && m_iTypeOfSwitch == INTERPOLATION){
+ ReqMode = m_iModeToGoTo;
+ StartTransitionWhenNotFinishedInter(ReqMode);
+ pTargetEntity->RegisterReference(&pTargetEntity);
+ Cams[ActiveCam].CamTargetEntity->RegisterReference(&Cams[ActiveCam].CamTargetEntity);
+ }else if(m_bStartInterScript && m_iTypeOfSwitch == JUMP_CUT){
+ m_uiTransitionState = 0;
+ m_vecDoingSpecialInterPolation = false;
+ Cams[ActiveCam].Mode = m_iModeToGoTo;
+ m_bJust_Switched = true;
+ Cams[ActiveCam].ResetStatics = true;
+ Cams[ActiveCam].m_cvecCamFixedModeVector = m_vecFixedModeVector;
+ Cams[ActiveCam].CamTargetEntity = pTargetEntity;
+ Cams[ActiveCam].m_cvecCamFixedModeSource = m_vecFixedModeSource;
+ Cams[ActiveCam].m_cvecCamFixedModeUpOffSet = m_vecFixedModeUpOffSet;
+ Cams[ActiveCam].m_bCamLookingAtVector = m_bLookingAtVector;
+ Cams[ActiveCam].m_vecLastAboveWaterCamPosition = Cams[(ActiveCam+1)%2].m_vecLastAboveWaterCamPosition;
+ m_bJust_Switched = true;
+ pTargetEntity->RegisterReference(&pTargetEntity);
+ Cams[ActiveCam].CamTargetEntity->RegisterReference(&Cams[ActiveCam].CamTargetEntity);
+ CarZoomValueSmooth = CarZoomValue;
+ m_fPedZoomValueSmooth = m_fPedZoomValue;
+ }
+ }
- // Have to fix to avoid collision
+ m_bStartInterScript = false;
- if(AngleToGoTo != 0.0f){
- Obscured = true;
- Rotating = true;
- if(CPad::GetPad(0)->ForceCameraBehindPlayer() || Shooting){
- if(!PickedASide)
- FixedTargetOrientation = Beta + AngleToGoTo; // can this even happen?
- }else
- FixedTargetOrientation = Beta + AngleToGoTo;
+ if(Cams[ActiveCam].CamTargetEntity == nil)
+ Cams[ActiveCam].CamTargetEntity = pTargetEntity;
- // This calculation is only really used to figure out how fast to rotate out of collision
+ // Ped visibility
+ if((Cams[ActiveCam].Mode == CCam::MODE_1STPERSON ||
+ Cams[ActiveCam].Mode == CCam::MODE_SNIPER ||
+ Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON ||
+ Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER) && pTargetEntity->IsPed() ||
+ Cams[ActiveCam].Mode == CCam::MODE_FLYBY)
+ FindPlayerPed()->bIsVisible = false;
+ else
+ FindPlayerPed()->bIsVisible = true;
- m_fAmountFractionObscured = 1.0f;
- CVector PlayerPos = FindPlayerPed()->GetPosition();
- float RotationDist = (AngleToGoTo == Center ? CenterDist : LateralDist) * RealGroundDist;
- // What's going on here? - AngleToGoTo?
- CVector RotatedSource = PlayerPos + CVector(Cos(Beta - AngleToGoTo), Sin(Beta - AngleToGoTo), 0.0f) * RotationDist;
+ if(!canUseObbeCam && WhoIsInControlOfTheCamera == CAMCONTROL_OBBE)
+ Restore();
+}
- CColPoint colpoint;
- CEntity *entity;
- if(CWorld::ProcessLineOfSight(PlayerPos, RotatedSource, colpoint, entity, true, false, false, true, false, false, false)){
- if((PlayerPos - RotatedSource).Magnitude() != 0.0f)
- m_fAmountFractionObscured = (PlayerPos - colpoint.point).Magnitude() / (PlayerPos - RotatedSource).Magnitude();
- else
- m_fAmountFractionObscured = 1.0f;
+// What a mess!
+void
+CCamera::UpdateTargetEntity(void)
+{
+ bool enteringCar = false; // not on PS2 but only used as && !enteringCar so we can keep it
+ bool obbeCam = false;
+
+ if(WhoIsInControlOfTheCamera == CAMCONTROL_OBBE){
+ obbeCam = true;
+ if(m_iModeObbeCamIsInForCar == OBBE_COPCAR_WHEEL || m_iModeObbeCamIsInForCar == OBBE_COPCAR){
+ if(FindPlayerPed()->GetPedState() != PED_ARRESTED)
+ obbeCam = false;
+ if(FindPlayerVehicle() == nil)
+ pTargetEntity = FindPlayerPed();
}
}
- if(m_fAmountFractionObscured < 0.0f) m_fAmountFractionObscured = 0.0f;
- if(m_fAmountFractionObscured > 1.0f) m_fAmountFractionObscured = 1.0f;
-
+ if((m_bLookingAtPlayer || obbeCam) && m_uiTransitionState == 0 ||
+ pTargetEntity == nil ||
+ m_bTargetJustBeenOnTrain){
+ if(FindPlayerVehicle())
+ pTargetEntity = FindPlayerVehicle();
+ else{
+ pTargetEntity = FindPlayerPed();
+#ifndef GTA_PS2_STUFF
+ // this keeps the camera on the player while entering cars
+ if(PLAYER->GetPedState() == PED_ENTER_CAR ||
+ PLAYER->GetPedState() == PED_CARJACK ||
+ PLAYER->GetPedState() == PED_OPEN_DOOR)
+ enteringCar = true;
+
+ if(!enteringCar)
+ if(Cams[ActiveCam].CamTargetEntity != pTargetEntity)
+ Cams[ActiveCam].CamTargetEntity = pTargetEntity;
+#endif
+ }
- // Figure out speed values for Beta rotation
+ bool cantOpen = true;
+ if(PLAYER &&
+ PLAYER->m_pMyVehicle &&
+ PLAYER->m_pMyVehicle->CanPedOpenLocks(PLAYER))
+ cantOpen = false;
+
+ if(PLAYER->GetPedState() == PED_ENTER_CAR && !cantOpen){
+ if(!enteringCar && CarZoomIndicator != 0.0f){
+ pTargetEntity = PLAYER->m_pMyVehicle;
+ if(PLAYER->m_pMyVehicle == nil)
+ pTargetEntity = PLAYER;
+ }
+ }
- float Acceleration, MaxSpeed;
- static float AccelerationMult = 0.35f;
- static float MaxSpeedMult = 0.85f;
- static float AccelerationMultClose = 0.7f;
- static float MaxSpeedMultClose = 1.6f;
- float BaseAcceleration = 0.025f;
- float BaseMaxSpeed = 0.09f;
- if(m_fCloseInPedHeightOffset > 0.00001f){
- if(AngleToGoTo == 0.0f){
- BaseAcceleration = 0.022f;
- BaseMaxSpeed = 0.04f;
- }else{
- BaseAcceleration = DefaultAcceleration;
- BaseMaxSpeed = DefaultMaxStep;
+ if((PLAYER->GetPedState() == PED_CARJACK || PLAYER->GetPedState() == PED_OPEN_DOOR) && !cantOpen){
+ if(!enteringCar && CarZoomIndicator != 0.0f)
+#ifdef GTA_PS2_STUFF
+// dunno if this has any amazing effects
+ {
+#endif
+ pTargetEntity = PLAYER->m_pMyVehicle;
+ if(PLAYER->m_pMyVehicle == nil)
+ pTargetEntity = PLAYER;
+#ifdef GTA_PS2_STUFF
+ }
+#endif
}
+
+ if(PLAYER->GetPedState() == PED_EXIT_CAR)
+ pTargetEntity = FindPlayerPed();
+ if(PLAYER->GetPedState() == PED_DRAG_FROM_CAR)
+ pTargetEntity = FindPlayerPed();
+ if(pTargetEntity->IsVehicle() && CarZoomIndicator != 0.0f && FindPlayerPed()->GetPedState() == PED_ARRESTED)
+ pTargetEntity = FindPlayerPed();
}
- if(AngleToGoTo == 0.0f){
- Acceleration = BaseAcceleration;
- MaxSpeed = BaseMaxSpeed;
- }else if(CPad::GetPad(0)->ForceCameraBehindPlayer() && !Shooting){
- Acceleration = 0.051f;
- MaxSpeed = 0.18f;
- }else if(m_fCloseInPedHeightOffset > 0.00001f){
- Acceleration = BaseAcceleration + AccelerationMultClose*sq(m_fAmountFractionObscured - 1.05f);
- MaxSpeed = BaseMaxSpeed + MaxSpeedMultClose*sq(m_fAmountFractionObscured - 1.05f);
- }else{
- Acceleration = DefaultAcceleration + AccelerationMult*sq(m_fAmountFractionObscured - 1.05f);
- MaxSpeed = DefaultMaxStep + MaxSpeedMult*sq(m_fAmountFractionObscured - 1.05f);
- }
- static float AccelerationLimit = 0.3f;
- static float MaxSpeedLimit = 0.65f;
- if(Acceleration > AccelerationLimit) Acceleration = AccelerationLimit;
- if(MaxSpeed > MaxSpeedLimit) MaxSpeed = MaxSpeedLimit;
+}
+const float SOUND_DIST = 20.0f;
- int MoveState = ((CPed*)CamTargetEntity)->m_nMoveState;
- if(MoveState != PEDMOVE_NONE && MoveState != PEDMOVE_STILL &&
- !CPad::GetPad(0)->ForceCameraBehindPlayer() && !Obscured && !Shooting){
- Rotating = false;
- BetaSpeed = 0.0f;
+void
+CCamera::UpdateSoundDistances(void)
+{
+ CVector center, end;
+ CEntity *entity;
+ CColPoint colPoint;
+ float f;
+ int n;
+
+ if((Cams[ActiveCam].Mode == CCam::MODE_1STPERSON ||
+ Cams[ActiveCam].Mode == CCam::MODE_SNIPER ||
+ Cams[ActiveCam].Mode == CCam::MODE_SNIPER_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_1STPERSON_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_HELICANNON_1STPERSON ||
+ Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON ||
+ Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER) &&
+ pTargetEntity->IsPed())
+ center = GetPosition() + 0.5f*GetForward();
+ else
+ center = GetPosition() + 5.0f*GetForward();
+
+ // check up
+ n = CTimer::GetFrameCounter() % 12;
+ if(n == 0){
+ SoundDistUpAsReadOld = SoundDistUpAsRead;
+ if(CWorld::ProcessVerticalLine(center, center.z+SOUND_DIST, colPoint, entity, true, false, false, false, true, false, nil))
+ SoundDistUpAsRead = colPoint.point.z - center.z;
+ else
+ SoundDistUpAsRead = SOUND_DIST;
}
+ f = (n + 1) / 6.0f;
+ SoundDistUp = (1.0f-f)*SoundDistUpAsReadOld + f*SoundDistUpAsRead;
+
+ // check left
+ n = (CTimer::GetFrameCounter()+2) % 12;
+ if(n == 0){
+ SoundDistLeftAsReadOld = SoundDistLeftAsRead;
+ end = center + SOUND_DIST*GetRight();
+ if(CWorld::ProcessLineOfSight(center, end, colPoint, entity, true, false, false, false, true, true, true))
+ SoundDistLeftAsRead = (colPoint.point - center).Magnitude();
+ else
+ SoundDistLeftAsRead = SOUND_DIST;
+ }
+ f = (n + 1) / 6.0f;
+ SoundDistLeft = (1.0f-f)*SoundDistLeftAsReadOld + f*SoundDistLeftAsRead;
+
+ // check right
+ // end = center - SOUND_DIST*GetRight(); // useless
+ n = (CTimer::GetFrameCounter()+4) % 12;
+ if(n == 0){
+ SoundDistRightAsReadOld = SoundDistRightAsRead;
+ end = center - SOUND_DIST*GetRight();
+ if(CWorld::ProcessLineOfSight(center, end, colPoint, entity, true, false, false, false, true, true, true))
+ SoundDistRightAsRead = (colPoint.point - center).Magnitude();
+ else
+ SoundDistRightAsRead = SOUND_DIST;
+ }
+ f = (n + 1) / 6.0f;
+ SoundDistRight = (1.0f-f)*SoundDistRightAsReadOld + f*SoundDistRightAsRead;
+}
- // Now do the Beta rotation
-
- float Distance = (IdealSource - TargetCoors).Magnitude2D();
- m_fDistanceBeforeChanges = Distance;
+void
+CCamera::InitialiseCameraForDebugMode(void)
+{
+ if(FindPlayerVehicle())
+ Cams[2].Source = FindPlayerVehicle()->GetPosition();
+ else if(FindPlayerPed())
+ Cams[2].Source = FindPlayerPed()->GetPosition();
+ Cams[2].Alpha = 0.0f;
+ Cams[2].Beta = 0.0f;
+ Cams[2].Mode = CCam::MODE_DEBUG;
+}
- if(Rotating){
- m_bFixingBeta = true;
+void
+CCamera::CamShake(float strength, float x, float y, float z)
+{
+ CVector Dist = Cams[ActiveCam].Source - CVector(x, y, z);
+ // a bit complicated...
+ float dist2d = Sqrt(SQR(Dist.x) + SQR(Dist.y));
+ float dist3d = Sqrt(SQR(dist2d) + SQR(Dist.z));
+ if(dist3d > 100.0f) dist3d = 100.0f;
+ if(dist3d < 0.0f) dist3d = 0.0f;
+ float mult = 1.0f - dist3d/100.0f;
+
+ float curForce = mult*(m_fCamShakeForce - (CTimer::GetTimeInMilliseconds() - m_uiCamShakeStart)/1000.0f);
+ strength = mult*strength;
+ if(clamp(curForce, 0.0f, 2.0f) < strength){
+ m_fCamShakeForce = strength;
+ m_uiCamShakeStart = CTimer::GetTimeInMilliseconds();
+ }
+}
- while(FixedTargetOrientation >= PI) FixedTargetOrientation -= 2*PI;
- while(FixedTargetOrientation < -PI) FixedTargetOrientation += 2*PI;
+// This seems to be CCamera::CamShake(float) on PS2
+void
+CamShakeNoPos(CCamera *cam, float strength)
+{
+ float curForce = cam->m_fCamShakeForce - (CTimer::GetTimeInMilliseconds() - cam->m_uiCamShakeStart)/1000.0f;
+ if(clamp(curForce, 0.0f, 2.0f) < strength){
+ cam->m_fCamShakeForce = strength;
+ cam->m_uiCamShakeStart = CTimer::GetTimeInMilliseconds();
+ }
+}
- while(Beta >= PI) Beta -= 2*PI;
- while(Beta < -PI) Beta += 2*PI;
-/*
- // This is inlined WellBufferMe
- DeltaBeta = FixedTargetOrientation - Beta;
- while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
- while(DeltaBeta < -PI) DeltaBeta += 2*PI;
-
- float ReqSpeed = DeltaBeta * MaxSpeed;
- // Add or subtract absolute depending on sign, genius!
- if(ReqSpeed - BetaSpeed > 0.0f)
- BetaSpeed += SpeedStep * Abs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep();
+void
+CCamera::TakeControl(CEntity *target, int16 mode, int16 typeOfSwitch, int32 controller)
+{
+ bool doSwitch = true;
+ if(controller == CAMCONTROL_OBBE && WhoIsInControlOfTheCamera == CAMCONTROL_SCRIPT)
+ doSwitch = false;
+ if(doSwitch){
+ WhoIsInControlOfTheCamera = controller;
+ if(target){
+ if(mode == CCam::MODE_NONE){
+ // Why are we checking the old entity?
+ if(pTargetEntity->IsPed())
+ mode = CCam::MODE_FOLLOWPED;
+ else if(pTargetEntity->IsVehicle())
+ mode = CCam::MODE_CAM_ON_A_STRING;
+ }
+ }else if(FindPlayerVehicle())
+ target = FindPlayerVehicle();
else
- BetaSpeed -= SpeedStep * Abs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep();
- // this would be simpler:
- // BetaSpeed += SpeedStep * (ReqSpeed - BetaSpeed) * CTimer::ms_fTimeStep;
-
- if(ReqSpeed < 0.0f && BetaSpeed < ReqSpeed)
- BetaSpeed = ReqSpeed;
- else if(ReqSpeed > 0.0f && BetaSpeed > ReqSpeed)
- BetaSpeed = ReqSpeed;
+ target = PLAYER;
+
+ m_bLookingAtVector = false;
+ pTargetEntity = target;
+ m_iModeToGoTo = mode;
+ m_iTypeOfSwitch = typeOfSwitch;
+ m_bLookingAtPlayer = false;
+ m_bStartInterScript = true;
+ // FindPlayerPed(); // unused
+ }
+}
- Beta += BetaSpeed * min(10.0f, CTimer::GetTimeStep());
-*/
- WellBufferMe(FixedTargetOrientation, &Beta, &BetaSpeed, MaxSpeed, Acceleration, true);
+void
+CCamera::TakeControlNoEntity(const CVector &position, int16 typeOfSwitch, int32 controller)
+{
+ bool doSwitch = true;
+ if(controller == CAMCONTROL_OBBE && WhoIsInControlOfTheCamera == CAMCONTROL_SCRIPT)
+ doSwitch = false;
+ if(doSwitch){
+ WhoIsInControlOfTheCamera = controller;
+ m_bLookingAtVector = true;
+ m_bLookingAtPlayer = false;
+ m_iModeToGoTo = CCam::MODE_FIXED;
+ m_vecFixedModeVector = position;
+ m_iTypeOfSwitch = typeOfSwitch;
+ m_bStartInterScript = true;
+ }
+}
- if(ResetStatics){
- Beta = FixedTargetOrientation;
- BetaSpeed = 0.0f;
- }
+void
+CCamera::TakeControlWithSpline(int16 typeOfSwitch)
+{
+ m_iModeToGoTo = CCam::MODE_FLYBY;
+ m_bLookingAtPlayer = false;
+ m_bLookingAtVector = false;
+ m_bcutsceneFinished = false;
+ m_iTypeOfSwitch = typeOfSwitch;
+ m_bStartInterScript = true;
- Source.x = TargetCoors.x + Distance * Cos(Beta);
- Source.y = TargetCoors.y + Distance * Sin(Beta);
-
- // Check if we can stop rotating
- DeltaBeta = FixedTargetOrientation - Beta;
- while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
- while(DeltaBeta < -PI) DeltaBeta += 2*PI;
- if(Abs(DeltaBeta) < DEGTORAD(1.0f) && !bBehindPlayerDesired){
- // Stop rotation
- PickedASide = false;
- Rotating = false;
- BetaSpeed = 0.0f;
- }
- }
+ //FindPlayerPed(); // unused
+};
+void
+CCamera::Restore(void)
+{
+ m_bLookingAtPlayer = true;
+ m_bLookingAtVector = false;
+ m_iTypeOfSwitch = INTERPOLATION;
+ m_bUseNearClipScript = false;
+ m_iModeObbeCamIsInForCar = OBBE_INVALID;
+ m_fPositionAlongSpline = 0.0;
+ m_bStartingSpline = false;
+ m_bScriptParametersSetForInterPol = false;
+ WhoIsInControlOfTheCamera = CAMCONTROL_GAME;
- if(TheCamera.m_bCamDirectlyBehind || TheCamera.m_bCamDirectlyInFront ||
- HackPlayerOnStoppingTrain || Rotating){
- if(TheCamera.m_bCamDirectlyBehind){
- Beta = TargetOrientation + PI;
- Source.x = TargetCoors.x + Distance * Cos(Beta);
- Source.y = TargetCoors.y + Distance * Sin(Beta);
- }
- if(TheCamera.m_bCamDirectlyInFront){
- Beta = TargetOrientation;
- Source.x = TargetCoors.x + Distance * Cos(Beta);
- Source.y = TargetCoors.y + Distance * Sin(Beta);
- }
- if(HackPlayerOnStoppingTrain){
- Beta = TargetOrientation + PI;
- Source.x = TargetCoors.x + Distance * Cos(Beta);
- Source.y = TargetCoors.y + Distance * Sin(Beta);
- m_fDimensionOfHighestNearCar = 0.0f;
- m_fCamBufferedHeight = 0.0f;
- m_fCamBufferedHeightSpeed = 0.0f;
- }
- // Beta and Source already set in the rotation code
+ if(FindPlayerVehicle()){
+ m_iModeToGoTo = CCam::MODE_CAM_ON_A_STRING;
+ pTargetEntity = FindPlayerVehicle();
}else{
- Source = IdealSource;
- BetaSpeed = 0.0f;
+ m_iModeToGoTo = CCam::MODE_FOLLOWPED;
+ pTargetEntity = PLAYER;
}
- // Subtract m_fUnknownZOffSet from both?
- TargetCoors.z -= m_fUnknownZOffSet;
- Source.z = IdealSource.z - m_fUnknownZOffSet;
-
- // Apply zoom now
- // m_fPedZoomValueSmooth makes the cam go down the further out it is
- // 0.25 -> 0.20 for nearest dist
- // 1.50 -> -0.05 for mid dist
- // 2.90 -> -0.33 for far dist
- Source.z += (2.5f - TheCamera.m_fPedZoomValueSmooth)*0.2f - 0.25f;
- // Zoom out camera
- Front = TargetCoors - Source;
- Front.Normalise();
- Source -= Front * TheCamera.m_fPedZoomValueSmooth;
- // and then we move up again
- // -0.375
- // 0.25
- // 0.95
- Source.z += (TheCamera.m_fPedZoomValueSmooth - 1.0f)*0.5f + m_fCloseInPedHeightOffset;
-
-
- // Process height offset to avoid peds and cars
-
- float TargetZOffSet = m_fUnknownZOffSet + m_fDimensionOfHighestNearCar;
- TargetZOffSet = max(TargetZOffSet, m_fPedBetweenCameraHeightOffset);
- float TargetHeight = CameraTarget.z + TargetZOffSet - Source.z;
-
- if(TargetHeight > m_fCamBufferedHeight){
- // Have to go up
- if(TargetZOffSet == m_fPedBetweenCameraHeightOffset && TargetZOffSet > m_fCamBufferedHeight)
- WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.04f, false);
- else if(TargetZOffSet == m_fUnknownZOffSet && TargetZOffSet > m_fCamBufferedHeight){
- // TODO: figure this out
- bool foo = false;
- switch(((CPhysical*)CamTargetEntity)->m_nSurfaceTouched)
- case SURFACE_GRASS:
- case SURFACE_DIRT:
- case SURFACE_PAVEMENT:
- case SURFACE_STEEL:
- case SURFACE_TIRE:
- case SURFACE_STONE:
- foo = true;
- if(foo)
- WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.4f, 0.05f, false);
- else
- WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.025f, false);
- }else
- WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.025f, false);
- StartedCountingForGoDown = false;
- }else{
- // Have to go down
- if(StartedCountingForGoDown){
- if(CTimer::GetTimeInMilliseconds() != TimeIndicatedWantedToGoDown){
- if(TargetHeight > 0.0f)
- WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.01f, false);
- else
- WellBufferMe(0.0f, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.01f, false);
- }
- }else{
- StartedCountingForGoDown = true;
- TimeIndicatedWantedToGoDown = CTimer::GetTimeInMilliseconds();
- }
+ if(PLAYER->GetPedState() == PED_ENTER_CAR ||
+ PLAYER->GetPedState() == PED_CARJACK ||
+ PLAYER->GetPedState() == PED_OPEN_DOOR){
+ m_iModeToGoTo = CCam::MODE_CAM_ON_A_STRING;
+ pTargetEntity = PLAYER->m_pSeekTarget;
}
-
- Source.z += m_fCamBufferedHeight;
-
-
- // Clip Source if necessary
-
- bool ClipSource = m_fCloseInPedHeightOffset > 0.00001f && m_fCamBufferedHeight > 0.001f;
- if(GoingBehind || ResetStatics || ClipSource){
- CColPoint colpoint;
- CEntity *entity;
- if(CWorld::ProcessLineOfSight(TargetCoors, Source, colpoint, entity, true, false, false, true, false, true, true)){
- Source = colpoint.point;
- if((TargetCoors - Source).Magnitude2D() < 1.0f)
- RwCameraSetNearClipPlane(Scene.camera, 0.05f);
- }
+ if(PLAYER->GetPedState() == PED_EXIT_CAR){
+ m_iModeToGoTo = CCam::MODE_FOLLOWPED;
+ pTargetEntity = PLAYER;
}
- TargetCoors.z += min(1.0f, m_fCamBufferedHeight/2.0f);
- m_cvecTargetCoorsForFudgeInter = TargetCoors;
-
- Front = TargetCoors - Source;
- m_fRealGroundDist = Front.Magnitude2D();
- m_fMinDistAwayFromCamWhenInterPolating = m_fRealGroundDist;
- Front.Normalise();
- GetVectorsReadyForRW();
- TheCamera.m_bCamDirectlyBehind = false;
- TheCamera.m_bCamDirectlyInFront = false;
- PreviouslyObscured = BuildingCheckObscured;
-
- ResetStatics = false;
+ m_bUseScriptZoomValuePed = false;
+ m_bUseScriptZoomValueCar = false;
+ m_bStartInterScript = true;
+ m_bCameraJustRestored = true;
}
void
-CCam::Process_BehindCar(const CVector &CameraTarget, float TargetOrientation, float, float)
+CCamera::RestoreWithJumpCut(void)
{
- FOV = DefaultFOV;
+ m_bRestoreByJumpCut = true;
+ m_bLookingAtPlayer = true;
+ m_bLookingAtVector = false;
+ m_iTypeOfSwitch = JUMP_CUT;
+ m_bUseNearClipScript = false;
+ m_iModeObbeCamIsInForCar = OBBE_INVALID;
+ m_fPositionAlongSpline = 0.0;
+ m_bStartingSpline = false;
+ m_bScriptParametersSetForInterPol = false;
+ WhoIsInControlOfTheCamera = CAMCONTROL_GAME;
+ m_bCameraJustRestored = true;
- if(!CamTargetEntity->IsVehicle())
- return;
+ if(FindPlayerVehicle()){
+ m_iModeToGoTo = CCam::MODE_CAM_ON_A_STRING;
+ pTargetEntity = FindPlayerVehicle();
+ }else{
+ m_iModeToGoTo = CCam::MODE_FOLLOWPED;
+ pTargetEntity = PLAYER;
+ }
- CVector TargetCoors = CameraTarget;
- TargetCoors.z -= 0.2f;
- CA_MAX_DISTANCE = 9.95f;
- CA_MIN_DISTANCE = 8.5f;
-
- CVector Dist = Source - TargetCoors;
- float Length = Dist.Magnitude2D();
- m_fDistanceBeforeChanges = Length;
- if(Length < 0.002f)
- Length = 0.002f;
- Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y);
- if(Length > CA_MAX_DISTANCE){
- Source.x = TargetCoors.x + Dist.x/Length * CA_MAX_DISTANCE;
- Source.y = TargetCoors.y + Dist.y/Length * CA_MAX_DISTANCE;
- }else if(Length < CA_MIN_DISTANCE){
- Source.x = TargetCoors.x + Dist.x/Length * CA_MIN_DISTANCE;
- Source.y = TargetCoors.y + Dist.y/Length * CA_MIN_DISTANCE;
+ if(PLAYER->GetPedState() == PED_ENTER_CAR ||
+ PLAYER->GetPedState() == PED_CARJACK ||
+ PLAYER->GetPedState() == PED_OPEN_DOOR){
+ m_iModeToGoTo = CCam::MODE_CAM_ON_A_STRING;
+ pTargetEntity = PLAYER->m_pSeekTarget;
+ }
+ if(PLAYER->GetPedState() == PED_EXIT_CAR){
+ m_iModeToGoTo = CCam::MODE_FOLLOWPED;
+ pTargetEntity = PLAYER;
}
- TargetCoors.z += 0.8f;
- WorkOutCamHeightWeeCar(TargetCoors, TargetOrientation);
- RotCamIfInFrontCar(TargetCoors, TargetOrientation);
- FixCamIfObscured(TargetCoors, 1.2f, TargetOrientation);
+ m_bUseScriptZoomValuePed = false;
+ m_bUseScriptZoomValueCar = false;
+}
- Front = TargetCoors - Source;
- m_cvecTargetCoorsForFudgeInter = TargetCoors;
- ResetStatics = false;
- GetVectorsReadyForRW();
+void
+CCamera::SetCamPositionForFixedMode(const CVector &Source, const CVector &UpOffSet)
+{
+ m_vecFixedModeSource = Source;
+ m_vecFixedModeUpOffSet = UpOffSet;
}
+
+
+/*
+ * On PS2 the transition happens between Cams[1] and Cams[2].
+ * On PC the whole system has been changed.
+ */
void
-CCam::WorkOutCamHeightWeeCar(CVector &TargetCoors, float TargetOrientation)
-{
- CColPoint colpoint;
- CEntity *ent;
- float TargetZOffSet = 0.0f;
- static bool PreviouslyFailedRoadHeightCheck = false;
- static float RoadHeightFix = 0.0f;
- static float RoadHeightFixSpeed = 0.0f;
-
- if(ResetStatics){
- RoadHeightFix = 0.0f;
- RoadHeightFixSpeed = 0.0f;
- Alpha = DEGTORAD(25.0f);
- AlphaSpeed = 0.0f;
+CCamera::StartTransition(int16 newMode)
+{
+ bool foo = false;
+ bool switchSyphonMode = false;
+ bool switchPedToCar = false;
+ bool switchPedMode = false;
+ bool switchFromFixed = false;
+ bool switch1stPersonToVehicle = false;
+ float betaOffset, targetBeta, camBeta, deltaBeta;
+ int door;
+ bool vehicleVertical;
+
+// missing on PS2
+ m_bItsOkToLookJustAtThePlayer = false;
+ m_fFractionInterToStopMovingTarget = 0.25f;
+ m_fFractionInterToStopCatchUpTarget = 0.75f;
+
+ if(Cams[ActiveCam].Mode == CCam::MODE_SYPHON_CRIM_IN_FRONT ||
+ Cams[ActiveCam].Mode == CCam::MODE_FOLLOWPED ||
+ Cams[ActiveCam].Mode == CCam::MODE_SYPHON ||
+ Cams[ActiveCam].Mode == CCam::MODE_SPECIAL_FIXED_FOR_SYPHON){
+ if(newMode == CCam::MODE_SYPHON_CRIM_IN_FRONT ||
+ newMode == CCam::MODE_FOLLOWPED ||
+ newMode == CCam::MODE_SYPHON ||
+ newMode == CCam::MODE_SPECIAL_FIXED_FOR_SYPHON)
+ m_bItsOkToLookJustAtThePlayer = true;
+ if(newMode == CCam::MODE_CAM_ON_A_STRING)
+ switchPedToCar = true;
+ }
+//
+
+ if(Cams[ActiveCam].Mode == CCam::MODE_SYPHON_CRIM_IN_FRONT && newMode == CCam::MODE_SYPHON)
+ switchSyphonMode = true;
+ if(Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM && newMode == CCam::MODE_FOLLOWPED)
+ switchPedMode = true;
+ if(Cams[ActiveCam].Mode == CCam::MODE_FIXED)
+ switchFromFixed = true;
+
+ m_bUseTransitionBeta = false;
+
+ if((Cams[ActiveCam].Mode == CCam::MODE_SNIPER ||
+ Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER ||
+ Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON ||
+ Cams[ActiveCam].Mode == CCam::MODE_SNIPER_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM_RUNABOUT ||
+ Cams[ActiveCam].Mode == CCam::MODE_HELICANNON_1STPERSON ||
+ Cams[ActiveCam].Mode == CCam::MODE_1STPERSON_RUNABOUT) &&
+ pTargetEntity->IsPed()){
+ float angle = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y) - HALFPI;
+ ((CPed*)pTargetEntity)->m_fRotationCur = angle;
+ ((CPed*)pTargetEntity)->m_fRotationDest = angle;
}
- float AlphaTarget = DEGTORAD(25.0f);
- if(CCullZones::CamNoRain() || CCullZones::PlayerNoRain())
- AlphaTarget = DEGTORAD(14.0f);
- WellBufferMe(AlphaTarget, &Alpha, &AlphaSpeed, 0.1f, 0.05f, true);
- Source.z = TargetCoors.z + CA_MAX_DISTANCE*Sin(Alpha);
- if(FindPlayerVehicle()){
- m_fUnknownZOffSet = 0.0f;
- bool FoundRoad = false;
- bool FoundRoof = false;
- float RoadZ = 0.0f;
- float RoofZ = 0.0f;
-
- if(CWorld::ProcessVerticalLine(Source, -1000.0f, colpoint, ent, true, false, false, false, false, false, nil) &&
- ent->IsBuilding()){
- FoundRoad = true;
- RoadZ = colpoint.point.z;
- }
+/* // PS2
+ ActiveCam = (ActiveCam+1)%2;
+ Cams[ActiveCam].Init();
+ Cams[ActiveCam].Mode = newMode;
+ */
- if(FoundRoad){
- if(Source.z - RoadZ < 0.9f){
- PreviouslyFailedRoadHeightCheck = true;
- TargetZOffSet = RoadZ + 0.9f - Source.z;
- }else{
- if(m_bCollisionChecksOn)
- PreviouslyFailedRoadHeightCheck = false;
- else
- TargetZOffSet = 0.0f;
+ Cams[ActiveCam].m_cvecCamFixedModeVector = m_vecFixedModeVector;
+ Cams[ActiveCam].CamTargetEntity = pTargetEntity;
+ Cams[ActiveCam].m_cvecCamFixedModeSource = m_vecFixedModeSource;
+ Cams[ActiveCam].m_cvecCamFixedModeUpOffSet = m_vecFixedModeUpOffSet;
+ Cams[ActiveCam].m_bCamLookingAtVector = m_bLookingAtVector;
+
+ if(newMode == CCam::MODE_SNIPER ||
+ newMode == CCam::MODE_ROCKETLAUNCHER ||
+ newMode == CCam::MODE_M16_1STPERSON ||
+ newMode == CCam::MODE_SNIPER_RUNABOUT ||
+ newMode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT ||
+ newMode == CCam::MODE_1STPERSON_RUNABOUT ||
+ newMode == CCam::MODE_M16_1STPERSON_RUNABOUT ||
+ newMode == CCam::MODE_FIGHT_CAM_RUNABOUT ||
+ newMode == CCam::MODE_HELICANNON_1STPERSON)
+ Cams[ActiveCam].Alpha = 0.0f;
+
+ // PS2 also copies values to ActiveCam here
+ switch(Cams[ActiveCam].Mode)
+ case CCam::MODE_SNIPER_RUNABOUT:
+ case CCam::MODE_ROCKETLAUNCHER_RUNABOUT:
+ case CCam::MODE_1STPERSON_RUNABOUT:
+ case CCam::MODE_M16_1STPERSON_RUNABOUT:
+ case CCam::MODE_FIGHT_CAM_RUNABOUT:
+ if(newMode == CCam::MODE_CAM_ON_A_STRING || newMode == CCam::MODE_BEHINDBOAT)
+ switch1stPersonToVehicle = true;
+
+ switch(newMode){
+ case CCam::MODE_BEHINDCAR:
+ Cams[ActiveCam].BetaSpeed = 0.0f;
+ break;
+
+ case CCam::MODE_FOLLOWPED:
+ // Getting out of vehicle normally
+ betaOffset = DEGTORAD(55.0f);
+ if(m_bJustCameOutOfGarage){
+ m_bUseTransitionBeta = true;
+/*
+ // weird logic...
+ if(CMenuManager::m_ControlMethod == CONTROL_CLASSIC)
+ Cams[ActiveCam].m_fTransitionBeta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y) + PI;
+ else if(Cams[ActiveCam].Front.x != 0.0f && Cams[ActiveCam].Front.y != 0.0f) // && is wrong here
+ Cams[ActiveCam].m_fTransitionBeta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y) + PI;
+ else
+ Cams[ActiveCam].m_fTransitionBeta = 0.0f;
+*/
+ // this is better:
+ if(Cams[ActiveCam].Front.x != 0.0f || Cams[ActiveCam].Front.y != 0.0f)
+ Cams[ActiveCam].m_fTransitionBeta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y) + PI;
+ else
+ Cams[ActiveCam].m_fTransitionBeta = 0.0f;
+ }
+ if(m_bTargetJustCameOffTrain)
+ m_bCamDirectlyInFront = true;
+ if(Cams[ActiveCam].Mode != CCam::MODE_CAM_ON_A_STRING)
+ break;
+ m_bUseTransitionBeta = true;
+ vehicleVertical = false;
+ if(((CPed*)pTargetEntity)->m_carInObjective &&
+ ((CPed*)pTargetEntity)->m_carInObjective->GetForward().x == 0.0f &&
+ ((CPed*)pTargetEntity)->m_carInObjective->GetForward().y == 0.0f)
+ vehicleVertical = true;
+ if(vehicleVertical){
+ Cams[ActiveCam].m_fTransitionBeta = 0.0f;
+ break;
+ }
+ camBeta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y);
+ if(((CPed*)pTargetEntity)->m_carInObjective)
+ targetBeta = CGeneral::GetATanOfXY(((CPed*)pTargetEntity)->m_carInObjective->GetForward().x, ((CPed*)pTargetEntity)->m_carInObjective->GetForward().y);
+ else
+ targetBeta = camBeta;
+ deltaBeta = targetBeta - camBeta;
+ while(deltaBeta >= PI) deltaBeta -= 2*PI;
+ while(deltaBeta < -PI) deltaBeta += 2*PI;
+ deltaBeta = Abs(deltaBeta);
+
+ door = FindPlayerPed()->m_vehEnterType;
+ if(deltaBeta > HALFPI){
+ if(((CPed*)pTargetEntity)->m_carInObjective){
+ if(((CPed*)pTargetEntity)->m_carInObjective->IsUpsideDown()){
+ if(door == CAR_DOOR_LF || door == CAR_DOOR_LR)
+ betaOffset = -DEGTORAD(95.0f);
+ }else{
+ if(door == CAR_DOOR_RF || door == CAR_DOOR_RR)
+ betaOffset = -DEGTORAD(95.0f);
+ }
}
+ Cams[ActiveCam].m_fTransitionBeta = targetBeta + betaOffset;
}else{
- if(CWorld::ProcessVerticalLine(Source, 1000.0f, colpoint, ent, true, false, false, false, false, false, nil) &&
- ent->IsBuilding()){
- FoundRoof = true;
- RoofZ = colpoint.point.z;
- }
- if(FoundRoof){
- if(Source.z - RoofZ < 0.9f){
- PreviouslyFailedRoadHeightCheck = true;
- TargetZOffSet = RoofZ + 0.9f - Source.z;
+ if(((CPed*)pTargetEntity)->m_carInObjective){
+ if(((CPed*)pTargetEntity)->m_carInObjective->IsUpsideDown()){
+ if(door == CAR_DOOR_RF || door == CAR_DOOR_RR)
+ betaOffset = -DEGTORAD(55.0f);
+ else if(door == CAR_DOOR_LF || door == CAR_DOOR_LR)
+ betaOffset = DEGTORAD(95.0f);
}else{
- if(m_bCollisionChecksOn)
- PreviouslyFailedRoadHeightCheck = false;
- else
- TargetZOffSet = 0.0f;
+ if(door == CAR_DOOR_LF || door == CAR_DOOR_LR)
+ betaOffset = -DEGTORAD(55.0f);
+ else if(door == CAR_DOOR_RF || door == CAR_DOOR_RR)
+ betaOffset = DEGTORAD(95.0f);
}
}
+ Cams[ActiveCam].m_fTransitionBeta = targetBeta + betaOffset + PI;
+ }
+ break;
+
+ case CCam::MODE_SNIPER:
+ case CCam::MODE_ROCKETLAUNCHER:
+ case CCam::MODE_M16_1STPERSON:
+ case CCam::MODE_SNIPER_RUNABOUT:
+ case CCam::MODE_ROCKETLAUNCHER_RUNABOUT:
+ case CCam::MODE_1STPERSON_RUNABOUT:
+ case CCam::MODE_M16_1STPERSON_RUNABOUT:
+ case CCam::MODE_FIGHT_CAM_RUNABOUT:
+ case CCam::MODE_HELICANNON_1STPERSON:
+ if(FindPlayerVehicle())
+ Cams[ActiveCam].Beta = Atan2(FindPlayerVehicle()->GetForward().x, FindPlayerVehicle()->GetForward().y);
+ else
+ Cams[ActiveCam].Beta = Atan2(PLAYER->GetForward().x, PLAYER->GetForward().y);
+ break;
+
+ case CCam::MODE_SYPHON:
+ Cams[ActiveCam].Alpha = 0.0f;
+ Cams[ActiveCam].AlphaSpeed = 0.0f;
+ break;
+
+ case CCam::MODE_CAM_ON_A_STRING:
+ // Get into vehicle
+ betaOffset = DEGTORAD(57.0f);
+ if(!m_bLookingAtPlayer || m_bJustCameOutOfGarage)
+ break;
+ m_bUseTransitionBeta = true;
+ targetBeta = CGeneral::GetATanOfXY(pTargetEntity->GetForward().x, pTargetEntity->GetForward().y);
+ camBeta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y);
+ deltaBeta = targetBeta - camBeta;
+ while(deltaBeta >= PI) deltaBeta -= 2*PI;
+ while(deltaBeta < -PI) deltaBeta += 2*PI;
+ deltaBeta = Abs(deltaBeta);
+ // switchFromFixed logic again here, skipped
+ if(switchFromFixed){
+ Cams[ActiveCam].m_fTransitionBeta = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y);
+ break;
}
- }
- if(TargetZOffSet > RoadHeightFix)
- RoadHeightFix = TargetZOffSet;
- else
- WellBufferMe(TargetZOffSet, &RoadHeightFix, &RoadHeightFixSpeed, 0.27f, 0.1f, false);
+ door = FindPlayerPed()->m_vehEnterType;
+ if(deltaBeta > HALFPI){
+ if(((CVehicle*)pTargetEntity)->IsUpsideDown()){
+ if(door == CAR_DOOR_LF || door == CAR_DOOR_LR) // BUG: game checks LF twice
+ betaOffset = -DEGTORAD(57.0f);
+ }else{
+ if(door == CAR_DOOR_RF || door == CAR_DOOR_RR)
+ betaOffset = -DEGTORAD(57.0f);
+ }
+ Cams[ActiveCam].m_fTransitionBeta = targetBeta + betaOffset + PI;
+ }else{
+ if(((CVehicle*)pTargetEntity)->IsUpsideDown()){
+ if(door == CAR_DOOR_RF || door == CAR_DOOR_RR)
+ betaOffset = -DEGTORAD(57.0f);
+ else if(door == CAR_DOOR_LF || door == CAR_DOOR_LR)
+ betaOffset = DEGTORAD(57.0f);
+ }else{
+ if(door == CAR_DOOR_LF || door == CAR_DOOR_LR)
+ betaOffset = -DEGTORAD(57.0f);
+ else if(door == CAR_DOOR_RF || door == CAR_DOOR_RR)
+ betaOffset = DEGTORAD(57.0f);
+ }
+ Cams[ActiveCam].m_fTransitionBeta = targetBeta + betaOffset;
+ }
+ break;
+
+ case CCam::MODE_BEHINDBOAT:
+ Cams[ActiveCam].BetaSpeed = 0.0f;
+ break;
+
+ case CCam::MODE_PED_DEAD_BABY:
+ Cams[ActiveCam].Alpha = DEGTORAD(15.0f);
+ break;
+
+ case CCam::MODE_FIGHT_CAM:
+ Cams[ActiveCam].Beta = 0.0f;
+ Cams[ActiveCam].BetaSpeed = 0.0f;
+ Cams[ActiveCam].Alpha = 0.0f;
+ Cams[ActiveCam].AlphaSpeed = 0.0f;
+ break;
+ }
- if((colpoint.surfaceB == SURFACE_DEFAULT || colpoint.surfaceB >= SURFACE_METAL6) &&
- colpoint.surfaceB != SURFACE_STEEL && colpoint.surfaceB != SURFACE_STONE &&
- RoadHeightFix > 1.4f)
- RoadHeightFix = 1.4f;
+ Cams[ActiveCam].Init();
+ Cams[ActiveCam].Mode = newMode;
+
+ m_uiTransitionDuration = 1350;
+ if(switchSyphonMode)
+ m_uiTransitionDuration = 1800;
+ else if(switchPedMode)
+ m_uiTransitionDuration = 750;
+// not on PS2
+ else if(switchPedToCar){
+ m_fFractionInterToStopMovingTarget = 0.2f;
+ m_fFractionInterToStopCatchUpTarget = 0.8f;
+ m_uiTransitionDuration = 950;
+ }else if(switchFromFixed){
+ m_fFractionInterToStopMovingTarget = 0.05f;
+ m_fFractionInterToStopCatchUpTarget = 0.95f;
+ }else if(switch1stPersonToVehicle){
+ m_fFractionInterToStopMovingTarget = 0.0f;
+ m_fFractionInterToStopCatchUpTarget = 1.0f;
+ m_uiTransitionDuration = 1;
+ }else
+ m_uiTransitionDuration = 1350; // already set above
+//
+ m_uiTransitionState = 1;
+ m_uiTimeTransitionStart = CTimer::GetTimeInMilliseconds();
+ m_uiTransitionJUSTStarted = 1;
+// PS2 returns here
+ if(m_vecDoingSpecialInterPolation){
+ m_cvecStartingSourceForInterPol = SourceDuringInter;
+ m_cvecStartingTargetForInterPol = TargetDuringInter;
+ m_cvecStartingUpForInterPol = UpDuringInter;
+ m_fStartingAlphaForInterPol = m_fAlphaDuringInterPol;
+ m_fStartingBetaForInterPol = m_fBetaDuringInterPol;
+ }else{
+ m_cvecStartingSourceForInterPol = Cams[ActiveCam].Source;
+ m_cvecStartingTargetForInterPol = Cams[ActiveCam].m_cvecTargetCoorsForFudgeInter;
+ m_cvecStartingUpForInterPol = Cams[ActiveCam].Up;
+ m_fStartingAlphaForInterPol = Cams[ActiveCam].m_fTrueAlpha;
+ m_fStartingBetaForInterPol = Cams[ActiveCam].m_fTrueBeta;
+ }
+ Cams[ActiveCam].m_bCamLookingAtVector = m_bLookingAtVector;
+ Cams[ActiveCam].m_cvecCamFixedModeVector = m_vecFixedModeVector;
+ Cams[ActiveCam].m_cvecCamFixedModeSource = m_vecFixedModeSource;
+ Cams[ActiveCam].m_cvecCamFixedModeUpOffSet = m_vecFixedModeUpOffSet;
+ Cams[ActiveCam].Mode = newMode; // already done above
+ Cams[ActiveCam].CamTargetEntity = pTargetEntity;
+ m_uiTransitionState = 1; // these three already done above
+ m_uiTimeTransitionStart = CTimer::GetTimeInMilliseconds();
+ m_uiTransitionJUSTStarted = 1;
+ m_fStartingFOVForInterPol = Cams[ActiveCam].FOV;
+ m_cvecSourceSpeedAtStartInter = Cams[ActiveCam].m_cvecSourceSpeedOverOneFrame;
+ m_cvecTargetSpeedAtStartInter = Cams[ActiveCam].m_cvecTargetSpeedOverOneFrame;
+ m_cvecUpSpeedAtStartInter = Cams[ActiveCam].m_cvecUpOverOneFrame;
+ m_fAlphaSpeedAtStartInter = Cams[ActiveCam].m_fAlphaSpeedOverOneFrame;
+ m_fBetaSpeedAtStartInter = Cams[ActiveCam].m_fBetaSpeedOverOneFrame;
+ m_fFOVSpeedAtStartInter = Cams[ActiveCam].m_fFovSpeedOverOneFrame;
+ Cams[ActiveCam].ResetStatics = true;
+ if(!m_bLookingAtPlayer && m_bScriptParametersSetForInterPol){
+ m_fFractionInterToStopMovingTarget = m_fScriptPercentageInterToStopMoving;
+ m_fFractionInterToStopCatchUpTarget = m_fScriptPercentageInterToCatchUp;
+ m_uiTransitionDuration = m_fScriptTimeForInterPolation;
+ }
+}
- Source.z += RoadHeightFix;
+void
+CCamera::StartTransitionWhenNotFinishedInter(int16 mode)
+{
+ m_vecDoingSpecialInterPolation = true;
+ StartTransition(mode);
}
void
-CCam::WorkOutCamHeight(const CVector &TargetCoors, float TargetOrientation, float TargetHeight)
+CCamera::StoreValuesDuringInterPol(CVector &source, CVector &target, CVector &up, float &FOV)
{
- static float LastTargetAlphaWithCollisionOn = 0.0f;
- static float LastTopAlphaSpeed = 0.0f;
- static float LastAlphaSpeedStep = 0.0f;
- static bool PreviousNearCheckNearClipSmall = false;
+ SourceDuringInter = source;
+ TargetDuringInter = target;
+ UpDuringInter = up;
+ FOVDuringInter = FOV;
+ CVector Dist = source - TargetDuringInter;
+ float DistOnGround = Dist.Magnitude2D();
+ m_fBetaDuringInterPol = CGeneral::GetATanOfXY(Dist.x, Dist.y);
+ m_fAlphaDuringInterPol = CGeneral::GetATanOfXY(DistOnGround, Dist.z);
+}
- bool CamClear = true;
- float ModeAlpha = 0.0f;
- if(ResetStatics){
- LastTargetAlphaWithCollisionOn = 0.0f;
- LastTopAlphaSpeed = 0.0f;
- LastAlphaSpeedStep = 0.0f;
- PreviousNearCheckNearClipSmall = false;
- }
- float TopAlphaSpeed = 0.15f;
- float AlphaSpeedStep = 0.015f;
+void
+CCamera::SetWideScreenOn(void)
+{
+ m_WideScreenOn = true;
+}
- float zoomvalue = TheCamera.CarZoomValueSmooth;
- if(zoomvalue < 0.1f)
- zoomvalue = 0.1f;
- if(TheCamera.CarZoomIndicator == 1.0f)
- ModeAlpha = CGeneral::GetATanOfXY(23.0f, zoomvalue); // near
- else if(TheCamera.CarZoomIndicator == 2.0f)
- ModeAlpha = CGeneral::GetATanOfXY(10.8f, zoomvalue); // mid
- else if(TheCamera.CarZoomIndicator == 3.0f)
- ModeAlpha = CGeneral::GetATanOfXY(7.0f, zoomvalue); // far
+void
+CCamera::SetWideScreenOff(void)
+{
+ m_bWantsToSwitchWidescreenOff = m_WideScreenOn;
+}
+void
+CCamera::ProcessWideScreenOn(void)
+{
+ if(m_bWantsToSwitchWidescreenOff){
+ m_bWantsToSwitchWidescreenOff = false;
+ m_WideScreenOn = false;
+ m_ScreenReductionPercentage = 0.0f;
+ m_fFOV_Wide_Screen = 0.0f;
+ m_fWideScreenReductionAmount = 0.0f;
+ }else{
+ m_fFOV_Wide_Screen = 0.3f*Cams[ActiveCam].FOV;
+ m_fWideScreenReductionAmount = 1.0f;
+ m_ScreenReductionPercentage = 30.0f;
+ }
+}
- float Length = (Source - TargetCoors).Magnitude2D();
- if(m_bCollisionChecksOn){ // there's another variable (on PC) but it's uninitialised
- CVector Forward = CamTargetEntity->GetForward();
- float CarAlpha = CGeneral::GetATanOfXY(Forward.Magnitude2D(), Forward.z);
- // this shouldn't be necessary....
- while(CarAlpha >= PI) CarAlpha -= 2*PI;
- while(CarAlpha < -PI) CarAlpha += 2*PI;
+void
+CCamera::DrawBordersForWideScreen(void)
+{
+ if(m_BlurType == MBLUR_NONE || m_BlurType == MBLUR_NORMAL)
+ SetMotionBlurAlpha(80);
+
+ CSprite2d::DrawRect(
+ CRect(0.0f, (SCREEN_HEIGHT/2) * m_ScreenReductionPercentage/100.0f - 8.0f,
+ SCREEN_WIDTH, 0.0f),
+ CRGBA(0, 0, 0, 255));
+
+ CSprite2d::DrawRect(
+ CRect(0.0f, SCREEN_HEIGHT,
+ SCREEN_WIDTH, SCREEN_HEIGHT - (SCREEN_HEIGHT/2) * m_ScreenReductionPercentage/100.0f - 8.0f),
+ CRGBA(0, 0, 0, 255));
+}
- while(Beta >= PI) Beta -= 2*PI;
- while(Beta < -PI) Beta += 2*PI;
- float deltaBeta = Beta - TargetOrientation;
- while(deltaBeta >= PI) deltaBeta -= 2*PI;
- while(deltaBeta < -PI) deltaBeta += 2*PI;
- float BehindCarNess = Cos(deltaBeta); // 1 if behind car, 0 if side, -1 if in front
- CarAlpha = -CarAlpha * BehindCarNess;
- if(CarAlpha < -0.01f)
- CarAlpha = -0.01f;
-
- float DeltaAlpha = CarAlpha - Alpha;
- while(DeltaAlpha >= PI) DeltaAlpha -= 2*PI;
- while(DeltaAlpha < -PI) DeltaAlpha += 2*PI;
- // What's this?? wouldn't it make more sense to clamp?
- float AngleLimit = DEGTORAD(1.8f);
- if(DeltaAlpha < -AngleLimit)
- DeltaAlpha += AngleLimit;
- else if(DeltaAlpha > AngleLimit)
- DeltaAlpha -= AngleLimit;
- else
- DeltaAlpha = 0.0f;
-
- // Now the collision
-
- float TargetAlpha = 0.0f;
- bool FoundRoofCenter = false;
- bool FoundRoofSide1 = false;
- bool FoundRoofSide2 = false;
- bool FoundCamRoof = false;
- bool FoundCamGround = false;
- float CamRoof = 0.0f;
- float CarBottom = TargetCoors.z - TargetHeight/2.0f;
-
- // Check car center
- float CarRoof = CWorld::FindRoofZFor3DCoord(TargetCoors.x, TargetCoors.y, CarBottom, &FoundRoofCenter);
-
- // Check sides of the car
- Forward = CamTargetEntity->GetForward(); // we actually still have that...
- Forward.Normalise(); // shouldn't be necessary
- float CarSideAngle = CGeneral::GetATanOfXY(Forward.x, Forward.y) + PI/2.0f;
- float SideX = 2.5f * Cos(CarSideAngle);
- float SideY = 2.5f * Sin(CarSideAngle);
- CWorld::FindRoofZFor3DCoord(TargetCoors.x + SideX, TargetCoors.y + SideY, CarBottom, &FoundRoofSide1);
- CWorld::FindRoofZFor3DCoord(TargetCoors.x - SideX, TargetCoors.y - SideY, CarBottom, &FoundRoofSide2);
-
- // Now find out at what height we'd like to place the camera
- float CamGround = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, TargetCoors.z + Length*Sin(Alpha + ModeAlpha) + m_fCloseInCarHeightOffset, &FoundCamGround);
- float CamTargetZ = 0.0f;
- if(FoundCamGround){
- // This is the normal case
- CamRoof = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, CamGround + TargetHeight, &FoundCamRoof);
- CamTargetZ = CamGround + TargetHeight*1.5f + 0.1f;
- }else{
- FoundCamRoof = false;
- CamTargetZ = TargetCoors.z;
+bool
+CCamera::IsItTimeForNewcam(int32 obbeMode, int32 time)
+{
+ CVehicle *veh;
+ uint32 t = time; // no annoying compiler warnings
+ CVector fwd;
+
+ if(obbeMode < 0)
+ return true;
+ switch(obbeMode){
+ case OBBE_WHEEL:
+ veh = FindPlayerVehicle();
+ if(veh == nil){
+ if(CTimer::GetTimeInMilliseconds() > t+5000)
+ return true;
+ SetNearClipScript(0.6f);
+ return false;
}
-
- if(FoundRoofCenter && !FoundCamRoof && (FoundRoofSide1 || FoundRoofSide2)){
- // Car is under something but camera isn't
- // This seems weird...
- TargetAlpha = CGeneral::GetATanOfXY(CA_MAX_DISTANCE, CarRoof - CamTargetZ - 1.5f);
- CamClear = false;
+ if(veh->IsBoat() || veh->GetModelIndex() == MI_RHINO)
+ return true;
+ if(CWorld::GetIsLineOfSightClear(pTargetEntity->GetPosition(), Cams[ActiveCam].Source, true, false, false, false, false, false, false)){
+ if(CTimer::GetTimeInMilliseconds() > t+5000)
+ return true;
+ SetNearClipScript(0.6f);
+ return false;
}
- if(FoundCamRoof){
- // Camera is under something
- float roof = FoundRoofCenter ? min(CamRoof, CarRoof) : CamRoof;
- // Same weirdness again?
- TargetAlpha = CGeneral::GetATanOfXY(CA_MAX_DISTANCE, roof - CamTargetZ - 1.5f);
- CamClear = false;
+ return true;
+ case OBBE_1:
+ if(FindPlayerVehicle() && FindPlayerVehicle()->IsBoat())
+ return true;
+ if(CWorld::GetIsLineOfSightClear(FindPlayerCoors(), m_vecFixedModeSource, true, false, false, false, false, false, false)){
+ fwd = FindPlayerCoors() - m_vecFixedModeSource;
+ fwd.z = 0.0f;
+
+ // too far and driving away from cam
+ if(fwd.Magnitude() > 20.0f && DotProduct(FindPlayerSpeed(), fwd) > 0.0f)
+ return true;
+ // too close
+ if(fwd.Magnitude() < 1.6f)
+ return true;
+ return false;
}
- while(TargetAlpha >= PI) TargetAlpha -= 2*PI;
- while(TargetAlpha < -PI) TargetAlpha += 2*PI;
- if(TargetAlpha < DEGTORAD(-7.0f))
- TargetAlpha = DEGTORAD(-7.0f);
-
- // huh?
- if(TargetAlpha > ModeAlpha)
- CamClear = true;
- // Camera is contrained by collision in some way
- PreviousNearCheckNearClipSmall = false;
- if(!CamClear){
- PreviousNearCheckNearClipSmall = true;
- RwCameraSetNearClipPlane(Scene.camera, 0.9f);
-
- DeltaAlpha = TargetAlpha - (Alpha + ModeAlpha);
- while(DeltaAlpha >= PI) DeltaAlpha -= 2*PI;
- while(DeltaAlpha < -PI) DeltaAlpha += 2*PI;
-
- TopAlphaSpeed = 0.3f;
- AlphaSpeedStep = 0.03f;
+ return true;
+ case OBBE_2:
+ if(FindPlayerVehicle() && FindPlayerVehicle()->IsBoat())
+ return true;
+ if(CWorld::GetIsLineOfSightClear(FindPlayerCoors(), m_vecFixedModeSource, true, false, false, false, false, false, false)){
+ fwd = FindPlayerCoors() - m_vecFixedModeSource;
+ fwd.z = 0.0f;
+
+ if(fwd.Magnitude() < 2.0f)
+ // very close, fix near clip
+ SetNearClipScript(max(fwd.Magnitude()*0.5f, 0.05f));
+ // too far and driving away from cam
+ if(fwd.Magnitude() > 19.0f && DotProduct(FindPlayerSpeed(), fwd) > 0.0f)
+ return true;
+ // too close
+ if(fwd.Magnitude() < 1.6f)
+ return true;
+ return false;
}
+ return true;
+ case OBBE_3:
+ if(CWorld::GetIsLineOfSightClear(FindPlayerCoors(), m_vecFixedModeSource, true, false, false, false, false, false, false)){
+ fwd = FindPlayerCoors() - m_vecFixedModeSource;
+ fwd.z = 0.0f;
+
+ // too far and driving away from cam
+ if(fwd.Magnitude() > 28.0f && DotProduct(FindPlayerSpeed(), fwd) > 0.0f)
+ return true;
+ return false;
+ }
+ return true;
+ case OBBE_1STPERSON:
+ return CTimer::GetTimeInMilliseconds() > t+3000;
+ case OBBE_5:
+ if(FindPlayerVehicle() && FindPlayerVehicle()->IsBoat())
+ return true;
+ if(CWorld::GetIsLineOfSightClear(FindPlayerCoors(), m_vecFixedModeSource, true, false, false, false, false, false, false)){
+ fwd = FindPlayerCoors() - m_vecFixedModeSource;
+ fwd.z = 0.0f;
+
+ // too far and driving away from cam
+ if(fwd.Magnitude() > 28.0f && DotProduct(FindPlayerSpeed(), fwd) > 0.0f)
+ return true;
+ return false;
+ }
+ return true;
+ case OBBE_ONSTRING:
+ return CTimer::GetTimeInMilliseconds() > t+3000;
+ case OBBE_COPCAR:
+ return CTimer::GetTimeInMilliseconds() > t+2000 && !FindPlayerVehicle()->GetIsOnScreen();
+ case OBBE_COPCAR_WHEEL:
+ if(FindPlayerVehicle() && FindPlayerVehicle()->IsBoat())
+ return true;
+ if(CWorld::GetIsLineOfSightClear(pTargetEntity->GetPosition(), Cams[ActiveCam].Source, true, false, false, false, false, false, false)){
+ if(CTimer::GetTimeInMilliseconds() > t+1000)
+ return true;
+ SetNearClipScript(0.6f);
+ return false;
+ }
+ return true;
+
+ // Ped modes
+ case OBBE_9:
+ if(CWorld::GetIsLineOfSightClear(FindPlayerCoors(), m_vecFixedModeSource, true, false, false, false, false, false, false)){
+ fwd = FindPlayerCoors() - m_vecFixedModeSource;
+ fwd.z = 0.0f;
+
+ // too far and driving away from cam
+ if(fwd.Magnitude() > 20.0f && DotProduct(FindPlayerSpeed(), fwd) > 0.0f)
+ return true;
+ return false;
+ }
+ return true;
+ case OBBE_10:
+ if(CWorld::GetIsLineOfSightClear(FindPlayerCoors(), m_vecFixedModeSource, true, false, false, false, false, false, false)){
+ fwd = FindPlayerCoors() - m_vecFixedModeSource;
+ fwd.z = 0.0f;
+
+ // too far and driving away from cam
+ if(fwd.Magnitude() > 8.0f && DotProduct(FindPlayerSpeed(), fwd) > 0.0f)
+ return true;
+ return false;
+ }
+ return true;
+ case OBBE_11:
+ if(CWorld::GetIsLineOfSightClear(FindPlayerCoors(), m_vecFixedModeSource, true, false, false, false, false, false, false)){
+ fwd = FindPlayerCoors() - m_vecFixedModeSource;
+ fwd.z = 0.0f;
+
+ // too far and driving away from cam
+ if(fwd.Magnitude() > 25.0f && DotProduct(FindPlayerSpeed(), fwd) > 0.0f)
+ return true;
+ return false;
+ }
+ return true;
+ case OBBE_12:
+ if(CWorld::GetIsLineOfSightClear(FindPlayerCoors(), m_vecFixedModeSource, true, false, false, false, false, false, false)){
+ fwd = FindPlayerCoors() - m_vecFixedModeSource;
+ fwd.z = 0.0f;
+
+ // too far and driving away from cam
+ if(fwd.Magnitude() > 8.0f && DotProduct(FindPlayerSpeed(), fwd) > 0.0f)
+ return true;
+ return false;
+ }
+ return true;
+ case OBBE_13:
+ return CTimer::GetTimeInMilliseconds() > t+5000;
+ default:
+ return false;
+ }
+}
- // Now do things if CamClear...but what is that anyway?
- float CamZ = TargetCoors.z + Length*Sin(Alpha + DeltaAlpha + ModeAlpha) + m_fCloseInCarHeightOffset;
- bool FoundGround, FoundRoof;
- float CamGround2 = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, CamZ, &FoundGround);
- if(FoundGround){
- if(CamClear)
- if(CamZ - CamGround2 < 1.5f){
- PreviousNearCheckNearClipSmall = true;
- RwCameraSetNearClipPlane(Scene.camera, 0.9f);
-
- float a;
- if(Length == 0.0f || CamGround2 + 1.5f - TargetCoors.z == 0.0f)
- a = Alpha;
- else
- a = CGeneral::GetATanOfXY(Length, CamGround2 + 1.5f - TargetCoors.z);
- while(a > PI) a -= 2*PI;
- while(a < -PI) a += 2*PI;
- DeltaAlpha = a - Alpha;
+bool
+CCamera::TryToStartNewCamMode(int obbeMode)
+{
+ CVehicle *veh;
+ CVector target, camPos, playerSpeed, fwd;
+ float ground;
+ bool foundGround;
+ int i;
+
+ if(obbeMode < 0)
+ return true;
+ switch(obbeMode){
+ case OBBE_WHEEL:
+ veh = FindPlayerVehicle();
+ if(veh == nil || veh->IsBoat() || veh->GetModelIndex() == MI_RHINO)
+ return false;
+ target = Multiply3x3(FindPlayerVehicle()->GetMatrix(), CVector(-1.4f, -2.3f, 0.3f));
+ target += FindPlayerVehicle()->GetPosition();
+ if(!CWorld::GetIsLineOfSightClear(veh->GetPosition(), target, true, false, false, false, false, false, false))
+ return false;
+ TakeControl(veh, CCam::MODE_WHEELCAM, JUMP_CUT, CAMCONTROL_OBBE);
+ return true;
+ case OBBE_1:
+ camPos = FindPlayerCoors();
+ playerSpeed = FindPlayerSpeed();
+ playerSpeed.z = 0.0f;
+ playerSpeed.Normalise();
+ camPos += 20.0f*playerSpeed;
+ camPos += 3.0f*CVector(playerSpeed.y, -playerSpeed.x, 0.0f);
+ if(FindPlayerVehicle() && FindPlayerVehicle()->IsBoat())
+ return false;
+
+ ground = CWorld::FindGroundZFor3DCoord(camPos.x, camPos.y, camPos.z+5.0f, &foundGround);
+ if(foundGround)
+ camPos.z = ground + 1.5f;
+ else{
+ ground = CWorld::FindRoofZFor3DCoord(camPos.x, camPos.y, camPos.z-5.0f, &foundGround);
+ if(foundGround)
+ camPos.z = ground + 1.5f;
+ }
+ if(!CWorld::GetIsLineOfSightClear(FindPlayerCoors(), camPos, true, false, false, false, false, false, false))
+ return false;
+
+ fwd = FindPlayerCoors() - camPos;
+ fwd.z = 0.0f;
+ // too far and driving away from cam
+ if(fwd.Magnitude() > 20.0f && DotProduct(FindPlayerSpeed(), fwd) > 0.0f)
+ return false;
+ // too close
+ if(fwd.Magnitude() < 1.6f)
+ return true;
+
+ SetCamPositionForFixedMode(camPos, CVector(0.0f, 0.0f, 0.0f));
+ TakeControl(FindPlayerEntity(), CCam::MODE_FIXED, JUMP_CUT, CAMCONTROL_OBBE);
+ return true;
+ case OBBE_2:
+ if(FindPlayerVehicle() && FindPlayerVehicle()->IsBoat())
+ return false;
+ camPos = FindPlayerCoors();
+ playerSpeed = FindPlayerSpeed();
+ playerSpeed.z = 0.0f;
+ playerSpeed.Normalise();
+ camPos += 16.0f*playerSpeed;
+ camPos += 2.5f*CVector(playerSpeed.y, -playerSpeed.x, 0.0f);
+
+ ground = CWorld::FindGroundZFor3DCoord(camPos.x, camPos.y, camPos.z+5.0f, &foundGround);
+ if(foundGround)
+ camPos.z = ground + 0.5f;
+ else{
+ ground = CWorld::FindRoofZFor3DCoord(camPos.x, camPos.y, camPos.z-5.0f, &foundGround);
+ if(foundGround)
+ camPos.z = ground + 0.5f;
+ }
+ if(!CWorld::GetIsLineOfSightClear(FindPlayerCoors(), camPos, true, false, false, false, false, false, false))
+ return false;
+
+ fwd = FindPlayerCoors() - camPos;
+ fwd.z = 0.0f;
+ // too far and driving away from cam
+ if(fwd.Magnitude() > 19.0f && DotProduct(FindPlayerSpeed(), fwd) > 0.0f)
+ return false;
+ // too close
+ if(fwd.Magnitude() < 1.6f)
+ return true;
+
+ SetCamPositionForFixedMode(camPos, CVector(0.0f, 0.0f, 0.0f));
+ TakeControl(FindPlayerEntity(), CCam::MODE_FIXED, JUMP_CUT, CAMCONTROL_OBBE);
+ return true;
+ case OBBE_3:
+ camPos = FindPlayerCoors();
+ playerSpeed = FindPlayerSpeed();
+ playerSpeed.z = 0.0f;
+ playerSpeed.Normalise();
+ camPos += 30.0f*playerSpeed;
+ camPos += 8.0f*CVector(playerSpeed.y, -playerSpeed.x, 0.0f);
+
+ if(!CWorld::GetIsLineOfSightClear(FindPlayerCoors(), camPos, true, false, false, false, false, false, false))
+ return false;
+
+ SetCamPositionForFixedMode(camPos, CVector(0.0f, 0.0f, 0.0f));
+ TakeControl(FindPlayerEntity(), CCam::MODE_FIXED, JUMP_CUT, CAMCONTROL_OBBE);
+ return true;
+ case OBBE_1STPERSON:
+ TakeControl(FindPlayerEntity(), CCam::MODE_FIXED, JUMP_CUT, CAMCONTROL_OBBE);
+ return true;
+ case OBBE_5:
+ camPos = FindPlayerCoors();
+ playerSpeed = FindPlayerSpeed();
+ playerSpeed.z = 0.0f;
+ playerSpeed.Normalise();
+ camPos += 30.0f*playerSpeed;
+ camPos += 6.0f*CVector(playerSpeed.y, -playerSpeed.x, 0.0f);
+
+ ground = CWorld::FindGroundZFor3DCoord(camPos.x, camPos.y, camPos.z+5.0f, &foundGround);
+ if(foundGround)
+ camPos.z = ground + 3.5f;
+ else{
+ ground = CWorld::FindRoofZFor3DCoord(camPos.x, camPos.y, camPos.z-5.0f, &foundGround);
+ if(foundGround)
+ camPos.z = ground + 3.5f;
+ }
+ if(!CWorld::GetIsLineOfSightClear(FindPlayerCoors(), camPos, true, false, false, false, false, false, false))
+ return false;
+
+ SetCamPositionForFixedMode(camPos, CVector(0.0f, 0.0f, 0.0f));
+ TakeControl(FindPlayerEntity(), CCam::MODE_FIXED, JUMP_CUT, CAMCONTROL_OBBE);
+ return true;
+ case OBBE_ONSTRING:
+ TakeControl(FindPlayerEntity(), CCam::MODE_CAM_ON_A_STRING, JUMP_CUT, CAMCONTROL_OBBE);
+ return true;
+ case OBBE_COPCAR:
+ if(FindPlayerPed()->m_pWanted->m_nWantedLevel < 1)
+ return false;
+ if(FindPlayerVehicle() == nil)
+ return false;
+ if(FindPlayerVehicle() && FindPlayerVehicle()->IsBoat())
+ return false;
+ i = CPools::GetVehiclePool()->GetSize();
+ while(--i >= 0){
+ veh = CPools::GetVehiclePool()->GetSlot(i);
+ if(veh && veh->IsCar() && veh != FindPlayerVehicle() && veh->bIsLawEnforcer){
+ float dx = veh->GetPosition().x - FindPlayerCoors().x;
+ float dy = veh->GetPosition().y - FindPlayerCoors().y;
+ float dist = (veh->GetPosition() - FindPlayerCoors()).Magnitude();
+ if(dist < 30.0f){
+ if(dx*FindPlayerVehicle()->GetForward().x + dy*FindPlayerVehicle()->GetForward().y < 0.0f &&
+ veh->GetForward().x*FindPlayerVehicle()->GetForward().x + veh->GetForward().y*FindPlayerVehicle()->GetForward().y > 0.8f){
+ TakeControl(veh, CCam::MODE_CAM_ON_A_STRING, JUMP_CUT, CAMCONTROL_OBBE);
+ return true;
+ }
}
- }else{
- if(CamClear){
- float CamRoof2 = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, CamZ, &FoundRoof);
- if(FoundRoof && CamZ - CamRoof2 < 1.5f){
- PreviousNearCheckNearClipSmall = true;
- RwCameraSetNearClipPlane(Scene.camera, 0.9f);
-
- if(CamRoof2 > TargetCoors.z + 3.5f)
- CamRoof2 = TargetCoors.z + 3.5f;
-
- float a;
- if(Length == 0.0f || CamRoof2 + 1.5f - TargetCoors.z == 0.0f)
- a = Alpha;
- else
- a = CGeneral::GetATanOfXY(Length, CamRoof2 + 1.5f - TargetCoors.z);
- while(a > PI) a -= 2*PI;
- while(a < -PI) a += 2*PI;
- DeltaAlpha = a - Alpha;
+ }
+ }
+ return false;
+ case OBBE_COPCAR_WHEEL:
+ if(FindPlayerPed()->m_pWanted->m_nWantedLevel < 1)
+ return false;
+ if(FindPlayerVehicle() == nil)
+ return false;
+ if(FindPlayerVehicle() && FindPlayerVehicle()->IsBoat())
+ return false;
+ i = CPools::GetVehiclePool()->GetSize();
+ while(--i >= 0){
+ veh = CPools::GetVehiclePool()->GetSlot(i);
+ if(veh && veh->IsCar() && veh != FindPlayerVehicle() && veh->bIsLawEnforcer){
+ float dx = veh->GetPosition().x - FindPlayerCoors().x;
+ float dy = veh->GetPosition().y - FindPlayerCoors().y;
+ float dist = (veh->GetPosition() - FindPlayerCoors()).Magnitude();
+ if(dist < 30.0f){
+ if(dx*FindPlayerVehicle()->GetForward().x + dy*FindPlayerVehicle()->GetForward().y < 0.0f &&
+ veh->GetForward().x*FindPlayerVehicle()->GetForward().x + veh->GetForward().y*FindPlayerVehicle()->GetForward().y > 0.8f){
+ target = Multiply3x3(veh->GetMatrix(), CVector(-1.4f, -2.3f, 0.3f));
+ target += veh->GetPosition();
+ if(!CWorld::GetIsLineOfSightClear(veh->GetPosition(), target, true, false, false, false, false, false, false))
+ return false;
+ TakeControl(veh, CCam::MODE_WHEELCAM, JUMP_CUT, CAMCONTROL_OBBE);
+ return true;
+ }
}
}
}
+ return false;
- LastTargetAlphaWithCollisionOn = DeltaAlpha + Alpha;
- LastTopAlphaSpeed = TopAlphaSpeed;
- LastAlphaSpeedStep = AlphaSpeedStep;
- }else{
- if(PreviousNearCheckNearClipSmall)
- RwCameraSetNearClipPlane(Scene.camera, 0.9f);
+ case OBBE_9:
+ camPos = FindPlayerCoors();
+ playerSpeed = FindPlayerSpeed();
+ playerSpeed.z = 0.0f;
+ playerSpeed.Normalise();
+ camPos += 15.0f*playerSpeed;
+ camPos += CVector(2.0f, 1.0f, 0.0f);
+
+ ground = CWorld::FindGroundZFor3DCoord(camPos.x, camPos.y, camPos.z+5.0f, &foundGround);
+ if(foundGround)
+ camPos.z = ground + 0.5f;
+ else{
+ ground = CWorld::FindRoofZFor3DCoord(camPos.x, camPos.y, camPos.z-5.0f, &foundGround);
+ if(foundGround)
+ camPos.z = ground + 0.5f;
+ }
+ if(!CWorld::GetIsLineOfSightClear(FindPlayerCoors(), camPos, true, false, false, false, false, false, false))
+ return false;
+
+ SetCamPositionForFixedMode(camPos, CVector(0.0f, 0.0f, 0.0f));
+ TakeControl(FindPlayerEntity(), CCam::MODE_FIXED, JUMP_CUT, CAMCONTROL_OBBE);
+ return true;
+ case OBBE_10:
+ camPos = FindPlayerCoors();
+ playerSpeed = FindPlayerSpeed();
+ playerSpeed.z = 0.0f;
+ playerSpeed.Normalise();
+ camPos += 5.0f*playerSpeed;
+ camPos += CVector(2.0f, 1.0f, 0.5f);
+
+ if(!CWorld::GetIsLineOfSightClear(FindPlayerCoors(), camPos, true, false, false, false, false, false, false))
+ return false;
+
+ SetCamPositionForFixedMode(camPos, CVector(0.0f, 0.0f, 0.0f));
+ TakeControl(FindPlayerEntity(), CCam::MODE_FIXED, JUMP_CUT, CAMCONTROL_OBBE);
+ return true;
+ case OBBE_11:
+ camPos = FindPlayerCoors();
+ playerSpeed = FindPlayerSpeed();
+ playerSpeed.z = 0.0f;
+ playerSpeed.Normalise();
+ camPos += 20.0f*playerSpeed;
+ camPos += CVector(2.0f, 1.0f, 20.0f);
+
+ if(!CWorld::GetIsLineOfSightClear(FindPlayerCoors(), camPos, true, false, false, false, false, false, false))
+ return false;
+
+ SetCamPositionForFixedMode(camPos, CVector(0.0f, 0.0f, 0.0f));
+ TakeControl(FindPlayerEntity(), CCam::MODE_FIXED, JUMP_CUT, CAMCONTROL_OBBE);
+ return true;
+ case OBBE_12:
+ camPos = FindPlayerCoors();
+ playerSpeed = FindPlayerSpeed();
+ playerSpeed.z = 0.0f;
+ playerSpeed.Normalise();
+ camPos += 5.0f*playerSpeed;
+ camPos += CVector(2.0f, 1.0f, 10.5f);
+
+ if(!CWorld::GetIsLineOfSightClear(FindPlayerCoors(), camPos, true, false, false, false, false, false, false))
+ return false;
+
+ SetCamPositionForFixedMode(camPos, CVector(0.0f, 0.0f, 0.0f));
+ TakeControl(FindPlayerEntity(), CCam::MODE_FIXED, JUMP_CUT, CAMCONTROL_OBBE);
+ return true;
+ case OBBE_13:
+#ifdef FIX_BUGS
+ TakeControl(FindPlayerEntity(), CCam::MODE_TOP_DOWN_PED, JUMP_CUT, CAMCONTROL_OBBE);
+#else
+ TakeControl(FindPlayerEntity(), CCam::MODE_TOPDOWN, JUMP_CUT, CAMCONTROL_OBBE);
+#endif
+ return true;
+ default:
+ return false;
}
-
- WellBufferMe(LastTargetAlphaWithCollisionOn, &Alpha, &AlphaSpeed, LastTopAlphaSpeed, LastAlphaSpeedStep, true);
-
- Source.z = TargetCoors.z + Sin(Alpha + ModeAlpha)*Length + m_fCloseInCarHeightOffset;
}
-// Rotate cam behind the car when the car is moving forward
-bool
-CCam::RotCamIfInFrontCar(CVector &TargetCoors, float TargetOrientation)
-{
- bool MovingForward = false;
- CPhysical *phys = (CPhysical*)CamTargetEntity;
-
- float ForwardSpeed = DotProduct(phys->GetForward(), phys->GetSpeed(CVector(0.0f, 0.0f, 0.0f)));
- if(ForwardSpeed > 0.02f)
- MovingForward = true;
+static int32 SequenceOfCams[16] = {
+ OBBE_WHEEL, OBBE_COPCAR, OBBE_3, OBBE_1, OBBE_3, OBBE_COPCAR_WHEEL,
+ OBBE_2, OBBE_3, OBBE_COPCAR_WHEEL, OBBE_COPCAR, OBBE_2, OBBE_3,
+ OBBE_5, OBBE_3,
+ OBBE_ONSTRING // actually unused...
+};
- float Dist = (Source - TargetCoors).Magnitude2D();
+void
+CCamera::ProcessObbeCinemaCameraCar(void)
+{
+ static int OldMode = -1;
+ static int32 TimeForNext = 0;
+ int i = 0;
- float DeltaBeta = TargetOrientation - Beta;
- while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
- while(DeltaBeta < -PI) DeltaBeta += 2*PI;
+ if(!bDidWeProcessAnyCinemaCam){
+ OldMode = -1;
+ CHud::SetHelpMessage(TheText.Get("CINCAM"), true);
+ }
- if(Abs(DeltaBeta) > DEGTORAD(20.0f) && MovingForward && TheCamera.m_uiTransitionState == 0)
- m_bFixingBeta = true;
+ if(!bDidWeProcessAnyCinemaCam || IsItTimeForNewcam(SequenceOfCams[OldMode], TimeForNext)){
+ // This is very strange code...
+ for(OldMode = (OldMode+1) % 14;
+ !TryToStartNewCamMode(SequenceOfCams[OldMode]) && i <= 14;
+ OldMode = (OldMode+1) % 14)
+ i++;
+ TimeForNext = CTimer::GetTimeInMilliseconds();
+ if(i >= 14){
+ OldMode = 14;
+ TryToStartNewCamMode(SequenceOfCams[14]);
+ }
+ }
- CPad *pad = CPad::GetPad(0);
- if(!(pad->GetLookBehindForCar() || pad->GetLookBehindForPed() || pad->GetLookLeft() || pad->GetLookRight()))
- if(DirectionWasLooking != LOOKING_FORWARD)
- TheCamera.m_bCamDirectlyBehind = true;
+ m_iModeObbeCamIsInForCar = OldMode;
+ bDidWeProcessAnyCinemaCam = true;
+}
- if(!m_bFixingBeta && !TheCamera.m_bUseTransitionBeta && !TheCamera.m_bCamDirectlyBehind && !TheCamera.m_bCamDirectlyInFront)
- return false;
+static int32 SequenceOfPedCams[5] = { OBBE_9, OBBE_10, OBBE_11, OBBE_12, OBBE_13 };
- bool SetBeta = false;
- if(TheCamera.m_bCamDirectlyBehind || TheCamera.m_bCamDirectlyInFront || TheCamera.m_bUseTransitionBeta)
- if(&TheCamera.Cams[TheCamera.ActiveCam] == this)
- SetBeta = true;
-
- if(m_bFixingBeta || SetBeta){
- WellBufferMe(TargetOrientation, &Beta, &BetaSpeed, 0.15f, 0.007f, true);
-
- if(TheCamera.m_bCamDirectlyBehind && &TheCamera.Cams[TheCamera.ActiveCam] == this)
- Beta = TargetOrientation;
- if(TheCamera.m_bCamDirectlyInFront && &TheCamera.Cams[TheCamera.ActiveCam] == this)
- Beta = TargetOrientation + PI;
- if(TheCamera.m_bUseTransitionBeta && &TheCamera.Cams[TheCamera.ActiveCam] == this)
- Beta = m_fTransitionBeta;
-
- Source.x = TargetCoors.x - Cos(Beta)*Dist;
- Source.y = TargetCoors.y - Sin(Beta)*Dist;
-
- // Check if we're done
- DeltaBeta = TargetOrientation - Beta;
- while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
- while(DeltaBeta < -PI) DeltaBeta += 2*PI;
- if(Abs(DeltaBeta) < DEGTORAD(2.0f))
- m_bFixingBeta = false;
+void
+CCamera::ProcessObbeCinemaCameraPed(void)
+{
+ // static bool bObbePedProcessed = false; // unused
+ static int PedOldMode = -1;
+ static int32 PedTimeForNext = 0;
+
+ if(!bDidWeProcessAnyCinemaCam)
+ PedOldMode = -1;
+
+ if(!bDidWeProcessAnyCinemaCam || IsItTimeForNewcam(SequenceOfPedCams[PedOldMode], PedTimeForNext)){
+ for(PedOldMode = (PedOldMode+1) % 5;
+ !TryToStartNewCamMode(SequenceOfPedCams[PedOldMode]);
+ PedOldMode = (PedOldMode+1) % 5);
+ PedTimeForNext = CTimer::GetTimeInMilliseconds();
}
- TheCamera.m_bCamDirectlyBehind = false;
- TheCamera.m_bCamDirectlyInFront = false;
- return true;
+ bDidWeProcessAnyCinemaCam = true;
}
-// Move the cam to avoid clipping through buildings
-bool
-CCam::FixCamIfObscured(CVector &TargetCoors, float TargetHeight, float TargetOrientation)
-{
- CVector Target = TargetCoors;
- bool UseEntityPos = false;
- CVector EntityPos;
- static CColPoint colPoint;
- static bool LastObscured = false;
-
- if(Mode == MODE_BEHINDCAR)
- Target.z += TargetHeight/2.0f;
- if(Mode == MODE_CAM_ON_A_STRING){
- UseEntityPos = true;
- Target.z += TargetHeight/2.0f;
- EntityPos = CamTargetEntity->GetPosition();
+void
+CCamera::DontProcessObbeCinemaCamera(void)
+{
+ bDidWeProcessAnyCinemaCam = false;
+}
+
+
+void
+CCamera::LoadTrainCamNodes(char const *name)
+{
+ CFileMgr::SetDir("data");
+
+ char token[16] = { 0 };
+ char filename[16] = { 0 };
+ uint8 *buf;
+ int bufpos = 0;
+ int field = 0;
+ int tokpos = 0;
+ char c;
+ int i;
+ int len;
+
+ strcpy(filename, name);
+ len = strlen(filename);
+ filename[len] = '.';
+ filename[len+1] = 'd';
+ filename[len+2] = 'a';
+ filename[len+3] = 't';
+
+ m_uiNumberOfTrainCamNodes = 0;
+
+ buf = new uint8[20000];
+ len = CFileMgr::LoadFile(filename, buf, 20000, "r");
+
+ for(i = 0; i < MAX_NUM_OF_NODES; i++){
+ m_arrTrainCamNode[i].m_cvecPointToLookAt = CVector(0.0f, 0.0f, 0.0f);
+ m_arrTrainCamNode[i].m_cvecMinPointInRange = CVector(0.0f, 0.0f, 0.0f);
+ m_arrTrainCamNode[i].m_cvecMaxPointInRange = CVector(0.0f, 0.0f, 0.0f);
+ m_arrTrainCamNode[i].m_fDesiredFOV = 0.0f;
+ m_arrTrainCamNode[i].m_fNearClip = 0.0f;
}
- CVector TempSource = Source;
-
- bool Obscured1 = false;
- bool Obscured2 = false;
- bool Fix1 = false;
- float Dist1 = 0.0f;
- float Dist2 = 0.0f;
- CEntity *ent;
- if(m_bCollisionChecksOn || LastObscured){
- Obscured1 = CWorld::ProcessLineOfSight(Target, TempSource, colPoint, ent, true, false, false, true, false, true, true);
- if(Obscured1){
- Dist1 = (Target - colPoint.point).Magnitude2D();
- Fix1 = true;
- if(UseEntityPos)
- Obscured1 = CWorld::ProcessLineOfSight(EntityPos, TempSource, colPoint, ent, true, false, false, true, false, true, true);
- }else if(m_bFixingBeta){
- float d = (TempSource - Target).Magnitude();
- TempSource.x = Target.x - d*Cos(TargetOrientation);
- TempSource.y = Target.y - d*Sin(TargetOrientation);
-
- // same check again
- Obscured2 = CWorld::ProcessLineOfSight(Target, TempSource, colPoint, ent, true, false, false, true, false, true, true);
- if(Obscured2){
- Dist2 = (Target - colPoint.point).Magnitude2D();
- if(UseEntityPos)
- Obscured2 = CWorld::ProcessLineOfSight(EntityPos, TempSource, colPoint, ent, true, false, false, true, false, true, true);
+ while(bufpos <= len){
+ c = buf[bufpos];
+ switch(c){
+ case '-':
+ case '.':
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+// case '10': case '11': case '12': case '13': // ahem...
+ token[tokpos++] = c;
+ bufpos++;
+ break;
+
+ case ',':
+ case ';': // game has the code for this duplicated but we handle both under the same case
+ switch((field+14)%14){
+ case 0:
+ m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecCamPosition.x = atof(token);
+ break;
+ case 1:
+ m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecCamPosition.y = atof(token);
+ break;
+ case 2:
+ m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecCamPosition.z = atof(token);
+ break;
+ case 3:
+ m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecPointToLookAt.x = atof(token);
+ break;
+ case 4:
+ m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecPointToLookAt.y = atof(token);
+ break;
+ case 5:
+ m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecPointToLookAt.z = atof(token);
+ break;
+ case 6:
+ m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecMinPointInRange.x = atof(token);
+ break;
+ case 7:
+ m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecMinPointInRange.y = atof(token);
+ break;
+ case 8:
+ m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecMinPointInRange.z = atof(token);
+ break;
+ case 9:
+ m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecMaxPointInRange.x = atof(token);
+ break;
+ case 10:
+ m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecMaxPointInRange.y = atof(token);
+ break;
+ case 11:
+ m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_cvecMaxPointInRange.z = atof(token);
+ break;
+ case 12:
+ m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_fDesiredFOV = atof(token);
+ break;
+ case 13:
+ m_arrTrainCamNode[m_uiNumberOfTrainCamNodes].m_fNearClip = atof(token);
+ m_uiNumberOfTrainCamNodes++;
+ break;
}
+ field++;
+ bufpos++;
+ memset(token, 0, sizeof(token));
+ tokpos = 0;
+ break;
+
+ default:
+ bufpos++;
+ break;
}
- LastObscured = Obscured1 || Obscured2;
}
- // nothing to do
- if(!LastObscured)
- return false;
+ delete[] buf;
+ CFileMgr::SetDir("");
+}
+
+void
+CCamera::Process_Train_Camera_Control(void)
+{
+ bool found = false;
+ CTrain *target = (CTrain*)pTargetEntity;
+ m_bUseSpecialFovTrain = true;
+ static bool OKtoGoBackToNodeCam = true; // only ever set to true
+ uint32 i;
+
+ if(target->m_nTrackId == TRACK_ELTRAIN && !m_bAboveGroundTrainNodesLoaded){
+ m_bAboveGroundTrainNodesLoaded = true;
+ m_bBelowGroundTrainNodesLoaded = false;
+ LoadTrainCamNodes("Train");
+ m_uiTimeLastChange = CTimer::GetTimeInMilliseconds();
+ OKtoGoBackToNodeCam = true;
+ m_iCurrentTrainCamNode = 0;
+ }
+ if(target->m_nTrackId == TRACK_SUBWAY && !m_bBelowGroundTrainNodesLoaded){
+ m_bBelowGroundTrainNodesLoaded = true;
+ m_bAboveGroundTrainNodesLoaded = false;
+ LoadTrainCamNodes("Train2");
+ m_uiTimeLastChange = CTimer::GetTimeInMilliseconds();
+ OKtoGoBackToNodeCam = true;
+ m_iCurrentTrainCamNode = 0;
+ }
- if(Fix1){
- Source.x = Target.x - Cos(Beta)*Dist1;
- Source.y = Target.y - Sin(Beta)*Dist1;
- if(Mode == MODE_BEHINDCAR)
- Source = colPoint.point;
+ m_bTargetJustBeenOnTrain = true;
+ uint32 node = m_iCurrentTrainCamNode;
+ for(i = 0; i < m_uiNumberOfTrainCamNodes && !found; i++){
+ if(target->IsWithinArea(m_arrTrainCamNode[node].m_cvecMinPointInRange.x,
+ m_arrTrainCamNode[node].m_cvecMinPointInRange.y,
+ m_arrTrainCamNode[node].m_cvecMinPointInRange.z,
+ m_arrTrainCamNode[node].m_cvecMaxPointInRange.x,
+ m_arrTrainCamNode[node].m_cvecMaxPointInRange.y,
+ m_arrTrainCamNode[node].m_cvecMaxPointInRange.z)){
+ m_iCurrentTrainCamNode = node;
+ found = true;
+ }
+ node++;
+ if(node >= m_uiNumberOfTrainCamNodes)
+ node = 0;
+ }
+
+ if(found){
+ SetWideScreenOn();
+ if(DotProduct(((CTrain*)pTargetEntity)->GetMoveSpeed(), pTargetEntity->GetForward()) < 0.001f){
+ TakeControl(FindPlayerPed(), CCam::MODE_FOLLOWPED, JUMP_CUT, CAMCONTROL_SCRIPT);
+ if(target->Doors[0].IsFullyOpen())
+ SetWideScreenOff();
+ }else{
+ SetCamPositionForFixedMode(m_arrTrainCamNode[m_iCurrentTrainCamNode].m_cvecCamPosition, CVector(0.0f, 0.0f, 0.0f));
+ if(m_arrTrainCamNode[m_iCurrentTrainCamNode].m_cvecPointToLookAt.x == 999.0f &&
+ m_arrTrainCamNode[m_iCurrentTrainCamNode].m_cvecPointToLookAt.y == 999.0f &&
+ m_arrTrainCamNode[m_iCurrentTrainCamNode].m_cvecPointToLookAt.z == 999.0f)
+ TakeControl(target, CCam::MODE_FIXED, JUMP_CUT, CAMCONTROL_SCRIPT);
+ else
+ TakeControlNoEntity(m_arrTrainCamNode[m_iCurrentTrainCamNode].m_cvecPointToLookAt, JUMP_CUT, CAMCONTROL_SCRIPT);
+ RwCameraSetNearClipPlane(Scene.camera, m_arrTrainCamNode[m_iCurrentTrainCamNode].m_fNearClip);
+ }
}else{
- WellBufferMe(Dist2, &m_fDistanceBeforeChanges, &DistanceSpeed, 0.2f, 0.025f, false);
- Source.x = Target.x - Cos(Beta)*m_fDistanceBeforeChanges;
- Source.y = Target.y - Sin(Beta)*m_fDistanceBeforeChanges;
+ if(DotProduct(((CTrain*)pTargetEntity)->GetMoveSpeed(), pTargetEntity->GetForward()) < 0.001f){
+ TakeControl(FindPlayerPed(), CCam::MODE_FOLLOWPED, JUMP_CUT, CAMCONTROL_SCRIPT);
+ if(target->Doors[0].IsFullyOpen())
+ SetWideScreenOff();
+ }
}
+}
+
- if(ResetStatics){
- m_fDistanceBeforeChanges = (Source - Target).Magnitude2D();
- DistanceSpeed = 0.0f;
- Source.x = colPoint.point.x;
- Source.y = colPoint.point.y;
+
+void
+CCamera::LoadPathSplines(int file)
+{
+ bool reading = true;
+ char c, token[32] = { 0 };
+ int i, j, n;
+
+ n = 0;
+
+ for(i = 0; i < MAX_NUM_OF_SPLINETYPES; i++)
+ for(j = 0; j < CCamPathSplines::MAXPATHLENGTH; j++)
+ m_arrPathArray[i].m_arr_PathData[j] = 0.0f;
+
+ m_bStartingSpline = false;
+
+ i = 0;
+ j = 0;
+ while(reading){
+ CFileMgr::Read(file, &c, 1);
+ switch(c){
+ case '\0':
+ reading = false;
+ break;
+
+ case '+': case '-': case '.':
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case 'e': case 'E':
+ token[n++] = c;
+ break;
+
+ case ',':
+#ifdef FIX_BUGS
+ if(i < MAX_NUM_OF_SPLINETYPES && j < CCamPathSplines::MAXPATHLENGTH)
+#endif
+ m_arrPathArray[i].m_arr_PathData[j] = atof(token);
+ j++;
+ memset(token, 0, 32);
+ n = 0;
+ break;
+
+ case ';':
+#ifdef FIX_BUGS
+ if(i < MAX_NUM_OF_SPLINETYPES && j < CCamPathSplines::MAXPATHLENGTH)
+#endif
+ m_arrPathArray[i].m_arr_PathData[j] = atof(token);
+ i++;
+ j = 0;
+ memset(token, 0, 32);
+ n = 0;
+ }
}
- return true;
}
void
-CCam::Process_Cam_On_A_String(const CVector &CameraTarget, float TargetOrientation, float, float)
+CCamera::FinishCutscene(void)
{
- if(!CamTargetEntity->IsVehicle())
- return;
+ SetPercentAlongCutScene(100.0f);
+ m_fPositionAlongSpline = 1.0f;
+ m_bcutsceneFinished = true;
+}
- FOV = DefaultFOV;
+uint32
+CCamera::GetCutSceneFinishTime(void)
+{
+ int cam = ActiveCam;
+ if (Cams[cam].Mode == CCam::MODE_FLYBY)
+ return Cams[cam].m_uiFinishTime;
+ cam = (cam + 1) % 2;
+ if (Cams[cam].Mode == CCam::MODE_FLYBY)
+ return Cams[cam].m_uiFinishTime;
- if(ResetStatics){
- AlphaSpeed = 0.0f;
- if(TheCamera.m_bIdleOn)
- TheCamera.m_uiTimeWeEnteredIdle = CTimer::GetTimeInMilliseconds();
- }
+ return 0;
+}
+
+void
+CCamera::SetCamCutSceneOffSet(const CVector &pos)
+{
+ m_vecCutSceneOffset = pos;
+};
- CBaseModelInfo *mi = CModelInfo::GetModelInfo(CamTargetEntity->GetModelIndex());
- CVector Dimensions = mi->GetColModel()->boundingBox.max - mi->GetColModel()->boundingBox.min;
- float BaseDist = Dimensions.Magnitude2D();
-
- CVector TargetCoors = CameraTarget;
- TargetCoors.z += Dimensions.z - 0.1f; // final
- Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y);
- while(Alpha >= PI) Alpha -= 2*PI;
- while(Alpha < -PI) Alpha += 2*PI;
- while(Beta >= PI) Beta -= 2*PI;
- while(Beta < -PI) Beta += 2*PI;
-
- m_fDistanceBeforeChanges = (Source - TargetCoors).Magnitude2D();
-
- Cam_On_A_String_Unobscured(TargetCoors, BaseDist);
- WorkOutCamHeight(TargetCoors, TargetOrientation, Dimensions.z);
- RotCamIfInFrontCar(TargetCoors, TargetOrientation);
- FixCamIfObscured(TargetCoors, Dimensions.z, TargetOrientation);
- FixCamWhenObscuredByVehicle(TargetCoors);
-
- m_cvecTargetCoorsForFudgeInter = TargetCoors;
- Front = TargetCoors - Source;
- Front.Normalise();
- GetVectorsReadyForRW();
- ResetStatics = false;
+void
+CCamera::SetPercentAlongCutScene(float percent)
+{
+ if(Cams[ActiveCam].Mode == CCam::MODE_FLYBY)
+ Cams[ActiveCam].m_fTimeElapsedFloat = percent/100.0f * Cams[ActiveCam].m_uiFinishTime;
+ else if(Cams[(ActiveCam+1)%2].Mode == CCam::MODE_FLYBY)
+ Cams[(ActiveCam+1)%2].m_fTimeElapsedFloat = percent/100.0f * Cams[(ActiveCam+1)%2].m_uiFinishTime;
}
-// Basic Cam on a string algorithm
void
-CCam::Cam_On_A_String_Unobscured(const CVector &TargetCoors, float BaseDist)
+CCamera::SetParametersForScriptInterpolation(float stopMoving, float catchUp, int32 time)
{
- CA_MAX_DISTANCE = BaseDist + 0.1f + TheCamera.CarZoomValueSmooth;
- CA_MIN_DISTANCE = min(BaseDist*0.6f, 3.5f);
+ m_fScriptPercentageInterToStopMoving = stopMoving * 0.01f;
+ m_fScriptPercentageInterToCatchUp = catchUp * 0.01f;
+ m_fScriptTimeForInterPolation = time;
+ m_bScriptParametersSetForInterPol = true;
+}
- CVector Dist = Source - TargetCoors;
+void
+CCamera::SetZoomValueFollowPedScript(int16 dist)
+{
+ switch (dist) {
+ case 0: m_fPedZoomValueScript = 0.25f; break;
+ case 1: m_fPedZoomValueScript = 1.5f; break;
+ case 2: m_fPedZoomValueScript = 2.9f; break;
+ default: m_fPedZoomValueScript = m_fPedZoomValueScript; break;
+ }
- if(ResetStatics)
- Source = TargetCoors + Dist*(CA_MAX_DISTANCE + 1.0f);
+ m_bUseScriptZoomValuePed = true;
+}
- float Length = Dist.Magnitude2D();
- if(Length < 0.001f){
- // This probably shouldn't happen. reset view
- CVector Forward = CamTargetEntity->GetForward();
- Forward.z = 0.0f;
- Forward.Normalise();
- Source = TargetCoors - Forward*CA_MAX_DISTANCE;
- Dist = Source - TargetCoors;
- Length = Dist.Magnitude2D();
+void
+CCamera::SetZoomValueCamStringScript(int16 dist)
+{
+ switch (dist) {
+ case 0: m_fCarZoomValueScript = 0.05f; break;
+ case 1: m_fCarZoomValueScript = 1.9f; break;
+ case 2: m_fCarZoomValueScript = 3.9f; break;
+ default: m_fCarZoomValueScript = m_fCarZoomValueScript; break;
}
- if(Length > CA_MAX_DISTANCE){
- Source.x = TargetCoors.x + Dist.x/Length * CA_MAX_DISTANCE;
- Source.y = TargetCoors.y + Dist.y/Length * CA_MAX_DISTANCE;
- }else if(Length < CA_MIN_DISTANCE){
- Source.x = TargetCoors.x + Dist.x/Length * CA_MIN_DISTANCE;
- Source.y = TargetCoors.y + Dist.y/Length * CA_MIN_DISTANCE;
+ m_bUseScriptZoomValueCar = true;
+}
+
+void
+CCamera::SetNearClipScript(float clip)
+{
+ m_fNearClipScript = clip;
+ m_bUseNearClipScript = true;
+}
+
+
+
+void
+CCamera::ProcessFade(void)
+{
+ float fade = (CTimer::GetTimeInMilliseconds() - m_uiFadeTimeStarted)/1000.0f;
+ // Why even set CDraw::FadeValue if m_fFLOATingFade sets it anyway?
+ if(m_bFading){
+ if(m_iFadingDirection == FADE_IN){
+ if(m_fTimeToFadeOut != 0.0f){
+ m_fFLOATingFade = 255.0f - 255.0f*fade/m_fTimeToFadeOut;
+ if(m_fFLOATingFade <= 0.0f){
+ m_bFading = false;
+ CDraw::FadeValue = 0;
+ m_fFLOATingFade = 0.0f;
+ }
+ }else{
+ m_bFading = false;
+ CDraw::FadeValue = 0;
+ m_fFLOATingFade = 0.0f;
+ }
+ }else if(m_iFadingDirection == FADE_OUT){
+ if(m_fTimeToFadeOut != 0.0f){
+ m_fFLOATingFade = 255.0f*fade/m_fTimeToFadeOut;
+ if(m_fFLOATingFade >= 255.0f){
+ m_bFading = false;
+ CDraw::FadeValue = 255;
+ m_fFLOATingFade = 255.0f;
+ }
+ }else{
+ m_bFading = false;
+ CDraw::FadeValue = 255;
+ m_fFLOATingFade = 255.0f;
+ }
+ }
+ CDraw::FadeValue = m_fFLOATingFade;
}
}
void
-CCam::FixCamWhenObscuredByVehicle(const CVector &TargetCoors)
+CCamera::ProcessMusicFade(void)
{
- // BUG? is this never reset
- static float HeightFixerCarsObscuring = 0.0f;
- static float HeightFixerCarsObscuringSpeed = 0.0f;
- CColPoint colPoint;
- CEntity *entity;
+ float fade = (CTimer::GetTimeInMilliseconds() - m_uiFadeTimeStartedMusic)/1000.0f;
+ if(m_bMusicFading){
+ if(m_iMusicFadingDirection == FADE_IN){
+ if(m_fTimeToFadeMusic == 0.0f)
+ m_fTimeToFadeMusic = 1.0f;
+
+ m_fFLOATingFadeMusic = 255.0f*fade/m_fTimeToFadeMusic;
+ if(m_fFLOATingFadeMusic > 255.0f){
+ m_bMusicFading = false;
+ m_fFLOATingFadeMusic = 0.0f;
+ DMAudio.SetEffectsFadeVol(127);
+ DMAudio.SetMusicFadeVol(127);
+ }else{
+ DMAudio.SetEffectsFadeVol(m_fFLOATingFadeMusic/255.0f * 127);
+ DMAudio.SetMusicFadeVol(m_fFLOATingFadeMusic/255.0f * 127);
+ }
+ }else if(m_iMusicFadingDirection == FADE_OUT){
+ if(m_fTimeToFadeMusic == 0.0f)
+ m_fTimeToFadeMusic = 1.0f;
+
+ if(m_bMoveCamToAvoidGeom || StillToFadeOut){
+ m_fFLOATingFadeMusic = 256.0f;
+ m_bMoveCamToAvoidGeom = false;
+ }else
+ m_fFLOATingFadeMusic = 255.0f*fade/m_fTimeToFadeMusic;
+
+ if(m_fFLOATingFadeMusic > 255.0f){
+ m_bMusicFading = false;
+ m_fFLOATingFadeMusic = 255.0f;
+ DMAudio.SetEffectsFadeVol(0);
+ DMAudio.SetMusicFadeVol(0);
+ }else{
+ DMAudio.SetEffectsFadeVol(127 - m_fFLOATingFadeMusic/255.0f * 127);
+ DMAudio.SetMusicFadeVol(127 - m_fFLOATingFadeMusic/255.0f * 127);
+ }
+ }
+ }
+}
- float HeightTarget = 0.0f;
- if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, false, true, false, false, false, false, false)){
- CBaseModelInfo *mi = CModelInfo::GetModelInfo(entity->GetModelIndex());
- HeightTarget = mi->GetColModel()->boundingBox.max.z + 1.0f + TargetCoors.z - Source.z;
- if(HeightTarget < 0.0f)
- HeightTarget = 0.0f;
+void
+CCamera::Fade(float timeout, int16 direction)
+{
+ m_bFading = true;
+ m_iFadingDirection = direction;
+ m_fTimeToFadeOut = timeout;
+ m_uiFadeTimeStarted = CTimer::GetTimeInMilliseconds();
+ if(!m_bIgnoreFadingStuffForMusic){
+ m_bMusicFading = true;
+ m_iMusicFadingDirection = direction;
+ m_fTimeToFadeMusic = timeout;
+ m_uiFadeTimeStartedMusic = CTimer::GetTimeInMilliseconds();
+// Not on PS2
+ if(!m_bJustJumpedOutOf1stPersonBecauseOfTarget && m_iMusicFadingDirection == FADE_OUT){
+ unknown++;
+ if(unknown >= 2){
+ m_bJustJumpedOutOf1stPersonBecauseOfTarget = true;
+ unknown = 0;
+ }else
+ m_bMoveCamToAvoidGeom = true;
+ }
}
- WellBufferMe(HeightTarget, &HeightFixerCarsObscuring, &HeightFixerCarsObscuringSpeed, 0.2f, 0.025f, false);
- Source.z += HeightFixerCarsObscuring;
}
-bool
-CCam::Using3rdPersonMouseCam()
+void
+CCamera::SetFadeColour(uint8 r, uint8 g, uint8 b)
{
- return CCamera::m_bUseMouse3rdPerson &&
- (Mode == MODE_FOLLOWPED ||
- TheCamera.m_bPlayerIsInGarage &&
- FindPlayerPed() && FindPlayerPed()->m_nPedState != PED_DRIVING &&
- Mode != MODE_TOPDOWN && this->CamTargetEntity == FindPlayerPed());
+ m_FadeTargetIsSplashScreen = r == 0 && g == 0 && b == 0;
+ CDraw::FadeRed = r;
+ CDraw::FadeGreen = g;
+ CDraw::FadeBlue = b;
}
bool
-CCam::GetWeaponFirstPersonOn()
+CCamera::GetFading(void)
{
- CEntity *target = this->CamTargetEntity;
- if (target && target->IsPed())
- return ((CPed*)target)->GetWeapon()->m_bAddRotOffset;
-
- return false;
+ return m_bFading;
}
-float
-CCamera::Find3rdPersonQuickAimPitch(void)
+int
+CCamera::GetFadingDirection(void)
{
- float clampedFrontZ = clamp(Cams[ActiveCam].Front.z, -1.0f, 1.0f);
+ if(m_bFading)
+ return m_iFadingDirection == FADE_IN ? FADE_IN : FADE_OUT;
+ else
+ return FADE_NONE;
+}
- // float rot = atan2(clampedFrontZ, sqrt(1.0f - sq(clampedFrontZ)));
- float rot = Asin(clampedFrontZ);
+int
+CCamera::GetScreenFadeStatus(void)
+{
+ if(m_fFLOATingFade == 0.0f)
+ return FADE_0;
+ if(m_fFLOATingFade == 255.0f)
+ return FADE_2;
+ return FADE_1;
+}
- return -(DEGTORAD(((0.5f - m_f3rdPersonCHairMultY) * 1.8f * 0.5f * Cams[ActiveCam].FOV)) + rot);
+
+
+void
+CCamera::RenderMotionBlur(void)
+{
+ if(m_BlurType == 0)
+ return;
+
+ CMBlur::MotionBlurRender(m_pRwCamera,
+ m_BlurRed, m_BlurGreen, m_BlurBlue,
+ m_motionBlur, m_BlurType, m_imotionBlurAddAlpha);
}
void
-CCamera::SetCamCutSceneOffSet(const CVector &pos)
+CCamera::SetMotionBlur(int r, int g, int b, int a, int type)
{
- m_vecCutSceneOffset = pos;
-};
+ m_BlurRed = r;
+ m_BlurGreen = g;
+ m_BlurBlue = b;
+ m_motionBlur = a;
+ m_BlurType = type;
+}
void
-CCamera::TakeControlWithSpline(short nSwitch)
+CCamera::SetMotionBlurAlpha(int a)
{
- m_iModeToGoTo = CCam::MODE_FLYBY;
- m_bLookingAtPlayer = false;
- m_bLookingAtVector = false;
- m_bcutsceneFinished = false;
- m_iTypeOfSwitch = nSwitch;
- m_bStartInterScript = true;
+ m_imotionBlurAddAlpha = a;
+}
- //FindPlayerPed(); // unused
-};
-void CCamera::SetCameraDirectlyInFrontForFollowPed_CamOnAString()
+
+int
+CCamera::GetLookDirection(void)
{
- m_bCamDirectlyInFront = true;
- CPlayerPed *player = FindPlayerPed();
- if (player)
- m_PedOrientForBehindOrInFront = CGeneral::GetATanOfXY(player->GetForward().x, player->GetForward().y);
+ if(Cams[ActiveCam].Mode == CCam::MODE_CAM_ON_A_STRING ||
+ Cams[ActiveCam].Mode == CCam::MODE_1STPERSON ||
+ Cams[ActiveCam].Mode == CCam::MODE_BEHINDBOAT ||
+ Cams[ActiveCam].Mode == CCam::MODE_FOLLOWPED)
+ return Cams[ActiveCam].DirectionWasLooking;
+ return LOOKING_FORWARD;;
}
-void CCamera::SetCameraDirectlyBehindForFollowPed_CamOnAString()
+bool
+CCamera::GetLookingForwardFirstPerson(void)
{
- m_bCamDirectlyBehind = true;
- CPlayerPed *player = FindPlayerPed();
- if (player)
- m_PedOrientForBehindOrInFront = CGeneral::GetATanOfXY(player->GetForward().x, player->GetForward().y);
+ return Cams[ActiveCam].Mode == CCam::MODE_1STPERSON &&
+ Cams[ActiveCam].DirectionWasLooking == LOOKING_FORWARD;
+}
+
+bool
+CCamera::GetLookingLRBFirstPerson(void)
+{
+ return Cams[ActiveCam].Mode == CCam::MODE_1STPERSON && Cams[ActiveCam].DirectionWasLooking != LOOKING_FORWARD;
}
void
-CCamera::SetWideScreenOn(void)
+CCamera::SetCameraDirectlyBehindForFollowPed_CamOnAString(void)
{
- m_WideScreenOn = true;
+ m_bCamDirectlyBehind = true;
+ CPlayerPed *player = FindPlayerPed();
+ if (player)
+ m_PedOrientForBehindOrInFront = CGeneral::GetATanOfXY(player->GetForward().x, player->GetForward().y);
}
void
-CCamera::SetWideScreenOff(void)
+CCamera::SetCameraDirectlyInFrontForFollowPed_CamOnAString(void)
{
- m_bWantsToSwitchWidescreenOff = m_WideScreenOn;
+ m_bCamDirectlyInFront = true;
+ CPlayerPed *player = FindPlayerPed();
+ if (player)
+ m_PedOrientForBehindOrInFront = CGeneral::GetATanOfXY(player->GetForward().x, player->GetForward().y);
}
void
@@ -1392,18 +3195,52 @@ CCamera::SetNewPlayerWeaponMode(int16 mode, int16 minZoom, int16 maxZoom)
}
void
+CCamera::ClearPlayerWeaponMode(void)
+{
+ PlayerWeaponMode.Mode = 0;
+ PlayerWeaponMode.MaxZoom = 1;
+ PlayerWeaponMode.MinZoom = -1;
+ PlayerWeaponMode.Duration = 0.0f;
+}
+
+void
CCamera::UpdateAimingCoors(CVector const &coors)
{
m_cvecAimingTargetCoors = coors;
}
void
-CCamera::SetCamPositionForFixedMode(const CVector &Source, const CVector &UpOffSet)
+CCamera::Find3rdPersonCamTargetVector(float dist, CVector pos, CVector &source, CVector &target)
{
- m_vecFixedModeSource = Source;
- m_vecFixedModeUpOffSet = UpOffSet;
+ if(CPad::GetPad(0)->GetLookBehindForPed()){
+ source = pos;
+ target = dist*Cams[ActiveCam].CamTargetEntity->GetForward() + source;
+ }else{
+ float angleX = DEGTORAD((m_f3rdPersonCHairMultX-0.5f) * 1.8f * 0.5f * Cams[ActiveCam].FOV * CDraw::GetAspectRatio());
+ float angleY = DEGTORAD((0.5f-m_f3rdPersonCHairMultY) * 1.8f * 0.5f * Cams[ActiveCam].FOV);
+ source = Cams[ActiveCam].Source;
+ target = Cams[ActiveCam].Front;
+ target += Cams[ActiveCam].Up * Tan(angleY);
+ target += CrossProduct(Cams[ActiveCam].Front, Cams[ActiveCam].Up) * Tan(angleX);
+ target.Normalise();
+ float dot = DotProduct(pos - source, target);
+ source += dot*target;
+ target = dist*target + source;
+ }
+}
+
+float
+CCamera::Find3rdPersonQuickAimPitch(void)
+{
+ float clampedFrontZ = clamp(Cams[ActiveCam].Front.z, -1.0f, 1.0f);
+
+ float rot = Asin(clampedFrontZ);
+
+ return -(DEGTORAD(((0.5f - m_f3rdPersonCHairMultY) * 1.8f * 0.5f * Cams[ActiveCam].FOV)) + rot);
}
+
+
void
CCamera::SetRwCamera(RwCamera *cam)
{
@@ -1412,53 +3249,112 @@ CCamera::SetRwCamera(RwCamera *cam)
CMBlur::MotionBlurOpen(m_pRwCamera);
}
-uint32
-CCamera::GetCutSceneFinishTime(void)
+void
+CCamera::CalculateDerivedValues(void)
{
- int cam = ActiveCam;
- if (Cams[cam].Mode == CCam::MODE_FLYBY)
- return Cams[cam].m_uiFinishTime;
- cam = (cam + 1) % 2;
- if (Cams[cam].Mode == CCam::MODE_FLYBY)
- return Cams[cam].m_uiFinishTime;
-
- return 0;
+ m_cameraMatrix = Invert(m_matrix);
+
+ float hfov = DEGTORAD(CDraw::GetFOV()/2.0f);
+ float c = cos(hfov);
+ float s = sin(hfov);
+
+ // right plane
+ m_vecFrustumNormals[0] = CVector(c, -s, 0.0f);
+ // left plane
+ m_vecFrustumNormals[1] = CVector(-c, -s, 0.0f);
+
+ c /= CDraw::FindAspectRatio();
+ s /= CDraw::FindAspectRatio();
+ // bottom plane
+ m_vecFrustumNormals[2] = CVector(0.0f, -s, -c);
+ // top plane
+ m_vecFrustumNormals[3] = CVector(0.0f, -s, c);
+
+ if(GetForward().x == 0.0f && GetForward().y == 0.0f)
+ GetForward().x = 0.0001f;
+ else
+ Orientation = Atan2(GetForward().x, GetForward().y);
+
+ CamFrontXNorm = GetForward().x;
+ CamFrontYNorm = GetForward().y;
+ float l = Sqrt(SQR(CamFrontXNorm) + SQR(CamFrontYNorm));
+ if(l == 0.0f)
+ CamFrontXNorm = 1.0f;
+ else{
+ CamFrontXNorm /= l;
+ CamFrontYNorm /= l;
+ }
}
-void
-CCamera::FinishCutscene(void)
+bool
+CCamera::IsPointVisible(const CVector &center, const CMatrix *mat)
{
- SetPercentAlongCutScene(100.0f);
- m_fPositionAlongSpline = 1.0f;
- m_bcutsceneFinished = true;
+ RwV3d c;
+ c = *(RwV3d*)&center;
+ RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix);
+ if(c.y < CDraw::GetNearClipZ()) return false;
+ if(c.y > CDraw::GetFarClipZ()) return false;
+ if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > 0.0f) return false;
+ if(c.x*m_vecFrustumNormals[1].x + c.y*m_vecFrustumNormals[1].y > 0.0f) return false;
+ if(c.y*m_vecFrustumNormals[2].y + c.z*m_vecFrustumNormals[2].z > 0.0f) return false;
+ if(c.y*m_vecFrustumNormals[3].y + c.z*m_vecFrustumNormals[3].z > 0.0f) return false;
+ return true;
}
-void
-CCamera::SetZoomValueFollowPedScript(int16 mode)
+bool
+CCamera::IsSphereVisible(const CVector &center, float radius, const CMatrix *mat)
{
- switch (mode) {
- case 0: m_fPedZoomValueScript = 0.25f; break;
- case 1: m_fPedZoomValueScript = 1.5f; break;
- case 2: m_fPedZoomValueScript = 2.9f; break;
- default: m_fPedZoomValueScript = m_fPedZoomValueScript; break;
- }
+ RwV3d c;
+ c = *(RwV3d*)&center;
+ RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix);
+ if(c.y + radius < CDraw::GetNearClipZ()) return false;
+ if(c.y - radius > CDraw::GetFarClipZ()) return false;
+ if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > radius) return false;
+ if(c.x*m_vecFrustumNormals[1].x + c.y*m_vecFrustumNormals[1].y > radius) return false;
+ if(c.y*m_vecFrustumNormals[2].y + c.z*m_vecFrustumNormals[2].z > radius) return false;
+ if(c.y*m_vecFrustumNormals[3].y + c.z*m_vecFrustumNormals[3].z > radius) return false;
+ return true;
+}
- m_bUseScriptZoomValuePed = true;
+bool
+CCamera::IsSphereVisible(const CVector &center, float radius)
+{
+ CMatrix mat = m_cameraMatrix;
+ return IsSphereVisible(center, radius, &mat);
}
-void
-CCamera::SetZoomValueCamStringScript(int16 mode)
+bool
+CCamera::IsBoxVisible(RwV3d *box, const CMatrix *mat)
{
- switch (mode) {
- case 0: m_fCarZoomValueScript = 0.05f; break;
- case 1: m_fCarZoomValueScript = 1.9f; break;
- case 2: m_fCarZoomValueScript = 3.9f; break;
- default: m_fCarZoomValueScript = m_fCarZoomValueScript; break;
+ int i;
+ int frustumTests[6] = { 0 };
+ RwV3dTransformPoints(box, box, 8, &mat->m_matrix);
+
+ for(i = 0; i < 8; i++){
+ if(box[i].y < CDraw::GetNearClipZ()) frustumTests[0]++;
+ if(box[i].y > CDraw::GetFarClipZ()) frustumTests[1]++;
+ if(box[i].x*m_vecFrustumNormals[0].x + box[i].y*m_vecFrustumNormals[0].y > 0.0f) frustumTests[2]++;
+ if(box[i].x*m_vecFrustumNormals[1].x + box[i].y*m_vecFrustumNormals[1].y > 0.0f) frustumTests[3]++;
+// Why not test z?
+// if(box[i].y*m_vecFrustumNormals[2].y + box[i].z*m_vecFrustumNormals[2].z > 0.0f) frustumTests[4]++;
+// if(box[i].y*m_vecFrustumNormals[3].y + box[i].z*m_vecFrustumNormals[3].z > 0.0f) frustumTests[5]++;
}
+ for(i = 0; i < 6; i++)
+ if(frustumTests[i] == 8)
+ return false; // Box is completely outside of one plane
+ return true;
+}
- m_bUseScriptZoomValueCar = true;
+
+
+CCamPathSplines::CCamPathSplines(void)
+{
+ int i;
+ for(i = 0; i < MAXPATHLENGTH; i++)
+ m_arr_PathData[i] = 0.0f;
}
+
STARTPATCHES
InjectHook(0x42C760, (bool (CCamera::*)(const CVector &center, float radius, const CMatrix *mat))&CCamera::IsSphereVisible, PATCH_JUMP);
InjectHook(0x46FD00, &CCamera::SetFadeColour, PATCH_JUMP);
@@ -1480,20 +3376,35 @@ STARTPATCHES
InjectHook(0x46FF90, &CCamera::SetZoomValueCamStringScript, PATCH_JUMP);
- InjectHook(0x456F40, WellBufferMe, PATCH_JUMP);
- InjectHook(0x4582F0, &CCam::GetVectorsReadyForRW, PATCH_JUMP);
- InjectHook(0x457710, &CCam::DoAverageOnVector, PATCH_JUMP);
- InjectHook(0x458060, &CCam::GetPedBetaAngleForClearView, PATCH_JUMP);
- InjectHook(0x457210, &CCam::Cam_On_A_String_Unobscured, PATCH_JUMP);
- InjectHook(0x457A80, &CCam::FixCamWhenObscuredByVehicle, PATCH_JUMP);
- InjectHook(0x457B90, &CCam::FixCamIfObscured, PATCH_JUMP);
- InjectHook(0x465DA0, &CCam::RotCamIfInFrontCar, PATCH_JUMP);
- InjectHook(0x4662D0, &CCam::WorkOutCamHeightWeeCar, PATCH_JUMP);
- InjectHook(0x466650, &CCam::WorkOutCamHeight, PATCH_JUMP);
-
- InjectHook(0x45E3A0, &CCam::Process_FollowPed, PATCH_JUMP);
- InjectHook(0x45BE60, &CCam::Process_BehindCar, PATCH_JUMP);
- InjectHook(0x45C090, &CCam::Process_Cam_On_A_String, PATCH_JUMP);
-
- InjectHook(0x473250, &CCamera::dtor, PATCH_JUMP);
+ InjectHook(0x46F8E0, &CCamera::ProcessWideScreenOn, PATCH_JUMP);
+ InjectHook(0x46FDE0, &CCamera::SetParametersForScriptInterpolation, PATCH_JUMP);
+ InjectHook(0x46BA20, &CCamera::GetLookingLRBFirstPerson, PATCH_JUMP);
+ InjectHook(0x470D80, &CCamera::StartTransitionWhenNotFinishedInter, PATCH_JUMP);
+ InjectHook(0x46FFF0, &CCamera::StartTransition, PATCH_JUMP);
+ InjectHook(0x46BEB0, &CCamera::InitialiseCameraForDebugMode, PATCH_JUMP);
+ InjectHook(0x471500, &CCamera::TakeControl, PATCH_JUMP);
+ InjectHook(0x4715B0, &CCamera::TakeControlNoEntity, PATCH_JUMP);
+ InjectHook(0x46B3A0, &CCamera::Fade, PATCH_JUMP);
+ InjectHook(0x46FE20, &CCamera::SetPercentAlongCutScene, PATCH_JUMP);
+ InjectHook(0x46B100, &CamShakeNoPos, PATCH_JUMP);
+ InjectHook(0x46B200, &CCamera::CamShake, PATCH_JUMP);
+ InjectHook(0x46F520, &CCamera::ProcessObbeCinemaCameraPed, PATCH_JUMP);
+ InjectHook(0x46F3E0, &CCamera::ProcessObbeCinemaCameraCar, PATCH_JUMP);
+ InjectHook(0x470DA0, &CCamera::StoreValuesDuringInterPol, PATCH_JUMP);
+ InjectHook(0x46B430, &CCamera::DrawBordersForWideScreen, PATCH_JUMP);
+ InjectHook(0x46F990, &CCamera::Restore, PATCH_JUMP);
+ InjectHook(0x46FAE0, &CCamera::RestoreWithJumpCut, PATCH_JUMP);
+ InjectHook(0x46F080, &CCamera::ProcessFade, PATCH_JUMP);
+ InjectHook(0x46EEA0, &CCamera::CalculateDerivedValues, PATCH_JUMP);
+ InjectHook(0x46F1E0, &CCamera::ProcessMusicFade, PATCH_JUMP);
+ InjectHook(0x46D1D0, &CCamera::LoadPathSplines, PATCH_JUMP);
+ InjectHook(0x4712A0, &CCamera::UpdateTargetEntity, PATCH_JUMP);
+ InjectHook(0x46B580, &CCamera::Find3rdPersonCamTargetVector, PATCH_JUMP);
+ InjectHook(0x46BAD0, &CCamera::Init, PATCH_JUMP);
+ InjectHook(0x46C9E0, &CCamera::LoadTrainCamNodes, PATCH_JUMP);
+ InjectHook(0x46F600, &CCamera::Process_Train_Camera_Control, PATCH_JUMP);
+ InjectHook(0x470EA0, &CCamera::UpdateSoundDistances, PATCH_JUMP);
+ InjectHook(0x46BF10, &CCamera::IsItTimeForNewcam, PATCH_JUMP);
+ InjectHook(0x471650, &CCamera::TryToStartNewCamMode, PATCH_JUMP);
+// InjectHook(0x46D3F0, &CCamera::Process, PATCH_JUMP);
ENDPATCHES
diff --git a/src/core/Camera.h b/src/core/Camera.h
index 980af5c1..f21fe913 100644
--- a/src/core/Camera.h
+++ b/src/core/Camera.h
@@ -4,11 +4,28 @@
class CEntity;
class CPed;
class CAutomobile;
+class CGarage;
-#define NUMBER_OF_VECTORS_FOR_AVERAGE 2
+extern int16 &DebugCamMode;
-struct CCam
+enum
+{
+ NUMBER_OF_VECTORS_FOR_AVERAGE = 2,
+ MAX_NUM_OF_SPLINETYPES = 4,
+ MAX_NUM_OF_NODES = 800 // for trains
+};
+
+#define DEFAULT_NEAR (0.9f)
+#define CAM_ZOOM_1STPRS (0.0f)
+#define CAM_ZOOM_1 (1.0f)
+#define CAM_ZOOM_2 (2.0f)
+#define CAM_ZOOM_3 (3.0f)
+#define CAM_ZOOM_TOPDOWN (4.0f)
+#define CAM_ZOOM_CINEMATIC (5.0f)
+
+class CCam
{
+public:
enum
{
MODE_NONE = 0,
@@ -66,17 +83,17 @@ struct CCam
bool m_bTheHeightFixerVehicleIsATrain;
bool LookBehindCamWasInFront;
bool LookingBehind;
- bool LookingLeft; // 32
+ bool LookingLeft;
bool LookingRight;
bool ResetStatics; //for interpolation type stuff to work
bool Rotating;
int16 Mode; // CameraMode
- uint32 m_uiFinishTime; // 52
+ uint32 m_uiFinishTime;
int m_iDoCollisionChecksOnFrameNum;
int m_iDoCollisionCheckEveryNumOfFrames;
- int m_iFrameNumWereAt; // 64
+ int m_iFrameNumWereAt;
int m_iRunningVectorArrayPos;
int m_iRunningVectorCounter;
int DirectionWasLooking;
@@ -85,9 +102,9 @@ struct CCam
float f_Roll; //used for adding a slight roll to the camera in the
float f_rollSpeed;
float m_fSyphonModeTargetZOffSet;
- float m_fUnknownZOffSet;
+ float m_fRoadOffSet;
float m_fAmountFractionObscured;
- float m_fAlphaSpeedOverOneFrame; // 100
+ float m_fAlphaSpeedOverOneFrame;
float m_fBetaSpeedOverOneFrame;
float m_fBufferedTargetBeta;
float m_fBufferedTargetOrientation;
@@ -95,7 +112,7 @@ struct CCam
float m_fCamBufferedHeight;
float m_fCamBufferedHeightSpeed;
float m_fCloseInPedHeightOffset;
- float m_fCloseInPedHeightOffsetSpeed; // 132
+ float m_fCloseInPedHeightOffsetSpeed;
float m_fCloseInCarHeightOffset;
float m_fCloseInCarHeightOffsetSpeed;
float m_fDimensionOfHighestNearCar;
@@ -103,7 +120,7 @@ struct CCam
float m_fFovSpeedOverOneFrame;
float m_fMinDistAwayFromCamWhenInterPolating;
float m_fPedBetweenCameraHeightOffset;
- float m_fPlayerInFrontSyphonAngleOffSet; // 164
+ float m_fPlayerInFrontSyphonAngleOffSet;
float m_fRadiusForDead;
float m_fRealGroundDist; //used for follow ped mode
float m_fTargetBeta;
@@ -111,7 +128,7 @@ struct CCam
float m_fTransitionBeta;
float m_fTrueBeta;
- float m_fTrueAlpha; // 200
+ float m_fTrueAlpha;
float m_fInitialPlayerOrientation; //used for first person
float Alpha;
@@ -120,34 +137,25 @@ struct CCam
float FOVSpeed;
float Beta;
float BetaSpeed;
- float Distance; // 232
+ float Distance;
float DistanceSpeed;
float CA_MIN_DISTANCE;
float CA_MAX_DISTANCE;
float SpeedVar;
- // ped onfoot zoom distance
- float m_fTargetZoomGroundOne;
- float m_fTargetZoomGroundTwo; // 256
- float m_fTargetZoomGroundThree;
- // ped onfoot alpha angle offset
- float m_fTargetZoomOneZExtra;
- float m_fTargetZoomTwoZExtra;
- float m_fTargetZoomThreeZExtra;
-
- float m_fTargetZoomZCloseIn;
- float m_fMinRealGroundDist;
- float m_fTargetCloseInDist;
-
- CVector m_cvecTargetCoorsForFudgeInter; // 360
- CVector m_cvecCamFixedModeVector; // 372
- CVector m_cvecCamFixedModeSource; // 384
- CVector m_cvecCamFixedModeUpOffSet; // 396
- CVector m_vecLastAboveWaterCamPosition; //408 //helper for when the player has gone under the water
- CVector m_vecBufferedPlayerBodyOffset; // 420
+ CVector m_cvecSourceSpeedOverOneFrame;
+ CVector m_cvecTargetSpeedOverOneFrame;
+ CVector m_cvecUpOverOneFrame;
+
+ CVector m_cvecTargetCoorsForFudgeInter;
+ CVector m_cvecCamFixedModeVector;
+ CVector m_cvecCamFixedModeSource;
+ CVector m_cvecCamFixedModeUpOffSet;
+ CVector m_vecLastAboveWaterCamPosition; //helper for when the player has gone under the water
+ CVector m_vecBufferedPlayerBodyOffset;
// The three vectors that determine this camera for this frame
- CVector Front; // 432 // Direction of looking in
+ CVector Front; // Direction of looking in
CVector Source; // Coors in world space
CVector SourceBeforeLookBehind;
CVector Up; // Just that
@@ -162,6 +170,10 @@ struct CCam
bool m_bFirstPersonRunAboutActive;
+ CCam(void) { Init(); }
+ void Init(void);
+ void Process(void);
+ void ProcessSpecialHeightRoutines(void);
void GetVectorsReadyForRW(void);
CVector DoAverageOnVector(const CVector &vec);
float GetPedBetaAngleForClearView(const CVector &Target, float Dist, float BetaOffset, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies);
@@ -171,21 +183,74 @@ struct CCam
bool FixCamIfObscured(CVector &TargetCoors, float TargetHeight, float TargetOrientation);
void Cam_On_A_String_Unobscured(const CVector &TargetCoors, float BaseDist);
void FixCamWhenObscuredByVehicle(const CVector &TargetCoors);
- bool Using3rdPersonMouseCam();
- bool GetWeaponFirstPersonOn();
-
- void Process_Debug(float *vec, float a, float b, float c);
+ void LookBehind(void);
+ void LookLeft(void);
+ void LookRight(void);
+ void ClipIfPedInFrontOfPlayer(void);
+ void KeepTrackOfTheSpeed(const CVector &source, const CVector &target, const CVector &up, const float &alpha, const float &beta, const float &fov);
+ bool Using3rdPersonMouseCam(void);
+ bool GetWeaponFirstPersonOn(void);
+ bool IsTargetInWater(const CVector &CamCoors);
+ void AvoidWallsTopDownPed(const CVector &TargetCoors, const CVector &Offset, float *Adjuster, float *AdjusterSpeed, float yDistLimit);
+ void PrintMode(void);
+
+ void Process_Debug(const CVector&, float, float, float);
+ void Process_Editor(const CVector&, float, float, float);
+ void Process_ModelView(const CVector &CameraTarget, float, float, float);
void Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, float, float);
+ void Process_FollowPedWithMouse(const CVector &CameraTarget, float TargetOrientation, float, float);
void Process_BehindCar(const CVector &CameraTarget, float TargetOrientation, float, float);
void Process_Cam_On_A_String(const CVector &CameraTarget, float TargetOrientation, float, float);
+ void Process_TopDown(const CVector &CameraTarget, float TargetOrientation, float SpeedVar, float TargetSpeedVar);
+ void Process_TopDownPed(const CVector &CameraTarget, float TargetOrientation, float, float);
+ void Process_Rocket(const CVector &CameraTarget, float, float, float);
+ void Process_M16_1stPerson(const CVector &CameraTarget, float, float, float);
+ void Process_1stPerson(const CVector &CameraTarget, float, float, float);
+ void Process_1rstPersonPedOnPC(const CVector &CameraTarget, float TargetOrientation, float, float);
+ void Process_Sniper(const CVector &CameraTarget, float, float, float);
+ void Process_Syphon(const CVector &CameraTarget, float, float, float);
+ void Process_Syphon_Crim_In_Front(const CVector &CameraTarget, float, float, float);
+ void Process_BehindBoat(const CVector &CameraTarget, float TargetOrientation, float, float);
+ void Process_Fight_Cam(const CVector &CameraTarget, float TargetOrientation, float, float);
+ void Process_FlyBy(const CVector&, float, float, float);
+ void Process_WheelCam(const CVector&, float, float, float);
+ void Process_Fixed(const CVector &CameraTarget, float, float, float);
+ void Process_Player_Fallen_Water(const CVector &CameraTarget, float TargetOrientation, float, float);
+ void Process_Circle(const CVector &CameraTarget, float, float, float);
+ void Process_SpecialFixedForSyphon(const CVector &CameraTarget, float, float, float);
+ void ProcessPedsDeadBaby(void);
+ bool ProcessArrestCamOne(void);
+ bool ProcessArrestCamTwo(void);
+
+ /* Some of the unused PS2 cams */
+ void Process_Chris_With_Binding_PlusRotation(const CVector &CameraTarget, float, float, float);
+ void Process_ReactionCam(const CVector &CameraTarget, float TargetOrientation, float, float);
+ void Process_FollowPed_WithBinding(const CVector &CameraTarget, float TargetOrientation, float, float);
+ // TODO:
+ // CCam::Process_CushyPillows_Arse
+ // CCam::Process_Look_At_Cars
+ // CCam::Process_CheesyZoom
+ // CCam::Process_Aiming
+ // CCam::Process_Bill // same as BehindCar due to unused variables
+ // CCam::Process_Im_The_Passenger_Woo_Woo
+ // CCam::Process_Blood_On_The_Tracks
+ // CCam::Process_Cam_Running_Side_Train
+ // CCam::Process_Cam_On_Train_Roof
+
+ // custom stuff
+ void Process_FollowPed_Rotation(const CVector &CameraTarget, float TargetOrientation, float, float);
+ void Process_FollowCar_SA(const CVector &CameraTarget, float TargetOrientation, float, float);
};
static_assert(sizeof(CCam) == 0x1A4, "CCam: wrong size");
static_assert(offsetof(CCam, Alpha) == 0xA8, "CCam: error");
static_assert(offsetof(CCam, Front) == 0x140, "CCam: error");
-struct CCamPathSplines
+class CCamPathSplines
{
- float m_arr_PathData[800];
+public:
+ enum {MAXPATHLENGTH=800};
+ float m_arr_PathData[MAXPATHLENGTH];
+ CCamPathSplines(void);
};
struct CTrainCamNode
@@ -223,6 +288,7 @@ enum
FADE_OUT = 0,
FADE_IN,
+ FADE_NONE
};
enum
@@ -248,13 +314,14 @@ enum
enum
{
- CAM_CONTROLLER_0,
- CAM_CONTROLLER_1,
- CAM_CONTROLLER_2
+ CAMCONTROL_GAME,
+ CAMCONTROL_SCRIPT,
+ CAMCONTROL_OBBE
};
-struct CCamera : public CPlaceable
+class CCamera : public CPlaceable
{
+public:
bool m_bAboveGroundTrainNodesLoaded;
bool m_bBelowGroundTrainNodesLoaded;
bool m_bCamDirectlyBehind;
@@ -296,16 +363,12 @@ struct CCamera : public CPlaceable
bool m_bHeadBob;
bool m_bFailedCullZoneTestPreviously;
-bool m_FadeTargetIsSplashScreen;
+ bool m_FadeTargetIsSplashScreen;
bool WorldViewerBeingUsed;
uint8 ActiveCam;
uint32 m_uiCamShakeStart;
uint32 m_uiFirstPersonCamLastInputTime;
-// where are those?
-//bool m_bVehicleSuspenHigh;
-//bool m_bEnable1rstPersonCamCntrlsScript;
-//bool m_bAllow1rstPersonWeaponsCamera;
uint32 m_uiLongestTimeInMill;
uint32 m_uiNumberOfTrainCamNodes;
@@ -321,7 +384,7 @@ bool m_FadeTargetIsSplashScreen;
int m_BlurRed;
int m_BlurType;
-uint32 unknown;
+uint32 unknown; // some counter having to do with music
int m_iWorkOutSpeedThisNumFrames;
int m_iNumFramesSoFar;
@@ -364,20 +427,20 @@ uint32 unknown;
float m_fOldBetaDiff;
float m_fPedZoomValue;
- float m_fPedZoomValueScript;
- float m_fPedZoomValueSmooth;
- float m_fPositionAlongSpline;
- float m_ScreenReductionPercentage;
- float m_ScreenReductionSpeed;
- float m_AlphaForPlayerAnim1rstPerson;
- float Orientation;
- float PedZoomIndicator;
- float PlayerExhaustion;
- float SoundDistUp, SoundDistLeft, SoundDistRight;
- float SoundDistUpAsRead, SoundDistLeftAsRead, SoundDistRightAsRead;
- float SoundDistUpAsReadOld, SoundDistLeftAsReadOld, SoundDistRightAsReadOld;
- float m_fWideScreenReductionAmount;
- float m_fStartingFOVForInterPol;
+ float m_fPedZoomValueScript;
+ float m_fPedZoomValueSmooth;
+ float m_fPositionAlongSpline;
+ float m_ScreenReductionPercentage;
+ float m_ScreenReductionSpeed;
+ float m_AlphaForPlayerAnim1rstPerson;
+ float Orientation;
+ float PedZoomIndicator;
+ float PlayerExhaustion;
+ float SoundDistUp, SoundDistLeft, SoundDistRight;
+ float SoundDistUpAsRead, SoundDistLeftAsRead, SoundDistRightAsRead;
+ float SoundDistUpAsReadOld, SoundDistLeftAsReadOld, SoundDistRightAsReadOld;
+ float m_fWideScreenReductionAmount;
+ float m_fStartingFOVForInterPol;
// not static yet
float m_fMouseAccelHorzntl;// acceleration multiplier for 1st person controls
@@ -387,8 +450,8 @@ uint32 unknown;
CCam Cams[3];
- void *pToGarageWeAreIn;
- void *pToGarageWeAreInForHackAvoidFirstPerson;
+ CGarage *pToGarageWeAreIn;
+ CGarage *pToGarageWeAreInForHackAvoidFirstPerson;
CQueuedMode m_PlayerMode;
CQueuedMode PlayerWeaponMode;
CVector m_PreviousCameraPosition;
@@ -399,17 +462,15 @@ uint32 unknown;
CVector m_vecFixedModeUpOffSet;
CVector m_vecCutSceneOffset;
- // one of those has to go
- CVector m_cvecStartingSourceForInterPol;
- CVector m_cvecStartingTargetForInterPol;
- CVector m_cvecStartingUpForInterPol;
- CVector m_cvecSourceSpeedAtStartInter;
- CVector m_cvecTargetSpeedAtStartInter;
- CVector m_cvecUpSpeedAtStartInter;
- CVector m_vecSourceWhenInterPol;
- CVector m_vecTargetWhenInterPol;
- CVector m_vecUpWhenInterPol;
- //CVector m_vecClearGeometryVec;
+ CVector m_cvecStartingSourceForInterPol;
+ CVector m_cvecStartingTargetForInterPol;
+ CVector m_cvecStartingUpForInterPol;
+ CVector m_cvecSourceSpeedAtStartInter;
+ CVector m_cvecTargetSpeedAtStartInter;
+ CVector m_cvecUpSpeedAtStartInter;
+ CVector m_vecSourceWhenInterPol;
+ CVector m_vecTargetWhenInterPol;
+ CVector m_vecUpWhenInterPol;
CVector m_vecGameCamPos;
CVector SourceDuringInter;
@@ -417,8 +478,8 @@ uint32 unknown;
CVector UpDuringInter;
RwCamera *m_pRwCamera;
CEntity *pTargetEntity;
- CCamPathSplines m_arrPathArray[4];
- CTrainCamNode m_arrTrainCamNode[800];
+ CCamPathSplines m_arrPathArray[MAX_NUM_OF_SPLINETYPES];
+ CTrainCamNode m_arrTrainCamNode[MAX_NUM_OF_NODES];
CMatrix m_cameraMatrix;
bool m_bGarageFixedCamPositionSet;
bool m_vecDoingSpecialInterPolation;
@@ -442,11 +503,11 @@ uint32 unknown;
float m_fScriptPercentageInterToStopMoving;
float m_fScriptPercentageInterToCatchUp;
-uint32 m_fScriptTimeForInterPolation;
+ uint32 m_fScriptTimeForInterPolation;
-int16 m_iFadingDirection;
-int m_iModeObbeCamIsInForCar;
+ int16 m_iFadingDirection;
+ int m_iModeObbeCamIsInForCar;
int16 m_iModeToGoTo;
int16 m_iMusicFadingDirection;
int16 m_iTypeOfSwitch;
@@ -455,67 +516,97 @@ int m_iModeObbeCamIsInForCar;
uint32 m_uiFadeTimeStartedMusic;
static bool &m_bUseMouse3rdPerson;
-
+#ifdef FREE_CAM
+ static bool bFreeCam;
+#endif
+
+ // High level and misc
+ void Init(void);
+ void Process(void);
+ void CamControl(void);
+ void UpdateTargetEntity(void);
+ void UpdateSoundDistances(void);
+ void InitialiseCameraForDebugMode(void);
+ void CamShake(float strength, float x, float y, float z);
bool Get_Just_Switched_Status() { return m_bJust_Switched; }
- inline const CMatrix& GetCameraMatrix(void) { return m_cameraMatrix; }
- CVector &GetGameCamPosition(void) { return m_vecGameCamPos; }
- float GetPositionAlongSpline(void) { return m_fPositionAlongSpline; }
- bool IsPointVisible(const CVector &center, const CMatrix *mat);
- bool IsSphereVisible(const CVector &center, float radius, const CMatrix *mat);
- bool IsSphereVisible(const CVector &center, float radius);
- bool IsBoxVisible(RwV3d *box, const CMatrix *mat);
- int GetLookDirection(void);
- bool GetLookingForwardFirstPerson(void);
-
- void Fade(float timeout, int16 direction);
- int GetScreenFadeStatus(void);
- void ProcessFade(void);
- void ProcessMusicFade(void);
- void SetFadeColour(uint8 r, uint8 g, uint8 b);
- void CamShake(float strength, float x, float y, float z);
+ // Who's in control
+ void TakeControl(CEntity *target, int16 mode, int16 typeOfSwitch, int32 controller);
+ void TakeControlNoEntity(const CVector &position, int16 typeOfSwitch, int32 controller);
+ void TakeControlWithSpline(int16 typeOfSwitch);
+ void Restore(void);
+ void RestoreWithJumpCut(void);
+ void SetCamPositionForFixedMode(const CVector &Source, const CVector &UppOffSet);
- void SetMotionBlur(int r, int g, int b, int a, int type);
- void SetMotionBlurAlpha(int a);
- void RenderMotionBlur(void);
- void ClearPlayerWeaponMode();
- void CalculateDerivedValues(void);
+ // Transition
+ void StartTransition(int16 mode);
+ void StartTransitionWhenNotFinishedInter(int16 mode);
+ void StoreValuesDuringInterPol(CVector &source, CVector &target, CVector &up, float &FOV);
- void DrawBordersForWideScreen(void);
- void Restore(void);
+ // Widescreen borders
void SetWideScreenOn(void);
void SetWideScreenOff(void);
- void SetNearClipScript(float);
-
- float Find3rdPersonQuickAimPitch(void);
+ void ProcessWideScreenOn(void);
+ void DrawBordersForWideScreen(void);
- void TakeControl(CEntity*, int16, int16, int32);
- void TakeControlNoEntity(const CVector&, int16, int32);
- void SetCamPositionForFixedMode(const CVector&, const CVector&);
- bool GetFading();
+ // Obbe's cam
+ bool IsItTimeForNewcam(int32 obbeMode, int32 time);
+ bool TryToStartNewCamMode(int32 obbeMode);
+ void DontProcessObbeCinemaCamera(void);
+ void ProcessObbeCinemaCameraCar(void);
+ void ProcessObbeCinemaCameraPed(void);
- void Init();
- void SetRwCamera(RwCamera*);
- void Process();
+ // Train
+ void LoadTrainCamNodes(char const *name);
+ void Process_Train_Camera_Control(void);
+ // Script
void LoadPathSplines(int file);
- uint32 GetCutSceneFinishTime(void);
void FinishCutscene(void);
+ float GetPositionAlongSpline(void) { return m_fPositionAlongSpline; }
+ uint32 GetCutSceneFinishTime(void);
+ void SetCamCutSceneOffSet(const CVector &pos);
+ void SetPercentAlongCutScene(float percent);
+ void SetParametersForScriptInterpolation(float stopMoving, float catchUp, int32 time);
+ void SetZoomValueFollowPedScript(int16 dist);
+ void SetZoomValueCamStringScript(int16 dist);
+ void SetNearClipScript(float);
- void SetCamCutSceneOffSet(const CVector&);
- void TakeControlWithSpline(short);
- void RestoreWithJumpCut(void);
+ // Fading
+ void ProcessFade(void);
+ void ProcessMusicFade(void);
+ void Fade(float timeout, int16 direction);
+ void SetFadeColour(uint8 r, uint8 g, uint8 b);
+ bool GetFading(void);
+ int GetFadingDirection(void);
+ int GetScreenFadeStatus(void);
+
+ // Motion blur
+ void RenderMotionBlur(void);
+ void SetMotionBlur(int r, int g, int b, int a, int type);
+ void SetMotionBlurAlpha(int a);
+
+ // Player looking and aiming
+ int GetLookDirection(void);
+ bool GetLookingForwardFirstPerson(void);
+ bool GetLookingLRBFirstPerson(void);
void SetCameraDirectlyInFrontForFollowPed_CamOnAString(void);
void SetCameraDirectlyBehindForFollowPed_CamOnAString(void);
- void SetZoomValueFollowPedScript(int16);
- void SetZoomValueCamStringScript(int16);
- void SetNewPlayerWeaponMode(int16, int16, int16);
- void UpdateAimingCoors(CVector const &);
-
- void SetPercentAlongCutScene(float);
- void SetParametersForScriptInterpolation(float, float, int32);
+ void SetNewPlayerWeaponMode(int16 mode, int16 minZoom, int16 maxZoom);
+ void ClearPlayerWeaponMode(void);
+ void UpdateAimingCoors(CVector const &coors);
+ void Find3rdPersonCamTargetVector(float dist, CVector pos, CVector &source, CVector &target);
+ float Find3rdPersonQuickAimPitch(void);
- void dtor(void) { this->CCamera::~CCamera(); }
+ // Physical camera
+ void SetRwCamera(RwCamera *cam);
+ const CMatrix& GetCameraMatrix(void) { return m_cameraMatrix; }
+ CVector &GetGameCamPosition(void) { return m_vecGameCamPos; }
+ void CalculateDerivedValues(void);
+ bool IsPointVisible(const CVector &center, const CMatrix *mat);
+ bool IsSphereVisible(const CVector &center, float radius, const CMatrix *mat);
+ bool IsSphereVisible(const CVector &center, float radius);
+ bool IsBoxVisible(RwV3d *box, const CMatrix *mat);
};
static_assert(offsetof(CCamera, DistanceToWater) == 0xe4, "CCamera: error");
static_assert(offsetof(CCamera, m_WideScreenOn) == 0x70, "CCamera: error");
@@ -525,8 +616,14 @@ static_assert(offsetof(CCamera, m_uiTransitionState) == 0x89, "CCamera: error");
static_assert(offsetof(CCamera, m_uiTimeTransitionStart) == 0x94, "CCamera: error");
static_assert(offsetof(CCamera, m_BlurBlue) == 0x9C, "CCamera: error");
static_assert(offsetof(CCamera, Cams) == 0x1A4, "CCamera: error");
+static_assert(offsetof(CCamera, pToGarageWeAreIn) == 0x690, "CCamera: error");
+static_assert(offsetof(CCamera, m_PreviousCameraPosition) == 0x6B0, "CCamera: error");
static_assert(offsetof(CCamera, m_vecCutSceneOffset) == 0x6F8, "CCamera: error");
+static_assert(offsetof(CCamera, m_arrPathArray) == 0x7a8, "CCamera: error");
static_assert(sizeof(CCamera) == 0xE9D8, "CCamera: wrong size");
+
extern CCamera &TheCamera;
-void CamShakeNoPos(CCamera*, float); \ No newline at end of file
+void CamShakeNoPos(CCamera*, float);
+void MakeAngleLessThan180(float &Angle);
+void WellBufferMe(float Target, float *CurrentValue, float *CurrentSpeed, float MaxSpeed, float Acceleration, bool IsAngle);
diff --git a/src/core/CdStream.cpp b/src/core/CdStream.cpp
index 57b1cbe2..a400c039 100644
--- a/src/core/CdStream.cpp
+++ b/src/core/CdStream.cpp
@@ -43,6 +43,7 @@ BOOL _gbCdStreamOverlapped;
BOOL _gbCdStreamAsync;
DWORD _gdwCdStreamFlags;
+DWORD WINAPI CdStreamThread(LPVOID lpThreadParameter);
void
CdStreamInitThread(void)
diff --git a/src/core/CdStream.h b/src/core/CdStream.h
index 55507aa8..9ef71b65 100644
--- a/src/core/CdStream.h
+++ b/src/core/CdStream.h
@@ -39,7 +39,6 @@ int32 CdStreamSync(int32 channel);
void AddToQueue(Queue *queue, int32 item);
int32 GetFirstInQueue(Queue *queue);
void RemoveFirstInQueue(Queue *queue);
-DWORD WINAPI CdStreamThread(LPVOID lpThreadParameter);
bool CdStreamAddImage(char const *path);
char *CdStreamGetImageName(int32 cd);
void CdStreamRemoveImages(void);
diff --git a/src/core/Collision.cpp b/src/core/Collision.cpp
index fc8428be..94ef769e 100644
--- a/src/core/Collision.cpp
+++ b/src/core/Collision.cpp
@@ -2061,6 +2061,19 @@ CColModel::operator=(const CColModel &other)
return *this;
}
+#include <new>
+struct CColLine_ : public CColLine
+{
+ CColLine *ctor(CVector *p0, CVector *p1) { return ::new (this) CColLine(*p0, *p1); }
+};
+
+struct CColModel_ : public CColModel
+{
+ CColModel *ctor(void) { return ::new (this) CColModel(); }
+ void dtor(void) { this->CColModel::~CColModel(); }
+};
+
+
STARTPATCHES
InjectHook(0x4B9C30, (CMatrix& (*)(const CMatrix &src, CMatrix &dst))Invert, PATCH_JUMP);
@@ -2099,15 +2112,15 @@ STARTPATCHES
InjectHook(0x411E40, (void (CColSphere::*)(float, const CVector&, uint8, uint8))&CColSphere::Set, PATCH_JUMP);
InjectHook(0x40B2A0, &CColBox::Set, PATCH_JUMP);
- InjectHook(0x40B320, &CColLine::ctor, PATCH_JUMP);
+ InjectHook(0x40B320, &CColLine_::ctor, PATCH_JUMP);
InjectHook(0x40B350, &CColLine::Set, PATCH_JUMP);
InjectHook(0x411E70, &CColTriangle::Set, PATCH_JUMP);
InjectHook(0x411EA0, &CColTrianglePlane::Set, PATCH_JUMP);
InjectHook(0x412140, &CColTrianglePlane::GetNormal, PATCH_JUMP);
- InjectHook(0x411680, &CColModel::ctor, PATCH_JUMP);
- InjectHook(0x4116E0, &CColModel::dtor, PATCH_JUMP);
+ InjectHook(0x411680, &CColModel_::ctor, PATCH_JUMP);
+ InjectHook(0x4116E0, &CColModel_::dtor, PATCH_JUMP);
InjectHook(0x411D80, &CColModel::RemoveCollisionVolumes, PATCH_JUMP);
InjectHook(0x411CB0, &CColModel::CalculateTrianglePlanes, PATCH_JUMP);
InjectHook(0x411D10, &CColModel::RemoveTrianglePlanes, PATCH_JUMP);
diff --git a/src/core/Collision.h b/src/core/Collision.h
index 9597a181..429fc17f 100644
--- a/src/core/Collision.h
+++ b/src/core/Collision.h
@@ -35,8 +35,6 @@ struct CColLine
CColLine(void) { };
CColLine(const CVector &p0, const CVector &p1) { this->p0 = p0; this->p1 = p1; };
void Set(const CVector &p0, const CVector &p1);
-
- CColLine *ctor(CVector *p0, CVector *p1) { return ::new (this) CColLine(*p0, *p1); }
};
struct CColTriangle
@@ -106,8 +104,6 @@ struct CColModel
void SetLinkPtr(CLink<CColModel*>*);
void GetTrianglePoint(CVector &v, int i) const;
- CColModel *ctor(void) { return ::new (this) CColModel(); }
- void dtor(void) { this->CColModel::~CColModel(); }
CColModel& operator=(const CColModel& other);
};
diff --git a/src/core/ControllerConfig.cpp b/src/core/ControllerConfig.cpp
index 92c51182..541257c6 100644
--- a/src/core/ControllerConfig.cpp
+++ b/src/core/ControllerConfig.cpp
@@ -417,6 +417,11 @@ void CControllerConfigManager::UpdateJoyInConfigMenus_ButtonDown(int32 button, i
case 13:
pad->PCTempJoyState.DPadUp = 255;
break;
+#ifdef REGISTER_START_BUTTON
+ case 12:
+ pad->PCTempJoyState.Start = 255;
+ break;
+#endif
case 11:
pad->PCTempJoyState.RightShock = 255;
break;
@@ -839,6 +844,11 @@ void CControllerConfigManager::UpdateJoyInConfigMenus_ButtonUp(int32 button, int
case 13:
pad->PCTempJoyState.DPadUp = 0;
break;
+#ifdef REGISTER_START_BUTTON
+ case 12:
+ pad->PCTempJoyState.Start = 0;
+ break;
+#endif
case 11:
pad->PCTempJoyState.RightShock = 0;
break;
diff --git a/src/core/CutsceneMgr.cpp b/src/core/CutsceneMgr.cpp
index 3df81b2b..283f34b8 100644
--- a/src/core/CutsceneMgr.cpp
+++ b/src/core/CutsceneMgr.cpp
@@ -1,3 +1,4 @@
+#define WITHWINDOWS // just for VK_SPACE
#include "common.h"
#include "patcher.h"
#include "General.h"
@@ -8,12 +9,14 @@
#include "FileMgr.h"
#include "main.h"
#include "AnimManager.h"
+#include "AnimBlendAssociation.h"
#include "AnimBlendAssocGroup.h"
#include "AnimBlendClumpData.h"
#include "Pad.h"
#include "DMAudio.h"
#include "World.h"
#include "PlayerPed.h"
+#include "Wanted.h"
#include "CutsceneHead.h"
#include "RpAnimBlend.h"
#include "ModelIndices.h"
@@ -27,79 +30,79 @@ const struct {
{ "BET", STREAMED_SOUND_BANK_INTRO },
{ "L1_LG", STREAMED_SOUND_CUTSCENE_LUIGI1_LG },
{ "L2_DSB", STREAMED_SOUND_CUTSCENE_LUIGI2_DSB },
- { "L3_DM", STREAMED_SOUND_CUTSCENE_LUIGI3_DM },
- { "L4_PAP", STREAMED_SOUND_CUTSCENE_LUIGI4_PAP },
- { "L5_TFB", STREAMED_SOUND_CUTSCENE_LUIGI5_TFB },
- { "J0_DM2", STREAMED_SOUND_CUTSCENE_JOEY0_DM2 },
- { "J1_LFL", STREAMED_SOUND_CUTSCENE_JOEY1_LFL },
- { "J2_KCL", STREAMED_SOUND_CUTSCENE_JOEY2_KCL },
- { "J3_VH", STREAMED_SOUND_CUTSCENE_JOEY3_VH },
- { "J4_ETH", STREAMED_SOUND_CUTSCENE_JOEY4_ETH },
- { "J5_DST", STREAMED_SOUND_CUTSCENE_JOEY5_DST },
- { "J6_TBJ", STREAMED_SOUND_CUTSCENE_JOEY6_TBJ },
- { "T1_TOL", STREAMED_SOUND_CUTSCENE_TONI1_TOL },
- { "T2_TPU", STREAMED_SOUND_CUTSCENE_TONI2_TPU },
- { "T3_MAS", STREAMED_SOUND_CUTSCENE_TONI3_MAS },
- { "T4_TAT", STREAMED_SOUND_CUTSCENE_TONI4_TAT },
- { "T5_BF", STREAMED_SOUND_CUTSCENE_TONI5_BF },
- { "S0_MAS", STREAMED_SOUND_CUTSCENE_SAL0_MAS },
- { "S1_PF", STREAMED_SOUND_CUTSCENE_SAL1_PF },
- { "S2_CTG", STREAMED_SOUND_CUTSCENE_SAL2_CTG },
- { "S3_RTC", STREAMED_SOUND_CUTSCENE_SAL3_RTC },
- { "S5_LRQ", STREAMED_SOUND_CUTSCENE_SAL5_LRQ },
- { "S4_BDBA", STREAMED_SOUND_CUTSCENE_SAL4_BDBA },
- { "S4_BDBB", STREAMED_SOUND_CUTSCENE_SAL4_BDBB },
- { "S2_CTG2", STREAMED_SOUND_CUTSCENE_SAL2_CTG2 },
- { "S4_BDBD", STREAMED_SOUND_CUTSCENE_SAL4_BDBD },
- { "S5_LRQB", STREAMED_SOUND_CUTSCENE_SAL5_LRQB },
- { "S5_LRQC", STREAMED_SOUND_CUTSCENE_SAL5_LRQC },
- { "A1_SS0", STREAMED_SOUND_CUTSCENE_ASUKA_1_SSO },
- { "A2_PP", STREAMED_SOUND_CUTSCENE_ASUKA_2_PP },
- { "A3_SS", STREAMED_SOUND_CUTSCENE_ASUKA_3_SS },
- { "A4_PDR", STREAMED_SOUND_CUTSCENE_ASUKA_4_PDR },
- { "A5_K2FT", STREAMED_SOUND_CUTSCENE_ASUKA_5_K2FT},
- { "K1_KBO", STREAMED_SOUND_CUTSCENE_KENJI1_KBO },
- { "K2_GIS", STREAMED_SOUND_CUTSCENE_KENJI2_GIS },
- { "K3_DS", STREAMED_SOUND_CUTSCENE_KENJI3_DS },
- { "K4_SHI", STREAMED_SOUND_CUTSCENE_KENJI4_SHI },
- { "K5_SD", STREAMED_SOUND_CUTSCENE_KENJI5_SD },
- { "R0_PDR2", STREAMED_SOUND_CUTSCENE_RAY0_PDR2 },
- { "R1_SW", STREAMED_SOUND_CUTSCENE_RAY1_SW },
- { "R2_AP", STREAMED_SOUND_CUTSCENE_RAY2_AP },
- { "R3_ED", STREAMED_SOUND_CUTSCENE_RAY3_ED },
- { "R4_GF", STREAMED_SOUND_CUTSCENE_RAY4_GF },
- { "R5_PB", STREAMED_SOUND_CUTSCENE_RAY5_PB },
- { "R6_MM", STREAMED_SOUND_CUTSCENE_RAY6_MM },
- { "D1_STOG", STREAMED_SOUND_CUTSCENE_DONALD1_STOG },
- { "D2_KK", STREAMED_SOUND_CUTSCENE_DONALD2_KK },
- { "D3_ADO", STREAMED_SOUND_CUTSCENE_DONALD3_ADO },
- { "D5_ES", STREAMED_SOUND_CUTSCENE_DONALD5_ES },
- { "D7_MLD", STREAMED_SOUND_CUTSCENE_DONALD7_MLD },
- { "D4_GTA", STREAMED_SOUND_CUTSCENE_DONALD4_GTA },
- { "D4_GTA2", STREAMED_SOUND_CUTSCENE_DONALD4_GTA2 },
- { "D6_STS", STREAMED_SOUND_CUTSCENE_DONALD6_STS },
- { "A6_BAIT", STREAMED_SOUND_CUTSCENE_ASUKA6_BAIT },
- { "A7_ETG", STREAMED_SOUND_CUTSCENE_ASUKA7_ETG },
- { "A8_PS", STREAMED_SOUND_CUTSCENE_ASUKA8_PS },
- { "A9_ASD", STREAMED_SOUND_CUTSCENE_ASUKA9_ASD },
- { "K4_SHI2", STREAMED_SOUND_CUTSCENE_KENJI4_SHI2 },
- { "C1_TEX", STREAMED_SOUND_CUTSCENE_CATALINA1_TEX },
- { "EL_PH1", STREAMED_SOUND_CUTSCENE_ELBURRO1_PH1 },
- { "EL_PH2", STREAMED_SOUND_CUTSCENE_ELBURRO2_PH2 },
- { "EL_PH3", STREAMED_SOUND_CUTSCENE_ELBURRO3_PH3 },
- { "EL_PH4", STREAMED_SOUND_CUTSCENE_ELBURRO4_PH4 },
- { "YD_PH1", STREAMED_SOUND_CUTSCENE_YARDIE_PH1 },
- { "YD_PH2", STREAMED_SOUND_CUTSCENE_YARDIE_PH2 },
- { "YD_PH3", STREAMED_SOUND_CUTSCENE_YARDIE_PH3 },
- { "YD_PH4", STREAMED_SOUND_CUTSCENE_YARDIE_PH4 },
- { "HD_PH1", STREAMED_SOUND_CUTSCENE_HOODS_PH1 },
- { "HD_PH2", STREAMED_SOUND_CUTSCENE_HOODS_PH2 },
- { "HD_PH3", STREAMED_SOUND_CUTSCENE_HOODS_PH3 },
- { "HD_PH4", STREAMED_SOUND_CUTSCENE_HOODS_PH4 },
- { "HD_PH5", STREAMED_SOUND_CUTSCENE_HOODS_PH5 },
- { "MT_PH1", STREAMED_SOUND_CUTSCENE_MARTY_PH1 },
- { "MT_PH2", STREAMED_SOUND_CUTSCENE_MARTY_PH2 },
- { "MT_PH3", STREAMED_SOUND_CUTSCENE_MARTY_PH3 },
+ { "L3_DM", STREAMED_SOUND_CUTSCENE_LUIGI3_DM },
+ { "L4_PAP", STREAMED_SOUND_CUTSCENE_LUIGI4_PAP },
+ { "L5_TFB", STREAMED_SOUND_CUTSCENE_LUIGI5_TFB },
+ { "J0_DM2", STREAMED_SOUND_CUTSCENE_JOEY0_DM2 },
+ { "J1_LFL", STREAMED_SOUND_CUTSCENE_JOEY1_LFL },
+ { "J2_KCL", STREAMED_SOUND_CUTSCENE_JOEY2_KCL },
+ { "J3_VH", STREAMED_SOUND_CUTSCENE_JOEY3_VH },
+ { "J4_ETH", STREAMED_SOUND_CUTSCENE_JOEY4_ETH },
+ { "J5_DST", STREAMED_SOUND_CUTSCENE_JOEY5_DST },
+ { "J6_TBJ", STREAMED_SOUND_CUTSCENE_JOEY6_TBJ },
+ { "T1_TOL", STREAMED_SOUND_CUTSCENE_TONI1_TOL },
+ { "T2_TPU", STREAMED_SOUND_CUTSCENE_TONI2_TPU },
+ { "T3_MAS", STREAMED_SOUND_CUTSCENE_TONI3_MAS },
+ { "T4_TAT", STREAMED_SOUND_CUTSCENE_TONI4_TAT },
+ { "T5_BF", STREAMED_SOUND_CUTSCENE_TONI5_BF },
+ { "S0_MAS", STREAMED_SOUND_CUTSCENE_SAL0_MAS },
+ { "S1_PF", STREAMED_SOUND_CUTSCENE_SAL1_PF },
+ { "S2_CTG", STREAMED_SOUND_CUTSCENE_SAL2_CTG },
+ { "S3_RTC", STREAMED_SOUND_CUTSCENE_SAL3_RTC },
+ { "S5_LRQ", STREAMED_SOUND_CUTSCENE_SAL5_LRQ },
+ { "S4_BDBA", STREAMED_SOUND_CUTSCENE_SAL4_BDBA },
+ { "S4_BDBB", STREAMED_SOUND_CUTSCENE_SAL4_BDBB },
+ { "S2_CTG2", STREAMED_SOUND_CUTSCENE_SAL2_CTG2 },
+ { "S4_BDBD", STREAMED_SOUND_CUTSCENE_SAL4_BDBD },
+ { "S5_LRQB", STREAMED_SOUND_CUTSCENE_SAL5_LRQB },
+ { "S5_LRQC", STREAMED_SOUND_CUTSCENE_SAL5_LRQC },
+ { "A1_SS0", STREAMED_SOUND_CUTSCENE_ASUKA_1_SSO },
+ { "A2_PP", STREAMED_SOUND_CUTSCENE_ASUKA_2_PP },
+ { "A3_SS", STREAMED_SOUND_CUTSCENE_ASUKA_3_SS },
+ { "A4_PDR", STREAMED_SOUND_CUTSCENE_ASUKA_4_PDR },
+ { "A5_K2FT", STREAMED_SOUND_CUTSCENE_ASUKA_5_K2FT},
+ { "K1_KBO", STREAMED_SOUND_CUTSCENE_KENJI1_KBO },
+ { "K2_GIS", STREAMED_SOUND_CUTSCENE_KENJI2_GIS },
+ { "K3_DS", STREAMED_SOUND_CUTSCENE_KENJI3_DS },
+ { "K4_SHI", STREAMED_SOUND_CUTSCENE_KENJI4_SHI },
+ { "K5_SD", STREAMED_SOUND_CUTSCENE_KENJI5_SD },
+ { "R0_PDR2", STREAMED_SOUND_CUTSCENE_RAY0_PDR2 },
+ { "R1_SW", STREAMED_SOUND_CUTSCENE_RAY1_SW },
+ { "R2_AP", STREAMED_SOUND_CUTSCENE_RAY2_AP },
+ { "R3_ED", STREAMED_SOUND_CUTSCENE_RAY3_ED },
+ { "R4_GF", STREAMED_SOUND_CUTSCENE_RAY4_GF },
+ { "R5_PB", STREAMED_SOUND_CUTSCENE_RAY5_PB },
+ { "R6_MM", STREAMED_SOUND_CUTSCENE_RAY6_MM },
+ { "D1_STOG", STREAMED_SOUND_CUTSCENE_DONALD1_STOG },
+ { "D2_KK", STREAMED_SOUND_CUTSCENE_DONALD2_KK },
+ { "D3_ADO", STREAMED_SOUND_CUTSCENE_DONALD3_ADO },
+ { "D5_ES", STREAMED_SOUND_CUTSCENE_DONALD5_ES },
+ { "D7_MLD", STREAMED_SOUND_CUTSCENE_DONALD7_MLD },
+ { "D4_GTA", STREAMED_SOUND_CUTSCENE_DONALD4_GTA },
+ { "D4_GTA2", STREAMED_SOUND_CUTSCENE_DONALD4_GTA2 },
+ { "D6_STS", STREAMED_SOUND_CUTSCENE_DONALD6_STS },
+ { "A6_BAIT", STREAMED_SOUND_CUTSCENE_ASUKA6_BAIT },
+ { "A7_ETG", STREAMED_SOUND_CUTSCENE_ASUKA7_ETG },
+ { "A8_PS", STREAMED_SOUND_CUTSCENE_ASUKA8_PS },
+ { "A9_ASD", STREAMED_SOUND_CUTSCENE_ASUKA9_ASD },
+ { "K4_SHI2", STREAMED_SOUND_CUTSCENE_KENJI4_SHI2 },
+ { "C1_TEX", STREAMED_SOUND_CUTSCENE_CATALINA1_TEX },
+ { "EL_PH1", STREAMED_SOUND_CUTSCENE_ELBURRO1_PH1 },
+ { "EL_PH2", STREAMED_SOUND_CUTSCENE_ELBURRO2_PH2 },
+ { "EL_PH3", STREAMED_SOUND_CUTSCENE_ELBURRO3_PH3 },
+ { "EL_PH4", STREAMED_SOUND_CUTSCENE_ELBURRO4_PH4 },
+ { "YD_PH1", STREAMED_SOUND_CUTSCENE_YARDIE_PH1 },
+ { "YD_PH2", STREAMED_SOUND_CUTSCENE_YARDIE_PH2 },
+ { "YD_PH3", STREAMED_SOUND_CUTSCENE_YARDIE_PH3 },
+ { "YD_PH4", STREAMED_SOUND_CUTSCENE_YARDIE_PH4 },
+ { "HD_PH1", STREAMED_SOUND_CUTSCENE_HOODS_PH1 },
+ { "HD_PH2", STREAMED_SOUND_CUTSCENE_HOODS_PH2 },
+ { "HD_PH3", STREAMED_SOUND_CUTSCENE_HOODS_PH3 },
+ { "HD_PH4", STREAMED_SOUND_CUTSCENE_HOODS_PH4 },
+ { "HD_PH5", STREAMED_SOUND_CUTSCENE_HOODS_PH5 },
+ { "MT_PH1", STREAMED_SOUND_CUTSCENE_MARTY_PH1 },
+ { "MT_PH2", STREAMED_SOUND_CUTSCENE_MARTY_PH2 },
+ { "MT_PH3", STREAMED_SOUND_CUTSCENE_MARTY_PH3 },
{ "MT_PH4", STREAMED_SOUND_CUTSCENE_MARTY_PH4 },
{ NULL, NULL }
};
@@ -128,135 +131,135 @@ CVector &CCutsceneMgr::ms_cutsceneOffset = *(CVector*)0x8F2C0C;
float &CCutsceneMgr::ms_cutsceneTimer = *(float*)0x941548;
uint32 &CCutsceneMgr::ms_cutsceneLoadStatus = *(uint32*)0x95CB40;
-RpAtomic *
-CalculateBoundingSphereRadiusCB(RpAtomic *atomic, void *data)
-{
- float radius = RpAtomicGetBoundingSphereMacro(atomic)->radius;
- RwV3d center = RpAtomicGetBoundingSphereMacro(atomic)->center;
-
- for (RwFrame *frame = RpAtomicGetFrame(atomic); RwFrameGetParent(frame); frame = RwFrameGetParent(frame))
- RwV3dTransformPoints(&center, &center, 1, RwFrameGetMatrix(frame));
-
- float size = RwV3dLength(&center) + radius;
- if (size > *(float *)data)
- *(float *)data = size;
- return atomic;
+RpAtomic *
+CalculateBoundingSphereRadiusCB(RpAtomic *atomic, void *data)
+{
+ float radius = RpAtomicGetBoundingSphereMacro(atomic)->radius;
+ RwV3d center = RpAtomicGetBoundingSphereMacro(atomic)->center;
+
+ for (RwFrame *frame = RpAtomicGetFrame(atomic); RwFrameGetParent(frame); frame = RwFrameGetParent(frame))
+ RwV3dTransformPoints(&center, &center, 1, RwFrameGetMatrix(frame));
+
+ float size = RwV3dLength(&center) + radius;
+ if (size > *(float *)data)
+ *(float *)data = size;
+ return atomic;
}
void
CCutsceneMgr::Initialise(void)
-{
- ms_numCutsceneObjs = 0;
- ms_loaded = false;
- ms_running = false;
- ms_animLoaded = false;
- ms_cutsceneProcessing = false;
- ms_useLodMultiplier = false;
-
- ms_pCutsceneDir = new CDirectory(CUTSCENEDIRSIZE);
+{
+ ms_numCutsceneObjs = 0;
+ ms_loaded = false;
+ ms_running = false;
+ ms_animLoaded = false;
+ ms_cutsceneProcessing = false;
+ ms_useLodMultiplier = false;
+
+ ms_pCutsceneDir = new CDirectory(CUTSCENEDIRSIZE);
ms_pCutsceneDir->ReadDirFile("ANIM\\CUTS.DIR");
}
-void
-CCutsceneMgr::Shutdown(void)
-{
- delete ms_pCutsceneDir;
+void
+CCutsceneMgr::Shutdown(void)
+{
+ delete ms_pCutsceneDir;
}
-void
-CCutsceneMgr::LoadCutsceneData(const char *szCutsceneName)
-{
- int file;
- uint32 size;
- uint32 offset;
- CPlayerPed *pPlayerPed;
-
- ms_cutsceneProcessing = true;
- if (!strcasecmp(szCutsceneName, "jb"))
- ms_useLodMultiplier = true;
- CTimer::Stop();
-
- ms_pCutsceneDir->numEntries = 0;
- ms_pCutsceneDir->ReadDirFile("ANIM\\CUTS.DIR");
-
- CStreaming::RemoveUnusedModelsInLoadedList();
- CGame::DrasticTidyUpMemory();
-
- strcpy(ms_cutsceneName, szCutsceneName);
- file = CFileMgr::OpenFile("ANIM\\CUTS.IMG", "rb");
-
- // Load animations
- sprintf(gString, "%s.IFP", szCutsceneName);
- if (ms_pCutsceneDir->FindItem(gString, offset, size)) {
- CStreaming::MakeSpaceFor(size << 11);
- CStreaming::ImGonnaUseStreamingMemory();
- CFileMgr::Seek(file, offset << 11, SEEK_SET);
- CAnimManager::LoadAnimFile(file, false);
- ms_cutsceneAssociations.CreateAssociations(szCutsceneName);
- CStreaming::IHaveUsedStreamingMemory();
- ms_animLoaded = true;
- } else {
- ms_animLoaded = false;
- }
-
- // Load camera data
- sprintf(gString, "%s.DAT", szCutsceneName);
- if (ms_pCutsceneDir->FindItem(gString, offset, size)) {
- CFileMgr::Seek(file, offset << 11, SEEK_SET);
- TheCamera.LoadPathSplines(file);
- }
-
- CFileMgr::CloseFile(file);
-
- if (CGeneral::faststricmp(ms_cutsceneName, "end")) {
- DMAudio.ChangeMusicMode(MUSICMODE_CUTSCENE);
- int trackId = FindCutsceneAudioTrackId(szCutsceneName);
- if (trackId != -1) {
- printf("Start preload audio %s\n", szCutsceneName);
- DMAudio.PreloadCutSceneMusic(trackId);
- printf("End preload audio %s\n", szCutsceneName);
- }
- }
-
- ms_cutsceneTimer = 0.0f;
- ms_loaded = true;
- ms_cutsceneOffset = CVector(0.0f, 0.0f, 0.0f);
-
- pPlayerPed = FindPlayerPed();
- CTimer::Update();
-
- pPlayerPed->m_pWanted->ClearQdCrimes();
- pPlayerPed->bIsVisible = false;
- pPlayerPed->m_fCurrentStamina = pPlayerPed->m_fMaxStamina;
- CPad::GetPad(0)->DisablePlayerControls |= PLAYERCONTROL_DISABLED_80;
- CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(true);
+void
+CCutsceneMgr::LoadCutsceneData(const char *szCutsceneName)
+{
+ int file;
+ uint32 size;
+ uint32 offset;
+ CPlayerPed *pPlayerPed;
+
+ ms_cutsceneProcessing = true;
+ if (!strcasecmp(szCutsceneName, "jb"))
+ ms_useLodMultiplier = true;
+ CTimer::Stop();
+
+ ms_pCutsceneDir->numEntries = 0;
+ ms_pCutsceneDir->ReadDirFile("ANIM\\CUTS.DIR");
+
+ CStreaming::RemoveUnusedModelsInLoadedList();
+ CGame::DrasticTidyUpMemory(true);
+
+ strcpy(ms_cutsceneName, szCutsceneName);
+ file = CFileMgr::OpenFile("ANIM\\CUTS.IMG", "rb");
+
+ // Load animations
+ sprintf(gString, "%s.IFP", szCutsceneName);
+ if (ms_pCutsceneDir->FindItem(gString, offset, size)) {
+ CStreaming::MakeSpaceFor(size << 11);
+ CStreaming::ImGonnaUseStreamingMemory();
+ CFileMgr::Seek(file, offset << 11, SEEK_SET);
+ CAnimManager::LoadAnimFile(file, false);
+ ms_cutsceneAssociations.CreateAssociations(szCutsceneName);
+ CStreaming::IHaveUsedStreamingMemory();
+ ms_animLoaded = true;
+ } else {
+ ms_animLoaded = false;
+ }
+
+ // Load camera data
+ sprintf(gString, "%s.DAT", szCutsceneName);
+ if (ms_pCutsceneDir->FindItem(gString, offset, size)) {
+ CFileMgr::Seek(file, offset << 11, SEEK_SET);
+ TheCamera.LoadPathSplines(file);
+ }
+
+ CFileMgr::CloseFile(file);
+
+ if (CGeneral::faststricmp(ms_cutsceneName, "end")) {
+ DMAudio.ChangeMusicMode(MUSICMODE_CUTSCENE);
+ int trackId = FindCutsceneAudioTrackId(szCutsceneName);
+ if (trackId != -1) {
+ printf("Start preload audio %s\n", szCutsceneName);
+ DMAudio.PreloadCutSceneMusic(trackId);
+ printf("End preload audio %s\n", szCutsceneName);
+ }
+ }
+
+ ms_cutsceneTimer = 0.0f;
+ ms_loaded = true;
+ ms_cutsceneOffset = CVector(0.0f, 0.0f, 0.0f);
+
+ pPlayerPed = FindPlayerPed();
+ CTimer::Update();
+
+ pPlayerPed->m_pWanted->ClearQdCrimes();
+ pPlayerPed->bIsVisible = false;
+ pPlayerPed->m_fCurrentStamina = pPlayerPed->m_fMaxStamina;
+ CPad::GetPad(0)->DisablePlayerControls |= PLAYERCONTROL_DISABLED_80;
+ CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(true);
}
-void
-CCutsceneMgr::SetHeadAnim(const char *animName, CObject *pObject)
-{
- CCutsceneHead *pCutsceneHead = (CCutsceneHead*)pObject;
- char szAnim[CUTSCENENAMESIZE * 2];
-
- sprintf(szAnim, "%s_%s", ms_cutsceneName, animName);
- pCutsceneHead->PlayAnimation(szAnim);
+void
+CCutsceneMgr::SetHeadAnim(const char *animName, CObject *pObject)
+{
+ CCutsceneHead *pCutsceneHead = (CCutsceneHead*)pObject;
+ char szAnim[CUTSCENENAMESIZE * 2];
+
+ sprintf(szAnim, "%s_%s", ms_cutsceneName, animName);
+ pCutsceneHead->PlayAnimation(szAnim);
}
-void
-CCutsceneMgr::FinishCutscene()
-{
- CCutsceneMgr::ms_cutsceneTimer = TheCamera.GetCutSceneFinishTime() * 0.001f;
- TheCamera.FinishCutscene();
-
- FindPlayerPed()->bIsVisible = true;
- CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(false);
+void
+CCutsceneMgr::FinishCutscene()
+{
+ CCutsceneMgr::ms_cutsceneTimer = TheCamera.GetCutSceneFinishTime() * 0.001f;
+ TheCamera.FinishCutscene();
+
+ FindPlayerPed()->bIsVisible = true;
+ CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(false);
}
void
CCutsceneMgr::SetupCutsceneToStart(void)
{
- TheCamera.SetCamCutSceneOffSet(ms_cutsceneOffset);
- TheCamera.TakeControlWithSpline(JUMP_CUT);
+ TheCamera.SetCamCutSceneOffSet(ms_cutsceneOffset);
+ TheCamera.TakeControlWithSpline(JUMP_CUT);
TheCamera.SetWideScreenOn();
ms_cutsceneOffset.z++;
@@ -273,9 +276,9 @@ CCutsceneMgr::SetupCutsceneToStart(void)
}
}
- CTimer::Update();
- CTimer::Update();
- ms_running = true;
+ CTimer::Update();
+ CTimer::Update();
+ ms_running = true;
ms_cutsceneTimer = 0.0f;
}
@@ -297,14 +300,14 @@ CCutsceneMgr::SetCutsceneAnim(const char *animName, CObject *pObject)
pAnimBlendClumpData->link.Prepend(&pNewAnim->link);
}
-CCutsceneHead *
-CCutsceneMgr::AddCutsceneHead(CObject *pObject, int modelId)
-{
- CCutsceneHead *pHead = new CCutsceneHead(pObject);
- pHead->SetModelIndex(modelId);
- CWorld::Add(pHead);
- ms_pCutsceneObjects[ms_numCutsceneObjs++] = pHead;
- return pHead;
+CCutsceneHead *
+CCutsceneMgr::AddCutsceneHead(CObject *pObject, int modelId)
+{
+ CCutsceneHead *pHead = new CCutsceneHead(pObject);
+ pHead->SetModelIndex(modelId);
+ CWorld::Add(pHead);
+ ms_pCutsceneObjects[ms_numCutsceneObjs++] = pHead;
+ return pHead;
}
CCutsceneObject *
@@ -333,89 +336,88 @@ CCutsceneMgr::CreateCutsceneObject(int modelId)
pCutsceneObject = new CCutsceneObject();
pCutsceneObject->SetModelIndex(modelId);
- ms_pCutsceneObjects[ms_numCutsceneObjs++] = pCutsceneObject;
+ ms_pCutsceneObjects[ms_numCutsceneObjs++] = pCutsceneObject;
return pCutsceneObject;
}
-void
-CCutsceneMgr::DeleteCutsceneData(void)
-{
- if (!ms_loaded) return;
-
- ms_cutsceneProcessing = false;
- ms_useLodMultiplier = false;
-
- for (--ms_numCutsceneObjs; ms_numCutsceneObjs >= 0; ms_numCutsceneObjs--) {
- CWorld::Remove(ms_pCutsceneObjects[ms_numCutsceneObjs]);
- ms_pCutsceneObjects[ms_numCutsceneObjs]->DeleteRwObject();
- delete ms_pCutsceneObjects[ms_numCutsceneObjs];
- }
- ms_numCutsceneObjs = 0;
-
- if (ms_animLoaded)
- CAnimManager::RemoveLastAnimFile();
-
- ms_animLoaded = false;
- TheCamera.RestoreWithJumpCut();
- TheCamera.SetWideScreenOff();
- ms_running = false;
- ms_loaded = false;
-
- FindPlayerPed()->bIsVisible = true;
- CPad::GetPad(0)->DisablePlayerControls &= ~PLAYERCONTROL_DISABLED_80;
- CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(false);
-
- if (CGeneral::faststricmp(ms_cutsceneName, "end")) {
- DMAudio.StopCutSceneMusic();
- if (CGeneral::faststricmp(ms_cutsceneName, "bet"))
- DMAudio.ChangeMusicMode(MUSICMODE_GAME);
- }
- CTimer::Stop();
- //TheCamera.GetScreenFadeStatus() == 2; // what for??
- CGame::DrasticTidyUpMemory();
- CTimer::Update();
+void
+CCutsceneMgr::DeleteCutsceneData(void)
+{
+ if (!ms_loaded) return;
+
+ ms_cutsceneProcessing = false;
+ ms_useLodMultiplier = false;
+
+ for (--ms_numCutsceneObjs; ms_numCutsceneObjs >= 0; ms_numCutsceneObjs--) {
+ CWorld::Remove(ms_pCutsceneObjects[ms_numCutsceneObjs]);
+ ms_pCutsceneObjects[ms_numCutsceneObjs]->DeleteRwObject();
+ delete ms_pCutsceneObjects[ms_numCutsceneObjs];
+ }
+ ms_numCutsceneObjs = 0;
+
+ if (ms_animLoaded)
+ CAnimManager::RemoveLastAnimFile();
+
+ ms_animLoaded = false;
+ TheCamera.RestoreWithJumpCut();
+ TheCamera.SetWideScreenOff();
+ ms_running = false;
+ ms_loaded = false;
+
+ FindPlayerPed()->bIsVisible = true;
+ CPad::GetPad(0)->DisablePlayerControls &= ~PLAYERCONTROL_DISABLED_80;
+ CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(false);
+
+ if (CGeneral::faststricmp(ms_cutsceneName, "end")) {
+ DMAudio.StopCutSceneMusic();
+ if (CGeneral::faststricmp(ms_cutsceneName, "bet"))
+ DMAudio.ChangeMusicMode(MUSICMODE_GAME);
+ }
+ CTimer::Stop();
+ CGame::DrasticTidyUpMemory(TheCamera.GetScreenFadeStatus() == 2);
+ CTimer::Update();
}
-void
-CCutsceneMgr::Update(void)
-{
- enum {
- CUTSCENE_LOADING_0 = 0,
- CUTSCENE_LOADING_AUDIO,
- CUTSCENE_LOADING_2,
- CUTSCENE_LOADING_3,
- CUTSCENE_LOADING_4
- };
-
- switch (ms_cutsceneLoadStatus) {
- case CUTSCENE_LOADING_AUDIO:
- SetupCutsceneToStart();
- if (CGeneral::faststricmp(ms_cutsceneName, "end"))
- DMAudio.PlayPreloadedCutSceneMusic();
- ms_cutsceneLoadStatus++;
- break;
- case CUTSCENE_LOADING_2:
- case CUTSCENE_LOADING_3:
- ms_cutsceneLoadStatus++;
- break;
- case CUTSCENE_LOADING_4:
- ms_cutsceneLoadStatus = CUTSCENE_LOADING_0;
- break;
- default:
- break;
- }
-
- if (!ms_running) return;
-
- ms_cutsceneTimer += CTimer::GetTimeStepNonClipped() * 0.02f;
- if (CGeneral::faststricmp(ms_cutsceneName, "end") && TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FLYBY && ms_cutsceneLoadStatus == CUTSCENE_LOADING_0) {
- if (CPad::GetPad(0)->GetCrossJustDown()
- || (CGame::playingIntro && CPad::GetPad(0)->GetStartJustDown())
- || CPad::GetPad(0)->GetLeftMouseJustDown()
- || CPad::GetPad(0)->GetEnterJustDown()
- || CPad::GetPad(0)->GetCharJustDown(VK_SPACE))
- FinishCutscene();
- }
+void
+CCutsceneMgr::Update(void)
+{
+ enum {
+ CUTSCENE_LOADING_0 = 0,
+ CUTSCENE_LOADING_AUDIO,
+ CUTSCENE_LOADING_2,
+ CUTSCENE_LOADING_3,
+ CUTSCENE_LOADING_4
+ };
+
+ switch (ms_cutsceneLoadStatus) {
+ case CUTSCENE_LOADING_AUDIO:
+ SetupCutsceneToStart();
+ if (CGeneral::faststricmp(ms_cutsceneName, "end"))
+ DMAudio.PlayPreloadedCutSceneMusic();
+ ms_cutsceneLoadStatus++;
+ break;
+ case CUTSCENE_LOADING_2:
+ case CUTSCENE_LOADING_3:
+ ms_cutsceneLoadStatus++;
+ break;
+ case CUTSCENE_LOADING_4:
+ ms_cutsceneLoadStatus = CUTSCENE_LOADING_0;
+ break;
+ default:
+ break;
+ }
+
+ if (!ms_running) return;
+
+ ms_cutsceneTimer += CTimer::GetTimeStepNonClipped() * 0.02f;
+ if (CGeneral::faststricmp(ms_cutsceneName, "end") && TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FLYBY && ms_cutsceneLoadStatus == CUTSCENE_LOADING_0) {
+ if (CPad::GetPad(0)->GetCrossJustDown()
+ || (CGame::playingIntro && CPad::GetPad(0)->GetStartJustDown())
+ || CPad::GetPad(0)->GetLeftMouseJustDown()
+ || CPad::GetPad(0)->GetEnterJustDown()
+ || CPad::GetPad(0)->GetCharJustDown(VK_SPACE))
+ FinishCutscene();
+ }
}
bool CCutsceneMgr::HasCutsceneFinished(void) { return TheCamera.GetPositionAlongSpline() == 1.0f; }
diff --git a/src/core/CutsceneMgr.h b/src/core/CutsceneMgr.h
index 381c71c9..7b809964 100644
--- a/src/core/CutsceneMgr.h
+++ b/src/core/CutsceneMgr.h
@@ -29,6 +29,7 @@ public:
static void SetRunning(bool running) { ms_running = running; }
static bool IsRunning(void) { return ms_running; }
static bool IsCutsceneProcessing(void) { return ms_cutsceneProcessing; }
+ static bool UseLodMultiplier(void) { return ms_useLodMultiplier; }
static CCutsceneObject* GetCutsceneObject(int id) { return ms_pCutsceneObjects[id]; }
static int GetCutsceneTimeInMilleseconds(void) { return 1000.0f * ms_cutsceneTimer; }
static char *GetCutsceneName(void) { return ms_cutsceneName; }
diff --git a/src/core/Debug.cpp b/src/core/Debug.cpp
index b80e9959..2b713198 100644
--- a/src/core/Debug.cpp
+++ b/src/core/Debug.cpp
@@ -1,12 +1,137 @@
+#include "common.h"
#include "Debug.h"
+#include "Font.h"
+#include "main.h"
+#include "Text.h"
-int CDebug::ms_nCurrentTextLine;
+bool gbDebugStuffInRelease = false;
-void CDebug::DebugInitTextBuffer()
+#define DEBUG_X_POS (300)
+#define DEBUG_Y_POS (41)
+#define DEBUG_LINE_HEIGHT (22)
+
+int16 CDebug::ms_nCurrentTextLine;
+char CDebug::ms_aTextBuffer[MAX_LINES][MAX_STR_LEN];
+
+void
+CDebug::DebugInitTextBuffer()
{
ms_nCurrentTextLine = 0;
}
-void CDebug::DebugDisplayTextBuffer()
+void
+CDebug::DebugAddText(const char *str)
+{
+ int32 i = 0;
+ if (*str != '\0') {
+ while (i < MAX_STR_LEN) {
+ ms_aTextBuffer[ms_nCurrentTextLine][i++] = *(str++);
+ if (*str == '\0')
+ break;
+ }
+ }
+
+ ms_aTextBuffer[ms_nCurrentTextLine++][i] = '\0';
+ if (ms_nCurrentTextLine >= MAX_LINES)
+ ms_nCurrentTextLine = 0;
+}
+
+void
+CDebug::DebugDisplayTextBuffer()
+{
+#ifndef MASTER
+ if (gbDebugStuffInRelease)
+ {
+ int32 i = 0;
+ int32 y = DEBUG_Y_POS;
+#ifdef FIX_BUGS
+ CFont::SetPropOn();
+ CFont::SetBackgroundOff();
+ CFont::SetScale(1.0f, 1.0f);
+ CFont::SetCentreOff();
+ CFont::SetRightJustifyOff();
+ CFont::SetJustifyOn();
+ CFont::SetRightJustifyWrap(0.0f);
+ CFont::SetBackGroundOnlyTextOff();
+ CFont::SetFontStyle(FONT_BANK);
+#else
+ // this is not even readable
+ CFont::SetPropOff();
+ CFont::SetBackgroundOff();
+ CFont::SetScale(1.0f, 1.0f);
+ CFont::SetCentreOff();
+ CFont::SetRightJustifyOn();
+ CFont::SetRightJustifyWrap(0.0f);
+ CFont::SetBackGroundOnlyTextOff();
+ CFont::SetFontStyle(FONT_BANK);
+ CFont::SetPropOff();
+#endif
+ do {
+ char *line;
+ while (true) {
+ line = ms_aTextBuffer[(ms_nCurrentTextLine + i++) % MAX_LINES];
+ if (*line != '\0')
+ break;
+ y += DEBUG_LINE_HEIGHT;
+ if (i == MAX_LINES) {
+ CFont::DrawFonts();
+ return;
+ }
+ }
+ AsciiToUnicode(line, gUString);
+ CFont::SetColor(CRGBA(0, 0, 0, 255));
+ CFont::PrintString(DEBUG_X_POS, y-1, gUString);
+ CFont::SetColor(CRGBA(255, 128, 128, 255));
+ CFont::PrintString(DEBUG_X_POS+1, y, gUString);
+ y += DEBUG_LINE_HEIGHT;
+ } while (i != MAX_LINES);
+ CFont::DrawFonts();
+ }
+#endif
+}
+
+
+// custom
+
+CDebug::ScreenStr CDebug::ms_aScreenStrs[MAX_SCREEN_STRS];
+int CDebug::ms_nScreenStrs;
+
+void
+CDebug::DisplayScreenStrings()
+{
+ int i;
+
+
+ CFont::SetPropOn();
+ CFont::SetBackgroundOff();
+ CFont::SetScale(1.0f, 1.0f);
+ CFont::SetCentreOff();
+ CFont::SetRightJustifyOff();
+ CFont::SetJustifyOff();
+ CFont::SetRightJustifyWrap(0.0f);
+ CFont::SetWrapx(9999.0f);
+ CFont::SetBackGroundOnlyTextOff();
+ CFont::SetFontStyle(FONT_BANK);
+
+ for(i = 0; i < ms_nScreenStrs; i++){
+ AsciiToUnicode(ms_aScreenStrs[i].str, gUString);
+ CFont::SetColor(CRGBA(0, 0, 0, 255));
+ CFont::PrintString(ms_aScreenStrs[i].x, ms_aScreenStrs[i].y, gUString);
+ CFont::SetColor(CRGBA(255, 255, 255, 255));
+ CFont::PrintString(ms_aScreenStrs[i].x+1, ms_aScreenStrs[i].y+1, gUString);
+ }
+ CFont::DrawFonts();
+
+ ms_nScreenStrs = 0;
+}
+
+void
+CDebug::PrintAt(const char *str, int x, int y)
{
+ if(ms_nScreenStrs >= MAX_SCREEN_STRS)
+ return;
+ strncpy(ms_aScreenStrs[ms_nScreenStrs].str, str, 256);
+ ms_aScreenStrs[ms_nScreenStrs].x = x*12;
+ ms_aScreenStrs[ms_nScreenStrs].y = y*22;
+ ms_nScreenStrs++;
}
diff --git a/src/core/Debug.h b/src/core/Debug.h
index 395f66af..d169a0b4 100644
--- a/src/core/Debug.h
+++ b/src/core/Debug.h
@@ -2,10 +2,33 @@
class CDebug
{
- static int ms_nCurrentTextLine;
+ enum
+ {
+ MAX_LINES = 15,
+ MAX_STR_LEN = 80,
+
+ MAX_SCREEN_STRS = 100,
+ };
+
+ static int16 ms_nCurrentTextLine;
+ static char ms_aTextBuffer[MAX_LINES][MAX_STR_LEN];
+
+ // custom
+ struct ScreenStr {
+ int x, y;
+ char str[256];
+ };
+ static ScreenStr ms_aScreenStrs[MAX_SCREEN_STRS];
+ static int ms_nScreenStrs;
public:
static void DebugInitTextBuffer();
static void DebugDisplayTextBuffer();
+ static void DebugAddText(const char *str);
+ // custom
+ static void PrintAt(const char *str, int x, int y);
+ static void DisplayScreenStrings();
};
+
+extern bool gbDebugStuffInRelease;
diff --git a/src/core/EventList.cpp b/src/core/EventList.cpp
index caf0cb3f..d1c76f33 100644
--- a/src/core/EventList.cpp
+++ b/src/core/EventList.cpp
@@ -5,10 +5,13 @@
#include "World.h"
#include "Wanted.h"
#include "EventList.h"
+#include "Messages.h"
+#include "Text.h"
+#include "main.h"
int32 CEventList::ms_nFirstFreeSlotIndex;
-//CEvent gaEvent[NUMEVENTS];
-CEvent *gaEvent = (CEvent*)0x6EF830;
+CEvent gaEvent[NUMEVENTS];
+//CEvent *gaEvent = (CEvent*)0x6EF830;
enum
{
@@ -206,7 +209,7 @@ CEventList::ReportCrimeForEvent(eEventType type, int32 crimeId, bool copsDontCar
case EVENT_CAR_SET_ON_FIRE: crime = CRIME_VEHICLE_BURNED; break;
default: crime = CRIME_NONE; break;
}
-
+
if(crime == CRIME_NONE)
return;
diff --git a/src/core/EventList.h b/src/core/EventList.h
index 2799fca4..1c03c9d6 100644
--- a/src/core/EventList.h
+++ b/src/core/EventList.h
@@ -63,4 +63,4 @@ public:
static void ReportCrimeForEvent(eEventType type, int32, bool);
};
-extern CEvent *gaEvent; \ No newline at end of file
+extern CEvent gaEvent[NUMEVENTS]; \ No newline at end of file
diff --git a/src/core/Fire.cpp b/src/core/Fire.cpp
index f83ad2c8..cfa849e9 100644
--- a/src/core/Fire.cpp
+++ b/src/core/Fire.cpp
@@ -1,19 +1,291 @@
#include "common.h"
#include "patcher.h"
+#include "Vector.h"
+#include "PlayerPed.h"
+#include "Entity.h"
+#include "PointLights.h"
+#include "Particle.h"
+#include "Timer.h"
+#include "Vehicle.h"
+#include "Shadows.h"
+#include "Automobile.h"
+#include "World.h"
+#include "General.h"
+#include "EventList.h"
+#include "DamageManager.h"
+#include "Ped.h"
#include "Fire.h"
CFireManager &gFireManager = *(CFireManager*)0x8F31D0;
-WRAPPER void CFire::Extinguish(void) { EAXJMP(0x479D40); }
-WRAPPER void CFireManager::Update(void) { EAXJMP(0x479310); }
-WRAPPER CFire* CFireManager::FindFurthestFire_NeverMindFireMen(CVector coors, float, float) { EAXJMP(0x479430); }
+CFire::CFire()
+{
+ m_bIsOngoing = false;
+ m_bIsScriptFire = false;
+ m_bPropagationFlag = true;
+ m_bAudioSet = true;
+ m_vecPos = CVector(0.0f, 0.0f, 0.0f);
+ m_pEntity = nil;
+ m_pSource = nil;
+ m_nFiremenPuttingOut = 0;
+ m_nExtinguishTime = 0;
+ m_nStartTime = 0;
+ field_20 = 1;
+ m_nNextTimeToAddFlames = 0;
+ m_fStrength = 0.8f;
+}
-uint32 CFireManager::GetTotalActiveFires() const
+CFire::~CFire() {}
+
+void
+CFire::ProcessFire(void)
{
- return m_nTotalFires;
+ float fDamagePlayer;
+ float fDamagePeds;
+ float fDamageVehicle;
+ int8 nRandNumber;
+ float fGreen;
+ float fRed;
+ CVector lightpos;
+ CVector firePos;
+ CPed *ped = (CPed *)m_pEntity;
+ CVehicle *veh = (CVehicle*)m_pEntity;
+
+ if (m_pEntity) {
+ m_vecPos = m_pEntity->GetPosition();
+
+ if (((CPed *)m_pEntity)->IsPed()) {
+ if (ped->m_pFire != this) {
+ Extinguish();
+ return;
+ }
+ if (ped->m_nMoveState != PEDMOVE_RUN)
+ m_vecPos.z -= 1.0f;
+ if (ped->bInVehicle && ped->m_pMyVehicle) {
+ if (ped->m_pMyVehicle->IsCar())
+ ped->m_pMyVehicle->m_fHealth = 75.0f;
+ } else if (m_pEntity == (CPed *)FindPlayerPed()) {
+ fDamagePlayer = 1.2f * CTimer::GetTimeStep();
+
+ ((CPlayerPed *)m_pEntity)->InflictDamage(
+ (CPlayerPed *)m_pSource, WEAPONTYPE_FLAMETHROWER,
+ fDamagePlayer, PEDPIECE_TORSO, 0);
+ } else {
+ fDamagePeds = 1.2f * CTimer::GetTimeStep();
+
+ if (((CPlayerPed *)m_pEntity)->InflictDamage(
+ (CPlayerPed *)m_pSource, WEAPONTYPE_FLAMETHROWER,
+ fDamagePeds, PEDPIECE_TORSO, 0)) {
+ m_pEntity->bRenderScorched = true;
+ }
+ }
+ } else if (m_pEntity->IsVehicle()) {
+ if (veh->m_pCarFire != this) {
+ Extinguish();
+ return;
+ }
+ if (!m_bIsScriptFire) {
+ fDamageVehicle = 1.2f * CTimer::GetTimeStep();
+ veh->InflictDamage((CVehicle *)m_pSource, WEAPONTYPE_FLAMETHROWER, fDamageVehicle);
+ }
+ }
+ }
+ if (!FindPlayerVehicle() && !FindPlayerPed()->m_pFire && !(FindPlayerPed()->bFireProof)
+ && ((FindPlayerPed()->GetPosition() - m_vecPos).MagnitudeSqr() < 2.0f)) {
+ FindPlayerPed()->DoStuffToGoOnFire();
+ gFireManager.StartFire(FindPlayerPed(), m_pSource, 0.8f, 1);
+ }
+ if (CTimer::GetTimeInMilliseconds() > m_nNextTimeToAddFlames) {
+ m_nNextTimeToAddFlames = CTimer::GetTimeInMilliseconds() + 80;
+ firePos = m_vecPos;
+
+ if (veh && veh->IsVehicle() && veh->IsCar()) {
+ CVehicleModelInfo *mi = ((CVehicleModelInfo*)CModelInfo::GetModelInfo(veh->GetModelIndex()));
+ CVector ModelInfo = mi->m_positions[CAR_POS_HEADLIGHTS];
+ ModelInfo = m_pEntity->GetMatrix() * ModelInfo;
+
+ firePos.x = ModelInfo.x;
+ firePos.y = ModelInfo.y;
+ firePos.z = ModelInfo.z + 0.15f;
+ }
+
+ CParticle::AddParticle(PARTICLE_CARFLAME, firePos,
+ CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(0.0125f, 0.1f) * m_fStrength),
+ 0, m_fStrength, 0, 0, 0, 0);
+
+ CGeneral::GetRandomNumber(); CGeneral::GetRandomNumber(); CGeneral::GetRandomNumber(); /* unsure why these three rands are called */
+
+ CParticle::AddParticle(PARTICLE_CARFLAME_SMOKE, firePos,
+ CVector(0.0f, 0.0f, 0.0f), 0, 0.0f, 0, 0, 0, 0);
+ }
+ if (CTimer::GetTimeInMilliseconds() < m_nExtinguishTime || m_bIsScriptFire) {
+ if (CTimer::GetTimeInMilliseconds() > m_nStartTime)
+ m_nStartTime = CTimer::GetTimeInMilliseconds() + 400;
+
+ nRandNumber = CGeneral::GetRandomNumber() & 127;
+ lightpos.x = m_vecPos.x;
+ lightpos.y = m_vecPos.y;
+ lightpos.z = m_vecPos.z + 5.0f;
+
+ if (!m_pEntity) {
+ CShadows::StoreStaticShadow((uint32)this, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &lightpos,
+ 7.0f, 0.0f, 0.0f, -7.0f,
+ 255, // this is 0 on PC which results in no shadow
+ nRandNumber / 2, nRandNumber / 2, 0,
+ 10.0f, 1.0f, 40.0f, 0, 0.0f);
+ }
+ fGreen = nRandNumber / 128;
+ fRed = nRandNumber / 128;
+
+ CPointLights::AddLight(0, m_vecPos, CVector(0.0f, 0.0f, 0.0f),
+ 12.0f, fRed, fGreen, 0, 0, 0);
+ } else {
+ Extinguish();
+ }
}
-CFire* CFireManager::FindNearestFire(CVector vecPos, float* pDistance)
+void
+CFire::ReportThisFire(void)
+{
+ gFireManager.m_nTotalFires++;
+ CEventList::RegisterEvent(EVENT_FIRE, m_vecPos, 1000);
+}
+
+void
+CFire::Extinguish(void)
+{
+ if (m_bIsOngoing) {
+ if (!m_bIsScriptFire)
+ gFireManager.m_nTotalFires--;
+
+ m_nExtinguishTime = 0;
+ m_bIsOngoing = false;
+
+ if (m_pEntity) {
+ if (m_pEntity->IsPed()) {
+ ((CPed *)m_pEntity)->RestorePreviousState();
+ ((CPed *)m_pEntity)->m_pFire = nil;
+ } else if (m_pEntity->IsVehicle()) {
+ ((CVehicle *)m_pEntity)->m_pCarFire = nil;
+ }
+ m_pEntity = nil;
+ }
+ }
+}
+
+void
+CFireManager::StartFire(CVector pos, float size, bool propagation)
+{
+ CFire *fire = GetNextFreeFire();
+
+ if (fire) {
+ fire->m_bIsOngoing = true;
+ fire->m_bIsScriptFire = false;
+ fire->m_bPropagationFlag = propagation;
+ fire->m_bAudioSet = true;
+ fire->m_vecPos = pos;
+ fire->m_nExtinguishTime = CTimer::GetTimeInMilliseconds() + 10000;
+ fire->m_nStartTime = CTimer::GetTimeInMilliseconds() + 400;
+ fire->m_pEntity = nil;
+ fire->m_pSource = nil;
+ fire->m_nNextTimeToAddFlames = 0;
+ fire->ReportThisFire();
+ fire->m_fStrength = size;
+ }
+}
+
+CFire *
+CFireManager::StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength, bool propagation)
+{
+ CPed *ped = (CPed *)entityOnFire;
+ CVehicle *veh = (CVehicle *)entityOnFire;
+
+ if (entityOnFire->IsPed()) {
+ if (ped->m_pFire)
+ return nil;
+ if (!ped->IsPedInControl())
+ return nil;
+ } else if (entityOnFire->IsVehicle()) {
+ if (veh->m_pCarFire)
+ return nil;
+ if (veh->IsCar() && ((CAutomobile *)veh)->Damage.GetEngineStatus() >= 225)
+ return nil;
+ }
+ CFire *fire = GetNextFreeFire();
+
+ if (fire) {
+ if (entityOnFire->IsPed()) {
+ ped->m_pFire = fire;
+ if (ped != FindPlayerPed()) {
+ if (fleeFrom) {
+ ped->SetFlee(fleeFrom, 10000);
+ } else {
+ CVector2D pos = entityOnFire->GetPosition();
+ ped->SetFlee(pos, 10000);
+ ped->m_fleeFrom = nil;
+ }
+ ped->bDrawLast = false;
+ ped->SetMoveState(PEDMOVE_SPRINT);
+ ped->SetMoveAnim();
+ ped->m_nPedState = PED_ON_FIRE;
+ }
+ if (fleeFrom) {
+ if (ped->m_nPedType == PEDTYPE_COP) {
+ CEventList::RegisterEvent(EVENT_COP_SET_ON_FIRE, EVENT_ENTITY_PED,
+ entityOnFire, (CPed *)fleeFrom, 10000);
+ } else {
+ CEventList::RegisterEvent(EVENT_PED_SET_ON_FIRE, EVENT_ENTITY_PED,
+ entityOnFire, (CPed *)fleeFrom, 10000);
+ }
+ }
+ } else {
+ if (entityOnFire->IsVehicle()) {
+ veh->m_pCarFire = fire;
+ if (fleeFrom) {
+ CEventList::RegisterEvent(EVENT_CAR_SET_ON_FIRE, EVENT_ENTITY_VEHICLE,
+ entityOnFire, (CPed *)fleeFrom, 10000);
+ }
+ }
+ }
+
+ fire->m_bIsOngoing = true;
+ fire->m_bIsScriptFire = false;
+ fire->m_vecPos = entityOnFire->GetPosition();
+
+ if (entityOnFire && entityOnFire->IsPed() && ped->IsPlayer()) {
+ fire->m_nExtinguishTime = CTimer::GetTimeInMilliseconds() + 3333;
+ } else if (entityOnFire->IsVehicle()) {
+ fire->m_nExtinguishTime = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(4000, 5000);
+ } else {
+ fire->m_nExtinguishTime = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(10000, 11000);
+ }
+ fire->m_nStartTime = CTimer::GetTimeInMilliseconds() + 400;
+ fire->m_pEntity = entityOnFire;
+
+ entityOnFire->RegisterReference(&fire->m_pEntity);
+ fire->m_pSource = fleeFrom;
+
+ if (fleeFrom)
+ fleeFrom->RegisterReference(&fire->m_pSource);
+ fire->ReportThisFire();
+ fire->m_nNextTimeToAddFlames = 0;
+ fire->m_fStrength = strength;
+ fire->m_bPropagationFlag = propagation;
+ fire->m_bAudioSet = true;
+ }
+ return fire;
+}
+
+void
+CFireManager::Update(void)
+{
+ for (int i = 0; i < NUM_FIRES; i++) {
+ if (m_aFires[i].m_bIsOngoing)
+ m_aFires[i].ProcessFire();
+ }
+}
+
+CFire* CFireManager::FindNearestFire(CVector vecPos, float *pDistance)
{
for (int i = 0; i < MAX_FIREMEN_ATTENDING; i++) {
int fireId = -1;
@@ -38,6 +310,44 @@ CFire* CFireManager::FindNearestFire(CVector vecPos, float* pDistance)
return nil;
}
+CFire *
+CFireManager::FindFurthestFire_NeverMindFireMen(CVector coords, float minRange, float maxRange)
+{
+ int furthestFire = -1;
+ float lastFireDist = 0.0f;
+ float fireDist;
+
+ for (int i = 0; i < NUM_FIRES; i++) {
+ if (m_aFires[i].m_bIsOngoing && !m_aFires[i].m_bIsScriptFire) {
+ fireDist = (m_aFires[i].m_vecPos - coords).Magnitude2D();
+ if (fireDist > minRange && fireDist < maxRange && fireDist > lastFireDist) {
+ lastFireDist = fireDist;
+ furthestFire = i;
+ }
+ }
+ }
+ if (furthestFire == -1)
+ return nil;
+ else
+ return &m_aFires[furthestFire];
+}
+
+CFire *
+CFireManager::GetNextFreeFire(void)
+{
+ for (int i = 0; i < NUM_FIRES; i++) {
+ if (!m_aFires[i].m_bIsOngoing && !m_aFires[i].m_bIsScriptFire)
+ return &m_aFires[i];
+ }
+ return nil;
+}
+
+uint32
+CFireManager::GetTotalActiveFires(void) const
+{
+ return m_nTotalFires;
+}
+
void
CFireManager::ExtinguishPoint(CVector point, float range)
{
@@ -49,16 +359,100 @@ CFireManager::ExtinguishPoint(CVector point, float range)
}
}
-WRAPPER void CFireManager::StartFire(CEntity *entityOnFire, CEntity *culprit, float, uint32) { EAXJMP(0x479590); }
-WRAPPER void CFireManager::StartFire(CVector, float, uint8) { EAXJMP(0x479500); }
-WRAPPER int32 CFireManager::StartScriptFire(const CVector& pos, CEntity* culprit, float, uint8) { EAXJMP(0x479E60); }
-WRAPPER bool CFireManager::IsScriptFireExtinguish(int16) { EAXJMP(0x479FC0); }
-WRAPPER void CFireManager::RemoveScriptFire(int16) { EAXJMP(0x479FE0); }
-WRAPPER void CFireManager::RemoveAllScriptFires(void) { EAXJMP(0x47A000); }
-WRAPPER void CFireManager::SetScriptFireAudio(int16, bool) { EAXJMP(0x47A040); }
+int32
+CFireManager::StartScriptFire(const CVector &pos, CEntity *target, float strength, bool propagation)
+{
+ CFire *fire;
+ CPed *ped = (CPed *)target;
+ CVehicle *veh = (CVehicle *)target;
+
+ if (target) {
+ if (target->IsPed()) {
+ if (ped->m_pFire)
+ ped->m_pFire->Extinguish();
+ } else if (target->IsVehicle()) {
+ if (veh->m_pCarFire)
+ veh->m_pCarFire->Extinguish();
+ if (veh->IsCar() && ((CAutomobile *)veh)->Damage.GetEngineStatus() >= 225) {
+ ((CAutomobile *)veh)->Damage.SetEngineStatus(215);
+ }
+ }
+ }
+
+ fire = GetNextFreeFire();
+ fire->m_bIsOngoing = true;
+ fire->m_bIsScriptFire = true;
+ fire->m_bPropagationFlag = propagation;
+ fire->m_bAudioSet = true;
+ fire->m_vecPos = pos;
+ fire->m_nStartTime = CTimer::GetTimeInMilliseconds() + 400;
+ fire->m_pEntity = target;
+
+ if (target)
+ target->RegisterReference(&fire->m_pEntity);
+ fire->m_pSource = nil;
+ fire->m_nNextTimeToAddFlames = 0;
+ fire->m_fStrength = strength;
+ if (target) {
+ if (target->IsPed()) {
+ ped->m_pFire = fire;
+ if (target != (CVehicle *)FindPlayerPed()) {
+ CVector2D pos = target->GetPosition();
+ ped->SetFlee(pos, 10000);
+ ped->SetMoveAnim();
+ ped->m_nPedState = PED_ON_FIRE;
+ }
+ } else if (target->IsVehicle()) {
+ veh->m_pCarFire = fire;
+ }
+ }
+ return fire - m_aFires;
+}
+
+bool
+CFireManager::IsScriptFireExtinguish(int16 index)
+{
+ return !m_aFires[index].m_bIsOngoing;
+}
+
+void
+CFireManager::RemoveAllScriptFires(void)
+{
+ for (int i = 0; i < NUM_FIRES; i++) {
+ if (m_aFires[i].m_bIsScriptFire) {
+ m_aFires[i].Extinguish();
+ m_aFires[i].m_bIsScriptFire = false;
+ }
+ }
+}
+
+void
+CFireManager::RemoveScriptFire(int16 index)
+{
+ m_aFires[index].Extinguish();
+ m_aFires[index].m_bIsScriptFire = false;
+}
+
+void
+CFireManager::SetScriptFireAudio(int16 index, bool state)
+{
+ m_aFires[index].m_bAudioSet = state;
+}
STARTPATCHES
- InjectHook(0x479DB0, &CFireManager::ExtinguishPoint, PATCH_JUMP);
+ InjectHook(0x4798D0, &CFire::ProcessFire, PATCH_JUMP);
+ InjectHook(0x4798B0, &CFire::ReportThisFire, PATCH_JUMP);
+ InjectHook(0x479D40, &CFire::Extinguish, PATCH_JUMP);
+ InjectHook(0x479500, (void(CFireManager::*)(CVector pos, float size, bool propagation))&CFireManager::StartFire, PATCH_JUMP);
+ InjectHook(0x479590, (CFire *(CFireManager::*)(CEntity *, CEntity *, float, bool))&CFireManager::StartFire, PATCH_JUMP);
+ InjectHook(0x479310, &CFireManager::Update, PATCH_JUMP);
+ InjectHook(0x479430, &CFireManager::FindFurthestFire_NeverMindFireMen, PATCH_JUMP);
InjectHook(0x479340, &CFireManager::FindNearestFire, PATCH_JUMP);
+ InjectHook(0x4792E0, &CFireManager::GetNextFreeFire, PATCH_JUMP);
+ InjectHook(0x479DB0, &CFireManager::ExtinguishPoint, PATCH_JUMP);
+ InjectHook(0x479E60, &CFireManager::StartScriptFire, PATCH_JUMP);
+ InjectHook(0x479FC0, &CFireManager::IsScriptFireExtinguish, PATCH_JUMP);
+ InjectHook(0x47A000, &CFireManager::RemoveAllScriptFires, PATCH_JUMP);
+ InjectHook(0x479FE0, &CFireManager::RemoveScriptFire, PATCH_JUMP);
+ InjectHook(0x47A040, &CFireManager::SetScriptFireAudio, PATCH_JUMP);
ENDPATCHES
-
diff --git a/src/core/Fire.h b/src/core/Fire.h
index 624bf608..a4599d11 100644
--- a/src/core/Fire.h
+++ b/src/core/Fire.h
@@ -7,18 +7,22 @@ class CFire
public:
bool m_bIsOngoing;
bool m_bIsScriptFire;
- bool m_bPropogationFlag;
+ bool m_bPropagationFlag;
bool m_bAudioSet;
CVector m_vecPos;
CEntity *m_pEntity;
CEntity *m_pSource;
- int m_nExtinguishTime;
- int m_nStartTime;
- int field_20;
- int field_24;
+ uint32 m_nExtinguishTime;
+ uint32 m_nStartTime;
+ int32 field_20;
+ uint32 m_nNextTimeToAddFlames;
uint32 m_nFiremenPuttingOut;
- float field_2C;
+ float m_fStrength;
+ CFire();
+ ~CFire();
+ void ProcessFire(void);
+ void ReportThisFire(void);
void Extinguish(void);
};
@@ -27,20 +31,21 @@ class CFireManager
enum {
MAX_FIREMEN_ATTENDING = 2,
};
- uint32 m_nTotalFires;
public:
+ uint32 m_nTotalFires;
CFire m_aFires[NUM_FIRES];
- void StartFire(CEntity *entityOnFire, CEntity *culprit, float, uint32);
- void StartFire(CVector, float, uint8);
+ void StartFire(CVector pos, float size, bool propagation);
+ CFire *StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength, bool propagation);
void Update(void);
- CFire *FindFurthestFire_NeverMindFireMen(CVector coors, float, float);
- CFire *FindNearestFire(CVector, float*);
+ CFire *FindFurthestFire_NeverMindFireMen(CVector coords, float minRange, float maxRange);
+ CFire *FindNearestFire(CVector vecPos, float *pDistance);
+ CFire *GetNextFreeFire(void);
uint32 GetTotalActiveFires() const;
- void ExtinguishPoint(CVector, float);
- int32 StartScriptFire(const CVector& pos, CEntity* culprit, float, uint8);
- bool IsScriptFireExtinguish(int16);
- void RemoveScriptFire(int16);
+ void ExtinguishPoint(CVector point, float range);
+ int32 StartScriptFire(const CVector &pos, CEntity *target, float strength, bool propagation);
+ bool IsScriptFireExtinguish(int16 index);
void RemoveAllScriptFires(void);
- void SetScriptFireAudio(int16, bool);
+ void RemoveScriptFire(int16 index);
+ void SetScriptFireAudio(int16 index, bool state);
};
extern CFireManager &gFireManager;
diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp
index 4c2f3afa..61fe96ea 100644
--- a/src/core/Frontend.cpp
+++ b/src/core/Frontend.cpp
@@ -64,7 +64,6 @@ bool &CMenuManager::m_bShutDownFrontEndRequested = *(bool*)0x95CD6A;
int8 &CMenuManager::m_PrefsUseWideScreen = *(int8*)0x95CD23;
int8 &CMenuManager::m_PrefsRadioStation = *(int8*)0x95CDA4;
-int8 &CMenuManager::m_bDisableMouseSteering = *(int8*)0x60252C; // 1
int32 &CMenuManager::m_PrefsBrightness = *(int32*)0x5F2E50; // 256
float &CMenuManager::m_PrefsLOD = *(float*)0x8F42C4;
int8 &CMenuManager::m_bFrontEnd_ReloadObrTxtGxt = *(int8*)0x628CFC;
@@ -94,10 +93,14 @@ int32 *&pControlEdit = *(int32**)0x628D08;
bool &DisplayComboButtonErrMsg = *(bool*)0x628D14;
int32 &MouseButtonJustClicked = *(int32*)0x628D0C;
int32 &JoyButtonJustClicked = *(int32*)0x628D10;
-uint32 &nTimeForSomething = *(uint32*)0x628D54;
bool &holdingScrollBar = *(bool*)0x628D59;
//int32 *pControlTemp = 0;
+#ifndef MASTER
+bool CMenuManager::m_PrefsMarketing = false;
+bool CMenuManager::m_PrefsDisableTutorials = false;
+#endif // !MASTER
+
// 0x5F311C
const char* FrontendFilenames[][2] = {
{"fe2_mainpanel_ul", "" },
@@ -181,6 +184,7 @@ ScaleAndCenterX(float x)
#endif
#define isPlainTextScreen(screen) (screen == MENUPAGE_BRIEFS || screen == MENUPAGE_STATS)
+
#ifdef PS2_LIKE_MENU
#define ChangeScreen(screen, option, updateDelay, withReverseAlpha) \
do { \
@@ -235,67 +239,100 @@ ScaleAndCenterX(float x)
m_nHoverOption = HOVEROPTION_NOT_HOVERING; \
} while(0)
-#define ScrollUpListByOne() \
- do { \
- if (m_nSelectedListRow == m_nFirstVisibleRowOnList) { \
- if (m_nFirstVisibleRowOnList > 0) { \
- m_nSelectedListRow--; \
- m_nFirstVisibleRowOnList--; \
- m_nCurListItemY -= LIST_HEIGHT / m_nTotalListRow; \
- } \
- } else { \
- m_nSelectedListRow--; \
- } \
- } while(0)
+// --- Functions not in the game/inlined starts
-#define ScrollDownListByOne() \
- do { \
- if (m_nSelectedListRow == m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1) { \
- if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) { \
- m_nSelectedListRow++; \
- m_nFirstVisibleRowOnList++; \
- m_nCurListItemY += LIST_HEIGHT / m_nTotalListRow; \
- } \
- } else { \
- if (m_nSelectedListRow < m_nTotalListRow - 1) { \
- m_nSelectedListRow++; \
- } \
- } \
- } while(0)
+inline void
+CMenuManager::ScrollUpListByOne()
+{
+ if (m_nSelectedListRow == m_nFirstVisibleRowOnList) {
+ if (m_nFirstVisibleRowOnList > 0) {
+ m_nSelectedListRow--;
+ m_nFirstVisibleRowOnList--;
+ m_nCurListItemY -= LIST_HEIGHT / m_nTotalListRow;
+ }
+ } else {
+ m_nSelectedListRow--;
+ }
+}
-#define PageUpList(playSoundOnSuccess) \
- do { \
- if (m_nTotalListRow > MAX_VISIBLE_LIST_ROW) { \
- if (m_nFirstVisibleRowOnList > 0) { \
- if(playSoundOnSuccess) \
- DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); \
- \
- m_nFirstVisibleRowOnList = max(0, m_nFirstVisibleRowOnList - MAX_VISIBLE_LIST_ROW); \
- m_nSelectedListRow = min(m_nSelectedListRow, m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1); \
- } else { \
- m_nFirstVisibleRowOnList = 0; \
- m_nSelectedListRow = 0; \
- } \
- m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList; \
- } \
- } while(0)
+inline void
+CMenuManager::ScrollDownListByOne()
+{
+ if (m_nSelectedListRow == m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1) {
+ if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) {
+ m_nSelectedListRow++;
+ m_nFirstVisibleRowOnList++;
+ m_nCurListItemY += LIST_HEIGHT / m_nTotalListRow;
+ }
+ } else {
+ if (m_nSelectedListRow < m_nTotalListRow - 1) {
+ m_nSelectedListRow++;
+ }
+ }
+}
-#define PageDownList(playSoundOnSuccess) \
- do { \
- if (m_nTotalListRow > MAX_VISIBLE_LIST_ROW) { \
- if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) { \
- if(playSoundOnSuccess) \
- DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); \
- \
- m_nFirstVisibleRowOnList = min(m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW, m_nTotalListRow - MAX_VISIBLE_LIST_ROW); \
- m_nSelectedListRow = max(m_nSelectedListRow, m_nFirstVisibleRowOnList); \
- } else { \
- m_nFirstVisibleRowOnList = m_nTotalListRow - MAX_VISIBLE_LIST_ROW; \
- m_nSelectedListRow = m_nTotalListRow - 1; \
- } \
- m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList; \
- } \
- } while(0)
+inline void
+CMenuManager::PageUpList(bool playSoundOnSuccess)
+{
+ if (m_nTotalListRow > MAX_VISIBLE_LIST_ROW) {
+ if (m_nFirstVisibleRowOnList > 0) {
+ if(playSoundOnSuccess)
+ DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
+
+ m_nFirstVisibleRowOnList = max(0, m_nFirstVisibleRowOnList - MAX_VISIBLE_LIST_ROW);
+ m_nSelectedListRow = min(m_nSelectedListRow, m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1);
+ } else {
+ m_nFirstVisibleRowOnList = 0;
+ m_nSelectedListRow = 0;
+ }
+ m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList;
+ }
+}
+
+inline void
+CMenuManager::PageDownList(bool playSoundOnSuccess)
+{
+ if (m_nTotalListRow > MAX_VISIBLE_LIST_ROW) {
+ if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) {
+ if(playSoundOnSuccess)
+ DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
+
+ m_nFirstVisibleRowOnList = min(m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW, m_nTotalListRow - MAX_VISIBLE_LIST_ROW);
+ m_nSelectedListRow = max(m_nSelectedListRow, m_nFirstVisibleRowOnList);
+ } else {
+ m_nFirstVisibleRowOnList = m_nTotalListRow - MAX_VISIBLE_LIST_ROW;
+ m_nSelectedListRow = m_nTotalListRow - 1;
+ }
+ m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList;
+ }
+}
+
+inline void
+CMenuManager::ThingsToDoBeforeLeavingPage()
+{
+ if ((m_nCurrScreen == MENUPAGE_SKIN_SELECT) && strcmp(m_aSkinName, m_PrefsSkinFile) != 0) {
+ CWorld::Players[0].SetPlayerSkin(m_PrefsSkinFile);
+ } else if (m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) {
+ if (m_nPrefsAudio3DProviderIndex != -1)
+ m_nPrefsAudio3DProviderIndex = DMAudio.GetCurrent3DProviderIndex();
+#ifdef TIDY_UP_PBP
+ DMAudio.StopFrontEndTrack();
+ OutputDebugString("FRONTEND AUDIO TRACK STOPPED");
+#endif
+ } else if (m_nCurrScreen == MENUPAGE_GRAPHICS_SETTINGS) {
+ m_nDisplayVideoMode = m_nPrefsVideoMode;
+ }
+
+ if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) {
+ CPlayerSkin::EndFrontendSkinEdit();
+ }
+
+ if ((m_nCurrScreen == MENUPAGE_SKIN_SELECT) || (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS)) {
+ m_nTotalListRow = 0;
+ }
+}
+
+// ------ Functions not in the game/inlined ends
void
CMenuManager::BuildStatLine(char *text, void *stat, uint8 aFloat, void *stat2)
@@ -492,7 +529,7 @@ WRAPPER void CMenuManager::DoSettingsBeforeStartingAGame() { EAXJMP(0x48AB40); }
#else
void CMenuManager::DoSettingsBeforeStartingAGame()
{
- CCamera::m_bUseMouse3rdPerson = m_ControlMethod == CONTROL_STANDART;
+ CCamera::m_bUseMouse3rdPerson = m_ControlMethod == CONTROL_STANDARD;
if (m_PrefsVsyncDisp != m_PrefsVsync)
m_PrefsVsync = m_PrefsVsyncDisp;
@@ -935,7 +972,7 @@ void CMenuManager::Draw()
rightText = TheText.Get(m_PrefsDMA ? "FEM_ON" : "FEM_OFF");
break;
case MENUACTION_MOUSESTEER:
- rightText = TheText.Get(m_bDisableMouseSteering ? "FEM_OFF" : "FEM_ON");
+ rightText = TheText.Get(CVehicle::m_bDisableMouseSteering ? "FEM_OFF" : "FEM_ON");
break;
}
@@ -1173,7 +1210,6 @@ void CMenuManager::DrawFrontEnd()
bbNames[5] = { "FESZ_QU",MENUPAGE_EXIT };
bbTabCount = 6;
}
- m_nCurrScreen = MENUPAGE_NEW_GAME;
} else {
if (bbTabCount != 8) {
bbNames[0] = { "FEB_STA",MENUPAGE_STATS };
@@ -1186,8 +1222,8 @@ void CMenuManager::DrawFrontEnd()
bbNames[7] = { "FESZ_QU",MENUPAGE_EXIT };
bbTabCount = 8;
}
- m_nCurrScreen = MENUPAGE_STATS;
}
+ m_nCurrScreen = bbNames[0].screenId;
bottomBarActive = true;
curBottomBarOption = 0;
}
@@ -1285,7 +1321,6 @@ void CMenuManager::DrawFrontEndNormal()
eFrontendSprites currentSprite;
switch (m_nCurrScreen) {
case MENUPAGE_STATS:
- case MENUPAGE_NEW_GAME:
case MENUPAGE_START_MENU:
case MENUPAGE_PAUSE_MENU:
case MENUPAGE_EXIT:
@@ -1315,7 +1350,7 @@ void CMenuManager::DrawFrontEndNormal()
currentSprite = FE_ICONCONTROLS;
break;
default:
- /* actually MENUPAGE_NEW_GAME too*/
+ /*case MENUPAGE_NEW_GAME: */
/*case MENUPAGE_BRIEFS: */
currentSprite = FE_ICONBRIEF;
break;
@@ -1323,23 +1358,39 @@ void CMenuManager::DrawFrontEndNormal()
m_aFrontEndSprites[currentSprite].Draw(CRect(MENU_X_LEFT_ALIGNED(50.0f), MENU_Y(50.0f), MENU_X_RIGHT_ALIGNED(50.0f), SCREEN_SCALE_FROM_BOTTOM(95.0f)), CRGBA(255, 255, 255, m_nMenuFadeAlpha > 255 ? 255 : m_nMenuFadeAlpha));
+ static float fadeAlpha = 0.0f;
+ static int lastState = 0;
+
+ // reverseAlpha = PS2 fading (wait for 255->0, then change screen)
if (m_nMenuFadeAlpha < 255) {
- static int LastFade = 0;
+ if (lastState == 1 && !reverseAlpha)
+ fadeAlpha = 0.f;
if (m_nMenuFadeAlpha <= 0 && reverseAlpha) {
reverseAlpha = false;
ChangeScreen(pendingScreen, pendingOption, true, false);
- } else if(CTimer::GetTimeInMillisecondsPauseMode() - LastFade > 10){
+ } else {
+ float timestep = CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerMillisecond();
+
+ // +20 per every 33 ms (1000.f/30.f - original frame limiter fps)
if (!reverseAlpha)
- m_nMenuFadeAlpha += 20;
+ fadeAlpha += (timestep * 100.f) * 20.f / 33.f;
else
- m_nMenuFadeAlpha = max(m_nMenuFadeAlpha - 30, 0);
+ fadeAlpha = max(0.0f, fadeAlpha - (timestep * 100.f) * 30.f / 33.f);
- LastFade = CTimer::GetTimeInMillisecondsPauseMode();
+ m_nMenuFadeAlpha = fadeAlpha;
}
+ lastState = 0;
} else {
- if (reverseAlpha)
- m_nMenuFadeAlpha -= 20;
+ if (lastState == 0) fadeAlpha = 255.f;
+
+ if (reverseAlpha) {
+ float timestep = CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerMillisecond();
+ fadeAlpha -= (timestep * 100.f) * 30.f / 33.f;
+
+ m_nMenuFadeAlpha = fadeAlpha;
+ }
+ lastState = 1;
// TODO: what is this? waiting mouse?
if(field_518 == 4){
@@ -1537,12 +1588,25 @@ void CMenuManager::DrawFrontEndNormal()
}
if (m_nMenuFadeAlpha < 255) {
- static int LastFade = 0;
+
+ // Famous transparent menu bug
+#ifdef FIX_BUGS
+ static float fadeAlpha = 0.0f;
+ if (m_nMenuFadeAlpha == 0 && fadeAlpha > 1.0f) fadeAlpha = 0.0f;
+
+ float timestep = CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerMillisecond();
+
+ // +20 per every 33 ms (1000.f/30.f - original frame limiter fps)
+ fadeAlpha += (timestep * 100.f) * 20.f / 33.f;
+ m_nMenuFadeAlpha = fadeAlpha;
+#else
+ static uint32 LastFade = 0;
if(CTimer::GetTimeInMillisecondsPauseMode() - LastFade > 10){
m_nMenuFadeAlpha += 20;
LastFade = CTimer::GetTimeInMillisecondsPauseMode();
}
+#endif
if (m_nMenuFadeAlpha > 255){
m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255));
@@ -1657,9 +1721,6 @@ int CMenuManager::GetStartOptionsCntrlConfigScreens()
}
#endif
-#if DONT_USE_SUSPICIOUS_FUNCS
-WRAPPER void CMenuManager::InitialiseChangedLanguageSettings() { EAXJMP(0x47A4D0); }
-#else
void CMenuManager::InitialiseChangedLanguageSettings()
{
if (m_bFrontEnd_ReloadObrTxtGxt) {
@@ -1670,6 +1731,17 @@ void CMenuManager::InitialiseChangedLanguageSettings()
CTimer::Update();
CGame::frenchGame = false;
CGame::germanGame = false;
+#ifdef MORE_LANGUAGES
+ switch (CMenuManager::m_PrefsLanguage) {
+ case LANGUAGE_RUSSIAN:
+ CFont::ReloadFonts(FONT_LANGSET_RUSSIAN);
+ break;
+ default:
+ CFont::ReloadFonts(FONT_LANGSET_EFIGS);
+ break;
+ }
+#endif
+
switch (CMenuManager::m_PrefsLanguage) {
case LANGUAGE_FRENCH:
CGame::frenchGame = true;
@@ -1677,12 +1749,16 @@ void CMenuManager::InitialiseChangedLanguageSettings()
case LANGUAGE_GERMAN:
CGame::germanGame = true;
break;
+#ifdef MORE_LANGUAGES
+ case LANGUAGE_RUSSIAN:
+ CGame::russianGame = true;
+ break;
+#endif
default:
break;
}
}
}
-#endif
void CMenuManager::LoadAllTextures()
{
@@ -1950,7 +2026,7 @@ WRAPPER void CMenuManager::Process(void) { EAXJMP(0x485100); }
#else
void CMenuManager::Process(void)
{
- m_bMenuNotProcessed = false;
+ m_bMenuStateChanged = false;
if (!m_bSaveMenuActive && TheCamera.GetScreenFadeStatus() != FADE_0)
return;
@@ -1993,7 +2069,7 @@ void CMenuManager::Process(void)
}
if (m_nCurrScreen == MENUPAGE_LOADING_IN_PROGRESS) {
if (CheckSlotDataValid(m_nCurrSaveSlot)) {
- TheCamera.m_bUseMouse3rdPerson = m_ControlMethod == CONTROL_STANDART;
+ TheCamera.m_bUseMouse3rdPerson = m_ControlMethod == CONTROL_STANDARD;
if (m_PrefsVsyncDisp != m_PrefsVsync)
m_PrefsVsync = m_PrefsVsyncDisp;
DMAudio.Service();
@@ -2164,15 +2240,15 @@ CMenuManager::ProcessButtonPresses(void)
field_535 = false;
}
- static int nTimeForSomething = 0;
+ static uint32 lastTimeClickedScrollButton = 0;
- if (CTimer::GetTimeInMillisecondsPauseMode() - nTimeForSomething >= 200) {
+ if (CTimer::GetTimeInMillisecondsPauseMode() - lastTimeClickedScrollButton >= 200) {
m_bPressedPgUpOnList = false;
m_bPressedPgDnOnList = false;
m_bPressedUpOnList = false;
m_bPressedDownOnList = false;
m_bPressedScrollButton = false;
- nTimeForSomething = CTimer::GetTimeInMillisecondsPauseMode();
+ lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode();
}
if (CPad::GetPad(0)->GetTabJustDown()) {
@@ -2211,7 +2287,7 @@ CMenuManager::ProcessButtonPresses(void)
m_nCurrExLayer = 19;
if (!m_bPressedUpOnList) {
m_bPressedUpOnList = true;
- nTimeForSomething = CTimer::GetTimeInMillisecondsPauseMode();
+ lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode();
DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
ScrollUpListByOne();
}
@@ -2233,7 +2309,7 @@ CMenuManager::ProcessButtonPresses(void)
m_nCurrExLayer = 19;
if (!m_bPressedDownOnList) {
m_bPressedDownOnList = true;
- nTimeForSomething = CTimer::GetTimeInMillisecondsPauseMode();
+ lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode();
DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
ScrollDownListByOne();
}
@@ -2248,7 +2324,7 @@ CMenuManager::ProcessButtonPresses(void)
m_nCurrExLayer = 19;
if (!m_bPressedPgUpOnList) {
m_bPressedPgUpOnList = true;
- nTimeForSomething = CTimer::GetTimeInMillisecondsPauseMode();
+ lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode();
m_bShowMouse = false;
DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
PageUpList(false);
@@ -2260,7 +2336,7 @@ CMenuManager::ProcessButtonPresses(void)
m_nCurrExLayer = 19;
if (!m_bPressedPgDnOnList) {
m_bPressedPgDnOnList = true;
- nTimeForSomething = CTimer::GetTimeInMillisecondsPauseMode();
+ lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode();
m_bShowMouse = false;
DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
PageDownList(false);
@@ -2346,7 +2422,7 @@ CMenuManager::ProcessButtonPresses(void)
case HOVEROPTION_CLICKED_SCROLL_UP:
if (!m_bPressedScrollButton) {
m_bPressedScrollButton = true;
- nTimeForSomething = CTimer::GetTimeInMillisecondsPauseMode();
+ lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode();
ScrollUpListByOne();
}
break;
@@ -2354,7 +2430,7 @@ CMenuManager::ProcessButtonPresses(void)
case HOVEROPTION_CLICKED_SCROLL_DOWN:
if (!m_bPressedScrollButton) {
m_bPressedScrollButton = true;
- nTimeForSomething = CTimer::GetTimeInMillisecondsPauseMode();
+ lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode();
ScrollDownListByOne();
}
break;
@@ -2701,6 +2777,8 @@ CMenuManager::ProcessButtonPresses(void)
if (CPad::GetPad(0)->GetEnterJustDown() || CPad::GetPad(0)->GetCrossJustDown()) {
DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
bottomBarActive = false;
+
+ // If there's a menu change with fade ongoing, finish it now
if (reverseAlpha)
m_nMenuFadeAlpha = 0;
return;
@@ -2877,6 +2955,14 @@ CMenuManager::ProcessButtonPresses(void)
CMenuManager::InitialiseChangedLanguageSettings();
SaveSettings();
break;
+#ifdef MORE_LANGUAGES
+ case MENUACTION_LANG_RUS:
+ m_PrefsLanguage = LANGUAGE_RUSSIAN;
+ m_bFrontEnd_ReloadObrTxtGxt = true;
+ CMenuManager::InitialiseChangedLanguageSettings();
+ SaveSettings();
+ break;
+#endif
case MENUACTION_POPULATESLOTS_CHANGEMENU:
PcSaveHelper.PopulateSlotInfo();
@@ -3080,10 +3166,10 @@ CMenuManager::ProcessButtonPresses(void)
PSGLOBAL(joy1)->GetCapabilities(&devCaps);
ControlsManager.InitDefaultControlConfigJoyPad(devCaps.dwButtons);
}
- CMenuManager::m_ControlMethod = CONTROL_STANDART;
+ CMenuManager::m_ControlMethod = CONTROL_STANDARD;
MousePointerStateHelper.bInvertVertically = false;
TheCamera.m_fMouseAccelHorzntl = 0.0025f;
- m_bDisableMouseSteering = true;
+ CVehicle::m_bDisableMouseSteering = true;
TheCamera.m_bHeadBob = false;
SaveSettings();
}
@@ -3093,7 +3179,7 @@ CMenuManager::ProcessButtonPresses(void)
#ifndef TIDY_UP_PBP
if (CMenuManager::m_ControlMethod == CONTROL_CLASSIC) {
CCamera::m_bUseMouse3rdPerson = true;
- CMenuManager::m_ControlMethod = CONTROL_STANDART;
+ CMenuManager::m_ControlMethod = CONTROL_STANDARD;
} else {
CCamera::m_bUseMouse3rdPerson = false;
CMenuManager::m_ControlMethod = CONTROL_CLASSIC;
@@ -3116,51 +3202,43 @@ CMenuManager::ProcessButtonPresses(void)
if (goBack) {
CMenuManager::ResetHelperText();
DMAudio.PlayFrontEndSound(SOUND_FRONTEND_EXIT, 0);
- if (m_nCurrScreen == MENUPAGE_PAUSE_MENU && !m_bGameNotLoaded && !m_bMenuNotProcessed){
- if (CMenuManager::m_PrefsVsyncDisp != CMenuManager::m_PrefsVsync) {
- CMenuManager::m_PrefsVsync = CMenuManager::m_PrefsVsyncDisp;
- }
- CMenuManager::RequestFrontEndShutDown();
- } else if (m_nCurrScreen == MENUPAGE_CHOOSE_SAVE_SLOT
-#ifdef PS2_SAVE_DIALOG
- || m_nCurrScreen == MENUPAGE_SAVE
-#endif
- ) {
- CMenuManager::RequestFrontEndShutDown();
- } else if (m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) {
- DMAudio.StopFrontEndTrack();
- OutputDebugString("FRONTEND AUDIO TRACK STOPPED");
- }
-
- int oldScreen = !m_bGameNotLoaded ? aScreens[m_nCurrScreen].m_PreviousPage[1] : aScreens[m_nCurrScreen].m_PreviousPage[0];
- int oldOption = !m_bGameNotLoaded ? aScreens[m_nCurrScreen].m_ParentEntry[1] : aScreens[m_nCurrScreen].m_ParentEntry[0];
-
#ifdef PS2_LIKE_MENU
- if (bottomBarActive){
- bottomBarActive = false;
- if (!m_bGameNotLoaded) {
+ if (m_nCurrScreen == MENUPAGE_PAUSE_MENU || bottomBarActive) {
+#else
+ if (m_nCurrScreen == MENUPAGE_PAUSE_MENU) {
+#endif
+ if (!m_bGameNotLoaded && !m_bMenuStateChanged) {
if (CMenuManager::m_PrefsVsyncDisp != CMenuManager::m_PrefsVsync) {
CMenuManager::m_PrefsVsync = CMenuManager::m_PrefsVsyncDisp;
}
CMenuManager::RequestFrontEndShutDown();
}
+
+ // We're already resuming, we don't need further processing.
+#if defined(FIX_BUGS) || defined(PS2_LIKE_MENU)
return;
+#endif
+ }
+#ifdef PS2_LIKE_MENU
+ else if (m_nCurrScreen == MENUPAGE_CHOOSE_SAVE_SLOT || m_nCurrScreen == MENUPAGE_SAVE) {
+#else
+ else if (m_nCurrScreen == MENUPAGE_CHOOSE_SAVE_SLOT) {
+#endif
+ CMenuManager::RequestFrontEndShutDown();
+ }
+ // It's now in ThingsToDoBeforeLeavingPage()
+#ifndef TIDY_UP_PBP
+ else if (m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) {
+ DMAudio.StopFrontEndTrack();
+ OutputDebugString("FRONTEND AUDIO TRACK STOPPED");
}
#endif
+ int oldScreen = !m_bGameNotLoaded ? aScreens[m_nCurrScreen].m_PreviousPage[1] : aScreens[m_nCurrScreen].m_PreviousPage[0];
+ int oldOption = !m_bGameNotLoaded ? aScreens[m_nCurrScreen].m_ParentEntry[1] : aScreens[m_nCurrScreen].m_ParentEntry[0];
+
if (oldScreen != -1) {
- if ((m_nCurrScreen == MENUPAGE_SKIN_SELECT) && strcmp(m_aSkinName, m_PrefsSkinFile) != 0) {
- CWorld::Players[0].SetPlayerSkin(m_PrefsSkinFile);
- }
- if ((m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) && (m_nPrefsAudio3DProviderIndex != -1)) {
- m_nPrefsAudio3DProviderIndex = DMAudio.GetCurrent3DProviderIndex();
- }
- if (m_nCurrScreen == MENUPAGE_GRAPHICS_SETTINGS) {
- m_nDisplayVideoMode = m_nPrefsVideoMode;
- }
- if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) {
- CPlayerSkin::EndFrontendSkinEdit();
- }
+ ThingsToDoBeforeLeavingPage();
#ifdef PS2_LIKE_MENU
if (!bottomBarActive &&
@@ -3168,10 +3246,8 @@ CMenuManager::ProcessButtonPresses(void)
bottomBarActive = true;
} else
#endif
+ {
ChangeScreen(oldScreen, oldOption, true, true);
-
- if ((m_nPrevScreen == MENUPAGE_SKIN_SELECT) || (m_nPrevScreen == MENUPAGE_KEYBOARD_CONTROLS)) {
- m_nTotalListRow = 0;
}
// We will go back for sure at this point, why process other things?!
@@ -3412,7 +3488,7 @@ void CMenuManager::ProcessOnOffMenuOptions()
SaveSettings();
break;
case MENUACTION_MOUSESTEER:
- m_bDisableMouseSteering = !m_bDisableMouseSteering;
+ CVehicle::m_bDisableMouseSteering = !CVehicle::m_bDisableMouseSteering;
DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
SaveSettings();
break;
@@ -3512,11 +3588,16 @@ WRAPPER void CMenuManager::SwitchMenuOnAndOff() { EAXJMP(0x488790); }
#else
void CMenuManager::SwitchMenuOnAndOff()
{
- if (!!(CPad::GetPad(0)->NewState.Start && !CPad::GetPad(0)->OldState.Start)
- || m_bShutDownFrontEndRequested || m_bStartUpFrontEndRequested) {
+ bool menuWasActive = !!m_bMenuActive;
- if (!m_bMenuActive)
- m_bMenuActive = true;
+ // Reminder: You need REGISTER_START_BUTTON defined to make it work.
+ if (CPad::GetPad(0)->GetStartJustDown()
+#ifdef FIX_BUGS
+ && !m_bGameNotLoaded
+#endif
+ || m_bShutDownFrontEndRequested || m_bStartUpFrontEndRequested) {
+
+ m_bMenuActive = !m_bMenuActive;
if (m_bShutDownFrontEndRequested)
m_bMenuActive = false;
@@ -3525,8 +3606,13 @@ void CMenuManager::SwitchMenuOnAndOff()
if (m_bMenuActive) {
CTimer::StartUserPause();
- }
- else {
+ } else {
+#ifdef PS2_LIKE_MENU
+ bottomBarActive = false;
+#endif
+#ifdef FIX_BUGS
+ ThingsToDoBeforeLeavingPage();
+#endif
ShutdownJustMenu();
SaveSettings();
m_bStartUpFrontEndRequested = false;
@@ -3553,7 +3639,7 @@ void CMenuManager::SwitchMenuOnAndOff()
PcSaveHelper.PopulateSlotInfo();
m_nCurrOption = 0;
}
-/* // Unused?
+/* // PS2 leftover
if (m_nCurrScreen != MENUPAGE_SOUND_SETTINGS && gMusicPlaying)
{
DMAudio.StopFrontEndTrack();
@@ -3561,8 +3647,8 @@ void CMenuManager::SwitchMenuOnAndOff()
gMusicPlaying = 0;
}
*/
- if (!m_bMenuActive)
- m_bMenuNotProcessed = true;
+ if (m_bMenuActive != menuWasActive)
+ m_bMenuStateChanged = true;
m_bStartUpFrontEndRequested = false;
m_bShutDownFrontEndRequested = false;
diff --git a/src/core/Frontend.h b/src/core/Frontend.h
index 6d7327d3..39e46ddd 100644
--- a/src/core/Frontend.h
+++ b/src/core/Frontend.h
@@ -51,6 +51,9 @@ enum eLanguages
LANGUAGE_GERMAN,
LANGUAGE_ITALIAN,
LANGUAGE_SPANISH,
+#ifdef MORE_LANGUAGES
+ LANGUAGE_RUSSIAN,
+#endif
};
enum eFrontendSprites
@@ -301,6 +304,9 @@ enum eMenuAction
MENUACTION_UNK108,
MENUACTION_UNK109,
MENUACTION_UNK110,
+#ifdef MORE_LANGUAGES
+ MENUACTION_LANG_RUS,
+#endif
};
enum eCheckHover
@@ -357,7 +363,7 @@ enum
enum eControlMethod
{
- CONTROL_STANDART = 0,
+ CONTROL_STANDARD = 0,
CONTROL_CLASSIC,
};
@@ -403,7 +409,7 @@ public:
int32 m_nHelperTextMsgId;
bool m_bLanguageLoaded;
bool m_bMenuActive;
- bool m_bMenuNotProcessed;
+ bool m_bMenuStateChanged;
bool m_bWaitingForNewKeyBind;
bool m_bStartGameLoading;
bool m_bFirstTime;
@@ -473,7 +479,6 @@ public:
static int32 &m_ControlMethod;
static int8 &m_PrefsDMA;
static int32 &m_PrefsLanguage;
- static int8 &m_bDisableMouseSteering;
static int32 &m_PrefsBrightness;
static float &m_PrefsLOD;
static int8 &m_bFrontEnd_ReloadObrTxtGxt;
@@ -492,6 +497,12 @@ public:
static int32 &sthWithButtons;
static int32 &sthWithButtons2;
+#ifndef MASTER
+ static bool m_PrefsMarketing;
+ static bool m_PrefsDisableTutorials;
+#endif // !MASTER
+
+
public:
static void BuildStatLine(char *text, void *stat, uint8 aFloat, void *stat2);
static void CentreMousePointer();
@@ -540,8 +551,14 @@ public:
void WaitForUserCD();
void PrintController();
- // New content:
- uint8 GetNumberOfMenuOptions();
+ // New (not in function or inlined in the game)
+ void ThingsToDoBeforeLeavingPage();
+ void ScrollUpListByOne();
+ void ScrollDownListByOne();
+ void PageUpList(bool);
+ void PageDownList(bool);
+
+ // uint8 GetNumberOfMenuOptions();
};
static_assert(sizeof(CMenuManager) == 0x564, "CMenuManager: error");
diff --git a/src/core/Game.cpp b/src/core/Game.cpp
index e89d62a0..8571e93e 100644
--- a/src/core/Game.cpp
+++ b/src/core/Game.cpp
@@ -1,7 +1,14 @@
+#pragma warning( push )
+#pragma warning( disable : 4005)
+#define DIRECTINPUT_VERSION 0x0800
+#include <dinput.h>
+#pragma warning( pop )
#include "common.h"
+#include "win.h"
#include "patcher.h"
#include "Game.h"
#include "main.h"
+#include "RwHelper.h"
#include "Accident.h"
#include "Antennas.h"
#include "Bridge.h"
@@ -17,6 +24,7 @@
#include "Cranes.h"
#include "Credits.h"
#include "CutsceneMgr.h"
+#include "DMAudio.h"
#include "Darkel.h"
#include "Debug.h"
#include "EventList.h"
@@ -28,24 +36,32 @@
#include "Frontend.h"
#include "GameLogic.h"
#include "Garages.h"
+#include "GenericGameStorage.h"
#include "Glass.h"
+#include "HandlingMgr.h"
#include "Heli.h"
+#include "Hud.h"
#include "IniFile.h"
+#include "Lights.h"
+#include "MBlur.h"
#include "Messages.h"
#include "Pad.h"
#include "Particle.h"
+#include "ParticleObject.h"
+#include "PedRoutes.h"
#include "Phones.h"
#include "Pickups.h"
#include "Plane.h"
+#include "PlayerSkin.h"
#include "Population.h"
+#include "Radar.h"
#include "Record.h"
+#include "References.h"
#include "Renderer.h"
#include "Replay.h"
#include "Restart.h"
#include "RoadBlocks.h"
-#include "PedRoutes.h"
#include "Rubbish.h"
-#include "RwHelper.h"
#include "SceneEdit.h"
#include "Script.h"
#include "Shadows.h"
@@ -54,11 +70,14 @@
#include "Sprite2d.h"
#include "Stats.h"
#include "Streaming.h"
+#include "SurfaceTable.h"
+#include "TempColModels.h"
#include "TimeCycle.h"
#include "TrafficLights.h"
#include "Train.h"
#include "TxdStore.h"
#include "User.h"
+#include "VisibilityPlugins.h"
#include "WaterCannon.h"
#include "WaterLevel.h"
#include "Weapon.h"
@@ -68,6 +87,10 @@
#include "ZoneCull.h"
#include "Zones.h"
+
+
+#define DEFAULT_VIEWWINDOW (0.7f)
+
eLevelName &CGame::currLevel = *(eLevelName*)0x941514;
bool &CGame::bDemoMode = *(bool*)0x5F4DD0;
bool &CGame::nastyGame = *(bool*)0x5F4DD4;
@@ -76,7 +99,11 @@ bool &CGame::germanGame = *(bool*)0x95CD1E;
bool &CGame::noProstitutes = *(bool*)0x95CDCF;
bool &CGame::playingIntro = *(bool*)0x95CDC2;
char *CGame::aDatFile = (char*)0x773A48;
+#ifdef MORE_LANGUAGES
+bool CGame::russianGame = false;
+#endif
+int &gameTxdSlot = *(int*)0x628D88;
bool
CGame::InitialiseOnceBeforeRW(void)
@@ -87,7 +114,139 @@ CGame::InitialiseOnceBeforeRW(void)
return true;
}
-int &gameTxdSlot = *(int*)0x628D88;
+bool
+CGame::InitialiseRenderWare(void)
+{
+ _TexturePoolsInitialise();
+
+ CTxdStore::Initialise();
+ CVisibilityPlugins::Initialise();
+
+ /* Create camera */
+ Scene.camera = CameraCreate(RsGlobal.width, RsGlobal.height, TRUE);
+ ASSERT(Scene.camera != nil);
+ if (!Scene.camera)
+ {
+ return (false);
+ }
+
+ RwCameraSetFarClipPlane(Scene.camera, 2000.0f);
+ RwCameraSetNearClipPlane(Scene.camera, 0.9f);
+
+ CameraSize(Scene.camera, nil, DEFAULT_VIEWWINDOW, DEFAULT_ASPECT_RATIO);
+
+ /* Create a world */
+ RwBBox bbox;
+
+ bbox.sup.x = bbox.sup.y = bbox.sup.z = 10000.0f;
+ bbox.inf.x = bbox.inf.y = bbox.inf.z = -10000.0f;
+
+ Scene.world = RpWorldCreate(&bbox);
+ ASSERT(Scene.world != nil);
+ if (!Scene.world)
+ {
+ CameraDestroy(Scene.camera);
+ Scene.camera = nil;
+ return (false);
+ }
+
+ /* Add the camera to the world */
+ RpWorldAddCamera(Scene.world, Scene.camera);
+ LightsCreate(Scene.world);
+
+ CreateDebugFont();
+
+ CFont::Initialise();
+ CHud::Initialise();
+ CPlayerSkin::Initialise();
+
+ return (true);
+}
+
+void CGame::ShutdownRenderWare(void)
+{
+ CMBlur::MotionBlurClose();
+ DestroySplashScreen();
+ CHud::Shutdown();
+ CFont::Shutdown();
+
+ for ( int32 i = 0; i < NUMPLAYERS; i++ )
+ CWorld::Players[i].DeletePlayerSkin();
+
+ CPlayerSkin::Shutdown();
+
+ DestroyDebugFont();
+
+ /* Destroy world */
+ LightsDestroy(Scene.world);
+ RpWorldRemoveCamera(Scene.world, Scene.camera);
+ RpWorldDestroy(Scene.world);
+
+ /* destroy camera */
+ CameraDestroy(Scene.camera);
+
+ Scene.world = nil;
+ Scene.camera = nil;
+
+ CVisibilityPlugins::Shutdown();
+
+ _TexturePoolsShutdown();
+}
+
+bool CGame::InitialiseOnceAfterRW(void)
+{
+ TheText.Load();
+ DMAudio.Initialise();
+ CTimer::Initialise();
+ CTempColModels::Initialise();
+ mod_HandlingManager.Initialise();
+ CSurfaceTable::Initialise("DATA\\SURFACE.DAT");
+ CPedStats::Initialise();
+ CTimeCycle::Initialise();
+
+ if ( DMAudio.GetNum3DProvidersAvailable() == 0 )
+ FrontEndMenuManager.m_nPrefsAudio3DProviderIndex = -1;
+
+ if ( FrontEndMenuManager.m_nPrefsAudio3DProviderIndex == -99 || FrontEndMenuManager.m_nPrefsAudio3DProviderIndex == -2 )
+ {
+ CMenuManager::m_PrefsSpeakers = 0;
+
+ for ( int32 i = 0; i < DMAudio.GetNum3DProvidersAvailable(); i++ )
+ {
+ wchar buff[64];
+
+ char *name = DMAudio.Get3DProviderName(i);
+ AsciiToUnicode(name, buff);
+ char *providername = UnicodeToAscii(buff);
+ strupr(providername);
+
+ if ( !strcmp(providername, "MILES FAST 2D POSITIONAL AUDIO") )
+ {
+ FrontEndMenuManager.m_nPrefsAudio3DProviderIndex = i;
+ break;
+ }
+ }
+ }
+
+ DMAudio.SetCurrent3DProvider(FrontEndMenuManager.m_nPrefsAudio3DProviderIndex);
+ DMAudio.SetSpeakerConfig(CMenuManager::m_PrefsSpeakers);
+ DMAudio.SetDynamicAcousticModelingStatus(CMenuManager::m_PrefsDMA);
+ DMAudio.SetMusicMasterVolume(CMenuManager::m_PrefsMusicVolume);
+ DMAudio.SetEffectsMasterVolume(CMenuManager::m_PrefsSfxVolume);
+ DMAudio.SetEffectsFadeVol(127);
+ DMAudio.SetMusicFadeVol(127);
+ CWorld::Players[0].SetPlayerSkin(CMenuManager::m_PrefsSkinFile);
+
+ return true;
+}
+
+void
+CGame::FinalShutdown(void)
+{
+ CTxdStore::Shutdown();
+ CPedStats::Shutdown();
+ CdStreamShutdown();
+}
bool CGame::Initialise(const char* datFile)
{
@@ -158,7 +317,7 @@ bool CGame::Initialise(const char* datFile)
CStreaming::Init();
} else {
CStreaming::Init();
- if (ConvertTextures()) {
+ if (CreateTxdImageForVideoCard()) {
CStreaming::Shutdown();
CdStreamAddImage("MODELS\\TXD.IMG");
CStreaming::Init();
@@ -196,7 +355,7 @@ bool CGame::Initialise(const char* datFile)
CSceneEdit::Init();
LoadingScreen("Loading the Game", "Load scripts", nil);
CTheScripts::Init();
- CGangs::Initialize();
+ CGangs::Initialise();
LoadingScreen("Loading the Game", "Setup game variables", nil);
CClock::Initialise(1000);
CHeli::InitHelis();
@@ -225,16 +384,227 @@ bool CGame::Initialise(const char* datFile)
CTheScripts::Process();
TheCamera.Process();
LoadingScreen("Loading the Game", "Load scene", nil);
- CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel);
- CCollision::ms_collisionInMemory = CGame::currLevel;
+ CModelInfo::RemoveColModelsFromOtherLevels(currLevel);
+ CCollision::ms_collisionInMemory = currLevel;
for (int i = 0; i < MAX_PADS; i++)
CPad::GetPad(i)->Clear(true);
return true;
}
-#if 0
-WRAPPER void CGame::Process(void) { EAXJMP(0x48C850); }
-#else
+bool CGame::ShutDown(void)
+{
+ CReplay::FinishPlayback();
+ CPlane::Shutdown();
+ CTrain::Shutdown();
+ CSpecialFX::Shutdown();
+#ifndef PS2
+ CGarages::Shutdown();
+#endif
+ CMovingThings::Shutdown();
+ gPhoneInfo.Shutdown();
+ CWeapon::ShutdownWeapons();
+ CPedType::Shutdown();
+ CMBlur::MotionBlurClose();
+
+ for (int32 i = 0; i < NUMPLAYERS; i++)
+ {
+ if ( CWorld::Players[i].m_pPed )
+ {
+ CWorld::Remove(CWorld::Players[i].m_pPed);
+ delete CWorld::Players[i].m_pPed;
+ CWorld::Players[i].m_pPed = nil;
+ }
+
+ CWorld::Players[i].Clear();
+ }
+
+ CRenderer::Shutdown();
+ CWorld::ShutDown();
+ DMAudio.DestroyAllGameCreatedEntities();
+ CModelInfo::ShutDown();
+ CAnimManager::Shutdown();
+ CCutsceneMgr::Shutdown();
+ CVehicleModelInfo::DeleteVehicleColourTextures();
+ CVehicleModelInfo::ShutdownEnvironmentMaps();
+ CRadar::Shutdown();
+ CStreaming::Shutdown();
+ CTxdStore::GameShutdown();
+ CCollision::Shutdown();
+ CWaterLevel::Shutdown();
+ CRubbish::Shutdown();
+ CClouds::Shutdown();
+ CShadows::Shutdown();
+ CCoronas::Shutdown();
+ CSkidmarks::Shutdown();
+ CWeaponEffects::Shutdown();
+ CParticle::Shutdown();
+ CPools::ShutDown();
+ CTxdStore::RemoveTxdSlot(gameTxdSlot);
+ CdStreamRemoveImages();
+ return true;
+}
+
+void CGame::ReInitGameObjectVariables(void)
+{
+ CGameLogic::InitAtStartOfGame();
+ TheCamera.CCamera::Init();
+ TheCamera.SetRwCamera(Scene.camera);
+ CDebug::DebugInitTextBuffer();
+ CWeather::Init();
+ CUserDisplay::Init();
+ CMessages::Init();
+ CRestart::Initialise();
+ CWorld::bDoingCarCollisions = false;
+ CHud::ReInitialise();
+ CRadar::Initialise();
+ CCarCtrl::ReInit();
+ CTimeCycle::Initialise();
+ CDraw::SetFOV(120.0f);
+ CDraw::ms_fLODDistance = 500.0f;
+ CStreaming::RequestBigBuildings(LEVEL_NONE);
+ CStreaming::LoadAllRequestedModels(false);
+ CPed::Initialise();
+ CEventList::Initialise();
+ CWeapon::InitialiseWeapons();
+ CPopulation::Initialise();
+
+ for (int i = 0; i < NUMPLAYERS; i++)
+ CWorld::Players[i].Clear();
+
+ CWorld::PlayerInFocus = 0;
+ CAntennas::Init();
+ CGlass::Init();
+ gPhoneInfo.Initialise();
+ CTheScripts::Init();
+ CGangs::Initialise();
+ CTimer::Initialise();
+ CClock::Initialise(1000);
+ CTheCarGenerators::Init();
+ CHeli::InitHelis();
+ CMovingThings::Init();
+ CDarkel::Init();
+ CStats::Init();
+ CPickups::Init();
+ CPacManPickups::Init();
+ CGarages::Init();
+ CSpecialFX::Init();
+ CWaterCannons::Init();
+ CParticle::ReloadConfig();
+ CCullZones::ResolveVisibilities();
+
+ if ( !FrontEndMenuManager.m_bLoadingSavedGame )
+ {
+ CCranes::InitCranes();
+ CTheScripts::StartTestScript();
+ CTheScripts::Process();
+ TheCamera.Process();
+ CTrain::InitTrains();
+ CPlane::InitPlanes();
+ }
+
+ for (int32 i = 0; i < MAX_PADS; i++)
+ CPad::GetPad(i)->Clear(true);
+}
+
+void CGame::ReloadIPLs(void)
+{
+ CTimer::Stop();
+ CWorld::RemoveStaticObjects();
+ ThePaths.Init();
+ CCullZones::Init();
+ CFileLoader::ReloadPaths("GTA3.IDE");
+ CFileLoader::LoadScene("INDUST.IPL");
+ CFileLoader::LoadScene("COMMER.IPL");
+ CFileLoader::LoadScene("SUBURBAN.IPL");
+ CFileLoader::LoadScene("CULL.IPL");
+ ThePaths.PreparePathData();
+ CTrafficLights::ScanForLightsOnMap();
+ CRoadBlocks::Init();
+ CCranes::InitCranes();
+ CGarages::Init();
+ CWorld::RepositionCertainDynamicObjects();
+ CCullZones::ResolveVisibilities();
+ CRenderer::SortBIGBuildings();
+ CTimer::Update();
+}
+
+void CGame::ShutDownForRestart(void)
+{
+ CReplay::FinishPlayback();
+ CReplay::EmptyReplayBuffer();
+ DMAudio.DestroyAllGameCreatedEntities();
+
+ for (int i = 0; i < NUMPLAYERS; i++)
+ CWorld::Players[i].Clear();
+
+ CGarages::SetAllDoorsBackToOriginalHeight();
+ CTheScripts::UndoBuildingSwaps();
+ CTheScripts::UndoEntityInvisibilitySettings();
+ CWorld::ClearForRestart();
+ CTimer::Shutdown();
+ CStreaming::FlushRequestList();
+ CStreaming::DeleteAllRwObjects();
+ CStreaming::RemoveAllUnusedModels();
+ CStreaming::ms_disableStreaming = false;
+ CRadar::RemoveRadarSections();
+ FrontEndMenuManager.UnloadTextures();
+ CParticleObject::RemoveAllParticleObjects();
+ CPedType::Shutdown();
+ CSpecialFX::Shutdown();
+ TidyUpMemory(true, false);
+}
+
+void CGame::InitialiseWhenRestarting(void)
+{
+ CRect rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ CRGBA color(255, 255, 255, 255);
+
+ CTimer::Initialise();
+ CSprite2d::SetRecipNearClip();
+
+ b_FoundRecentSavedGameWantToLoad = false;
+
+ TheCamera.Init();
+
+ if ( FrontEndMenuManager.m_bLoadingSavedGame == true )
+ {
+ RestoreForStartLoad();
+ CStreaming::LoadScene(TheCamera.GetPosition());
+ }
+
+ ReInitGameObjectVariables();
+
+ if ( FrontEndMenuManager.m_bLoadingSavedGame == true )
+ {
+ if ( GenericLoad() == true )
+ {
+ DMAudio.ResetTimers(CTimer::GetTimeInMilliseconds());
+ CTrain::InitTrains();
+ CPlane::InitPlanes();
+ }
+ else
+ {
+ for ( int32 i = 0; i < 50; i++ )
+ {
+ HandleExit();
+ FrontEndMenuManager.MessageScreen("FED_LFL"); // Loading save game has failed. The game will restart now.
+ }
+
+ ShutDownForRestart();
+ CTimer::Stop();
+ CTimer::Initialise();
+ FrontEndMenuManager.m_bLoadingSavedGame = false;
+ ReInitGameObjectVariables();
+ currLevel = LEVEL_INDUSTRIAL;
+ CCollision::SortOutCollisionAfterLoad();
+ }
+ }
+
+ CTimer::Update();
+
+ DMAudio.ChangeMusicMode(MUSICMODE_GAME);
+}
+
extern void (*DebugMenuProcess)(void);
void CGame::Process(void)
{
@@ -310,50 +680,34 @@ void CGame::Process(void)
}
}
}
-#endif
-void CGame::ReloadIPLs(void)
+void CGame::DrasticTidyUpMemory(bool)
{
- CTimer::Stop();
- CWorld::RemoveStaticObjects();
- ThePaths.Init();
- CCullZones::Init();
- CFileLoader::ReloadPaths("GTA3.IDE");
- CFileLoader::LoadScene("INDUST.IPL");
- CFileLoader::LoadScene("COMMER.IPL");
- CFileLoader::LoadScene("SUBURBAN.IPL");
- CFileLoader::LoadScene("CULL.IPL");
- ThePaths.PreparePathData();
- CTrafficLights::ScanForLightsOnMap();
- CRoadBlocks::Init();
- CCranes::InitCranes();
- CGarages::Init();
- CWorld::RepositionCertainDynamicObjects();
- CCullZones::ResolveVisibilities();
- CRenderer::SortBIGBuildings();
- CTimer::Update();
+#ifdef PS2
+ // meow
+#endif
}
-#if 0
-WRAPPER void CGame::FinalShutdown(void) { EAXJMP(0x48BEC0); }
-#else
-void
-CGame::FinalShutdown(void)
+void CGame::TidyUpMemory(bool, bool)
{
- CTxdStore::Shutdown();
- CPedStats::Shutdown();
- CdStreamShutdown();
-}
+#ifdef PS2
+ // meow
#endif
-
-WRAPPER bool CGame::InitialiseRenderWare(void) { EAXJMP(0x48BBA0); }
-WRAPPER void CGame::ShutdownRenderWare(void) { EAXJMP(0x48BCB0); }
-WRAPPER void CGame::ShutDown(void) { EAXJMP(0x48C3A0); }
-WRAPPER void CGame::ShutDownForRestart(void) { EAXJMP(0x48C6B0); }
-WRAPPER void CGame::InitialiseWhenRestarting(void) { EAXJMP(0x48C740); }
-WRAPPER bool CGame::InitialiseOnceAfterRW(void) { EAXJMP(0x48BD50); }
+}
STARTPATCHES
- InjectHook(0x48C850, CGame::Process, PATCH_JUMP);
+ InjectHook(0x48BB80, CGame::InitialiseOnceBeforeRW, PATCH_JUMP);
+ InjectHook(0x48BBA0, CGame::InitialiseRenderWare, PATCH_JUMP);
+ InjectHook(0x48BCB0, CGame::ShutdownRenderWare, PATCH_JUMP);
+ InjectHook(0x48BD50, CGame::InitialiseOnceAfterRW, PATCH_JUMP);
InjectHook(0x48BEC0, CGame::FinalShutdown, PATCH_JUMP);
+ InjectHook(0x48BED0, CGame::Initialise, PATCH_JUMP);
+ InjectHook(0x48C3A0, CGame::ShutDown, PATCH_JUMP);
+ InjectHook(0x48C4B0, CGame::ReInitGameObjectVariables, PATCH_JUMP);
+ InjectHook(0x48C620, CGame::ReloadIPLs, PATCH_JUMP);
+ InjectHook(0x48C6B0, CGame::ShutDownForRestart, PATCH_JUMP);
+ InjectHook(0x48C740, CGame::InitialiseWhenRestarting, PATCH_JUMP);
+ InjectHook(0x48C850, CGame::Process, PATCH_JUMP);
+ InjectHook(0x48CA10, CGame::DrasticTidyUpMemory, PATCH_JUMP);
+ InjectHook(0x48CA20, CGame::TidyUpMemory, PATCH_JUMP);
ENDPATCHES
diff --git a/src/core/Game.h b/src/core/Game.h
index 7b20099c..318ff54b 100644
--- a/src/core/Game.h
+++ b/src/core/Game.h
@@ -16,23 +16,27 @@ public:
static bool &nastyGame;
static bool &frenchGame;
static bool &germanGame;
+#ifdef MORE_LANGUAGES
+ static bool russianGame;
+#endif
static bool &noProstitutes;
static bool &playingIntro;
static char *aDatFile; //[32];
- static bool Initialise(const char *datFile);
static bool InitialiseOnceBeforeRW(void);
static bool InitialiseRenderWare(void);
- static bool InitialiseOnceAfterRW(void);
- static void InitialiseWhenRestarting(void);
- static void ShutDown(void);
static void ShutdownRenderWare(void);
+ static bool InitialiseOnceAfterRW(void);
static void FinalShutdown(void);
+ static bool Initialise(const char *datFile);
+ static bool ShutDown(void);
+ static void ReInitGameObjectVariables(void);
+ static void ReloadIPLs(void);
static void ShutDownForRestart(void);
+ static void InitialiseWhenRestarting(void);
static void Process(void);
- static void ReloadIPLs(void);
-
+
// NB: these do something on PS2
- static void TidyUpMemory(bool, bool) {}
- static void DrasticTidyUpMemory(void) {}
+ static void TidyUpMemory(bool, bool);
+ static void DrasticTidyUpMemory(bool);
};
diff --git a/src/core/General.h b/src/core/General.h
index a7b240c2..f32846eb 100644
--- a/src/core/General.h
+++ b/src/core/General.h
@@ -1,5 +1,7 @@
#pragma once
+#include <ctype.h>
+
class CGeneral
{
public:
diff --git a/src/core/MenuScreens.h b/src/core/MenuScreens.h
index 427d01bf..ace6a719 100644
--- a/src/core/MenuScreens.h
+++ b/src/core/MenuScreens.h
@@ -65,6 +65,9 @@ const CMenuScreen aScreens[] = {
MENUACTION_LANG_GER, "FEL_GER", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_LANG_ITA, "FEL_ITA", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_LANG_SPA, "FEL_SPA", SAVESLOT_NONE, MENUPAGE_NONE,
+#ifdef MORE_LANGUAGES
+ MENUACTION_LANG_RUS, "FEL_RUS", SAVESLOT_NONE, MENUPAGE_NONE,
+#endif
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp
index 51102c7b..6bbe00f2 100644
--- a/src/core/Pad.cpp
+++ b/src/core/Pad.cpp
@@ -5,6 +5,10 @@
#pragma warning( pop )
#include "common.h"
+#ifdef XINPUT
+#include <Xinput.h>
+#pragma comment( lib, "Xinput9_1_0.lib" )
+#endif
#include "patcher.h"
#include "Pad.h"
#include "ControllerConfig.h"
@@ -547,12 +551,79 @@ void CPad::AddToPCCheatString(char c)
#undef _CHEATCMP
}
+#ifdef XINPUT
+void CPad::AffectFromXinput(uint32 pad)
+{
+ XINPUT_STATE xstate;
+ memset(&xstate, 0, sizeof(XINPUT_STATE));
+ if (XInputGetState(pad, &xstate) == ERROR_SUCCESS)
+ {
+ PCTempJoyState.Circle = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_B) ? 255 : 0;
+ PCTempJoyState.Cross = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_A) ? 255 : 0;
+ PCTempJoyState.Square = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_X) ? 255 : 0;
+ PCTempJoyState.Triangle = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_Y) ? 255 : 0;
+ PCTempJoyState.DPadDown = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) ? 255 : 0;
+ PCTempJoyState.DPadLeft = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) ? 255 : 0;
+ PCTempJoyState.DPadRight = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) ? 255 : 0;
+ PCTempJoyState.DPadUp = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) ? 255 : 0;
+ PCTempJoyState.LeftShock = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) ? 255 : 0;
+ PCTempJoyState.LeftShoulder1 = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) ? 255 : 0;
+ PCTempJoyState.LeftShoulder2 = xstate.Gamepad.bLeftTrigger;
+ PCTempJoyState.RightShock = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) ? 255 : 0;
+ PCTempJoyState.RightShoulder1 = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) ? 255 : 0;
+ PCTempJoyState.RightShoulder2 = xstate.Gamepad.bRightTrigger;
+
+ PCTempJoyState.Select = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) ? 255 : 0;
+#ifdef REGISTER_START_BUTTON
+ PCTempJoyState.Start = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_START) ? 255 : 0;
+#endif
+ float lx = (float)xstate.Gamepad.sThumbLX / (float)0x7FFF;
+ float ly = (float)xstate.Gamepad.sThumbLY / (float)0x7FFF;
+ float rx = (float)xstate.Gamepad.sThumbRX / (float)0x7FFF;
+ float ry = (float)xstate.Gamepad.sThumbRY / (float)0x7FFF;
+
+ if (Abs(lx) > 0.3f || Abs(ly) > 0.3f) {
+ PCTempJoyState.LeftStickX = (int32)(lx * 128.0f);
+ PCTempJoyState.LeftStickY = (int32)(-ly * 128.0f);
+ }
+
+ if (Abs(rx) > 0.3f || Abs(ry) > 0.3f) {
+ PCTempJoyState.RightStickX = (int32)(rx * 128.0f);
+ PCTempJoyState.RightStickY = (int32)(ry * 128.0f);
+ }
+
+ XINPUT_VIBRATION VibrationState;
+
+ memset(&VibrationState, 0, sizeof(XINPUT_VIBRATION));
+
+ uint16 iLeftMotor = (uint16)((float)ShakeFreq / 255.0f * (float)0xffff);
+ uint16 iRightMotor = (uint16)((float)ShakeFreq / 255.0f * (float)0xffff);
+
+ if (ShakeDur < CTimer::GetTimeStepInMilliseconds())
+ ShakeDur = 0;
+ else
+ ShakeDur -= CTimer::GetTimeStepInMilliseconds();
+ if (ShakeDur == 0) ShakeFreq = 0;
+
+ VibrationState.wLeftMotorSpeed = iLeftMotor;
+ VibrationState.wRightMotorSpeed = iRightMotor;
+
+ XInputSetState(pad, &VibrationState);
+ }
+}
+#endif
+
void CPad::UpdatePads(void)
{
bool bUpdate = true;
GetPad(0)->UpdateMouse();
+#ifdef XINPUT
+ GetPad(0)->AffectFromXinput(0);
+ GetPad(1)->AffectFromXinput(1);
+#else
CapturePad(0);
+#endif
ControlsManager.ClearSimButtonPressCheckers();
@@ -565,10 +636,13 @@ void CPad::UpdatePads(void)
if ( bUpdate )
{
GetPad(0)->Update(0);
+ GetPad(1)->Update(0);
}
-
+
+#if defined(MASTER) && !defined(XINPUT)
GetPad(1)->NewState.Clear();
GetPad(1)->OldState.Clear();
+#endif
OldKeyState = NewKeyState;
NewKeyState = TempKeyState;
diff --git a/src/core/Pad.h b/src/core/Pad.h
index 09691128..ca44a9f7 100644
--- a/src/core/Pad.h
+++ b/src/core/Pad.h
@@ -2,9 +2,9 @@
enum {
PLAYERCONTROL_ENABLED = 0,
- PLAYERCONTROL_DISABLED_1 = 1,
+ PLAYERCONTROL_DISABLED_1 = 1, // used by first person camera
PLAYERCONTROL_DISABLED_2 = 2,
- PLAYERCONTROL_DISABLED_4 = 4,
+ PLAYERCONTROL_GARAGE = 4,
PLAYERCONTROL_DISABLED_8 = 8,
PLAYERCONTROL_DISABLED_10 = 16,
PLAYERCONTROL_DISABLED_20 = 32, // used on CPlayerInfo::MakePlayerSafe
@@ -247,6 +247,10 @@ public:
static char *EditString(char *pStr, int32 nSize);
static int32 *EditCodesForControls(int32 *pRsKeys, int32 nSize);
+#ifdef XINPUT
+ void AffectFromXinput(uint32 pad);
+#endif
+
// mouse
bool GetLeftMouseJustDown() { return !!(NewMouseControllerState.LMB && !OldMouseControllerState.LMB); }
bool GetRightMouseJustDown() { return !!(NewMouseControllerState.RMB && !OldMouseControllerState.RMB); }
@@ -399,6 +403,8 @@ public:
bool GetLeftShoulder2JustDown() { return !!(NewState.LeftShoulder2 && !OldState.LeftShoulder2); }
bool GetRightShoulder1JustDown() { return !!(NewState.RightShoulder1 && !OldState.RightShoulder1); }
bool GetRightShoulder2JustDown() { return !!(NewState.RightShoulder2 && !OldState.RightShoulder2); }
+ bool GetLeftShockJustDown() { return !!(NewState.LeftShock && !OldState.LeftShock); }
+ bool GetRightShockJustDown() { return !!(NewState.RightShock && !OldState.RightShock); }
bool GetStartJustDown() { return !!(NewState.Start && !OldState.Start); }
bool GetLeftStickXJustDown() { return !!(NewState.LeftStickX && !OldState.LeftStickX); }
bool GetLeftStickYJustDown() { return !!(NewState.LeftStickY && !OldState.LeftStickY); }
@@ -422,8 +428,15 @@ public:
bool GetLeftShoulder2(void) { return !!NewState.LeftShoulder2; }
bool GetRightShoulder1(void) { return !!NewState.RightShoulder1; }
bool GetRightShoulder2(void) { return !!NewState.RightShoulder2; }
+ int16 GetLeftStickX(void) { return NewState.LeftStickX; }
+ int16 GetLeftStickY(void) { return NewState.LeftStickY; }
+ int16 GetRightStickX(void) { return NewState.RightStickX; }
+ int16 GetRightStickY(void) { return NewState.RightStickY; }
- bool ArePlayerControlsDisabled(void) { return DisablePlayerControls != PLAYERCONTROL_ENABLED; }
+ bool ArePlayerControlsDisabled(void) { return DisablePlayerControls != PLAYERCONTROL_ENABLED; }
+ void SetDisablePlayerControls(uint8 who) { DisablePlayerControls |= who; }
+ void SetEnablePlayerControls(uint8 who) { DisablePlayerControls &= ~who; }
+ bool IsPlayerControlsDisabledBy(uint8 who) { return DisablePlayerControls & who; }
};
VALIDATE_SIZE(CPad, 0xFC);
diff --git a/src/core/Placeable.cpp b/src/core/Placeable.cpp
index d2cec82b..c882fc27 100644
--- a/src/core/Placeable.cpp
+++ b/src/core/Placeable.cpp
@@ -63,6 +63,8 @@ CPlaceable::IsWithinArea(float x1, float y1, float z1, float x2, float y2, float
z1 <= GetPosition().z && GetPosition().z <= z2;
}
+#include <new>
+
class CPlaceable_ : public CPlaceable
{
public:
diff --git a/src/core/PlayerInfo.cpp b/src/core/PlayerInfo.cpp
index e0c0259e..ead32ee7 100644
--- a/src/core/PlayerInfo.cpp
+++ b/src/core/PlayerInfo.cpp
@@ -2,7 +2,9 @@
#include "patcher.h"
#include "main.h"
#include "PlayerPed.h"
+#include "Wanted.h"
#include "PlayerInfo.h"
+#include "Fire.h"
#include "Frontend.h"
#include "PlayerSkin.h"
#include "Darkel.h"
@@ -12,6 +14,7 @@
#include "Remote.h"
#include "World.h"
#include "Replay.h"
+#include "Camera.h"
#include "Pad.h"
#include "ProjectileInfo.h"
#include "Explosion.h"
diff --git a/src/core/PlayerSkin.cpp b/src/core/PlayerSkin.cpp
index 4d2c31df..4f730b90 100644
--- a/src/core/PlayerSkin.cpp
+++ b/src/core/PlayerSkin.cpp
@@ -1,22 +1,22 @@
-#include "common.h"
-#include "patcher.h"
-#include "main.h"
-#include "PlayerSkin.h"
-#include "TxdStore.h"
-#include "rtbmp.h"
-#include "ClumpModelInfo.h"
-#include "VisibilityPlugins.h"
-#include "World.h"
-#include "PlayerInfo.h"
-#include "CdStream.h"
-#include "FileMgr.h"
-#include "Directory.h"
-#include "RwHelper.h"
-#include "Timer.h"
-#include "Lights.h"
-
-int CPlayerSkin::m_txdSlot;
-
+#include "common.h"
+#include "patcher.h"
+#include "main.h"
+#include "PlayerSkin.h"
+#include "TxdStore.h"
+#include "rtbmp.h"
+#include "ClumpModelInfo.h"
+#include "VisibilityPlugins.h"
+#include "World.h"
+#include "PlayerInfo.h"
+#include "CdStream.h"
+#include "FileMgr.h"
+#include "Directory.h"
+#include "RwHelper.h"
+#include "Timer.h"
+#include "Lights.h"
+
+int CPlayerSkin::m_txdSlot;
+
void
FindPlayerDff(uint32 &offset, uint32 &size)
{
@@ -32,8 +32,8 @@ FindPlayerDff(uint32 &offset, uint32 &size)
offset = info.offset;
size = info.size;
-}
-
+}
+
void
LoadPlayerDff(void)
{
@@ -65,22 +65,22 @@ LoadPlayerDff(void)
if (streamWasAdded)
CdStreamRemoveImages();
-}
-
+}
+
void
CPlayerSkin::Initialise(void)
{
m_txdSlot = CTxdStore::AddTxdSlot("skin");
CTxdStore::Create(m_txdSlot);
CTxdStore::AddRef(m_txdSlot);
-}
-
+}
+
void
CPlayerSkin::Shutdown(void)
{
CTxdStore::RemoveTxdSlot(m_txdSlot);
-}
-
+}
+
RwTexture *
CPlayerSkin::GetSkinTexture(const char *texName)
{
@@ -112,8 +112,8 @@ CPlayerSkin::GetSkinTexture(const char *texName)
RwImageDestroy(image);
}
return tex;
-}
-
+}
+
void
CPlayerSkin::BeginFrontendSkinEdit(void)
{
@@ -163,11 +163,11 @@ CPlayerSkin::RenderFrontendSkinEdit(void)
RpClumpRender(gpPlayerClump);
}
-STARTPATCHES
-InjectHook(0x59B9B0, &CPlayerSkin::Initialise, PATCH_JUMP);
-InjectHook(0x59B9E0, &CPlayerSkin::Shutdown, PATCH_JUMP);
-InjectHook(0x59B9F0, &CPlayerSkin::GetSkinTexture, PATCH_JUMP);
-InjectHook(0x59BC70, &CPlayerSkin::BeginFrontendSkinEdit, PATCH_JUMP);
-InjectHook(0x59BCB0, &CPlayerSkin::EndFrontendSkinEdit, PATCH_JUMP);
-InjectHook(0x59BCE0, &CPlayerSkin::RenderFrontendSkinEdit, PATCH_JUMP);
+STARTPATCHES
+InjectHook(0x59B9B0, &CPlayerSkin::Initialise, PATCH_JUMP);
+InjectHook(0x59B9E0, &CPlayerSkin::Shutdown, PATCH_JUMP);
+InjectHook(0x59B9F0, &CPlayerSkin::GetSkinTexture, PATCH_JUMP);
+InjectHook(0x59BC70, &CPlayerSkin::BeginFrontendSkinEdit, PATCH_JUMP);
+InjectHook(0x59BCB0, &CPlayerSkin::EndFrontendSkinEdit, PATCH_JUMP);
+InjectHook(0x59BCE0, &CPlayerSkin::RenderFrontendSkinEdit, PATCH_JUMP);
ENDPATCHES \ No newline at end of file
diff --git a/src/core/Radar.cpp b/src/core/Radar.cpp
index 6421520b..f1d8ec96 100644
--- a/src/core/Radar.cpp
+++ b/src/core/Radar.cpp
@@ -75,9 +75,6 @@ static_assert(RADAR_TILE_SIZE == (WORLD_SIZE_Y / RADAR_NUM_TILES), "CRadar: not
#define RADAR_MIN_SPEED (0.3f)
#define RADAR_MAX_SPEED (0.9f)
-#if 0
-WRAPPER void CRadar::CalculateBlipAlpha(float) { EAXJMP(0x4A4F90); }
-#else
uint8 CRadar::CalculateBlipAlpha(float dist)
{
if (dist <= 1.0f)
@@ -88,55 +85,35 @@ uint8 CRadar::CalculateBlipAlpha(float dist)
return 128;
}
-#endif
-#if 0
-WRAPPER void CRadar::ChangeBlipBrightness(int32, int32) { EAXJMP(0x4A57A0); }
-#else
void CRadar::ChangeBlipBrightness(int32 i, int32 bright)
{
int index = GetActualBlipArrayIndex(i);
if (index != -1)
ms_RadarTrace[index].m_bDim = bright != 1;
}
-#endif
-#if 0
-WRAPPER void CRadar::ChangeBlipColour(int32, int32) { EAXJMP(0x4A5770); }
-#else
void CRadar::ChangeBlipColour(int32 i, int32 color)
{
int index = GetActualBlipArrayIndex(i);
if (index != -1)
ms_RadarTrace[index].m_nColor = color;
}
-#endif
-#if 0
-WRAPPER void CRadar::ChangeBlipDisplay(int32, eBlipDisplay) { EAXJMP(0x4A5810); }
-#else
void CRadar::ChangeBlipDisplay(int32 i, eBlipDisplay display)
{
int index = GetActualBlipArrayIndex(i);
if (index != -1)
ms_RadarTrace[index].m_eBlipDisplay = display;
}
-#endif
-#if 0
-WRAPPER void CRadar::ChangeBlipScale(int32, int32) { EAXJMP(0x4A57E0); }
-#else
void CRadar::ChangeBlipScale(int32 i, int32 scale)
{
int index = GetActualBlipArrayIndex(i);
if (index != -1)
ms_RadarTrace[index].m_wScale = scale;
}
-#endif
-#if 0
-WRAPPER void CRadar::ClearBlip(int32) { EAXJMP(0x4A5720); }
-#else
void CRadar::ClearBlip(int32 i)
{
int index = GetActualBlipArrayIndex(i);
@@ -148,11 +125,7 @@ void CRadar::ClearBlip(int32 i)
ms_RadarTrace[index].m_IconID = RADAR_SPRITE_NONE;
}
}
-#endif
-#if 0
-WRAPPER void CRadar::ClearBlipForEntity(eBlipType, int32) { EAXJMP(0x4A56C0); }
-#else
void CRadar::ClearBlipForEntity(eBlipType type, int32 id)
{
for (int i = 0; i < NUMRADARBLIPS; i++) {
@@ -165,11 +138,7 @@ void CRadar::ClearBlipForEntity(eBlipType type, int32 id)
}
};
}
-#endif
-#if 0
-WRAPPER int CRadar::ClipRadarPoly(CVector2D *poly, const CVector2D *in) { EAXJMP(0x4A64A0); }
-#else
// Why not a proper clipping algorithm?
int CRadar::ClipRadarPoly(CVector2D *poly, const CVector2D *rect)
{
@@ -249,7 +218,6 @@ int CRadar::ClipRadarPoly(CVector2D *poly, const CVector2D *rect)
return n;
}
-#endif
bool CRadar::DisplayThisBlip(int32 counter)
{
@@ -263,9 +231,6 @@ bool CRadar::DisplayThisBlip(int32 counter)
}
}
-#if 0
-WRAPPER void CRadar::Draw3dMarkers() { EAXJMP(0x4A4C70); }
-#else
void CRadar::Draw3dMarkers()
{
for (int i = 0; i < NUMRADARBLIPS; i++) {
@@ -317,12 +282,7 @@ void CRadar::Draw3dMarkers()
}
}
}
-#endif
-
-#if 0
-WRAPPER void CRadar::DrawBlips() { EAXJMP(0x4A42F0); }
-#else
void CRadar::DrawBlips()
{
if (!TheCamera.m_WideScreenOn && CHud::m_Wants_To_Draw_Hud) {
@@ -580,12 +540,7 @@ void CRadar::DrawBlips()
}
}
}
-#endif
-
-#if 0
-WRAPPER void CRadar::DrawMap () { EAXJMP(0x4A4200); }
-#else
void CRadar::DrawMap()
{
if (!TheCamera.m_WideScreenOn && CHud::m_Wants_To_Draw_Hud) {
@@ -605,11 +560,7 @@ void CRadar::DrawMap()
DrawRadarMap();
}
}
-#endif
-#if 0
-WRAPPER void CRadar::DrawRadarMap() { EAXJMP(0x4A6C20); }
-#else
void CRadar::DrawRadarMap()
{
// Game calculates an unused CRect here
@@ -642,11 +593,7 @@ void CRadar::DrawRadarMap()
DrawRadarSection(x, y + 1);
DrawRadarSection(x + 1, y + 1);
}
-#endif
-#if 0
-WRAPPER void CRadar::DrawRadarMask() { EAXJMP(0x4A69C0); }
-#else
void CRadar::DrawRadarMask()
{
CVector2D corners[4] = {
@@ -690,11 +637,7 @@ void CRadar::DrawRadarMask()
RwD3D8SetRenderState(rwRENDERSTATESTENCILFUNCTION, rwSTENCILFUNCTIONGREATER);
}
-#endif
-#if 0
-WRAPPER void CRadar::DrawRadarSection(int32, int32) { EAXJMP(0x4A67E0); }
-#else
void CRadar::DrawRadarSection(int32 x, int32 y)
{
int i;
@@ -738,20 +681,12 @@ void CRadar::DrawRadarSection(int32 x, int32 y)
// if(numVertices > 2)
RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::GetVertices(), numVertices);
}
-#endif
-#if 0
-WRAPPER void CRadar::DrawRadarSprite(uint16 sprite, float x, float y, uint8 alpha) { EAXJMP(0x4A5EF0); }
-#else
void CRadar::DrawRadarSprite(uint16 sprite, float x, float y, uint8 alpha)
{
RadarSprites[sprite]->Draw(CRect(x - SCREEN_SCALE_X(8.0f), y - SCREEN_SCALE_Y(8.0f), x + SCREEN_SCALE_X(8.0f), y + SCREEN_SCALE_Y(8.0f)), CRGBA(255, 255, 255, alpha));
}
-#endif
-#if 0
-WRAPPER void CRadar::DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int32 alpha) { EAXJMP(0x4A5D10); }
-#else
void CRadar::DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int32 alpha)
{
CVector curPosn[4];
@@ -778,11 +713,7 @@ void CRadar::DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float
sprite->Draw(curPosn[2].x, curPosn[2].y, curPosn[3].x, curPosn[3].y, curPosn[0].x, curPosn[0].y, curPosn[1].x, curPosn[1].y, CRGBA(255, 255, 255, alpha));
}
-#endif
-#if 0
-WRAPPER int32 CRadar::GetActualBlipArrayIndex(int32) { EAXJMP(0x4A41C0); }
-#else
int32 CRadar::GetActualBlipArrayIndex(int32 i)
{
if (i == -1)
@@ -792,11 +723,7 @@ int32 CRadar::GetActualBlipArrayIndex(int32 i)
else
return (uint16)i;
}
-#endif
-#if 0
-WRAPPER int32 CRadar::GetNewUniqueBlipIndex(int32) { EAXJMP(0x4A4180); }
-#else
int32 CRadar::GetNewUniqueBlipIndex(int32 i)
{
if (ms_RadarTrace[i].m_BlipIndex >= UINT16_MAX - 1)
@@ -805,11 +732,7 @@ int32 CRadar::GetNewUniqueBlipIndex(int32 i)
ms_RadarTrace[i].m_BlipIndex++;
return i | (ms_RadarTrace[i].m_BlipIndex << 16);
}
-#endif
-#if 0
-WRAPPER uint32 CRadar::GetRadarTraceColour(uint32 color, bool bright) { EAXJMP(0x4A5BB0); }
-#else
uint32 CRadar::GetRadarTraceColour(uint32 color, bool bright)
{
int32 c;
@@ -862,7 +785,6 @@ uint32 CRadar::GetRadarTraceColour(uint32 color, bool bright)
};
return c;
}
-#endif
const char* gRadarTexNames[] = {
"radar00", "radar01", "radar02", "radar03", "radar04", "radar05", "radar06", "radar07",
@@ -875,9 +797,6 @@ const char* gRadarTexNames[] = {
"radar56", "radar57", "radar58", "radar59", "radar60", "radar61", "radar62", "radar63",
};
-#if 0
-WRAPPER void CRadar::Initialise() { EAXJMP(0x4A3EF0); }
-#else
void
CRadar::Initialise()
{
@@ -894,11 +813,7 @@ CRadar::Initialise()
for (int i = 0; i < 64; i++)
gRadarTxdIds[i] = CTxdStore::FindTxdSlot(gRadarTexNames[i]);
}
-#endif
-#if 0
-WRAPPER float CRadar::LimitRadarPoint(CVector2D &point) { EAXJMP(0x4A4F30); }
-#else
float CRadar::LimitRadarPoint(CVector2D &point)
{
float dist, invdist;
@@ -911,11 +826,7 @@ float CRadar::LimitRadarPoint(CVector2D &point)
}
return dist;
}
-#endif
-#if 0
-WRAPPER void CRadar::LoadAllRadarBlips(int32) { EAXJMP(0x4A6F30); }
-#else
void CRadar::LoadAllRadarBlips(uint8 *buf, uint32 size)
{
Initialise();
@@ -927,11 +838,7 @@ INITSAVEBUF
VALIDATESAVEBUF(size);
}
-#endif
-#if 0
-WRAPPER void CRadar::LoadTextures() { EAXJMP(0x4A4030); }
-#else
void
CRadar::LoadTextures()
{
@@ -959,42 +866,26 @@ CRadar::LoadTextures()
WeaponSprite.SetTexture("radar_weapon");
CTxdStore::PopCurrentTxd();
}
-#endif
-#if 0
-WRAPPER void RemoveMapSection(int32, int32) { EAXJMP(0x00); }
-#else
void RemoveMapSection(int32 x, int32 y)
{
if (x >= 0 && x <= 7 && y >= 0 && y <= 7)
CStreaming::RemoveTxd(gRadarTxdIds[x + RADAR_NUM_TILES * y]);
}
-#endif
-#if 0
-WRAPPER void CRadar::RemoveRadarSections() { EAXJMP(0x4A60E0); }
-#else
void CRadar::RemoveRadarSections()
{
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++)
RemoveMapSection(i, j);
}
-#endif
-#if 0
-WRAPPER void CRadar::RequestMapSection(int32, int32) { EAXJMP(0x00); }
-#else
void CRadar::RequestMapSection(int32 x, int32 y)
{
ClipRadarTileCoords(x, y);
CStreaming::RequestTxd(gRadarTxdIds[x + RADAR_NUM_TILES * y], STREAMFLAGS_DONT_REMOVE | STREAMFLAGS_DEPENDENCY);
}
-#endif
-#if 0
-WRAPPER void CRadar::SaveAllRadarBlips(uint8 *buf, uint32 *size) { EAXJMP(0x4A6E30); }
-#else
void CRadar::SaveAllRadarBlips(uint8 *buf, uint32 *size)
{
*size = SAVE_HEADER_SIZE + sizeof(ms_RadarTrace);
@@ -1006,11 +897,7 @@ INITSAVEBUF
VALIDATESAVEBUF(*size);
}
-#endif
-#if 0
-WRAPPER void CRadar::SetBlipSprite(int32, int32) { EAXJMP(0x4A5840); }
-#else
void CRadar::SetBlipSprite(int32 i, int32 icon)
{
int index = CRadar::GetActualBlipArrayIndex(i);
@@ -1018,11 +905,7 @@ void CRadar::SetBlipSprite(int32 i, int32 icon)
ms_RadarTrace[index].m_IconID = icon;
}
}
-#endif
-#if 0
-WRAPPER int32 CRadar::SetCoordBlip(eBlipType, CVector, int32, eBlipDisplay display) { EAXJMP(0x4A5590); }
-#else
int CRadar::SetCoordBlip(eBlipType type, CVector pos, int32 color, eBlipDisplay display)
{
int nextBlip;
@@ -1043,11 +926,7 @@ int CRadar::SetCoordBlip(eBlipType type, CVector pos, int32 color, eBlipDisplay
ms_RadarTrace[nextBlip].m_IconID = RADAR_SPRITE_NONE;
return CRadar::GetNewUniqueBlipIndex(nextBlip);
}
-#endif
-#if 0
-WRAPPER int CRadar::SetEntityBlip(eBlipType type, int32, int32, eBlipDisplay) { EAXJMP(0x4A5640); }
-#else
int CRadar::SetEntityBlip(eBlipType type, int32 handle, int32 color, eBlipDisplay display)
{
int nextBlip;
@@ -1066,11 +945,7 @@ int CRadar::SetEntityBlip(eBlipType type, int32 handle, int32 color, eBlipDispla
ms_RadarTrace[nextBlip].m_IconID = RADAR_SPRITE_NONE;
return GetNewUniqueBlipIndex(nextBlip);
}
-#endif
-#if 0
-WRAPPER void CRadar::SetRadarMarkerState(int32, bool) { EAXJMP(0x4A5C60); }
-#else
void CRadar::SetRadarMarkerState(int32 counter, bool flag)
{
CEntity *e;
@@ -1091,11 +966,7 @@ void CRadar::SetRadarMarkerState(int32 counter, bool flag)
if (e)
e->bHasBlip = flag;
}
-#endif
-#if 0
-WRAPPER void CRadar::ShowRadarMarker(CVector pos, uint32 color, float radius) { EAXJMP(0x4A59C0); }
-#else
void CRadar::ShowRadarMarker(CVector pos, uint32 color, float radius) {
float f1 = radius * 1.4f;
float f2 = radius * 0.5f;
@@ -1117,11 +988,7 @@ void CRadar::ShowRadarMarker(CVector pos, uint32 color, float radius) {
p2 = pos - TheCamera.GetRight()*f2;
CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
}
-#endif
-#if 0
-WRAPPER void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint8 red, uint8 green, uint8 blue, uint8 alpha) { EAXJMP(0x4A5870); }
-#else
void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint8 red, uint8 green, uint8 blue, uint8 alpha)
{
if (!CHud::m_Wants_To_Draw_Hud || TheCamera.m_WideScreenOn)
@@ -1130,7 +997,6 @@ void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint8 red, uint8 gree
CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size + 1.0f), y - SCREEN_SCALE_Y(size + 1.0f), SCREEN_SCALE_X(size + 1.0f) + x, SCREEN_SCALE_Y(size + 1.0f) + y), CRGBA(0, 0, 0, alpha));
CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size), y - SCREEN_SCALE_Y(size), SCREEN_SCALE_X(size) + x, SCREEN_SCALE_Y(size) + y), CRGBA(red, green, blue, alpha));
}
-#endif
void CRadar::ShowRadarTraceWithHeight(float x, float y, uint32 size, uint8 red, uint8 green, uint8 blue, uint8 alpha, uint8 mode)
{
@@ -1156,9 +1022,6 @@ void CRadar::ShowRadarTraceWithHeight(float x, float y, uint32 size, uint8 red,
}
}
-#if 0
-WRAPPER void CRadar::Shutdown() { EAXJMP(0x4A3F60); }
-#else
void CRadar::Shutdown()
{
AsukaSprite.Delete();
@@ -1183,20 +1046,12 @@ void CRadar::Shutdown()
WeaponSprite.Delete();
RemoveRadarSections();
}
-#endif
-#if 0
-WRAPPER void CRadar::StreamRadarSections(const CVector &posn) { EAXJMP(0x4A6B60); }
-#else
void CRadar::StreamRadarSections(const CVector &posn)
{
StreamRadarSections(floorf((2000.0f + posn.x) / 500.0f), ceilf(7.0f - (2000.0f + posn.y) / 500.0f));
}
-#endif
-#if 0
-WRAPPER void CRadar::StreamRadarSections(int32 x, int32 y) { EAXJMP(0x4A6100); }
-#else
void CRadar::StreamRadarSections(int32 x, int32 y)
{
for (int i = 0; i < RADAR_NUM_TILES; ++i) {
@@ -1208,11 +1063,7 @@ void CRadar::StreamRadarSections(int32 x, int32 y)
};
};
}
-#endif
-#if 0
-WRAPPER void CRadar::TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &in, int32 x, int32 y) { EAXJMP(0x4A5530); }
-#else
void CRadar::TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &in, int32 x, int32 y)
{
out.x = in.x - (x * RADAR_TILE_SIZE + WORLD_MIN_X);
@@ -1220,11 +1071,7 @@ void CRadar::TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &
out.x /= RADAR_TILE_SIZE;
out.y /= RADAR_TILE_SIZE;
}
-#endif
-#if 0
-WRAPPER void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D &in) { EAXJMP(0x4A5300); }
-#else
void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D &in)
{
float s, c;
@@ -1255,19 +1102,18 @@ void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D
out = out * m_radarRange + vec2DRadarOrigin;
}
-#endif
// Radar space goes from -1.0 to 1.0 in x and y, top right is (1.0, 1.0)
void CRadar::TransformRadarPointToScreenSpace(CVector2D &out, const CVector2D &in)
{
- // FIX? scale RADAR_LEFT here somehow
+#ifdef FIX_BUGS
+ out.x = (in.x + 1.0f)*0.5f*SCREEN_SCALE_X(RADAR_WIDTH) + SCREEN_SCALE_X(RADAR_LEFT);
+#else
out.x = (in.x + 1.0f)*0.5f*SCREEN_SCALE_X(RADAR_WIDTH) + RADAR_LEFT;
+#endif
out.y = (1.0f - in.y)*0.5f*SCREEN_SCALE_Y(RADAR_HEIGHT) + SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT);
}
-#if 0
-WRAPPER void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in) { EAXJMP(0x4A50D0); }
-#else
void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in)
{
float s, c;
@@ -1299,11 +1145,7 @@ void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D
out.x = s * y + c * x;
out.y = c * y - s * x;
}
-#endif
-#if 0
-WRAPPER void CRadar::GetTextureCorners(int32 x, int32 y, CVector2D *out) { EAXJMP(0x4A61C0); };
-#else
// Transform from section indices to world coordinates
void CRadar::GetTextureCorners(int32 x, int32 y, CVector2D *out)
{
@@ -1326,11 +1168,7 @@ void CRadar::GetTextureCorners(int32 x, int32 y, CVector2D *out)
out[3].x = RADAR_TILE_SIZE * (x);
out[3].y = RADAR_TILE_SIZE * (y);
}
-#endif
-#if 0
-WRAPPER void CRadar::ClipRadarTileCoords(int32 &, int32 &) { EAXJMP(0x00); };
-#else
void CRadar::ClipRadarTileCoords(int32 &x, int32 &y)
{
if (x < 0)
@@ -1342,24 +1180,16 @@ void CRadar::ClipRadarTileCoords(int32 &x, int32 &y)
if (y > RADAR_NUM_TILES-1)
y = RADAR_NUM_TILES-1;
}
-#endif
-#if 0
-WRAPPER bool CRadar::IsPointInsideRadar(const CVector2D &) { EAXJMP(0x4A6160); }
-#else
bool CRadar::IsPointInsideRadar(const CVector2D &point)
{
if (point.x < -1.0f || point.x > 1.0f) return false;
if (point.y < -1.0f || point.y > 1.0f) return false;
return true;
}
-#endif
// clip line p1,p2 against (-1.0, 1.0) in x and y, set out to clipped point closest to p1
-#if 0
-WRAPPER int CRadar::LineRadarBoxCollision(CVector2D &, const CVector2D &, const CVector2D &) { EAXJMP(0x4A6250); }
-#else
int CRadar::LineRadarBoxCollision(CVector2D &out, const CVector2D &p1, const CVector2D &p2)
{
float d1, d2;
@@ -1430,7 +1260,6 @@ int CRadar::LineRadarBoxCollision(CVector2D &out, const CVector2D &p1, const CVe
return edge;
}
-#endif
STARTPATCHES
InjectHook(0x4A3EF0, CRadar::Initialise, PATCH_JUMP);
diff --git a/src/core/RwHelper.cpp b/src/core/RwHelper.cpp
index 1030d69e..6325bf15 100644
--- a/src/core/RwHelper.cpp
+++ b/src/core/RwHelper.cpp
@@ -352,7 +352,25 @@ WRAPPER bool CheckVideoCardCaps(void) { EAXJMP(0x592740); }
WRAPPER void WriteVideoCardCapsFile(void) { EAXJMP(0x5927D0); }
WRAPPER void ConvertingTexturesScreen(uint32, uint32, const char*) { EAXJMP(0x592880); }
WRAPPER void DealWithTxdWriteError(uint32, uint32, const char*) { EAXJMP(0x592BF0); }
-WRAPPER bool ConvertTextures() { EAXJMP(0x592C70); }
+WRAPPER bool CreateTxdImageForVideoCard() { EAXJMP(0x592C70); }
+
+void CreateDebugFont()
+{
+ ;
+}
+
+void DestroyDebugFont()
+{
+ ;
+}
+
+void FlushObrsPrintfs()
+{
+ ;
+}
+
+WRAPPER void _TexturePoolsInitialise() { EAXJMP(0x598B10); }
+WRAPPER void _TexturePoolsShutdown() { EAXJMP(0x598B30); }
STARTPATCHES
//InjectHook(0x526450, GetFirstObjectCallback, PATCH_JUMP);
diff --git a/src/core/RwHelper.h b/src/core/RwHelper.h
index 1f0290cc..a9f0bdf4 100644
--- a/src/core/RwHelper.h
+++ b/src/core/RwHelper.h
@@ -3,6 +3,9 @@
void *RwMallocAlign(RwUInt32 size, RwUInt32 align);
void RwFreeAlign(void *mem);
+void CreateDebugFont();
+void DestroyDebugFont();
+void FlushObrsPrintfs();
void DefinedState(void);
RwFrame *GetFirstChild(RwFrame *frame);
RwObject *GetFirstObject(RwFrame *frame);
@@ -17,7 +20,7 @@ bool CheckVideoCardCaps(void);
void WriteVideoCardCapsFile(void);
void ConvertingTexturesScreen(uint32, uint32, const char*);
void DealWithTxdWriteError(uint32, uint32, const char*);
-bool ConvertTextures(); // not a real name
+bool CreateTxdImageForVideoCard();
bool RpClumpGtaStreamRead1(RwStream *stream);
RpClump *RpClumpGtaStreamRead2(RwStream *stream);
@@ -31,3 +34,7 @@ void CameraDestroy(RwCamera *camera);
RwCamera *CameraCreate(RwInt32 width,
RwInt32 height,
RwBool zBuffer);
+
+
+void _TexturePoolsInitialise();
+void _TexturePoolsShutdown(); \ No newline at end of file
diff --git a/src/core/Stats.h b/src/core/Stats.h
index 826dcd73..41d926e6 100644
--- a/src/core/Stats.h
+++ b/src/core/Stats.h
@@ -62,6 +62,8 @@ public:
static int32 &CarsCrushed;
static int32(&FastestTimes)[TOTAL_FASTEST_TIMES];
static int32(&HighestScores)[TOTAL_HIGHEST_SCORES];
+ static int32 &KgOfExplosivesUsed;
+ static int32 &CarsCrushed;
public:
static void RegisterFastestTime(int32, int32);
diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp
index 3a830d37..3dcb767a 100644
--- a/src/core/Streaming.cpp
+++ b/src/core/Streaming.cpp
@@ -10,6 +10,7 @@
#include "TxdStore.h"
#include "ModelIndices.h"
#include "Pools.h"
+#include "Wanted.h"
#include "Directory.h"
#include "RwHelper.h"
#include "World.h"
@@ -198,7 +199,7 @@ CStreaming::Init(void)
// PC only, figure out how much memory we got
#ifdef GTA_PC
#define MB (1024*1024)
- extern DWORD &_dwMemAvailPhys;
+ extern unsigned long &_dwMemAvailPhys;
ms_memoryAvailable = (_dwMemAvailPhys - 10*MB)/2;
if(ms_memoryAvailable < 50*MB)
ms_memoryAvailable = 50*MB;
diff --git a/src/core/Timer.cpp b/src/core/Timer.cpp
index bcf84560..18d6b6a3 100644
--- a/src/core/Timer.cpp
+++ b/src/core/Timer.cpp
@@ -75,9 +75,6 @@ void CTimer::Shutdown(void)
;
}
-#if 0
-WRAPPER void CTimer::Update(void) { EAXJMP(0x4ACF70); }
-#else
void CTimer::Update(void)
{
m_snPreviousTimeInMilliseconds = m_snTimeInMilliseconds;
@@ -149,7 +146,6 @@ void CTimer::Update(void)
m_FrameCounter++;
}
-#endif
void CTimer::Suspend(void)
{
@@ -218,6 +214,11 @@ void CTimer::EndUserPause(void)
m_UserPause = false;
}
+uint32 CTimer::GetCyclesPerFrame()
+{
+ return 20;
+}
+
#if 1
STARTPATCHES
InjectHook(0x4ACE60, CTimer::Initialise, PATCH_JUMP);
diff --git a/src/core/Timer.h b/src/core/Timer.h
index 89c4a430..2498ec8a 100644
--- a/src/core/Timer.h
+++ b/src/core/Timer.h
@@ -2,7 +2,7 @@
class CTimer
{
-public:
+
static uint32 &m_snTimeInMilliseconds;
static uint32 &m_snTimeInMillisecondsPauseMode;
static uint32 &m_snTimeInMillisecondsNonClipped;
@@ -11,19 +11,20 @@ public:
static float &ms_fTimeScale;
static float &ms_fTimeStep;
static float &ms_fTimeStepNonClipped;
+public:
static bool &m_UserPause;
static bool &m_CodePause;
- static float GetTimeStep(void) { return ms_fTimeStep; }
+ static const float &GetTimeStep(void) { return ms_fTimeStep; }
static void SetTimeStep(float ts) { ms_fTimeStep = ts; }
static float GetTimeStepInSeconds() { return ms_fTimeStep / 50.0f; }
static float GetTimeStepInMilliseconds() { return ms_fTimeStep / 50.0f * 1000.0f; }
- static float GetTimeStepNonClipped(void) { return ms_fTimeStepNonClipped; }
+ static const float &GetTimeStepNonClipped(void) { return ms_fTimeStepNonClipped; }
static float GetTimeStepNonClippedInSeconds(void) { return ms_fTimeStepNonClipped / 50.0f; }
static void SetTimeStepNonClipped(float ts) { ms_fTimeStepNonClipped = ts; }
- static uint32 GetFrameCounter(void) { return m_FrameCounter; }
+ static const uint32 &GetFrameCounter(void) { return m_FrameCounter; }
static void SetFrameCounter(uint32 fc) { m_FrameCounter = fc; }
- static uint32 GetTimeInMilliseconds(void) { return m_snTimeInMilliseconds; }
+ static const uint32 &GetTimeInMilliseconds(void) { return m_snTimeInMilliseconds; }
static void SetTimeInMilliseconds(uint32 t) { m_snTimeInMilliseconds = t; }
static uint32 GetTimeInMillisecondsNonClipped(void) { return m_snTimeInMillisecondsNonClipped; }
static void SetTimeInMillisecondsNonClipped(uint32 t) { m_snTimeInMillisecondsNonClipped = t; }
@@ -31,8 +32,9 @@ public:
static void SetTimeInMillisecondsPauseMode(uint32 t) { m_snTimeInMillisecondsPauseMode = t; }
static uint32 GetPreviousTimeInMilliseconds(void) { return m_snPreviousTimeInMilliseconds; }
static void SetPreviousTimeInMilliseconds(uint32 t) { m_snPreviousTimeInMilliseconds = t; }
- static float GetTimeScale(void) { return ms_fTimeScale; }
+ static const float &GetTimeScale(void) { return ms_fTimeScale; }
static void SetTimeScale(float ts) { ms_fTimeScale = ts; }
+ static uint32 GetCyclesPerFrame();
static bool GetIsPaused() { return m_UserPause || m_CodePause; }
static bool GetIsUserPaused() { return m_UserPause; }
diff --git a/src/core/TxdStore.cpp b/src/core/TxdStore.cpp
index ab970b99..c751147d 100644
--- a/src/core/TxdStore.cpp
+++ b/src/core/TxdStore.cpp
@@ -10,7 +10,7 @@ CPool<TxdDef,TxdDef> *&CTxdStore::ms_pTxdPool = *(CPool<TxdDef,TxdDef>**)0x8F5FB
RwTexDictionary *&CTxdStore::ms_pStoredTxd = *(RwTexDictionary**)0x9405BC;
void
-CTxdStore::Initialize(void)
+CTxdStore::Initialise(void)
{
if(ms_pTxdPool == nil)
ms_pTxdPool = new CPool<TxdDef,TxdDef>(TXDSTORESIZE);
@@ -187,7 +187,7 @@ CTxdStore::RemoveTxd(int slot)
}
STARTPATCHES
- InjectHook(0x527440, CTxdStore::Initialize, PATCH_JUMP);
+ InjectHook(0x527440, CTxdStore::Initialise, PATCH_JUMP);
InjectHook(0x527470, CTxdStore::Shutdown, PATCH_JUMP);
InjectHook(0x527490, CTxdStore::GameShutdown, PATCH_JUMP);
InjectHook(0x5274E0, CTxdStore::AddTxdSlot, PATCH_JUMP);
diff --git a/src/core/TxdStore.h b/src/core/TxdStore.h
index a9e57d31..12ac708f 100644
--- a/src/core/TxdStore.h
+++ b/src/core/TxdStore.h
@@ -13,7 +13,7 @@ class CTxdStore
static CPool<TxdDef,TxdDef> *&ms_pTxdPool;
static RwTexDictionary *&ms_pStoredTxd;
public:
- static void Initialize(void);
+ static void Initialise(void);
static void Shutdown(void);
static void GameShutdown(void);
static int AddTxdSlot(const char *name);
diff --git a/src/core/Wanted.cpp b/src/core/Wanted.cpp
index 7af753e8..29294a2b 100644
--- a/src/core/Wanted.cpp
+++ b/src/core/Wanted.cpp
@@ -7,19 +7,16 @@
#include "ZoneCull.h"
#include "Darkel.h"
#include "DMAudio.h"
+#include "CopPed.h"
#include "Wanted.h"
+#include "General.h"
int32 &CWanted::MaximumWantedLevel = *(int32*)0x5F7714; // 6
int32 &CWanted::nMaximumWantedLevel = *(int32*)0x5F7718; // 6400
-WRAPPER void CWanted::Reset() { EAXJMP(0x4AD790) };
-WRAPPER void CWanted::Update() { EAXJMP(0x4AD7B0) };
-
void
CWanted::Initialise()
{
- int i;
-
m_nChaos = 0;
m_nLastUpdateTime = 0;
m_nLastWantedLevelChange = 0;
@@ -34,10 +31,12 @@ CWanted::Initialise()
m_bArmyRequired = false;
m_fCrimeSensitivity = 1.0f;
m_nWantedLevel = 0;
- m_CopsBeatingSuspect = 0;
- for(i = 0; i < 10; i++)
+ m_CopsBeatingSuspect = 0;
+
+ for (int i = 0; i < ARRAY_SIZE(m_pCops); i++)
m_pCops[i] = nil;
- ClearQdCrimes();
+
+ ClearQdCrimes();
}
bool
@@ -61,7 +60,7 @@ CWanted::AreArmyRequired()
int32
CWanted::NumOfHelisRequired()
{
- if (m_bIgnoredByCops)
+ if (m_bIgnoredByCops || m_bIgnoredByEveryone)
return 0;
switch (m_nWantedLevel) {
@@ -79,9 +78,10 @@ CWanted::NumOfHelisRequired()
void
CWanted::SetWantedLevel(int32 level)
{
- ClearQdCrimes();
if (level > MaximumWantedLevel)
level = MaximumWantedLevel;
+
+ ClearQdCrimes();
switch (level) {
case 0:
m_nChaos = 0;
@@ -360,10 +360,107 @@ CWanted::WorkOutPolicePresence(CVector posn, float radius)
return numPolice;
}
+void
+CWanted::Update(void)
+{
+ if (CTimer::GetTimeInMilliseconds() - m_nLastUpdateTime > 1000) {
+ if (m_nWantedLevel > 1) {
+ m_nLastUpdateTime = CTimer::GetTimeInMilliseconds();
+ } else {
+ float radius = 18.0f;
+ CVector playerPos = FindPlayerCoors();
+ if (WorkOutPolicePresence(playerPos, radius) == 0) {
+ m_nLastUpdateTime = CTimer::GetTimeInMilliseconds();
+ m_nChaos = max(0, m_nChaos - 1);
+ UpdateWantedLevel();
+ }
+ }
+ UpdateCrimesQ();
+ bool orderMessedUp = false;
+ int currCopNum = 0;
+ bool foundEmptySlot = false;
+ for (int i = 0; i < ARRAY_SIZE(m_pCops); i++) {
+ if (m_pCops[i]) {
+ ++currCopNum;
+ if (foundEmptySlot)
+ orderMessedUp = true;
+ } else {
+ foundEmptySlot = true;
+ }
+ }
+ if (currCopNum != m_CurrentCops) {
+ printf("CopPursuit total messed up: re-setting\n");
+ m_CurrentCops = currCopNum;
+ }
+ if (orderMessedUp) {
+ printf("CopPursuit pointer list messed up: re-sorting\n");
+ bool fixed = true;
+ for (int i = 0; i < ARRAY_SIZE(m_pCops); i++) {
+ if (!m_pCops[i]) {
+ for (int j = i; j < ARRAY_SIZE(m_pCops); j++) {
+ if (m_pCops[j]) {
+ m_pCops[i] = m_pCops[j];
+ m_pCops[j] = nil;
+ fixed = false;
+ break;
+ }
+ }
+ if (fixed)
+ break;
+ }
+ }
+ }
+ }
+}
+
+void
+CWanted::ResetPolicePursuit(void)
+{
+ for(int i = 0; i < ARRAY_SIZE(m_pCops); i++) {
+ CCopPed *cop = m_pCops[i];
+ if (!cop)
+ continue;
+
+ cop->m_bIsInPursuit = false;
+ cop->m_objective = OBJECTIVE_NONE;
+ cop->m_prevObjective = OBJECTIVE_NONE;
+ cop->m_nLastPedState = PED_NONE;
+ if (!cop->DyingOrDead()) {
+ cop->SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f));
+ }
+ m_pCops[i] = nil;
+ }
+ m_CurrentCops = 0;
+}
+
+void
+CWanted::Reset(void)
+{
+ ResetPolicePursuit();
+ Initialise();
+}
+
+void
+CWanted::UpdateCrimesQ(void)
+{
+ for(int i = 0; i < ARRAY_SIZE(m_aCrimes); i++) {
+
+ CCrimeBeingQd &crime = m_aCrimes[i];
+ if (crime.m_nType != CRIME_NONE) {
+ if (CTimer::GetTimeInMilliseconds() > crime.m_nTime + 500 && !crime.m_bReported) {
+ ReportCrimeNow(crime.m_nType, crime.m_vecPosn, crime.m_bPoliceDoesntCare);
+ crime.m_bReported = true;
+ }
+ if (CTimer::GetTimeInMilliseconds() > crime.m_nTime + 10000)
+ crime.m_nType = CRIME_NONE;
+ }
+ }
+}
+
STARTPATCHES
InjectHook(0x4AD6E0, &CWanted::Initialise, PATCH_JUMP);
-// InjectHook(0x4AD790, &CWanted::Reset, PATCH_JUMP);
-// InjectHook(0x4AD7B0, &CWanted::Update, PATCH_JUMP);
+ InjectHook(0x4AD790, &CWanted::Reset, PATCH_JUMP);
+ InjectHook(0x4AD7B0, &CWanted::Update, PATCH_JUMP);
InjectHook(0x4AD900, &CWanted::UpdateWantedLevel, PATCH_JUMP);
InjectHook(0x4AD9F0, &CWanted::RegisterCrime, PATCH_JUMP);
InjectHook(0x4ADA10, &CWanted::RegisterCrime_Immediately, PATCH_JUMP);
@@ -374,10 +471,10 @@ STARTPATCHES
InjectHook(0x4ADBC0, &CWanted::AreFbiRequired, PATCH_JUMP);
InjectHook(0x4ADBE0, &CWanted::AreArmyRequired, PATCH_JUMP);
InjectHook(0x4ADC00, &CWanted::NumOfHelisRequired, PATCH_JUMP);
-// InjectHook(0x4ADC40, &CWanted::ResetPolicePursuit, PATCH_JUMP);
+ InjectHook(0x4ADC40, &CWanted::ResetPolicePursuit, PATCH_JUMP);
InjectHook(0x4ADD00, &CWanted::WorkOutPolicePresence, PATCH_JUMP);
InjectHook(0x4ADF20, &CWanted::ClearQdCrimes, PATCH_JUMP);
InjectHook(0x4ADFD0, &CWanted::AddCrimeToQ, PATCH_JUMP);
-// InjectHook(0x4AE090, &CWanted::UpdateCrimesQ, PATCH_JUMP);
+ InjectHook(0x4AE090, &CWanted::UpdateCrimesQ, PATCH_JUMP);
InjectHook(0x4AE110, &CWanted::ReportCrimeNow, PATCH_JUMP);
ENDPATCHES
diff --git a/src/core/Wanted.h b/src/core/Wanted.h
index f6dbe8d0..9823529c 100644
--- a/src/core/Wanted.h
+++ b/src/core/Wanted.h
@@ -30,7 +30,7 @@ class CCrimeBeingQd
public:
eCrimeType m_nType;
uint32 m_nId;
- int32 m_nTime;
+ uint32 m_nTime;
CVector m_vecPosn;
bool m_bReported;
bool m_bPoliceDoesntCare;
@@ -78,6 +78,8 @@ public:
void ReportCrimeNow(eCrimeType type, const CVector &coors, bool policeDoesntCare);
void UpdateWantedLevel();
void Reset();
+ void ResetPolicePursuit();
+ void UpdateCrimesQ();
void Update();
bool IsIgnored(void) { return m_bIgnoredByCops || m_bIgnoredByEveryone; }
diff --git a/src/core/World.cpp b/src/core/World.cpp
index cbceb292..4a0230ce 100644
--- a/src/core/World.cpp
+++ b/src/core/World.cpp
@@ -19,12 +19,14 @@
#include "Messages.h"
#include "Replay.h"
#include "Population.h"
+#include "Fire.h"
+
+CColPoint *gaTempSphereColPoints = (CColPoint*)0x6E64C0; // [32]
CPtrList *CWorld::ms_bigBuildingsList = (CPtrList*)0x6FAB60;
CPtrList &CWorld::ms_listMovingEntityPtrs = *(CPtrList*)0x8F433C;
CSector (*CWorld::ms_aSectors)[NUMSECTORS_X] = (CSector (*)[NUMSECTORS_Y])0x665608;
uint16 &CWorld::ms_nCurrentScanCode = *(uint16*)0x95CC64;
-CColPoint &CWorld::ms_testSpherePoint = *(CColPoint*)0x6E64C0;
uint8 &CWorld::PlayerInFocus = *(uint8 *)0x95CD61;
CPlayerInfo (&CWorld::Players)[NUMPLAYERS] = *(CPlayerInfo (*)[NUMPLAYERS])*(uintptr*)0x9412F0;
@@ -38,6 +40,7 @@ bool &CWorld::bProcessCutsceneOnly = *(bool*)0x95CD8B;
bool &CWorld::bDoingCarCollisions = *(bool*)0x95CD8C;
bool &CWorld::bIncludeCarTyres = *(bool*)0x95CDAA;
+WRAPPER void CWorld::ClearForRestart(void) { EAXJMP(0x4AE850); }
WRAPPER void CWorld::AddParticles(void) { EAXJMP(0x4B4010); }
WRAPPER void CWorld::ShutDown(void) { EAXJMP(0x4AE450); }
WRAPPER void CWorld::RepositionCertainDynamicObjects() { EAXJMP(0x4B42B0); }
@@ -52,6 +55,7 @@ WRAPPER void CWorld::FindObjectsOfTypeInRangeSectorList(uint32, CPtrList&, CVect
WRAPPER void CWorld::FindMissionEntitiesIntersectingCube(const CVector&, const CVector&, int16*, int16, CEntity**, bool, bool, bool) { EAXJMP(0x4B3680); }
WRAPPER void CWorld::ClearCarsFromArea(float, float, float, float, float, float) { EAXJMP(0x4B50E0); }
WRAPPER void CWorld::ClearPedsFromArea(float, float, float, float, float, float) { EAXJMP(0x4B52B0); }
+WRAPPER void CWorld::CallOffChaseForArea(float, float, float, float) { EAXJMP(0x4B5530); }
void
CWorld::Initialise()
@@ -609,9 +613,9 @@ CWorld::GetIsLineOfSightSectorListClear(CPtrList &list, const CColLine &line, bo
}
void
-CWorld::FindObjectsInRangeSectorList(CPtrList &list, CVector &centre, float distance, bool ignoreZ, short *nextObject, short lastObject, CEntity **objects)
+CWorld::FindObjectsInRangeSectorList(CPtrList &list, CVector &centre, float radius, bool ignoreZ, short *nextObject, short lastObject, CEntity **objects)
{
- float distSqr = distance * distance;
+ float radiusSqr = radius * radius;
float objDistSqr;
for (CPtrNode *node = list.first; node; node = node->next) {
@@ -625,7 +629,7 @@ CWorld::FindObjectsInRangeSectorList(CPtrList &list, CVector &centre, float dist
else
objDistSqr = diff.MagnitudeSqr();
- if (objDistSqr < distSqr && *nextObject < lastObject) {
+ if (objDistSqr < radiusSqr && *nextObject < lastObject) {
if (objects) {
objects[*nextObject] = object;
}
@@ -636,22 +640,22 @@ CWorld::FindObjectsInRangeSectorList(CPtrList &list, CVector &centre, float dist
}
void
-CWorld::FindObjectsInRange(CVector &centre, float distance, bool ignoreZ, short *nextObject, short lastObject, CEntity **objects, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies)
+CWorld::FindObjectsInRange(CVector &centre, float radius, bool ignoreZ, short *nextObject, short lastObject, CEntity **objects, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies)
{
- int minX = GetSectorIndexX(centre.x - distance);
+ int minX = GetSectorIndexX(centre.x - radius);
if (minX <= 0) minX = 0;
- int minY = GetSectorIndexY(centre.y - distance);
+ int minY = GetSectorIndexY(centre.y - radius);
if (minY <= 0) minY = 0;
- int maxX = GetSectorIndexX(centre.x + distance);
+ int maxX = GetSectorIndexX(centre.x + radius);
#ifdef FIX_BUGS
if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X - 1;
#else
if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X;
#endif
- int maxY = GetSectorIndexY(centre.y + distance);
+ int maxY = GetSectorIndexY(centre.y + radius);
#ifdef FIX_BUGS
if (maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y - 1;
#else
@@ -665,48 +669,48 @@ CWorld::FindObjectsInRange(CVector &centre, float distance, bool ignoreZ, short
for(int curX = minX; curX <= maxX; curX++) {
CSector *sector = GetSector(curX, curY);
if (checkBuildings) {
- FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, distance, ignoreZ, nextObject, lastObject, objects);
- FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects);
+ FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, radius, ignoreZ, nextObject, lastObject, objects);
+ FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, radius, ignoreZ, nextObject, lastObject, objects);
}
if (checkVehicles) {
- FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, distance, ignoreZ, nextObject, lastObject, objects);
- FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects);
+ FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, radius, ignoreZ, nextObject, lastObject, objects);
+ FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, radius, ignoreZ, nextObject, lastObject, objects);
}
if (checkPeds) {
- FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, distance, ignoreZ, nextObject, lastObject, objects);
- FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects);
+ FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, radius, ignoreZ, nextObject, lastObject, objects);
+ FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, radius, ignoreZ, nextObject, lastObject, objects);
}
if (checkObjects) {
- FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, distance, ignoreZ, nextObject, lastObject, objects);
- FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects);
+ FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, radius, ignoreZ, nextObject, lastObject, objects);
+ FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, radius, ignoreZ, nextObject, lastObject, objects);
}
if (checkDummies) {
- FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, distance, ignoreZ, nextObject, lastObject, objects);
- FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects);
+ FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, radius, ignoreZ, nextObject, lastObject, objects);
+ FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, radius, ignoreZ, nextObject, lastObject, objects);
}
}
}
}
CEntity*
-CWorld::TestSphereAgainstWorld(CVector centre, float distance, CEntity *entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects)
+CWorld::TestSphereAgainstWorld(CVector centre, float radius, CEntity *entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects)
{
CEntity* foundE = nil;
- int minX = GetSectorIndexX(centre.x - distance);
+ int minX = GetSectorIndexX(centre.x - radius);
if (minX <= 0) minX = 0;
- int minY = GetSectorIndexY(centre.y - distance);
+ int minY = GetSectorIndexY(centre.y - radius);
if (minY <= 0) minY = 0;
- int maxX = GetSectorIndexX(centre.x + distance);
+ int maxX = GetSectorIndexX(centre.x + radius);
#ifdef FIX_BUGS
if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X - 1;
#else
if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X;
#endif
- int maxY = GetSectorIndexY(centre.y + distance);
+ int maxY = GetSectorIndexY(centre.y + radius);
#ifdef FIX_BUGS
if (maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y - 1;
#else
@@ -719,47 +723,47 @@ CWorld::TestSphereAgainstWorld(CVector centre, float distance, CEntity *entityTo
for (int curX = minX; curX <= maxX; curX++) {
CSector* sector = GetSector(curX, curY);
if (checkBuildings) {
- foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, distance, entityToIgnore, false);
+ foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, radius, entityToIgnore, false);
if (foundE)
return foundE;
- foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, distance, entityToIgnore, false);
+ foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, radius, entityToIgnore, false);
if (foundE)
return foundE;
}
if (checkVehicles) {
- foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, distance, entityToIgnore, false);
+ foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, radius, entityToIgnore, false);
if (foundE)
return foundE;
- foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, distance, entityToIgnore, false);
+ foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, radius, entityToIgnore, false);
if (foundE)
return foundE;
}
if (checkPeds) {
- foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, distance, entityToIgnore, false);
+ foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, radius, entityToIgnore, false);
if (foundE)
return foundE;
- foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, distance, entityToIgnore, false);
+ foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, radius, entityToIgnore, false);
if (foundE)
return foundE;
}
if (checkObjects) {
- foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, distance, entityToIgnore, ignoreSomeObjects);
+ foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, radius, entityToIgnore, ignoreSomeObjects);
if (foundE)
return foundE;
- foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, distance, entityToIgnore, ignoreSomeObjects);
+ foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, radius, entityToIgnore, ignoreSomeObjects);
if (foundE)
return foundE;
}
if (checkDummies) {
- foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, distance, entityToIgnore, false);
+ foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, radius, entityToIgnore, false);
if (foundE)
return foundE;
- foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, distance, entityToIgnore, false);
+ foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, radius, entityToIgnore, false);
if (foundE)
return foundE;
}
@@ -806,7 +810,7 @@ CWorld::TestSphereAgainstSectorList(CPtrList &list, CVector spherePos, float rad
if (e->GetBoundRadius() + radius > distance) {
CColModel *eCol = CModelInfo::GetModelInfo(e->m_modelIndex)->GetColModel();
int collidedSpheres = CCollision::ProcessColModels(sphereMat, sphereCol, e->GetMatrix(),
- *eCol, &ms_testSpherePoint, nil, nil);
+ *eCol, gaTempSphereColPoints, nil, nil);
if (collidedSpheres != 0 ||
(e->IsVehicle() && ((CVehicle*)e)->m_vehType == VEHICLE_TYPE_CAR &&
@@ -1051,6 +1055,19 @@ CWorld::ExtinguishAllCarFiresInArea(CVector point, float range)
}
void
+CWorld::SetCarsOnFire(float x, float y, float z, float radius, CEntity *reason)
+{
+ int poolSize = CPools::GetVehiclePool()->GetSize();
+ for (int poolIndex = poolSize - 1; poolIndex >= 0; poolIndex--) {
+ CVehicle *veh = CPools::GetVehiclePool()->GetSlot(poolIndex);
+ if (veh && veh->m_status != STATUS_WRECKED && !veh->m_pCarFire && !veh->bFireProof) {
+ if (Abs(veh->GetPosition().z - z) < 5.0f && Abs(veh->GetPosition().x - x) < radius && Abs(veh->GetPosition().y - y) < radius)
+ gFireManager.StartFire(veh, reason, 0.8f, true);
+ }
+ }
+}
+
+void
CWorld::Process(void)
{
if (!(CTimer::GetFrameCounter() & 63))
diff --git a/src/core/World.h b/src/core/World.h
index 1ad65ac4..c4103eb2 100644
--- a/src/core/World.h
+++ b/src/core/World.h
@@ -60,8 +60,6 @@ class CWorld
static uint16 &ms_nCurrentScanCode;
public:
- static CColPoint& ms_testSpherePoint;
-
static uint8 &PlayerInFocus;
static CPlayerInfo (&Players)[NUMPLAYERS];
static CEntity *&pIgnoreEntity;
@@ -101,7 +99,7 @@ public:
static bool GetIsLineOfSightSectorClear(CSector &sector, const CColLine &line, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false);
static bool GetIsLineOfSightSectorListClear(CPtrList &list, const CColLine &line, bool ignoreSeeThrough, bool ignoreSomeObjects = false);
- static CEntity *TestSphereAgainstWorld(CVector centre, float distance, CEntity *entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects);
+ static CEntity *TestSphereAgainstWorld(CVector centre, float radius, CEntity *entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects);
static CEntity *TestSphereAgainstSectorList(CPtrList&, CVector, float, CEntity*, bool);
static void FindObjectsInRangeSectorList(CPtrList&, CVector&, float, bool, short*, short, CEntity**);
static void FindObjectsInRange(CVector&, float, bool, short*, short, CEntity**, bool, bool, bool, bool, bool);
@@ -117,6 +115,7 @@ public:
static void FindMissionEntitiesIntersectingCube(const CVector&, const CVector&, int16*, int16, CEntity**, bool, bool, bool);
static void ClearCarsFromArea(float, float, float, float, float, float);
static void ClearPedsFromArea(float, float, float, float, float, float);
+ static void CallOffChaseForArea(float, float, float, float);
static float GetSectorX(float f) { return ((f - WORLD_MIN_X)/SECTOR_SIZE_X); }
static float GetSectorY(float f) { return ((f - WORLD_MIN_Y)/SECTOR_SIZE_Y); }
@@ -132,15 +131,19 @@ public:
static void StopAllLawEnforcersInTheirTracks();
static void SetAllCarsCanBeDamaged(bool);
static void ExtinguishAllCarFiresInArea(CVector, float);
+ static void SetCarsOnFire(float, float, float, float, CEntity*);
static void Initialise();
static void AddParticles();
static void ShutDown();
+ static void ClearForRestart(void);
static void RepositionCertainDynamicObjects();
static void RemoveStaticObjects();
static void Process();
};
+extern CColPoint *gaTempSphereColPoints;
+
class CPlayerPed;
class CVehicle;
CPlayerPed *FindPlayerPed(void);
diff --git a/src/core/Zones.cpp b/src/core/Zones.cpp
index 363fc3d9..4bce3e79 100644
--- a/src/core/Zones.cpp
+++ b/src/core/Zones.cpp
@@ -1,5 +1,6 @@
#include "common.h"
#include "patcher.h"
+#include <ctype.h>
#include "Zones.h"
diff --git a/src/core/common.h b/src/core/common.h
index 3127cb12..b58b93af 100644
--- a/src/core/common.h
+++ b/src/core/common.h
@@ -8,9 +8,12 @@
#pragma warning(disable: 4996) // POSIX names
#include <stdint.h>
+#include <string.h>
#include <math.h>
-//#include <assert.h>
-#include <new>
+
+#ifdef WITHWINDOWS
+#include <Windows.h>
+#endif
#ifdef WITHD3D
#include <windows.h>
@@ -30,6 +33,16 @@
#undef near
#endif
+#ifndef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a)))
+#endif
+
typedef uint8_t uint8;
typedef int8_t int8;
typedef uint16_t uint16;
@@ -202,6 +215,7 @@ 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 lerp(norm, min, max) ( (norm) * ((max) - (min)) + (min) )
#define STRINGIFY(x) #x
#define STR(x) STRINGIFY(x)
diff --git a/src/core/config.h b/src/core/config.h
index 9235e744..373fca2f 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -94,12 +94,17 @@ enum Config {
NUM_GARAGES = 32,
NUM_PROJECTILES = 32,
+ NUM_GLASSPANES = 45,
+ NUM_GLASSENTITIES = 32,
NUM_WATERCANNONS = 3,
NUMPEDROUTES = 200,
NUMPHONES = 50,
NUMPEDGROUPS = 31,
NUMMODELSPERPEDGROUP = 8,
+ NUMSHOTINFOS = 100,
+
+ NUMROADBLOCKS = 600,
NUMVISIBLEENTITIES = 2000,
NUMINVISIBLEENTITIES = 150,
@@ -114,6 +119,8 @@ enum Config {
NUM_AUDIO_REFLECTIONS = 5,
NUM_SCRIPT_MAX_ENTITIES = 40,
+
+ NUM_GARAGE_STORED_CARS = 6
};
// We'll use this once we're ready to become independent of the game
@@ -164,15 +171,19 @@ enum Config {
// not in any game
# define NASTY_GAME // nasty game for all languages
# define NO_MOVIES // disable intro videos
-# define NO_CDCHECK
+# define NO_CDCHECK
# define CHATTYSPLASH // print what the game is loading
+//# define TIMEBARS // print debug timers
#endif
#define FIX_BUGS // fixes bugs that we've came across during reversing, TODO: use this more
-#define TOGGLEABLE_BETA_FEATURES // toggleable from debug menu. doesn't have too many things
+#define TOGGLEABLE_BETA_FEATURES // toggleable from debug menu. not too many things
+#define MORE_LANGUAGES // Add more translations to the game
// Pad
+#define XINPUT
#define KANGAROO_CHEAT
+#define REGISTER_START_BUTTON // currently only in menu sadly. resumes the game
// Hud, frontend and radar
#define ASPECT_RATIO_SCALE // Not just makes everything scale with aspect ratio, also adds support for all aspect ratios
@@ -199,5 +210,9 @@ enum Config {
// Peds
#define ANIMATE_PED_COL_MODEL
#define VC_PED_PORTS // various ports from VC's CPed, mostly subtle
-#define NEW_WALK_AROUND_ALGORITHM // to make walking around vehicles/objects less awkward
+// #define NEW_WALK_AROUND_ALGORITHM // to make walking around vehicles/objects less awkward
#define CANCELLABLE_CAR_ENTER
+
+// Camera
+#define IMPROVED_CAMERA // Better Debug cam, and maybe more in the future
+#define FREE_CAM // Rotating cam
diff --git a/src/core/main.cpp b/src/core/main.cpp
index 2a15e20e..674527f5 100644
--- a/src/core/main.cpp
+++ b/src/core/main.cpp
@@ -51,6 +51,7 @@
#include "Script.h"
#include "Debug.h"
#include "Console.h"
+#include "timebars.h"
#define DEFAULT_VIEWWINDOW (Tan(DEGTORAD(CDraw::GetFOV() * 0.5f)))
@@ -90,7 +91,6 @@ void DoFade(void);
void Render2dStuffAfterFade(void);
CSprite2d *LoadSplash(const char *name);
-void DestroySplashScreen(void);
extern void (*DebugMenuProcess)(void);
@@ -142,6 +142,11 @@ Idle(void *arg)
#endif
CTimer::Update();
+
+#ifdef TIMEBARS
+ tbInit();
+#endif
+
CSprite2d::InitPerFrame();
CFont::InitPerFrame();
@@ -156,16 +161,39 @@ Idle(void *arg)
FrontEndMenuManager.Process();
} else {
CPointLights::InitPerFrame();
+#ifdef TIMEBARS
+ tbStartTimer(0, "CGame::Process");
+#endif
CGame::Process();
+#ifdef TIMEBARS
+ tbEndTimer("CGame::Process");
+ tbStartTimer(0, "DMAudio.Service");
+#endif
DMAudio.Service();
+
+#ifdef TIMEBARS
+ tbEndTimer("DMAudio.Service");
+#endif
}
if (RsGlobal.quit)
return;
#else
CPointLights::InitPerFrame();
+#ifdef TIMEBARS
+ tbStartTimer(0, "CGame::Process");
+#endif
CGame::Process();
+#ifdef TIMEBARS
+ tbEndTimer("CGame::Process");
+ tbStartTimer(0, "DMAudio.Service");
+#endif
+
DMAudio.Service();
+
+#ifdef TIMEBARS
+ tbEndTimer("DMAudio.Service");
+#endif
#endif
if(CGame::bDemoMode && CTimer::GetTimeInMilliseconds() > (3*60 + 30)*1000 && !CCutsceneMgr::IsCutsceneProcessing()){
@@ -193,8 +221,18 @@ Idle(void *arg)
RsMouseSetPos(&pos);
}
#endif
+#ifdef TIMEBARS
+ tbStartTimer(0, "CnstrRenderList");
+#endif
CRenderer::ConstructRenderList();
+#ifdef TIMEBARS
+ tbEndTimer("CnstrRenderList");
+ tbStartTimer(0, "PreRender");
+#endif
CRenderer::PreRender();
+#ifdef TIMEBARS
+ tbEndTimer("PreRender");
+#endif
if(CWeather::LightningFlash && !CCullZones::CamNoRain()){
if(!DoRWStuffStartOfFrame_Horizon(255, 255, 255, 255, 255, 255, 255))
@@ -212,16 +250,31 @@ Idle(void *arg)
RwCameraSetFarClipPlane(Scene.camera, CTimeCycle::GetFarClip());
RwCameraSetFogDistance(Scene.camera, CTimeCycle::GetFogStart());
+#ifdef TIMEBARS
+ tbStartTimer(0, "RenderScene");
+#endif
RenderScene();
+#ifdef TIMEBARS
+ tbEndTimer("RenderScene");
+#endif
RenderDebugShit();
RenderEffects();
+#ifdef TIMEBARS
+ tbStartTimer(0, "RenderMotionBlur");
+#endif
if((TheCamera.m_BlurType == MBLUR_NONE || TheCamera.m_BlurType == MBLUR_NORMAL) &&
TheCamera.m_ScreenReductionPercentage > 0.0f)
TheCamera.SetMotionBlurAlpha(150);
TheCamera.RenderMotionBlur();
-
+#ifdef TIMEBARS
+ tbEndTimer("RenderMotionBlur");
+ tbStartTimer(0, "Render2dStuff");
+#endif
Render2dStuff();
+#ifdef TIMEBARS
+ tbEndTimer("Render2dStuff");
+#endif
}else{
float viewWindow = DEFAULT_VIEWWINDOW;
#ifdef ASPECT_RATIO_SCALE
@@ -239,10 +292,29 @@ Idle(void *arg)
if (FrontEndMenuManager.m_bMenuActive)
DefinedState();
#endif
+#ifdef TIMEBARS
+ tbStartTimer(0, "RenderMenus");
+#endif
RenderMenus();
+#ifdef TIMEBARS
+ tbEndTimer("RenderMenus");
+ tbStartTimer(0, "DoFade");
+#endif
DoFade();
+#ifdef TIMEBARS
+ tbEndTimer("DoFade");
+ tbStartTimer(0, "Render2dStuff-Fade");
+#endif
Render2dStuffAfterFade();
+#ifdef TIMEBARS
+ tbEndTimer("Render2dStuff-Fade");
+#endif
CCredits::Render();
+
+#ifdef TIMEBARS
+ tbDisplay();
+#endif
+
DoRWStuffEndOfFrame();
// if(g_SlowMode)
@@ -325,8 +397,9 @@ DoRWStuffStartOfFrame_Horizon(int16 TopRed, int16 TopGreen, int16 TopBlue, int16
void
DoRWStuffEndOfFrame(void)
{
+ CDebug::DisplayScreenStrings(); // custom
CDebug::DebugDisplayTextBuffer();
- // FlushObrsPrintfs();
+ FlushObrsPrintfs();
RwCameraEndUpdate(Scene.camera);
RsCameraShowRaster(Scene.camera);
}
diff --git a/src/core/main.h b/src/core/main.h
index 570189b3..5e9401b9 100644
--- a/src/core/main.h
+++ b/src/core/main.h
@@ -28,6 +28,7 @@ void InitialiseGame(void);
void LoadingScreen(const char *str1, const char *str2, const char *splashscreen);
void LoadingIslandScreen(const char *levelName);
CSprite2d *LoadSplash(const char *name);
+void DestroySplashScreen(void);
char *GetLevelSplashScreen(int level);
char *GetRandomSplashScreen(void);
void LittleTest(void);
diff --git a/src/core/obrstr.cpp b/src/core/obrstr.cpp
new file mode 100644
index 00000000..3663d134
--- /dev/null
+++ b/src/core/obrstr.cpp
@@ -0,0 +1,119 @@
+#include "common.h"
+#include "Debug.h"
+#include "obrstr.h"
+
+char obrstr[128];
+char obrstr2[128];
+
+void ObrInt(int32 n1)
+{
+ IntToStr(n1, obrstr);
+ CDebug::DebugAddText(obrstr);
+}
+
+void ObrInt2(int32 n1, int32 n2)
+{
+ IntToStr(n1, obrstr);
+ strcat(obrstr, " ");
+ IntToStr(n2, obrstr2);
+ strcat(obrstr, obrstr2);
+ CDebug::DebugAddText(obrstr);
+}
+
+void ObrInt3(int32 n1, int32 n2, int32 n3)
+{
+ IntToStr(n1, obrstr);
+ strcat(obrstr, " ");
+ IntToStr(n2, obrstr2);
+ strcat(obrstr, obrstr2);
+ strcat(obrstr, " ");
+ IntToStr(n3, obrstr2);
+ strcat(obrstr, obrstr2);
+ CDebug::DebugAddText(obrstr);
+}
+
+void ObrInt4(int32 n1, int32 n2, int32 n3, int32 n4)
+{
+ IntToStr(n1, obrstr);
+ strcat(obrstr, " ");
+ IntToStr(n2, obrstr2);
+ strcat(obrstr, obrstr2);
+ strcat(obrstr, " ");
+ IntToStr(n3, obrstr2);
+ strcat(obrstr, obrstr2);
+ strcat(obrstr, " ");
+ IntToStr(n4, obrstr2);
+ strcat(obrstr, obrstr2);
+ CDebug::DebugAddText(obrstr);
+}
+
+void ObrInt5(int32 n1, int32 n2, int32 n3, int32 n4, int32 n5)
+{
+ IntToStr(n1, obrstr);
+ strcat(obrstr, " ");
+ IntToStr(n2, obrstr2);
+ strcat(obrstr, obrstr2);
+ strcat(obrstr, " ");
+ IntToStr(n3, obrstr2);
+ strcat(obrstr, obrstr2);
+ strcat(obrstr, " ");
+ IntToStr(n4, obrstr2);
+ strcat(obrstr, obrstr2);
+ strcat(obrstr, " ");
+ IntToStr(n5, obrstr2);
+ strcat(obrstr, obrstr2);
+ CDebug::DebugAddText(obrstr);
+}
+
+void ObrInt6(int32 n1, int32 n2, int32 n3, int32 n4, int32 n5, int32 n6)
+{
+ IntToStr(n1, obrstr);
+ strcat(obrstr, " ");
+ IntToStr(n2, obrstr2);
+ strcat(obrstr, obrstr2);
+ strcat(obrstr, " ");
+ IntToStr(n3, obrstr2);
+ strcat(obrstr, obrstr2);
+ strcat(obrstr, " ");
+ IntToStr(n4, obrstr2);
+ strcat(obrstr, obrstr2);
+ strcat(obrstr, " ");
+ IntToStr(n5, obrstr2);
+ strcat(obrstr, obrstr2);
+ strcat(obrstr, " ");
+ IntToStr(n6, obrstr2);
+ strcat(obrstr, obrstr2);
+ CDebug::DebugAddText(obrstr);
+}
+
+void IntToStr(int32 inNum, char *outStr)
+{
+ bool isNeg = inNum < 0;
+
+ if (isNeg) {
+ inNum = -inNum;
+ *outStr = '-';
+ }
+
+ int16 digits = 1;
+
+ if (inNum > 9) {
+ int32 _inNum = inNum;
+ do {
+ digits++;
+ _inNum /= 10;
+ } while (_inNum > 9);
+ }
+
+ int32 strSize = digits;
+ if (isNeg)
+ strSize++;
+
+ char *pStr = &outStr[strSize];
+ int32 i = 0;
+ do {
+ *(pStr-- - 1) = (inNum % 10) + '0';
+ inNum /= 10;
+ } while (++i < strSize);
+ outStr[strSize] = '\0';
+} \ No newline at end of file
diff --git a/src/core/obrstr.h b/src/core/obrstr.h
new file mode 100644
index 00000000..6838afb5
--- /dev/null
+++ b/src/core/obrstr.h
@@ -0,0 +1,9 @@
+#pragma once
+
+void ObrInt(int32 n1);
+void ObrInt2(int32 n1, int32 n2);
+void ObrInt3(int32 n1, int32 n2, int32 n3);
+void ObrInt4(int32 n1, int32 n2, int32 n3, int32 n4);
+void ObrInt5(int32 n1, int32 n2, int32 n3, int32 n4, int32 n5);
+void ObrInt6(int32 n1, int32 n2, int32 n3, int32 n4, int32 n5, int32 n6);
+void IntToStr(int32 inNum, char *outStr); \ No newline at end of file
diff --git a/src/core/patcher.cpp b/src/core/patcher.cpp
index 5fdbdf8b..19ca5f07 100644
--- a/src/core/patcher.cpp
+++ b/src/core/patcher.cpp
@@ -1,6 +1,11 @@
#include "common.h"
#include "patcher.h"
+#include <algorithm>
+#include <vector>
+
+#include <Windows.h>
+
StaticPatcher *StaticPatcher::ms_head;
StaticPatcher::StaticPatcher(Patcher func)
@@ -20,3 +25,55 @@ StaticPatcher::Apply()
}
ms_head = nil;
}
+
+std::vector<uint32> usedAddresses;
+
+static DWORD protect[2];
+static uint32 protect_address;
+static uint32 protect_size;
+
+void
+Protect_internal(uint32 address, uint32 size)
+{
+ protect_address = address;
+ protect_size = size;
+ VirtualProtect((void*)address, size, PAGE_EXECUTE_READWRITE, &protect[0]);
+}
+
+void
+Unprotect_internal(void)
+{
+ VirtualProtect((void*)protect_address, protect_size, protect[0], &protect[1]);
+}
+
+void
+InjectHook_internal(uint32 address, uint32 hook, int type)
+{
+ if(std::any_of(usedAddresses.begin(), usedAddresses.end(),
+ [address](uint32 value) { return value == address; })) {
+ debug("Used address %#06x twice when injecting hook\n", address);
+ }
+
+ usedAddresses.push_back(address);
+
+
+ switch(type){
+ case PATCH_JUMP:
+ VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &protect[0]);
+ *(uint8*)address = 0xE9;
+ break;
+ case PATCH_CALL:
+ VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &protect[0]);
+ *(uint8*)address = 0xE8;
+ break;
+ default:
+ VirtualProtect((void*)(address + 1), 4, PAGE_EXECUTE_READWRITE, &protect[0]);
+ break;
+ }
+
+ *(ptrdiff_t*)(address + 1) = hook - address - 5;
+ if(type == PATCH_NOTHING)
+ VirtualProtect((void*)(address + 1), 4, protect[0], &protect[1]);
+ else
+ VirtualProtect((void*)address, 5, protect[0], &protect[1]);
+} \ No newline at end of file
diff --git a/src/core/patcher.h b/src/core/patcher.h
index 87a6bea4..2722b6fd 100644
--- a/src/core/patcher.h
+++ b/src/core/patcher.h
@@ -6,13 +6,7 @@
#define VARJMP(a) { _asm jmp a }
#define WRAPARG(a) UNREFERENCED_PARAMETER(a)
-#define NOVMT __declspec(novtable)
-#define SETVMT(a) *((DWORD_PTR*)this) = (DWORD_PTR)a
-
-#include <algorithm>
-#include <vector>
-
-#include "common.h"
+#include <string.h> //memset
enum
{
@@ -103,72 +97,30 @@ isVC(void)
InjectHook(a, func); \
}
+void InjectHook_internal(uint32 address, uint32 hook, int type);
+void Protect_internal(uint32 address, uint32 size);
+void Unprotect_internal(void);
+
template<typename T, typename AT> inline void
Patch(AT address, T value)
{
- DWORD dwProtect[2];
- VirtualProtect((void*)address, sizeof(T), PAGE_EXECUTE_READWRITE, &dwProtect[0]);
+ Protect_internal((uint32)address, sizeof(T));
*(T*)address = value;
- VirtualProtect((void*)address, sizeof(T), dwProtect[0], &dwProtect[1]);
+ Unprotect_internal();
}
template<typename AT> inline void
Nop(AT address, unsigned int nCount)
{
- DWORD dwProtect[2];
- VirtualProtect((void*)address, nCount, PAGE_EXECUTE_READWRITE, &dwProtect[0]);
+ Protect_internal((uint32)address, nCount);
memset((void*)address, 0x90, nCount);
- VirtualProtect((void*)address, nCount, dwProtect[0], &dwProtect[1]);
-}
-
-template<typename AT> inline void
-ClearCC(AT address, unsigned int nCount)
-{
- DWORD dwProtect[2];
- VirtualProtect((void*)address, nCount, PAGE_EXECUTE_READWRITE, &dwProtect[0]);
- memset((void*)address, 0xCC, nCount);
- VirtualProtect((void*)address, nCount, dwProtect[0], &dwProtect[1]);
+ Unprotect_internal();
}
-extern std::vector<int32> usedAddresses;
-
-template<typename AT, typename HT> inline void
-InjectHook(AT address, HT hook, unsigned int nType=PATCH_NOTHING)
+template <typename T> inline void
+InjectHook(uintptr_t address, T hook, unsigned int nType = PATCH_NOTHING)
{
- if(std::any_of(usedAddresses.begin(), usedAddresses.end(),
- [address](AT value) { return (int32)value == address; })) {
- debug("Used address %#06x twice when injecting hook\n", address);
- }
-
- usedAddresses.push_back((int32)address);
-
- DWORD dwProtect[2];
- switch ( nType )
- {
- case PATCH_JUMP:
- VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect[0]);
- *(BYTE*)address = 0xE9;
- break;
- case PATCH_CALL:
- VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect[0]);
- *(BYTE*)address = 0xE8;
- break;
- default:
- VirtualProtect((void*)((DWORD)address + 1), 4, PAGE_EXECUTE_READWRITE, &dwProtect[0]);
- break;
- }
- DWORD dwHook;
- _asm
- {
- mov eax, hook
- mov dwHook, eax
- }
-
- *(ptrdiff_t*)((DWORD)address + 1) = (DWORD)dwHook - (DWORD)address - 5;
- if ( nType == PATCH_NOTHING )
- VirtualProtect((void*)((DWORD)address + 1), 4, dwProtect[0], &dwProtect[1]);
- else
- VirtualProtect((void*)address, 5, dwProtect[0], &dwProtect[1]);
+ InjectHook_internal(address, reinterpret_cast<uintptr_t>((void *&)hook), nType);
}
inline void ExtractCall(void *dst, uint32_t a)
diff --git a/src/core/re3.cpp b/src/core/re3.cpp
index 6f0a4682..6d4ff252 100644
--- a/src/core/re3.cpp
+++ b/src/core/re3.cpp
@@ -20,12 +20,10 @@
#include "debugmenu_public.h"
#include "Particle.h"
#include "Console.h"
+#include "Debug.h"
-#include <vector>
#include <list>
-std::vector<int32> usedAddresses;
-
void **rwengine = *(void***)0x5A10E1;
DebugMenuAPI gDebugMenuAPI;
@@ -114,13 +112,16 @@ SpawnCar(int id)
CStreaming::LoadAllRequestedModels(false);
if(CStreaming::HasModelLoaded(id)){
playerpos = FindPlayerCoors();
- int node = ThePaths.FindNodeClosestToCoors(playerpos, 0, 100.0f, false, false);
- if(node < 0)
- return;
+ int node;
+ if(!CModelInfo::IsBoatModel(id)){
+ node = ThePaths.FindNodeClosestToCoors(playerpos, 0, 100.0f, false, false);
+ if(node < 0)
+ return;
+ }
CVehicle *v;
if(CModelInfo::IsBoatModel(id))
- return;
+ v = new CBoat(id, RANDOM_VEHICLE);
else
v = new CAutomobile(id, RANDOM_VEHICLE);
@@ -130,7 +131,11 @@ SpawnCar(int id)
if(carCol2)
DebugMenuEntrySetAddress(carCol2, &v->m_currentColour2);
- v->GetPosition() = ThePaths.m_pathNodes[node].pos;
+ if(CModelInfo::IsBoatModel(id))
+ v->GetPosition() = TheCamera.GetPosition() + TheCamera.GetForward()*15.0f;
+ else
+ 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;
@@ -197,6 +202,12 @@ PlaceOnRoad(void)
((CAutomobile*)veh)->PlaceOnRoadProperly();
}
+static void
+ResetCamStatics(void)
+{
+ TheCamera.Cams[TheCamera.ActiveCam].ResetStatics = true;
+}
+
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",
@@ -358,7 +369,21 @@ DebugMenuPopulate(void)
DebugMenuAddCmd("Debug", "Start Credits", CCredits::Start);
DebugMenuAddCmd("Debug", "Stop Credits", CCredits::Stop);
-
+
+ extern bool PrintDebugCode;
+ extern int16 &DebugCamMode;
+ DebugMenuAddVarBool8("Cam", "Use mouse Cam", (int8*)&CCamera::m_bUseMouse3rdPerson, nil);
+#ifdef FREE_CAM
+ DebugMenuAddVarBool8("Cam", "Free Cam", (int8*)&CCamera::bFreeCam, nil);
+#endif
+ DebugMenuAddVarBool8("Cam", "Print Debug Code", (int8*)&PrintDebugCode, nil);
+ DebugMenuAddVar("Cam", "Cam Mode", &DebugCamMode, nil, 1, 0, CCam::MODE_EDITOR, nil);
+ DebugMenuAddCmd("Cam", "Normal", []() { DebugCamMode = 0; });
+ DebugMenuAddCmd("Cam", "Follow Ped With Bind", []() { DebugCamMode = CCam::MODE_FOLLOW_PED_WITH_BIND; });
+ DebugMenuAddCmd("Cam", "Reaction", []() { DebugCamMode = CCam::MODE_REACTION; });
+ DebugMenuAddCmd("Cam", "Chris", []() { DebugCamMode = CCam::MODE_CHRIS; });
+ DebugMenuAddCmd("Cam", "Reset Statics", ResetCamStatics);
+
CTweakVars::AddDBG("Debug");
}
}
@@ -433,7 +458,8 @@ void re3_debug(const char *format, ...)
vsprintf_s(re3_buff, re3_buffsize, format, va);
va_end(va);
- printf("%s", re3_buff);
+// printf("%s", re3_buff);
+ CDebug::DebugAddText(re3_buff);
}
void re3_trace(const char *filename, unsigned int lineno, const char *func, const char *format, ...)
diff --git a/src/core/timebars.cpp b/src/core/timebars.cpp
new file mode 100644
index 00000000..30421731
--- /dev/null
+++ b/src/core/timebars.cpp
@@ -0,0 +1,121 @@
+#ifndef MASTER
+#include "common.h"
+#include "Font.h"
+#include "Frontend.h"
+#include "Timer.h"
+#include "Text.h"
+
+#define MAX_TIMERS (50)
+#define MAX_MS_COLLECTED (40)
+
+// enables frame time output
+#define FRAMETIME
+
+struct sTimeBar
+{
+ char name[20];
+ float startTime;
+ float endTime;
+ int32 unk;
+};
+
+struct
+{
+ sTimeBar Timers[MAX_TIMERS];
+ uint32 count;
+} TimerBar;
+float MaxTimes[MAX_TIMERS];
+float MaxFrameTime;
+
+uint32 curMS;
+uint32 msCollected[MAX_MS_COLLECTED];
+#ifdef FRAMETIME
+float FrameInitTime;
+#endif
+
+void tbInit()
+{
+ TimerBar.count = 0;
+ uint32 i = CTimer::GetFrameCounter() & 0x7F;
+ if (i == 0) {
+ do
+ MaxTimes[i++] = 0.0f;
+ while (i != MAX_TIMERS);
+#ifdef FRAMETIME
+ MaxFrameTime = 0.0f;
+#endif
+ }
+#ifdef FRAMETIME
+ FrameInitTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerFrame();
+#endif
+}
+
+void tbStartTimer(int32 unk, char *name)
+{
+ strcpy(TimerBar.Timers[TimerBar.count].name, name);
+ TimerBar.Timers[TimerBar.count].unk = unk;
+ TimerBar.Timers[TimerBar.count].startTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerFrame();
+ TimerBar.count++;
+}
+
+void tbEndTimer(char* name)
+{
+ uint32 n = 1500;
+ for (uint32 i = 0; i < TimerBar.count; i++) {
+ if (strcmp(name, TimerBar.Timers[i].name) == 0)
+ n = i;
+ }
+ assert(n != 1500);
+ TimerBar.Timers[n].endTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerFrame();
+}
+
+float Diag_GetFPS()
+{
+ return 39000.0f / (msCollected[(curMS - 1) % MAX_MS_COLLECTED] - msCollected[curMS % MAX_MS_COLLECTED]);
+}
+
+void tbDisplay()
+{
+ char temp[200];
+ wchar wtemp[200];
+
+#ifdef FRAMETIME
+ float FrameEndTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerFrame();
+#endif
+
+ msCollected[(curMS++) % MAX_MS_COLLECTED] = RsTimer();
+ CFont::SetBackgroundOff();
+ CFont::SetBackgroundColor(CRGBA(0, 0, 0, 128));
+ CFont::SetScale(0.48f, 1.12f);
+ CFont::SetCentreOff();
+ CFont::SetJustifyOff();
+ CFont::SetWrapx(640.0f);
+ CFont::SetRightJustifyOff();
+ CFont::SetPropOn();
+ CFont::SetFontStyle(FONT_BANK);
+ sprintf(temp, "FPS: %.2f", Diag_GetFPS());
+ AsciiToUnicode(temp, wtemp);
+ CFont::SetColor(CRGBA(255, 255, 255, 255));
+ if (!CMenuManager::m_PrefsMarketing || !CMenuManager::m_PrefsDisableTutorials) {
+ CFont::PrintString(RsGlobal.maximumWidth * (4.0f / DEFAULT_SCREEN_WIDTH), RsGlobal.maximumHeight * (4.0f / DEFAULT_SCREEN_HEIGHT), wtemp);
+
+#ifndef FINAL
+ // Timers output (my own implementation)
+ for (uint32 i = 0; i < TimerBar.count; i++) {
+ MaxTimes[i] = max(MaxTimes[i], TimerBar.Timers[i].endTime - TimerBar.Timers[i].startTime);
+ sprintf(temp, "%s: %.2f", &TimerBar.Timers[i].name[0], MaxTimes[i]);
+ AsciiToUnicode(temp, wtemp);
+ CFont::PrintString(RsGlobal.maximumWidth * (4.0f / DEFAULT_SCREEN_WIDTH), RsGlobal.maximumHeight * ((8.0f * (i + 2)) / DEFAULT_SCREEN_HEIGHT), wtemp);
+ }
+
+#ifdef FRAMETIME
+ MaxFrameTime = max(MaxFrameTime, FrameEndTime - FrameInitTime);
+ sprintf(temp, "Frame Time: %.2f", MaxFrameTime);
+ AsciiToUnicode(temp, wtemp);
+
+ CFont::PrintString(RsGlobal.maximumWidth * (4.0f / DEFAULT_SCREEN_WIDTH), RsGlobal.maximumHeight * ((8.0f * (TimerBar.count + 4)) / DEFAULT_SCREEN_HEIGHT), wtemp);
+#endif // FRAMETIME
+#endif // !FINAL
+ }
+}
+#endif // !MASTER \ No newline at end of file
diff --git a/src/core/timebars.h b/src/core/timebars.h
new file mode 100644
index 00000000..8ffccd8e
--- /dev/null
+++ b/src/core/timebars.h
@@ -0,0 +1,6 @@
+#pragma once
+
+void tbInit();
+void tbStartTimer(int32, char*);
+void tbEndTimer(char*);
+void tbDisplay(); \ No newline at end of file
diff --git a/src/entities/Building.cpp b/src/entities/Building.cpp
index 188cbfe7..7813c87f 100644
--- a/src/entities/Building.cpp
+++ b/src/entities/Building.cpp
@@ -21,6 +21,8 @@ CBuilding::ReplaceWithNewModel(int32 id)
CStreaming::RequestModel(id, STREAMFLAGS_DONT_REMOVE);
}
+#include <new>
+
class CBuilding_ : public CBuilding
{
public:
diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp
index 04a93420..8bec1ac8 100644
--- a/src/entities/Entity.cpp
+++ b/src/entities/Entity.cpp
@@ -865,6 +865,8 @@ CEntity::ModifyMatrixForBannerInWind(void)
UpdateRwFrame();
}
+#include <new>
+
class CEntity_ : public CEntity
{
public:
diff --git a/src/math/Vector.h b/src/math/Vector.h
index cd436123..6f544ada 100644
--- a/src/math/Vector.h
+++ b/src/math/Vector.h
@@ -38,6 +38,14 @@ public:
}else
x = 1.0f;
}
+
+ void Normalise(float norm) {
+ float sq = MagnitudeSqr();
+ float invsqrt = RecipSqrt(norm, sq);
+ x *= invsqrt;
+ y *= invsqrt;
+ z *= invsqrt;
+ }
const CVector &operator+=(CVector const &right) {
x += right.x;
diff --git a/src/modelinfo/VehicleModelInfo.cpp b/src/modelinfo/VehicleModelInfo.cpp
index 87f01177..42ad635b 100644
--- a/src/modelinfo/VehicleModelInfo.cpp
+++ b/src/modelinfo/VehicleModelInfo.cpp
@@ -1113,6 +1113,8 @@ public:
};
STARTPATCHES
+ InjectHook(0x427820, &CVehicleModelInfo::SetComponentsToUse, PATCH_JUMP);
+
InjectHook(0x51FDC0, &CVehicleModelInfo_::DeleteRwObject_, PATCH_JUMP);
InjectHook(0x51FCB0, &CVehicleModelInfo_::CreateInstance_, PATCH_JUMP);
InjectHook(0x51FC60, &CVehicleModelInfo_::SetClump_, PATCH_JUMP);
diff --git a/src/modelinfo/VehicleModelInfo.h b/src/modelinfo/VehicleModelInfo.h
index 1a6d6a55..5969c4ca 100644
--- a/src/modelinfo/VehicleModelInfo.h
+++ b/src/modelinfo/VehicleModelInfo.h
@@ -132,5 +132,6 @@ public:
static void ShutdownEnvironmentMaps(void);
static int GetMaximumNumberOfPassengersFromNumberOfDoors(int id);
+ static void SetComponentsToUse(int8 c1, int8 c2) { ms_compsToUse[0] = c1; ms_compsToUse[1] = c2; }
};
static_assert(sizeof(CVehicleModelInfo) == 0x1F8, "CVehicleModelInfo: error");
diff --git a/src/objects/DummyObject.cpp b/src/objects/DummyObject.cpp
index 9649cf7a..ba09ac3e 100644
--- a/src/objects/DummyObject.cpp
+++ b/src/objects/DummyObject.cpp
@@ -12,6 +12,8 @@ CDummyObject::CDummyObject(CObject *obj)
m_level = obj->m_level;
}
+#include <new>
+
class CDummyObject_ : public CDummyObject
{
public:
diff --git a/src/objects/Object.cpp b/src/objects/Object.cpp
index 357d67d7..aa366aa0 100644
--- a/src/objects/Object.cpp
+++ b/src/objects/Object.cpp
@@ -5,6 +5,7 @@
#include "Pools.h"
#include "Radar.h"
#include "Object.h"
+#include "DummyObject.h"
WRAPPER void CObject::ObjectDamage(float amount) { EAXJMP(0x4BB240); }
WRAPPER void CObject::DeleteAllTempObjectInArea(CVector, float) { EAXJMP(0x4BBED0); }
@@ -37,8 +38,8 @@ CObject::CObject(void)
bIsPickup = false;
m_obj_flag2 = false;
bOutOfStock = false;
- m_obj_flag8 = false;
- m_obj_flag10 = false;
+ bGlassCracked = false;
+ bGlassBroken = false;
bHasBeenDamaged = false;
m_nRefModelIndex = -1;
bUseVehicleColours = false;
@@ -141,6 +142,8 @@ CObject::CanBeDeleted(void)
}
}
+#include <new>
+
class CObject_ : public CObject
{
public:
diff --git a/src/objects/Object.h b/src/objects/Object.h
index b9c570f5..27346e23 100644
--- a/src/objects/Object.h
+++ b/src/objects/Object.h
@@ -1,7 +1,6 @@
#pragma once
#include "Physical.h"
-#include "DummyObject.h"
enum {
GAME_OBJECT = 1,
@@ -26,6 +25,7 @@ enum {
};
class CVehicle;
+class CDummyObject;
class CObject : public CPhysical
{
@@ -36,8 +36,8 @@ public:
int8 bIsPickup : 1;
int8 m_obj_flag2 : 1;
int8 bOutOfStock : 1;
- int8 m_obj_flag8 : 1;
- int8 m_obj_flag10 : 1;
+ int8 bGlassCracked : 1;
+ int8 bGlassBroken : 1;
int8 bHasBeenDamaged : 1;
int8 bUseVehicleColours : 1;
int8 m_obj_flag80 : 1;
diff --git a/src/objects/Projectile.cpp b/src/objects/Projectile.cpp
index 0f6542e7..32bc6bdb 100644
--- a/src/objects/Projectile.cpp
+++ b/src/objects/Projectile.cpp
@@ -14,6 +14,8 @@ CProjectile::CProjectile(int32 model) : CObject()
ObjectCreatedBy = MISSION_OBJECT;
}
+#include <new>
+
class CProjectile_ : public CProjectile
{
public:
diff --git a/src/peds/CivilianPed.cpp b/src/peds/CivilianPed.cpp
index bb61e086..533d7c98 100644
--- a/src/peds/CivilianPed.cpp
+++ b/src/peds/CivilianPed.cpp
@@ -4,6 +4,8 @@
#include "Phones.h"
#include "General.h"
#include "PlayerPed.h"
+#include "Wanted.h"
+#include "DMAudio.h"
#include "World.h"
#include "Vehicle.h"
#include "SurfaceTable.h"
@@ -377,6 +379,8 @@ CCivilianPed::ProcessControl(void)
Avoid();
}
+#include <new>
+
class CCivilianPed_ : public CCivilianPed
{
public:
diff --git a/src/peds/CopPed.cpp b/src/peds/CopPed.cpp
index 53ae1747..b5812136 100644
--- a/src/peds/CopPed.cpp
+++ b/src/peds/CopPed.cpp
@@ -3,12 +3,19 @@
#include "World.h"
#include "PlayerPed.h"
#include "CopPed.h"
+#include "Wanted.h"
+#include "DMAudio.h"
#include "ModelIndices.h"
#include "Vehicle.h"
#include "RpAnimBlend.h"
+#include "AnimBlendAssociation.h"
#include "General.h"
-
-WRAPPER void CCopPed::ProcessControl() { EAXJMP(0x4C1400); }
+#include "ZoneCull.h"
+#include "PathFind.h"
+#include "RoadBlocks.h"
+#include "CarCtrl.h"
+#include "Renderer.h"
+#include "Camera.h"
CCopPed::CCopPed(eCopType copType) : CPed(PEDTYPE_COP)
{
@@ -58,11 +65,16 @@ CCopPed::CCopPed(eCopType copType) : CPed(PEDTYPE_COP)
m_bIsDisabledCop = false;
field_1356 = 0;
m_attackTimer = 0;
- field_1351 = 0;
- m_bZoneDisabledButClose = false;
+ m_bBeatingSuspect = false;
+ m_bStopAndShootDisabledZone = false;
m_bZoneDisabled = false;
field_1364 = -1;
m_pPointGunAt = nil;
+
+ // VC also initializes in here, but as nil
+#ifdef FIX_BUGS
+ m_wRoadblockNode = -1;
+#endif
}
CCopPed::~CCopPed()
@@ -163,7 +175,7 @@ CCopPed::ClearPursuit(void)
bIsRunning = false;
bNotAllowedToDuck = false;
bKindaStayInSamePlace = false;
- m_bZoneDisabledButClose = false;
+ m_bStopAndShootDisabledZone = false;
m_bZoneDisabled = false;
ClearObjective();
if (IsPedInControl()) {
@@ -181,15 +193,15 @@ CCopPed::ClearPursuit(void)
}
}
-// TO-DO: m_MaxCops in for loop may be a bug, check it out after CopAI
+// TODO: I don't know why they needed that parameter.
void
-CCopPed::SetPursuit(bool iMayAlreadyBeInPursuit)
+CCopPed::SetPursuit(bool ignoreCopLimit)
{
CWanted *wanted = FindPlayerPed()->m_pWanted;
if (m_bIsInPursuit || !IsPedInControl())
return;
- if (wanted->m_CurrentCops < wanted->m_MaxCops || iMayAlreadyBeInPursuit) {
+ if (wanted->m_CurrentCops < wanted->m_MaxCops || ignoreCopLimit) {
for (int i = 0; i < wanted->m_MaxCops; ++i) {
if (!wanted->m_pCops[i]) {
m_bIsInPursuit = true;
@@ -205,7 +217,7 @@ CCopPed::SetPursuit(bool iMayAlreadyBeInPursuit)
SetObjectiveTimer(0);
bNotAllowedToDuck = true;
bIsRunning = true;
- m_bZoneDisabledButClose = false;
+ m_bStopAndShootDisabledZone = false;
}
}
}
@@ -275,19 +287,474 @@ CCopPed::ScanForCrimes(void)
}
}
+void
+CCopPed::CopAI(void)
+{
+ CWanted *wanted = FindPlayerPed()->m_pWanted;
+ int wantedLevel = wanted->m_nWantedLevel;
+ CPhysical *playerOrHisVeh = FindPlayerVehicle() ? (CPhysical*)FindPlayerVehicle() : (CPhysical*)FindPlayerPed();
+
+ if (wanted->m_bIgnoredByEveryone || wanted->m_bIgnoredByCops) {
+ if (m_nPedState != PED_ARREST_PLAYER)
+ ClearPursuit();
+
+ return;
+ }
+ if (CCullZones::NoPolice() && m_bIsInPursuit && !m_bIsDisabledCop) {
+ if (bHitSomethingLastFrame) {
+ m_bZoneDisabled = true;
+ m_bIsDisabledCop = true;
+#ifdef FIX_BUGS
+ m_wRoadblockNode = -1;
+#else
+ m_wRoadblockNode = 0;
+#endif
+ bKindaStayInSamePlace = true;
+ bIsRunning = false;
+ bNotAllowedToDuck = false;
+ bCrouchWhenShooting = false;
+ SetIdle();
+ ClearObjective();
+ ClearPursuit();
+ m_prevObjective = OBJECTIVE_NONE;
+ m_nLastPedState = PED_NONE;
+ SetAttackTimer(0);
+
+ // Safe distance for disabled zone? Or to just make game easier?
+ if (m_fDistanceToTarget > 15.0f)
+ m_bStopAndShootDisabledZone = true;
+ }
+ } else if (m_bZoneDisabled && !CCullZones::NoPolice()) {
+ m_bZoneDisabled = false;
+ m_bIsDisabledCop = false;
+ m_bStopAndShootDisabledZone = false;
+ bKindaStayInSamePlace = false;
+ bCrouchWhenShooting = false;
+ bDuckAndCover = false;
+ ClearPursuit();
+ }
+ if (wantedLevel > 0) {
+ if (!m_bIsDisabledCop) {
+ if (!m_bIsInPursuit || wanted->m_CurrentCops > wanted->m_MaxCops) {
+ CCopPed *copFarthestToTarget = nil;
+ float copFarthestToTargetDist = m_fDistanceToTarget;
+
+ int oldCopNum = wanted->m_CurrentCops;
+ int maxCops = wanted->m_MaxCops;
+
+ for (int i = 0; i < max(maxCops, oldCopNum); i++) {
+ CCopPed *cop = wanted->m_pCops[i];
+ if (cop && cop->m_fDistanceToTarget > copFarthestToTargetDist) {
+ copFarthestToTargetDist = cop->m_fDistanceToTarget;
+ copFarthestToTarget = wanted->m_pCops[i];
+ }
+ }
+
+ if (m_bIsInPursuit) {
+ if (copFarthestToTarget && oldCopNum > maxCops) {
+ if (copFarthestToTarget == this && m_fDistanceToTarget > 10.0f) {
+ ClearPursuit();
+ } else if(copFarthestToTargetDist > 10.0f)
+ copFarthestToTarget->ClearPursuit();
+ }
+ } else {
+ if (oldCopNum < maxCops) {
+ SetPursuit(true);
+ } else {
+ if (m_fDistanceToTarget <= 10.0f || copFarthestToTarget && m_fDistanceToTarget < copFarthestToTargetDist) {
+ if (copFarthestToTarget && copFarthestToTargetDist > 10.0f)
+ copFarthestToTarget->ClearPursuit();
+
+ SetPursuit(true);
+ }
+ }
+ }
+ } else
+ SetPursuit(false);
+
+ if (!m_bIsInPursuit)
+ return;
+
+ if (wantedLevel > 1 && GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED)
+ SetCurrentWeapon(WEAPONTYPE_COLT45);
+ else if (wantedLevel == 1 && GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED && !FindPlayerPed()->m_pCurrentPhysSurface) {
+ // i.e. if player is on top of car, cop will still use colt45.
+ SetCurrentWeapon(WEAPONTYPE_UNARMED);
+ }
+
+ if (FindPlayerVehicle()) {
+ if (m_bBeatingSuspect) {
+ --wanted->m_CopsBeatingSuspect;
+ m_bBeatingSuspect = false;
+ }
+ if (m_fDistanceToTarget * FindPlayerSpeed().Magnitude() > 4.0f)
+ ClearPursuit();
+ }
+ return;
+ }
+ float weaponRange = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_fRange;
+ SetLookFlag(playerOrHisVeh, true);
+ TurnBody();
+ SetCurrentWeapon(WEAPONTYPE_COLT45);
+ if (!bIsDucking) {
+ if (m_attackTimer >= CTimer::GetTimeInMilliseconds()) {
+ if (m_nPedState != PED_ATTACK && m_nPedState != PED_FIGHT && !m_bZoneDisabled) {
+ CVector targetDist = playerOrHisVeh->GetPosition() - GetPosition();
+ if (m_fDistanceToTarget > 30.0f) {
+ CAnimBlendAssociation* crouchShootAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RBLOCK_CSHOOT);
+ if (crouchShootAssoc)
+ crouchShootAssoc->blendDelta = -1000.0f;
+
+ // Target is coming onto us
+ if (DotProduct(playerOrHisVeh->m_vecMoveSpeed, targetDist) > 0.0f) {
+ m_bIsDisabledCop = false;
+ bKindaStayInSamePlace = false;
+ bNotAllowedToDuck = false;
+ bDuckAndCover = false;
+ SetPursuit(false);
+ SetObjective(OBJECTIVE_KILL_CHAR_ANY_MEANS, FindPlayerPed());
+ }
+ } else if (m_fDistanceToTarget < 5.0f
+ && (!FindPlayerVehicle() || FindPlayerVehicle()->m_vecMoveSpeed.MagnitudeSqr() < sq(1.f/200.f))) {
+ m_bIsDisabledCop = false;
+ bKindaStayInSamePlace = false;
+ bNotAllowedToDuck = false;
+ bDuckAndCover = false;
+ } else {
+ // VC checks for != nil compared to buggy behaviour of III. I check for != -1 here.
+#ifdef VC_PED_PORTS
+ float dotProd;
+ if (m_wRoadblockNode != -1) {
+ CTreadable *roadBlockRoad = ThePaths.m_mapObjects[CRoadBlocks::RoadBlockObjects[m_wRoadblockNode]];
+ dotProd = DotProduct2D(playerOrHisVeh->GetPosition() - roadBlockRoad->GetPosition(), GetPosition() - roadBlockRoad->GetPosition());
+ } else
+ dotProd = -1.0f;
+
+ if(dotProd >= 0.0f) {
+#else
+
+#ifndef FIX_BUGS
+ float copRoadDotProd, targetRoadDotProd;
+#else
+ float copRoadDotProd = 1.0f, targetRoadDotProd = 1.0f;
+ if (m_wRoadblockNode != -1)
+#endif
+ {
+ CTreadable* roadBlockRoad = ThePaths.m_mapObjects[CRoadBlocks::RoadBlockObjects[m_wRoadblockNode]];
+ CVector2D roadFwd = roadBlockRoad->GetForward();
+ copRoadDotProd = DotProduct2D(GetPosition() - roadBlockRoad->GetPosition(), roadFwd);
+ targetRoadDotProd = DotProduct2D(playerOrHisVeh->GetPosition() - roadBlockRoad->GetPosition(), roadFwd);
+ }
+ // Roadblock may be towards road's fwd or opposite, so check both
+ if ((copRoadDotProd >= 0.0f || targetRoadDotProd >= 0.0f)
+ && (copRoadDotProd <= 0.0f || targetRoadDotProd <= 0.0f)) {
+#endif
+ bIsPointingGunAt = true;
+ } else {
+ m_bIsDisabledCop = false;
+ bKindaStayInSamePlace = false;
+ bNotAllowedToDuck = false;
+ bCrouchWhenShooting = false;
+ bIsDucking = false;
+ bDuckAndCover = false;
+ SetPursuit(false);
+ }
+ }
+ }
+ } else {
+ if (m_fDistanceToTarget < weaponRange) {
+ CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
+ CVector gunPos = weaponInfo->m_vecFireOffset;
+ for (RwFrame *i = GetNodeFrame(PED_HANDR); i; i = RwFrameGetParent(i))
+ RwV3dTransformPoints((RwV3d*)&gunPos, (RwV3d*)&gunPos, 1, RwFrameGetMatrix(i));
+
+ CColPoint foundCol;
+ CEntity *foundEnt;
+ if (!CWorld::ProcessLineOfSight(gunPos, playerOrHisVeh->GetPosition(), foundCol, foundEnt,
+ false, true, false, false, true, false, false)
+ || foundEnt && foundEnt == playerOrHisVeh) {
+ m_pPointGunAt = playerOrHisVeh;
+ if (playerOrHisVeh)
+ playerOrHisVeh->RegisterReference((CEntity**) &m_pPointGunAt);
+
+ SetAttack(playerOrHisVeh);
+ SetShootTimer(CGeneral::GetRandomNumberInRange(500, 1000));
+ }
+ SetAttackTimer(CGeneral::GetRandomNumberInRange(100, 300));
+ }
+ SetMoveState(PEDMOVE_STILL);
+ }
+ }
+ } else {
+ if (!m_bIsDisabledCop || m_bZoneDisabled) {
+ if (m_nPedState != PED_AIM_GUN) {
+ if (m_bIsInPursuit)
+ ClearPursuit();
+
+ if (IsPedInControl()) {
+ // Entering the vehicle
+ if (m_pMyVehicle && !bInVehicle) {
+ if (m_pMyVehicle->IsLawEnforcementVehicle()) {
+ if (m_pMyVehicle->pDriver) {
+ if (m_pMyVehicle->pDriver->m_nPedType == PEDTYPE_COP) {
+ if (m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER)
+ SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_pMyVehicle);
+ } else if (m_pMyVehicle->pDriver->IsPlayer()) {
+ FindPlayerPed()->SetWantedLevelNoDrop(1);
+ }
+ } else if (m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) {
+ SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle);
+ }
+ } else {
+ m_pMyVehicle = nil;
+ ClearObjective();
+ SetWanderPath(CGeneral::GetRandomNumber() & 7);
+ }
+ }
+#ifdef VC_PED_PORTS
+ else {
+ if (m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT && CharCreatedBy == RANDOM_CHAR) {
+ for (int i = 0; i < m_numNearPeds; i++) {
+ CPed *nearPed = m_nearPeds[i];
+ if (nearPed->CharCreatedBy == RANDOM_CHAR) {
+ if ((nearPed->m_nPedType == PEDTYPE_CRIMINAL || nearPed->IsGangMember())
+ && nearPed->IsPedInControl()) {
+
+ bool anotherCopChasesHim = false;
+ if (nearPed->m_nPedState == PED_FLEE_ENTITY) {
+ if (nearPed->m_fleeFrom && nearPed->m_fleeFrom->IsPed() &&
+ ((CPed*)nearPed->m_fleeFrom)->m_nPedType == PEDTYPE_COP) {
+ anotherCopChasesHim = true;
+ }
+ }
+ if (!anotherCopChasesHim) {
+ SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, nearPed);
+ nearPed->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, this);
+ nearPed->bBeingChasedByPolice = true;
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+#endif
+ }
+ }
+ } else {
+ if (m_bIsInPursuit && m_nPedState != PED_AIM_GUN)
+ ClearPursuit();
+
+ m_bIsDisabledCop = false;
+ bKindaStayInSamePlace = false;
+ bNotAllowedToDuck = false;
+ bCrouchWhenShooting = false;
+ bIsDucking = false;
+ bDuckAndCover = false;
+ if (m_pMyVehicle)
+ SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle);
+ }
+ }
+}
+
+void
+CCopPed::ProcessControl(void)
+{
+ if (m_nZoneLevel > LEVEL_NONE && m_nZoneLevel != CCollision::ms_collisionInMemory)
+ return;
+
+ CPed::ProcessControl();
+ if (bWasPostponed)
+ return;
+
+ if (m_nPedState == PED_DEAD) {
+ ClearPursuit();
+ m_objective = OBJECTIVE_NONE;
+ return;
+ }
+ if (m_nPedState == PED_DIE)
+ return;
+
+ if (m_nPedState == PED_ARREST_PLAYER) {
+ ArrestPlayer();
+ return;
+ }
+ GetWeapon()->Update(m_audioEntityId);
+ if (m_moved.Magnitude() > 0.0f)
+ Avoid();
+
+ CPhysical *playerOrHisVeh = FindPlayerVehicle() ? (CPhysical*)FindPlayerVehicle() : (CPhysical*)FindPlayerPed();
+ CPlayerPed *player = FindPlayerPed();
+
+ m_fDistanceToTarget = (playerOrHisVeh->GetPosition() - GetPosition()).Magnitude();
+ if (player->m_nPedState == PED_ARRESTED || player->DyingOrDead()) {
+ if (m_fDistanceToTarget < 5.0f) {
+ SetArrestPlayer(player);
+ return;
+ }
+ if (IsPedInControl())
+ SetIdle();
+ }
+ if (m_bIsInPursuit) {
+ if (player->m_nPedState != PED_ARRESTED && !player->DyingOrDead()) {
+ switch (m_nCopType) {
+ case COP_FBI:
+ Say(SOUND_PED_PURSUIT_FBI);
+ break;
+ case COP_SWAT:
+ Say(SOUND_PED_PURSUIT_SWAT);
+ break;
+ case COP_ARMY:
+ Say(SOUND_PED_PURSUIT_ARMY);
+ break;
+ default:
+ Say(SOUND_PED_PURSUIT_COP);
+ break;
+ }
+ }
+ }
+
+ if (IsPedInControl()) {
+ CopAI();
+ /* switch (m_nCopType)
+ {
+ case COP_FBI:
+ CopAI();
+ break;
+ case COP_SWAT:
+ CopAI();
+ break;
+ case COP_ARMY:
+ CopAI();
+ break;
+ default:
+ CopAI();
+ break;
+ } */
+ } else if (InVehicle()) {
+ if (m_pMyVehicle->pDriver == this && m_pMyVehicle->AutoPilot.m_nCarMission == MISSION_NONE &&
+ CanPedDriveOff() && m_pMyVehicle->VehicleCreatedBy != MISSION_VEHICLE) {
+
+ CCarCtrl::JoinCarWithRoadSystem(m_pMyVehicle);
+ m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE;
+ m_pMyVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS;
+ m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 17;
+ }
+ }
+ if (IsPedInControl() || m_nPedState == PED_DRIVING)
+ ScanForCrimes();
+
+ // They may have used goto to jump here in case of PED_ATTACK.
+ if (m_nPedState == PED_IDLE || m_nPedState == PED_ATTACK) {
+ if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT &&
+ player && player->EnteringCar() && m_fDistanceToTarget < 1.3f) {
+ SetArrestPlayer(player);
+ }
+ } else {
+ if (m_nPedState == PED_SEEK_POS) {
+ if (player->m_nPedState == PED_ARRESTED) {
+ SetIdle();
+ SetLookFlag(player, false);
+ SetLookTimer(1000);
+ RestorePreviousObjective();
+ } else {
+ if (player->m_pMyVehicle && player->m_pMyVehicle->m_nNumGettingIn != 0) {
+ // This is 1.3f when arresting in car without seeking first (in above)
+#if defined(VC_PED_PORTS) || defined(FIX_BUGS)
+ m_distanceToCountSeekDone = 1.3f;
+#else
+ m_distanceToCountSeekDone = 2.0f;
+#endif
+ }
+
+ if (bDuckAndCover) {
+ if (!bNotAllowedToDuck && Seek()) {
+ SetMoveState(PEDMOVE_STILL);
+ SetMoveAnim();
+ SetPointGunAt(m_pedInObjective);
+ }
+ } else if (Seek()) {
+ CVehicle *playerVeh = FindPlayerVehicle();
+ if (!playerVeh && player && player->EnteringCar()) {
+ SetArrestPlayer(player);
+ } else if (1.5f + GetPosition().z <= m_vecSeekPos.z || GetPosition().z - 0.3f >= m_vecSeekPos.z) {
+ SetMoveState(PEDMOVE_STILL);
+ } else if (playerVeh && playerVeh->CanPedEnterCar() && playerVeh->m_nNumGettingIn == 0) {
+ SetCarJack(playerVeh);
+ }
+ }
+ }
+ } else if (m_nPedState == PED_SEEK_ENTITY) {
+ if (!m_pSeekTarget) {
+ RestorePreviousState();
+ } else {
+ m_vecSeekPos = m_pSeekTarget->GetPosition();
+ if (Seek()) {
+ if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT && m_fDistanceToTarget < 2.5f && player) {
+ if (player->m_nPedState == PED_ARRESTED || player->m_nPedState == PED_ENTER_CAR ||
+ (player->m_nPedState == PED_CARJACK && m_fDistanceToTarget < 1.3f)) {
+ SetArrestPlayer(player);
+ } else
+ RestorePreviousState();
+ } else {
+ RestorePreviousState();
+ }
+
+ }
+ }
+ }
+ }
+ if (!m_bStopAndShootDisabledZone)
+ return;
+
+ bool dontShoot = false;
+ if (GetIsOnScreen() && CRenderer::IsEntityCullZoneVisible(this)) {
+ if (((CTimer::GetFrameCounter() + m_randomSeed) & 0x1F) == 17) {
+ CEntity *foundBuilding = nil;
+ CColPoint foundCol;
+ CVector lookPos = GetPosition() + CVector(0.0f, 0.0f, 0.7f);
+ CVector camPos = TheCamera.GetGameCamPosition();
+ CWorld::ProcessLineOfSight(camPos, lookPos, foundCol, foundBuilding,
+ true, false, false, false, false, false, false);
+
+ // He's at least 15.0 far, in disabled zone, collided into somewhere (that's why m_bStopAndShootDisabledZone set),
+ // and now has building on front of him. He's stupid, we don't need him.
+ if (foundBuilding) {
+ FlagToDestroyWhenNextProcessed();
+ dontShoot = true;
+ }
+ }
+ } else {
+ FlagToDestroyWhenNextProcessed();
+ dontShoot = true;
+ }
+
+ if (!dontShoot) {
+ bStopAndShoot = true;
+ bKindaStayInSamePlace = true;
+ bIsPointingGunAt = true;
+ SetAttack(m_pedInObjective);
+ }
+}
+
+#include <new>
+
class CCopPed_ : public CCopPed
{
public:
CCopPed *ctor(eCopType type) { return ::new (this) CCopPed(type); };
void dtor(void) { CCopPed::~CCopPed(); }
+ void ProcessControl_(void) { CCopPed::ProcessControl(); }
};
STARTPATCHES
InjectHook(0x4C11B0, &CCopPed_::ctor, PATCH_JUMP);
InjectHook(0x4C13E0, &CCopPed_::dtor, PATCH_JUMP);
+ InjectHook(0x4C1400, &CCopPed_::ProcessControl_, PATCH_JUMP);
InjectHook(0x4C28C0, &CCopPed::ClearPursuit, PATCH_JUMP);
InjectHook(0x4C2B00, &CCopPed::SetArrestPlayer, PATCH_JUMP);
InjectHook(0x4C27D0, &CCopPed::SetPursuit, PATCH_JUMP);
InjectHook(0x4C2C90, &CCopPed::ArrestPlayer, PATCH_JUMP);
InjectHook(0x4C26A0, &CCopPed::ScanForCrimes, PATCH_JUMP);
+ InjectHook(0x4C1B50, &CCopPed::CopAI, PATCH_JUMP);
ENDPATCHES
diff --git a/src/peds/CopPed.h b/src/peds/CopPed.h
index 7705eb12..625cae49 100644
--- a/src/peds/CopPed.h
+++ b/src/peds/CopPed.h
@@ -19,8 +19,8 @@ public:
int8 m_bIsInPursuit;
int8 m_bIsDisabledCop;
int8 field_1350;
- int8 field_1351;
- int8 m_bZoneDisabledButClose;
+ bool m_bBeatingSuspect;
+ int8 m_bStopAndShootDisabledZone;
int8 m_bZoneDisabled;
int8 field_1354;
int8 field_1355;
@@ -40,6 +40,7 @@ public:
void SetPursuit(bool);
void ArrestPlayer(void);
void ScanForCrimes(void);
+ void CopAI(void);
};
static_assert(sizeof(CCopPed) == 0x558, "CCopPed: error");
diff --git a/src/peds/EmergencyPed.cpp b/src/peds/EmergencyPed.cpp
index ee559f57..3a5067e7 100644
--- a/src/peds/EmergencyPed.cpp
+++ b/src/peds/EmergencyPed.cpp
@@ -1,6 +1,7 @@
#include "common.h"
#include "patcher.h"
#include "EmergencyPed.h"
+#include "DMAudio.h"
#include "ModelIndices.h"
#include "Vehicle.h"
#include "Fire.h"
@@ -413,6 +414,8 @@ CEmergencyPed::MedicAI(void)
}
}
+#include <new>
+
class CEmergencyPed_ : public CEmergencyPed
{
public:
diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp
index db6b7ee2..54816b1c 100644
--- a/src/peds/Ped.cpp
+++ b/src/peds/Ped.cpp
@@ -7,13 +7,21 @@
#include "World.h"
#include "RpAnimBlend.h"
#include "Ped.h"
+#include "Wanted.h"
#include "PlayerPed.h"
+#include "PedType.h"
+#include "AnimBlendClumpData.h"
+#include "AnimBlendAssociation.h"
+#include "Fire.h"
+#include "DMAudio.h"
#include "General.h"
#include "SurfaceTable.h"
#include "VisibilityPlugins.h"
#include "AudioManager.h"
#include "HandlingMgr.h"
#include "Replay.h"
+#include "Camera.h"
+#include "Radar.h"
#include "PedPlacement.h"
#include "Shadows.h"
#include "Weather.h"
@@ -552,7 +560,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
bScriptObjectiveCompleted = false;
bKindaStayInSamePlace = false;
- m_ped_flagE2 = false;
+ bBeingChasedByPolice = false;
bNotAllowedToDuck = false;
bCrouchWhenShooting = false;
bIsDucking = false;
@@ -799,6 +807,10 @@ CPed::IsPedInControl(void)
bool
CPed::CanStrafeOrMouseControl(void)
{
+#ifdef FREE_CAM
+ if (CCamera::bFreeCam)
+ return false;
+#endif
return m_nPedState == PED_NONE || m_nPedState == PED_IDLE || m_nPedState == PED_FLEE_POS || m_nPedState == PED_FLEE_ENTITY ||
m_nPedState == PED_ATTACK || m_nPedState == PED_FIGHT || m_nPedState == PED_AIM_GUN || m_nPedState == PED_JUMP;
}
@@ -2720,6 +2732,10 @@ CPed::SetObjective(eObjective newObj, void *entity)
return;
}
+#ifdef VC_PED_PORTS
+ SetObjectiveTimer(0);
+ ClearPointGunAt();
+#endif
bObjectiveCompleted = false;
if (!IsTemporaryObjective(m_objective) || IsTemporaryObjective(newObj)) {
if (m_objective != newObj) {
@@ -3444,8 +3460,12 @@ CPed::ClearAll(void)
m_fleeFrom = nil;
m_fleeTimer = 0;
bUsesCollision = true;
+#ifdef VC_PED_PORTS
+ ClearPointGunAt();
+#else
ClearAimFlag();
ClearLookFlag();
+#endif
bIsPointingGunAt = false;
bRenderPedInCar = true;
bKnockedUpIntoAir = false;
@@ -3603,11 +3623,11 @@ CPed::InflictDamage(CEntity *damagedBy, eWeaponType method, float damage, ePedPi
if (DyingOrDead())
return false;
- if (!bUsesCollision && method != WEAPONTYPE_WATER)
+ if (!bUsesCollision && method != WEAPONTYPE_DROWNING)
return false;
if (bOnlyDamagedByPlayer && damagedBy != player && damagedBy != FindPlayerVehicle() &&
- method != WEAPONTYPE_WATER && method != WEAPONTYPE_EXPLOSION)
+ method != WEAPONTYPE_DROWNING && method != WEAPONTYPE_EXPLOSION)
return false;
float healthImpact;
@@ -3953,10 +3973,10 @@ CPed::InflictDamage(CEntity *damagedBy, eWeaponType method, float damage, ePedPi
}
}
break;
- case WEAPONTYPE_WATER:
+ case WEAPONTYPE_DROWNING:
dieAnim = ANIM_DROWN;
break;
- case WEAPONTYPE_FALL_DAMAGE:
+ case WEAPONTYPE_FALL:
if (bCollisionProof)
return false;
@@ -3982,7 +4002,7 @@ CPed::InflictDamage(CEntity *damagedBy, eWeaponType method, float damage, ePedPi
}
}
- if (m_fArmour != 0.0f && method != WEAPONTYPE_WATER) {
+ if (m_fArmour != 0.0f && method != WEAPONTYPE_DROWNING) {
if (player == this)
CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastArmourLoss = CTimer::GetTimeInMilliseconds();
@@ -4008,7 +4028,7 @@ CPed::InflictDamage(CEntity *damagedBy, eWeaponType method, float damage, ePedPi
}
if (bInVehicle) {
- if (method != WEAPONTYPE_WATER) {
+ if (method != WEAPONTYPE_DROWNING) {
#ifdef VC_PED_PORTS
if (m_pMyVehicle) {
if (m_pMyVehicle->IsCar() && m_pMyVehicle->pDriver == this) {
@@ -4075,7 +4095,7 @@ CPed::InflictDamage(CEntity *damagedBy, eWeaponType method, float damage, ePedPi
} else {
CDarkel::RegisterKillNotByPlayer(this, method);
}
- if (method == WEAPONTYPE_WATER)
+ if (method == WEAPONTYPE_DROWNING)
bIsInTheAir = false;
return true;
@@ -6968,7 +6988,11 @@ CPed::FinishLaunchCB(CAnimBlendAssociation *animAssoc, void *arg)
#endif
) {
+#ifdef FREE_CAM
+ if (TheCamera.Cams[0].Using3rdPersonMouseCam() && !CCamera::bFreeCam) {
+#else
if (TheCamera.Cams[0].Using3rdPersonMouseCam()) {
+#endif
float fpsAngle = ped->WorkOutHeadingForMovingFirstPerson(ped->m_fRotationCur);
ped->m_vecMoveSpeed.x = -velocityFromAnim * Sin(fpsAngle);
ped->m_vecMoveSpeed.y = velocityFromAnim * Cos(fpsAngle);
@@ -9589,7 +9613,7 @@ CPed::ProcessControl(void)
float neededTurnToCriminal = angleToLookCriminal - angleToFace;
if (neededTurnToCriminal > DEGTORAD(150.0f) && neededTurnToCriminal < DEGTORAD(210.0f)) {
- ((CCopPed*)this)->m_bZoneDisabledButClose = true;
+ ((CCopPed*)this)->m_bStopAndShootDisabledZone = true;
}
}
}
@@ -12169,11 +12193,11 @@ CPed::PlacePedOnDryLand(void)
if (!CWorld::TestSphereAgainstWorld(potentialGround, 5.0f, nil, true, false, false, false, false, false))
return false;
- CVector potentialGroundDist = CWorld::ms_testSpherePoint.point - GetPosition();
+ CVector potentialGroundDist = gaTempSphereColPoints[0].point - GetPosition();
potentialGroundDist.z = 0.0f;
potentialGroundDist.Normalise();
- CVector posToCheck = 0.5f * potentialGroundDist + CWorld::ms_testSpherePoint.point;
+ CVector posToCheck = 0.5f * potentialGroundDist + gaTempSphereColPoints[0].point;
posToCheck.z = 3.0f + waterLevel;
if (CWorld::ProcessVerticalLine(posToCheck, waterLevel - 1.0f, foundCol, foundEnt, true, true, false, true, false, false, false)) {
@@ -14559,7 +14583,7 @@ CPed::ProcessEntityCollision(CEntity *collidingEnt, CColPoint *collidingPoints)
|| m_pCollidingEntity == collidingEnt) {
if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL) && -0.016f * CTimer::GetTimeStep() > m_vecMoveSpeed.z) {
- InflictDamage(collidingEnt, WEAPONTYPE_FALL_DAMAGE, 15.0f, PEDPIECE_TORSO, 2);
+ InflictDamage(collidingEnt, WEAPONTYPE_FALL, 15.0f, PEDPIECE_TORSO, 2);
}
} else {
float damage = 100.0f * max(speed - 0.25f, 0.0f);
@@ -14572,7 +14596,7 @@ CPed::ProcessEntityCollision(CEntity *collidingEnt, CColPoint *collidingPoints)
CVector2D offset = -m_vecMoveSpeed;
dir = GetLocalDirection(offset);
}
- InflictDamage(collidingEnt, WEAPONTYPE_FALL_DAMAGE, damage, PEDPIECE_TORSO, dir);
+ InflictDamage(collidingEnt, WEAPONTYPE_FALL, damage, PEDPIECE_TORSO, dir);
if (IsPlayer() && damage2 > 5.0f)
Say(SOUND_PED_LAND);
}
@@ -14583,7 +14607,7 @@ CPed::ProcessEntityCollision(CEntity *collidingEnt, CColPoint *collidingPoints)
if (m_vecMoveSpeed.z >= -0.25f && (speedSqr = m_vecMoveSpeed.MagnitudeSqr()) <= sq(0.5f)) {
if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL) && -0.016f * CTimer::GetTimeStep() > m_vecMoveSpeed.z) {
- InflictDamage(collidingEnt, WEAPONTYPE_FALL_DAMAGE, 15.0f, PEDPIECE_TORSO, 2);
+ InflictDamage(collidingEnt, WEAPONTYPE_FALL, 15.0f, PEDPIECE_TORSO, 2);
}
} else {
if (speedSqr == 0.0f)
@@ -14594,7 +14618,7 @@ CPed::ProcessEntityCollision(CEntity *collidingEnt, CColPoint *collidingPoints)
CVector2D offset = -m_vecMoveSpeed;
dir = GetLocalDirection(offset);
}
- InflictDamage(collidingEnt, WEAPONTYPE_FALL_DAMAGE, 350.0f * sq(speedSqr), PEDPIECE_TORSO, dir);
+ InflictDamage(collidingEnt, WEAPONTYPE_FALL, 350.0f * sq(speedSqr), PEDPIECE_TORSO, dir);
}
}
#endif
@@ -15020,7 +15044,7 @@ CPed::ProcessBuoyancy(void)
CVector pos = GetPosition();
if (PlacePedOnDryLand()) {
if (m_fHealth > 20.0f)
- InflictDamage(nil, WEAPONTYPE_WATER, 15.0f, PEDPIECE_TORSO, false);
+ InflictDamage(nil, WEAPONTYPE_DROWNING, 15.0f, PEDPIECE_TORSO, false);
if (bIsInTheAir) {
RpAnimBlendClumpSetBlendDeltas(GetClump(), ASSOC_PARTIAL, -1000.0f);
@@ -15042,7 +15066,7 @@ CPed::ProcessBuoyancy(void)
m_vecMoveSpeed.y *= speedMult;
m_vecMoveSpeed.z *= speedMult;
bIsStanding = false;
- InflictDamage(nil, WEAPONTYPE_WATER, 3.0f * CTimer::GetTimeStep(), PEDPIECE_TORSO, 0);
+ InflictDamage(nil, WEAPONTYPE_DROWNING, 3.0f * CTimer::GetTimeStep(), PEDPIECE_TORSO, 0);
}
if (buoyancyImpulse.z / m_fMass > 0.002f * CTimer::GetTimeStep()) {
if (speedMult == 0.0f) {
@@ -17447,6 +17471,8 @@ CPed::SetExitBoat(CVehicle *boat)
CWaterLevel::FreeBoatWakeArray();
}
+#include <new>
+
class CPed_ : public CPed
{
public:
diff --git a/src/peds/Ped.h b/src/peds/Ped.h
index a19dc9f0..2edd5d68 100644
--- a/src/peds/Ped.h
+++ b/src/peds/Ped.h
@@ -3,14 +3,9 @@
#include "Physical.h"
#include "Weapon.h"
#include "PedStats.h"
-#include "PedType.h"
#include "PedIK.h"
#include "AnimManager.h"
-#include "AnimBlendClumpData.h"
-#include "AnimBlendAssociation.h"
#include "WeaponInfo.h"
-#include "Fire.h"
-#include "DMAudio.h"
#include "EventList.h"
#define FEET_OFFSET 1.04f
@@ -19,6 +14,10 @@
struct CPathNode;
class CAccident;
class CObject;
+class CFire;
+struct AnimBlendFrameData;
+class CAnimBlendAssociation;
+enum eCrimeType;
struct PedAudioData
{
@@ -339,7 +338,7 @@ public:
uint8 bScriptObjectiveCompleted : 1;
uint8 bKindaStayInSamePlace : 1;
- uint8 m_ped_flagE2 : 1; // bBeingChasedByPolice?
+ uint8 bBeingChasedByPolice : 1; // Unused VC leftover. Should've been set for criminal/gang members
uint8 bNotAllowedToDuck : 1;
uint8 bCrouchWhenShooting : 1;
uint8 bIsDucking : 1;
diff --git a/src/peds/PedIK.cpp b/src/peds/PedIK.cpp
index 38ab429e..cc4b0dd0 100644
--- a/src/peds/PedIK.cpp
+++ b/src/peds/PedIK.cpp
@@ -80,7 +80,7 @@ CPedIK::RotateTorso(AnimBlendFrameData *animBlend, LimbOrientation *limb, bool c
}
void
-CPedIK::GetComponentPosition(RwV3d *pos, PedNode node)
+CPedIK::GetComponentPosition(RwV3d *pos, uint32 node)
{
RwFrame *f;
RwMatrix *mat;
diff --git a/src/peds/PedIK.h b/src/peds/PedIK.h
index dc3f8dda..df9017f3 100644
--- a/src/peds/PedIK.h
+++ b/src/peds/PedIK.h
@@ -1,6 +1,5 @@
#pragma once
#include "common.h"
-#include "PedModelInfo.h"
#include "AnimBlendClumpData.h"
struct LimbOrientation
@@ -52,7 +51,7 @@ public:
bool PointGunInDirection(float phi, float theta);
bool PointGunInDirectionUsingArm(float phi, float theta);
bool PointGunAtPosition(CVector const& position);
- void GetComponentPosition(RwV3d *pos, PedNode node);
+ void GetComponentPosition(RwV3d *pos, uint32 node);
static RwMatrix *GetWorldMatrix(RwFrame *source, RwMatrix *destination);
void RotateTorso(AnimBlendFrameData* animBlend, LimbOrientation* limb, bool changeRoll);
void ExtractYawAndPitchLocal(RwMatrixTag *mat, float *yaw, float *pitch);
diff --git a/src/peds/PedPlacement.cpp b/src/peds/PedPlacement.cpp
index b22e1d58..e5f6a077 100644
--- a/src/peds/PedPlacement.cpp
+++ b/src/peds/PedPlacement.cpp
@@ -1,5 +1,6 @@
#include "common.h"
#include "patcher.h"
+#include "Ped.h"
#include "PedPlacement.h"
#include "World.h"
diff --git a/src/peds/PedPlacement.h b/src/peds/PedPlacement.h
index b1b5be93..6ba4ae71 100644
--- a/src/peds/PedPlacement.h
+++ b/src/peds/PedPlacement.h
@@ -1,7 +1,5 @@
#pragma once
-#include "Ped.h"
-
class CPedPlacement {
public:
static void FindZCoorForPed(CVector* pos);
diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp
index c6580d32..6dbf7687 100644
--- a/src/peds/PlayerPed.cpp
+++ b/src/peds/PlayerPed.cpp
@@ -1,11 +1,16 @@
#include "common.h"
#include "patcher.h"
#include "PlayerPed.h"
+#include "Wanted.h"
+#include "Fire.h"
+#include "DMAudio.h"
+#include "Pad.h"
#include "Camera.h"
#include "WeaponEffects.h"
#include "ModelIndices.h"
#include "World.h"
#include "RpAnimBlend.h"
+#include "AnimBlendAssociation.h"
#include "General.h"
#include "Pools.h"
#include "Darkel.h"
@@ -60,7 +65,7 @@ void CPlayerPed::ClearWeaponTarget()
TheCamera.ClearPlayerWeaponMode();
CWeaponEffects::ClearCrossHair();
}
- ClearPointGunAt();
+ ClearPointGunAt();
}
void
@@ -683,7 +688,14 @@ CPlayerPed::PlayerControl1stPersonRunAround(CPad *padUsed)
float padMove = CVector2D(leftRight, upDown).Magnitude();
float padMoveInGameUnit = padMove / PAD_MOVE_TO_GAME_WORLD_MOVE;
if (padMoveInGameUnit > 0.0f) {
+#ifdef FREE_CAM
+ if (!CCamera::bFreeCam)
+ m_fRotationDest = CGeneral::LimitRadianAngle(TheCamera.Orientation);
+ else
+ m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -leftRight, upDown) - TheCamera.Orientation;
+#else
m_fRotationDest = CGeneral::LimitRadianAngle(TheCamera.Orientation);
+#endif
m_fMoveSpeed = min(padMoveInGameUnit, 0.07f * CTimer::GetTimeStep() + m_fMoveSpeed);
} else {
m_fMoveSpeed = 0.0f;
@@ -976,6 +988,12 @@ CPlayerPed::ProcessPlayerWeapon(CPad *padUsed)
if (padUsed->TargetJustDown()) {
SetStoredState();
m_nPedState = PED_SNIPER_MODE;
+#ifdef FREE_CAM
+ if (CCamera::bFreeCam && TheCamera.Cams[0].Using3rdPersonMouseCam()) {
+ m_fRotationCur = CGeneral::LimitRadianAngle(-TheCamera.Orientation);
+ SetHeading(m_fRotationCur);
+ }
+#endif
if (GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER)
TheCamera.SetNewPlayerWeaponMode(CCam::MODE_ROCKETLAUNCHER, 0, 0);
else if (GetWeapon()->m_eWeaponType == WEAPONTYPE_SNIPERRIFLE)
@@ -995,7 +1013,12 @@ CPlayerPed::ProcessPlayerWeapon(CPad *padUsed)
if (padUsed->GetWeapon() && m_nMoveState != PEDMOVE_SPRINT) {
if (m_nSelectedWepSlot == m_currentWeapon) {
if (m_pPointGunAt) {
- SetAttack(m_pPointGunAt);
+#ifdef FREE_CAM
+ if (CCamera::bFreeCam && weaponInfo->m_eWeaponFire == WEAPON_FIRE_MELEE && m_fMoveSpeed < 1.0f)
+ StartFightAttack(padUsed->GetWeapon());
+ else
+#endif
+ SetAttack(m_pPointGunAt);
} else if (m_currentWeapon != WEAPONTYPE_UNARMED) {
if (m_nPedState == PED_ATTACK) {
if (padUsed->WeaponJustDown()) {
@@ -1022,11 +1045,65 @@ CPlayerPed::ProcessPlayerWeapon(CPad *padUsed)
bIsAttacking = false;
}
}
+
+#ifdef FREE_CAM
+ // Rotate player/arm when shooting. We don't have auto-rotation anymore
+ if (CCamera::m_bUseMouse3rdPerson && CCamera::bFreeCam &&
+ m_nSelectedWepSlot == m_currentWeapon && m_nMoveState != PEDMOVE_SPRINT) {
+
+ // Weapons except throwable and melee ones
+ if (weaponInfo->m_bCanAim || weaponInfo->m_b1stPerson || weaponInfo->m_bExpands) {
+ if ((padUsed->GetTarget() && weaponInfo->m_bCanAimWithArm) || padUsed->GetWeapon()) {
+ float limitedCam = CGeneral::LimitRadianAngle(-TheCamera.Orientation);
+
+ // On this one we can rotate arm.
+ if (weaponInfo->m_bCanAimWithArm) {
+ if (!padUsed->GetWeapon()) { // making this State != ATTACK still stops it after attack. Re-start it immediately!
+ SetPointGunAt(nil);
+ bIsPointingGunAt = false; // to not stop after attack
+ }
+
+ SetLookFlag(limitedCam, true);
+ SetAimFlag(limitedCam);
+#ifdef VC_PED_PORTS
+ SetLookTimer(INT_MAX); // removing this makes head move for real, but I experinced some bugs.
+#endif
+ } else {
+ m_fRotationDest = limitedCam;
+ m_headingRate = 50.0f;
+
+ // Anim. fix for shotgun, ak47 and m16 (we must finish rot. it quickly)
+ if (weaponInfo->m_bCanAim && padUsed->WeaponJustDown()) {
+ m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur);
+ float limitedRotDest = m_fRotationDest;
+
+ if (m_fRotationCur - PI > m_fRotationDest) {
+ limitedRotDest += 2 * PI;
+ } else if (PI + m_fRotationCur < m_fRotationDest) {
+ limitedRotDest -= 2 * PI;
+ }
+
+ m_fRotationCur += (limitedRotDest - m_fRotationCur) / 2;
+ }
+ }
+ } else if (weaponInfo->m_bCanAimWithArm)
+ ClearPointGunAt();
+ else
+ RestoreHeadingRate();
+ }
+ }
+#endif
+
if (padUsed->GetTarget() && m_nSelectedWepSlot == m_currentWeapon && m_nMoveState != PEDMOVE_SPRINT) {
if (m_pPointGunAt) {
// what??
if (!m_pPointGunAt
- || CCamera::m_bUseMouse3rdPerson || m_pPointGunAt->IsPed() && ((CPed*)m_pPointGunAt)->bInVehicle) {
+#ifdef FREE_CAM
+ || (!CCamera::bFreeCam && CCamera::m_bUseMouse3rdPerson)
+#else
+ || CCamera::m_bUseMouse3rdPerson
+#endif
+ || m_pPointGunAt->IsPed() && ((CPed*)m_pPointGunAt)->bInVehicle) {
ClearWeaponTarget();
return;
}
@@ -1042,7 +1119,12 @@ CPlayerPed::ProcessPlayerWeapon(CPad *padUsed)
}
TheCamera.SetNewPlayerWeaponMode(CCam::MODE_SYPHON, 0, 0);
TheCamera.UpdateAimingCoors(m_pPointGunAt->GetPosition());
- } else if (weaponInfo->m_bCanAim && !CCamera::m_bUseMouse3rdPerson) {
+ }
+#ifdef FREE_CAM
+ else if ((CCamera::bFreeCam && weaponInfo->m_eWeaponFire == WEAPON_FIRE_MELEE) || (weaponInfo->m_bCanAim && !CCamera::m_bUseMouse3rdPerson)) {
+#else
+ else if (weaponInfo->m_bCanAim && !CCamera::m_bUseMouse3rdPerson) {
+#endif
if (padUsed->TargetJustDown())
FindWeaponLockOnTarget();
}
@@ -1414,6 +1496,8 @@ CPlayerPed::ProcessControl(void)
}
}
+#include <new>
+
class CPlayerPed_ : public CPlayerPed
{
public:
diff --git a/src/peds/PlayerPed.h b/src/peds/PlayerPed.h
index b27cd983..c139bbbc 100644
--- a/src/peds/PlayerPed.h
+++ b/src/peds/PlayerPed.h
@@ -1,8 +1,10 @@
#pragma once
#include "Ped.h"
-#include "Wanted.h"
-#include "Pad.h"
+
+class CPad;
+class CCopPed;
+class CWanted;
class CPlayerPed : public CPed
{
diff --git a/src/peds/Population.cpp b/src/peds/Population.cpp
index d87764ff..3bf81066 100644
--- a/src/peds/Population.cpp
+++ b/src/peds/Population.cpp
@@ -4,6 +4,8 @@
#include "General.h"
#include "World.h"
#include "Population.h"
+#include "CopPed.h"
+#include "Wanted.h"
#include "FileMgr.h"
#include "Gangs.h"
#include "ModelIndices.h"
@@ -11,6 +13,7 @@
#include "CivilianPed.h"
#include "EmergencyPed.h"
#include "Replay.h"
+#include "Camera.h"
#include "CutsceneMgr.h"
#include "CarCtrl.h"
#include "IniFile.h"
@@ -110,7 +113,8 @@ CPopulation::ChooseCivilianOccupation(int32 group)
return ms_pPedGroups[group].models[CGeneral::GetRandomNumberInRange(0, NUMMODELSPERPEDGROUP)];
}
-eCopType
+// returns eCopType
+int32
CPopulation::ChoosePolicePedOccupation()
{
CGeneral::GetRandomNumber();
@@ -512,9 +516,9 @@ CPopulation::AddPed(ePedType pedType, uint32 miOrCopType, CVector const &coors)
uint32 weapon;
if (CGeneral::GetRandomNumberInRange(0, 100) >= 50)
- weapon = ped->GiveWeapon(CGangs::GetGangInfo(pedType - PEDTYPE_GANG1)->m_Weapon2, 25001);
+ weapon = ped->GiveWeapon((eWeaponType)CGangs::GetGangInfo(pedType - PEDTYPE_GANG1)->m_Weapon2, 25001);
else
- weapon = ped->GiveWeapon(CGangs::GetGangInfo(pedType - PEDTYPE_GANG1)->m_Weapon1, 25001);
+ weapon = ped->GiveWeapon((eWeaponType)CGangs::GetGangInfo(pedType - PEDTYPE_GANG1)->m_Weapon1, 25001);
ped->SetCurrentWeapon(weapon);
return ped;
}
@@ -576,7 +580,7 @@ CPopulation::AddToPopulation(float minDist, float maxDist, float minDistOffScree
}
// Yeah, float
float maxPossiblePedsForArea = (zoneInfo.pedDensity + zoneInfo.carDensity) * playerInfo->m_fRoadDensity * PedDensityMultiplier * CIniFile::PedNumberMultiplier;
- // maxPossiblePedsForArea = min(maxPossiblePedsForArea, MaxNumberOfPedsInUse);
+ maxPossiblePedsForArea = min(maxPossiblePedsForArea, MaxNumberOfPedsInUse);
if (ms_nTotalPeds < maxPossiblePedsForArea || addCop) {
int decisionThreshold = CGeneral::GetRandomNumberInRange(0, 1000);
diff --git a/src/peds/Population.h b/src/peds/Population.h
index b299c0a1..f9e6c3b7 100644
--- a/src/peds/Population.h
+++ b/src/peds/Population.h
@@ -2,11 +2,11 @@
#include "Game.h"
#include "PedType.h"
-#include "CopPed.h"
class CPed;
class CVehicle;
class CDummyObject;
+class CObject;
struct PedGroup
{
@@ -71,7 +71,7 @@ public:
static bool IsPointInSafeZone(CVector *coors);
static void RemovePed(CPed *ent);
static int32 ChooseCivilianOccupation(int32);
- static eCopType ChoosePolicePedOccupation();
+ static int32 ChoosePolicePedOccupation();
static int32 ChooseGangOccupation(int);
static void FindCollisionZoneForCoors(CVector*, int*, eLevelName*);
static void FindClosestZoneForCoors(CVector*, int*, eLevelName, eLevelName);
diff --git a/src/render/Coronas.cpp b/src/render/Coronas.cpp
index b0868d0a..c934540b 100644
--- a/src/render/Coronas.cpp
+++ b/src/render/Coronas.cpp
@@ -59,9 +59,6 @@ int &CCoronas::bChangeBrightnessImmediately = *(int*)0x8E2C30;
CRegisteredCorona *CCoronas::aCoronas = (CRegisteredCorona*)0x72E518;
-//WRAPPER void CCoronas::Render(void) { EAXJMP(0x4F8FB0); }
-//WRAPPER void CCoronas::RenderReflections(void) { EAXJMP(0x4F9B40); }
-
const char aCoronaSpriteNames[][32] = {
"coronastar",
"corona",
diff --git a/src/render/Font.cpp b/src/render/Font.cpp
index 7a16ad03..6f336f1e 100644
--- a/src/render/Font.cpp
+++ b/src/render/Font.cpp
@@ -1,515 +1,636 @@
-#include "common.h"
-#include "patcher.h"
-#include "Sprite2d.h"
-#include "TxdStore.h"
-#include "Font.h"
-
-CFontDetails &CFont::Details = *(CFontDetails*)0x8F317C;
-int16 &CFont::NewLine = *(int16*)0x95CC94;
-CSprite2d *CFont::Sprite = (CSprite2d*)0x95CC04;
-
-int16 CFont::Size[3][193] = {
- {
- 13, 12, 31, 35, 23, 35, 31, 9, 14, 15, 25, 30, 11, 17, 13, 31,
- 23, 16, 22, 21, 24, 23, 23, 20, 23, 22, 10, 35, 26, 26, 26, 26,
- 30, 26, 24, 23, 24, 22, 21, 24, 26, 10, 20, 26, 22, 29, 26, 25,
- 23, 25, 24, 24, 22, 25, 24, 29, 29, 23, 25, 37, 22, 37, 35, 37,
- 35, 21, 22, 21, 21, 22, 13, 22, 21, 10, 16, 22, 11, 32, 21, 21,
- 23, 22, 16, 20, 14, 21, 20, 30, 25, 21, 21, 33, 33, 33, 33, 35,
- 27, 27, 27, 27, 32, 24, 23, 23, 23, 23, 11, 11, 11, 11, 26, 26,
- 26, 26, 26, 26, 26, 25, 26, 21, 21, 21, 21, 32, 23, 22, 22, 22,
- 22, 11, 11, 11, 11, 22, 22, 22, 22, 22, 22, 22, 22, 26, 21, 24,
- 12, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 18, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 20
- },
-
- {
- 13, 9, 21, 35, 23, 35, 35, 11, 35, 35, 25, 35, 11, 17, 13, 33,
- 28, 14, 22, 21, 24, 23, 23, 21, 23, 22, 10, 35, 13, 35, 13, 33,
- 5, 25, 22, 23, 24, 21, 21, 24, 24, 9, 20, 24, 21, 27, 25, 25,
- 22, 25, 23, 20, 23, 23, 23, 31, 23, 23, 23, 37, 33, 37, 35, 37,
- 35, 21, 19, 19, 21, 19, 17, 21, 21, 8, 17, 18, 14, 24, 21, 21,
- 20, 22, 19, 20, 20, 19, 20, 26, 21, 20, 21, 33, 33, 33, 33, 35,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 16
- },
-
- {
- 15, 14, 16, 25, 19, 26, 22, 11, 18, 18, 27, 26, 13, 19, 9, 27,
- 19, 18, 19, 19, 22, 19, 20, 18, 19, 20, 12, 32, 15, 32, 15, 35,
- 15, 19, 19, 19, 19, 19, 16, 19, 20, 9, 19, 20, 14, 29, 19, 20,
- 19, 19, 19, 19, 21, 19, 20, 32, 20, 19, 19, 33, 31, 39, 37, 39,
- 37, 21, 21, 21, 23, 21, 19, 23, 23, 10, 19, 20, 16, 26, 23, 23,
- 20, 20, 20, 22, 21, 22, 22, 26, 22, 22, 23, 35, 35, 35, 35, 37,
- 19, 19, 19, 19, 29, 19, 19, 19, 19, 19, 9, 9, 9, 9, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 30, 19, 19, 19, 19,
- 19, 10, 10, 10, 10, 19, 19, 19, 19, 19, 19, 19, 19, 19, 23, 35,
- 12, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 11, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19
- }
-};
-
-uint16 foreign_table[128] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 177, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 175,
- 128, 129, 130, 0, 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
- 0, 173, 142, 143, 144, 0, 145, 0, 0, 146, 147, 148, 149, 0, 0, 150,
- 151, 152, 153, 0, 154, 0, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
- 0, 174, 165, 166, 167, 0, 168, 0, 0, 169, 170, 171, 172, 0, 0, 0,
-};
-
-void
-CFont::Initialise(void)
-{
- int slot;
-
- slot = CTxdStore::AddTxdSlot("fonts");
- CTxdStore::LoadTxd(slot, "MODELS/FONTS.TXD");
- CTxdStore::AddRef(slot);
- CTxdStore::PushCurrentTxd();
- CTxdStore::SetCurrentTxd(slot);
- Sprite[0].SetTexture("font2", "font2_mask");
- Sprite[1].SetTexture("pager", "pager_mask");
- Sprite[2].SetTexture("font1", "font1_mask");
- SetScale(1.0f, 1.0f);
- SetSlantRefPoint(SCREEN_WIDTH, 0.0f);
- SetSlant(0.0f);
- SetColor(CRGBA(0xFF, 0xFF, 0xFF, 0));
- SetJustifyOff();
- SetCentreOff();
- SetWrapx(640.0f);
- SetCentreSize(640.0f);
- SetBackgroundOff();
- SetBackgroundColor(CRGBA(0x80, 0x80, 0x80, 0x80));
- SetBackGroundOnlyTextOff();
- SetPropOn();
- SetFontStyle(0);
- SetRightJustifyWrap(0.0f);
- SetAlphaFade(255.0f);
- SetDropShadowPosition(0);
- CTxdStore::PopCurrentTxd();
-}
-
-void
-CFont::Shutdown(void)
-{
- Sprite[0].Delete();
- Sprite[1].Delete();
- Sprite[2].Delete();
- CTxdStore::RemoveTxdSlot(CTxdStore::FindTxdSlot("fonts"));
-}
-
-void
-CFont::InitPerFrame(void)
-{
- Details.bank = CSprite2d::GetBank(30, Sprite[0].m_pTexture);
- CSprite2d::GetBank(15, Sprite[1].m_pTexture);
- CSprite2d::GetBank(15, Sprite[2].m_pTexture);
- SetDropShadowPosition(0);
- NewLine = 0;
-}
-
-void
-CFont::PrintChar(float x, float y, uint16 c)
-{
- if(x <= 0.0f || x > SCREEN_WIDTH ||
- y <= 0.0f || y > SCREEN_HEIGHT) // BUG: game uses SCREENW again
- return;
-
- float w = GetCharacterWidth(c) / 32.0f;
- float xoff = c & 0xF;
- float yoff = c >> 4;
-
- if(Details.style == FONT_BANK || Details.style == FONT_HEADING){
- if(Details.dropShadowPosition != 0){
- CSprite2d::AddSpriteToBank(Details.bank + Details.style, // BUG: game doesn't add bank
- CRect(x + SCREEN_SCALE_X(Details.dropShadowPosition),
- y + SCREEN_SCALE_Y(Details.dropShadowPosition),
- x + SCREEN_SCALE_X(Details.dropShadowPosition) + 32.0f * Details.scaleX * 1.0f,
- y + SCREEN_SCALE_Y(Details.dropShadowPosition) + 40.0f * Details.scaleY * 0.5f),
- Details.dropColor,
- xoff/16.0f, yoff/12.8f,
- (xoff+1.0f)/16.0f - 0.001f, yoff/12.8f,
- xoff/16.0f, (yoff+1.0f)/12.8f,
- (xoff+1.0f)/16.0f - 0.001f, (yoff+1.0f)/12.8f - 0.0001f);
- }
- CSprite2d::AddSpriteToBank(Details.bank + Details.style, // BUG: game doesn't add bank
- CRect(x, y,
- x + 32.0f * Details.scaleX * 1.0f,
- y + 40.0f * Details.scaleY * 0.5f),
- Details.color,
- xoff/16.0f, yoff/12.8f,
- (xoff+1.0f)/16.0f - 0.001f, yoff/12.8f,
- xoff/16.0f, (yoff+1.0f)/12.8f - 0.002f,
- (xoff+1.0f)/16.0f - 0.001f, (yoff+1.0f)/12.8f - 0.002f);
- }else{
- CSprite2d::AddSpriteToBank(Details.bank + Details.style, // BUG: game doesn't add bank
- CRect(x, y,
- x + 32.0f * Details.scaleX * w,
- y + 32.0f * Details.scaleY * 0.5f),
- Details.color,
- xoff/16.0f, yoff/16.0f,
- (xoff+w)/16.0f, yoff/16.0f,
- xoff/16.0f, (yoff+1.0f)/16.0f,
- (xoff+w)/16.0f - 0.0001f, (yoff+1.0f)/16.0f - 0.0001f);
- }
-}
-
-void
-CFont::PrintString(float xstart, float ystart, uint16 *s)
-{
- CRect rect;
- int numSpaces;
- float lineLength;
- float x, y;
- bool first;
- uint16 *start, *t;
-
- if(*s == '*')
- return;
-
- if(Details.background){
- GetNumberLines(xstart, ystart, s); // BUG: result not used
- GetTextRect(&rect, xstart, ystart, s);
- CSprite2d::DrawRect(rect, Details.backgroundColor);
- }
-
- lineLength = 0.0f;
- numSpaces = 0;
- first = true;
- if(Details.centre || Details.rightJustify)
- x = 0.0f;
- else
- x = xstart;
- y = ystart;
- start = s;
-
- // This is super ugly, I blame R*
- for(;;){
- for(;;){
- for(;;){
- if(*s == '\0')
- return;
- int xend = Details.centre ? Details.centreSize :
- Details.rightJustify ? xstart - Details.rightJustifyWrap :
- Details.wrapX;
- if(x + GetStringWidth(s) > xend && !first){
- // flush line
- float spaceWidth = !Details.justify || Details.centre ? 0.0f :
- (Details.wrapX - lineLength) / numSpaces;
- float xleft = Details.centre ? xstart - x/2 :
- Details.rightJustify ? xstart - x :
- xstart;
- PrintString(xleft, y, start, s, spaceWidth);
- // reset things
- lineLength = 0.0f;
- numSpaces = 0;
- first = true;
- if(Details.centre || Details.rightJustify)
- x = 0.0f;
- else
- x = xstart;
- y += 32.0f * CFont::Details.scaleY * 0.5f + 2.0f * CFont::Details.scaleY;
- start = s;
- }else
- break;
- }
- // advance by one word
- t = GetNextSpace(s);
- if(t[0] == '\0' ||
- t[0] == ' ' && t[1] == '\0')
- break;
- if(!first)
- numSpaces++;
- first = false;
- x += GetStringWidth(s) + GetCharacterSize(*t - ' ');
- lineLength = x;
- s = t+1;
- }
- // print rest
- if(t[0] == ' ' && t[1] == '\0')
- t[0] = '\0';
- x += GetStringWidth(s);
- s = t;
- float xleft = Details.centre ? xstart - x/2 :
- Details.rightJustify ? xstart - x :
- xstart;
- PrintString(xleft, y, start, s, 0.0f);
- }
-}
-
-int
-CFont::GetNumberLines(float xstart, float ystart, uint16 *s)
-{
- int n;
- float x, y;
- uint16 *t;
-
- n = 0;
- if(Details.centre || Details.rightJustify)
- x = 0.0f;
- else
- x = xstart;
- y = ystart;
-
- while(*s){
- if(x + GetStringWidth(s) > (Details.centre ? Details.centreSize : Details.wrapX)){
- // reached end of line
- if(Details.centre || Details.rightJustify)
- x = 0.0f;
- else
- x = xstart;
- n++;
- // Why even?
- y += 32.0f * CFont::Details.scaleY * 0.5f + 2.0f * CFont::Details.scaleY;
- }else{
- // still space in current line
- t = GetNextSpace(s);
- if(*t == '\0'){
- // end of string
- x += GetStringWidth(s);
- n++;
- s = t;
- }else{
- x += GetStringWidth(s);
- x += GetCharacterSize(*t - ' ');
- s = t+1;
- }
- }
- }
-
- return n;
-}
-
-void
-CFont::GetTextRect(CRect *rect, float xstart, float ystart, uint16 *s)
-{
- int numLines;
- float x, y;
- int16 maxlength;
- uint16 *t;
-
- maxlength = 0;
- numLines = 0;
- if(Details.centre || Details.rightJustify)
- x = 0.0f;
- else
- x = xstart;
- y = ystart;
-
- while(*s){
- if(x + GetStringWidth(s) > (Details.centre ? Details.centreSize : Details.wrapX)){
- // reached end of line
- if(x > maxlength)
- maxlength = x;
- if(Details.centre || Details.rightJustify)
- x = 0.0f;
- else
- x = xstart;
- numLines++;
- y += 32.0f * CFont::Details.scaleY * 0.5f + 2.0f * CFont::Details.scaleY;
- }else{
- // still space in current line
- t = GetNextSpace(s);
- if(*t == '\0'){
- // end of string
- x += GetStringWidth(s);
- if(x > maxlength)
- maxlength = x;
- numLines++;
- s = t;
- }else{
- x += GetStringWidth(s);
- x += GetCharacterSize(*t - ' ');
- s = t+1;
- }
- }
- }
-
- if(Details.centre){
- if(Details.backgroundOnlyText){
- rect->left = xstart - maxlength/2 - 4.0f;
- rect->right = xstart + maxlength/2 + 4.0f;
- rect->bottom = (32.0f * CFont::Details.scaleY * 0.5f + 2.0f * CFont::Details.scaleY) * numLines +
- ystart + 2.0f;
- rect->top = ystart - 2.0f;
- }else{
- rect->left = xstart - Details.centreSize*0.5f - 4.0f;
- rect->right = xstart + Details.centreSize*0.5f + 4.0f;
- rect->bottom = (32.0f * CFont::Details.scaleY * 0.5f + 2.0f * CFont::Details.scaleY) * numLines +
- ystart + 2.0f;
- rect->top = ystart - 2.0f;
- }
- }else{
- rect->left = xstart - 4.0f;
- rect->right = Details.wrapX;
- // WTF?
- rect->bottom = ystart - 4.0f + 4.0f;
- rect->top = (32.0f * CFont::Details.scaleY * 0.5f + 2.0f * CFont::Details.scaleY) * numLines +
- ystart + 2.0f + 2.0f;
- }
-}
-
-void
-CFont::PrintString(float x, float y, uint16 *start, uint16 *end, float spwidth)
-{
- uint16 *s, c, unused;
-
- for(s = start; s < end; s++){
- if(*s == '~')
- s = ParseToken(s, &unused);
- c = *s - ' ';
- if(Details.slant != 0.0f)
- y = (Details.slantRefX - x)*Details.slant + Details.slantRefY;
- PrintChar(x, y, c);
- x += GetCharacterSize(c);
- if(c == 0) // space
- x += spwidth;
- }
-}
-
-float
-CFont::GetCharacterWidth(uint16 c)
-{
- if(Details.proportional)
- return Size[Details.style][c];
- else
- return Size[Details.style][192];
-}
-
-float
-CFont::GetCharacterSize(uint16 c)
-{
- if(Details.proportional)
- return Size[Details.style][c] * Details.scaleX;
- else
- return Size[Details.style][192] * Details.scaleX;
-}
-
-float
-CFont::GetStringWidth(uint16 *s, bool spaces)
-{
- float w;
-
- w = 0.0f;
- for(; (*s != ' ' || spaces) && *s != '\0'; s++){
- if(*s == '~'){
- s++;
- while(*s != '~') s++;
- s++;
- if(*s == ' ' && !spaces)
- break;
- }
- w += GetCharacterSize(*s - ' ');
- }
- return w;
-}
-
-uint16*
-CFont::GetNextSpace(uint16 *s)
-{
- for(; *s != ' ' && *s != '\0'; s++)
- if(*s == '~'){
- s++;
- while(*s != '~') s++;
- s++;
- if(*s == ' ')
- break;
- }
- return s;
-}
-
-uint16*
-CFont::ParseToken(uint16 *s, uint16*)
-{
- s++;
- if(Details.color.r || Details.color.g || Details.color.b)
- switch(*s){
- case 'N':
- case 'n':
- NewLine = 1;
- break;
- case 'b': SetColor(CRGBA(0x80, 0xA7, 0xF3, 0xFF)); break;
- case 'g': SetColor(CRGBA(0x5F, 0xA0, 0x6A, 0xFF)); break;
- case 'h': SetColor(CRGBA(0xE1, 0xE1, 0xE1, 0xFF)); break;
- case 'l': SetColor(CRGBA(0x00, 0x00, 0x00, 0xFF)); break;
- case 'p': SetColor(CRGBA(0xA8, 0x6E, 0xFC, 0xFF)); break;
- case 'r': SetColor(CRGBA(0x71, 0x2B, 0x49, 0xFF)); break;
- case 'w': SetColor(CRGBA(0xAF, 0xAF, 0xAF, 0xFF)); break;
- case 'y': SetColor(CRGBA(0xD2, 0xC4, 0x6A, 0xFF)); break;
- }
- while(*s != '~') s++;
- return s+1;
-}
-
-void
-CFont::DrawFonts(void)
-{
- CSprite2d::DrawBank(Details.bank);
- CSprite2d::DrawBank(Details.bank+1);
- CSprite2d::DrawBank(Details.bank+2);
-}
-
-uint16
-CFont::character_code(uint8 c)
-{
- if(c < 128)
- return c;
- return foreign_table[c-128];
-}
-
-STARTPATCHES
-
- InjectHook(0x500A40, CFont::Initialise, PATCH_JUMP);
- InjectHook(0x500BA0, CFont::Shutdown, PATCH_JUMP);
- InjectHook(0x500BE0, CFont::InitPerFrame, PATCH_JUMP);
- InjectHook(0x500C30, CFont::PrintChar, PATCH_JUMP);
- InjectHook(0x500F50, (void (*)(float, float, uint16*))CFont::PrintString, PATCH_JUMP);
- InjectHook(0x501260, CFont::GetNumberLines, PATCH_JUMP);
- InjectHook(0x5013B0, CFont::GetTextRect, PATCH_JUMP);
- InjectHook(0x501730, (void (*)(float, float, uint16*, uint16*, float))CFont::PrintString, PATCH_JUMP);
- InjectHook(0x5017E0, CFont::GetCharacterWidth, PATCH_JUMP);
- InjectHook(0x501840, CFont::GetCharacterSize, PATCH_JUMP);
- InjectHook(0x5018A0, CFont::GetStringWidth, PATCH_JUMP);
- InjectHook(0x501960, CFont::GetNextSpace, PATCH_JUMP);
- InjectHook(0x5019A0, CFont::ParseToken, PATCH_JUMP);
- InjectHook(0x501B50, CFont::DrawFonts, PATCH_JUMP);
- InjectHook(0x501E80, CFont::character_code, PATCH_JUMP);
-
- InjectHook(0x501B80, CFont::SetScale, PATCH_JUMP);
- InjectHook(0x501BA0, CFont::SetSlantRefPoint, PATCH_JUMP);
- InjectHook(0x501BC0, CFont::SetSlant, PATCH_JUMP);
- InjectHook(0x501BD0, CFont::SetColor, PATCH_JUMP);
- InjectHook(0x501C60, CFont::SetJustifyOn, PATCH_JUMP);
- InjectHook(0x501C80, CFont::SetJustifyOff, PATCH_JUMP);
- InjectHook(0x501C90, CFont::SetCentreOn, PATCH_JUMP);
- InjectHook(0x501CB0, CFont::SetCentreOff, PATCH_JUMP);
- InjectHook(0x501CC0, CFont::SetWrapx, PATCH_JUMP);
- InjectHook(0x501CD0, CFont::SetCentreSize, PATCH_JUMP);
- InjectHook(0x501CE0, CFont::SetBackgroundOn, PATCH_JUMP);
- InjectHook(0x501CF0, CFont::SetBackgroundOff, PATCH_JUMP);
- InjectHook(0x501D00, CFont::SetBackgroundColor, PATCH_JUMP);
- InjectHook(0x501D30, CFont::SetBackGroundOnlyTextOn, PATCH_JUMP);
- InjectHook(0x501D40, CFont::SetBackGroundOnlyTextOff, PATCH_JUMP);
- InjectHook(0x501D50, CFont::SetRightJustifyOn, PATCH_JUMP);
- InjectHook(0x501D70, CFont::SetRightJustifyOff, PATCH_JUMP);
- InjectHook(0x501D90, CFont::SetPropOff, PATCH_JUMP);
- InjectHook(0x501DA0, CFont::SetPropOn, PATCH_JUMP);
- InjectHook(0x501DB0, CFont::SetFontStyle, PATCH_JUMP);
- InjectHook(0x501DC0, CFont::SetRightJustifyWrap, PATCH_JUMP);
- InjectHook(0x501DD0, CFont::SetAlphaFade, PATCH_JUMP);
- InjectHook(0x501DE0, CFont::SetDropColor, PATCH_JUMP);
- InjectHook(0x501E70, CFont::SetDropShadowPosition, PATCH_JUMP);
-
-ENDPATCHES
+#include "common.h"
+#include "patcher.h"
+#include "Sprite2d.h"
+#include "TxdStore.h"
+#include "Font.h"
+
+CFontDetails &CFont::Details = *(CFontDetails*)0x8F317C;
+int16 &CFont::NewLine = *(int16*)0x95CC94;
+CSprite2d *CFont::Sprite = (CSprite2d*)0x95CC04;
+
+#ifdef MORE_LANGUAGES
+uint8 CFont::LanguageSet = FONT_LANGSET_EFIGS;
+int32 CFont::Slot = -1;
+
+int16 CFont::Size[2][3][193] = {
+ {
+#else
+int16 CFont::Size[3][193] = {
+#endif
+ {
+ 13, 12, 31, 35, 23, 35, 31, 9, 14, 15, 25, 30, 11, 17, 13, 31,
+ 23, 16, 22, 21, 24, 23, 23, 20, 23, 22, 10, 35, 26, 26, 26, 26,
+ 30, 26, 24, 23, 24, 22, 21, 24, 26, 10, 20, 26, 22, 29, 26, 25,
+ 23, 25, 24, 24, 22, 25, 24, 29, 29, 23, 25, 37, 22, 37, 35, 37,
+ 35, 21, 22, 21, 21, 22, 13, 22, 21, 10, 16, 22, 11, 32, 21, 21,
+ 23, 22, 16, 20, 14, 21, 20, 30, 25, 21, 21, 33, 33, 33, 33, 35,
+ 27, 27, 27, 27, 32, 24, 23, 23, 23, 23, 11, 11, 11, 11, 26, 26,
+ 26, 26, 26, 26, 26, 25, 26, 21, 21, 21, 21, 32, 23, 22, 22, 22,
+ 22, 11, 11, 11, 11, 22, 22, 22, 22, 22, 22, 22, 22, 26, 21, 24,
+ 12, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 18, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 20
+ },
+
+ {
+ 13, 9, 21, 35, 23, 35, 35, 11, 35, 35, 25, 35, 11, 17, 13, 33,
+ 28, 14, 22, 21, 24, 23, 23, 21, 23, 22, 10, 35, 13, 35, 13, 33,
+ 5, 25, 22, 23, 24, 21, 21, 24, 24, 9, 20, 24, 21, 27, 25, 25,
+ 22, 25, 23, 20, 23, 23, 23, 31, 23, 23, 23, 37, 33, 37, 35, 37,
+ 35, 21, 19, 19, 21, 19, 17, 21, 21, 8, 17, 18, 14, 24, 21, 21,
+ 20, 22, 19, 20, 20, 19, 20, 26, 21, 20, 21, 33, 33, 33, 33, 35,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 16
+ },
+
+ {
+ 15, 14, 16, 25, 19, 26, 22, 11, 18, 18, 27, 26, 13, 19, 9, 27,
+ 19, 18, 19, 19, 22, 19, 20, 18, 19, 20, 12, 32, 15, 32, 15, 35,
+ 15, 19, 19, 19, 19, 19, 16, 19, 20, 9, 19, 20, 14, 29, 19, 20,
+ 19, 19, 19, 19, 21, 19, 20, 32, 20, 19, 19, 33, 31, 39, 37, 39,
+ 37, 21, 21, 21, 23, 21, 19, 23, 23, 10, 19, 20, 16, 26, 23, 23,
+ 20, 20, 20, 22, 21, 22, 22, 26, 22, 22, 23, 35, 35, 35, 35, 37,
+ 19, 19, 19, 19, 29, 19, 19, 19, 19, 19, 9, 9, 9, 9, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 30, 19, 19, 19, 19,
+ 19, 10, 10, 10, 10, 19, 19, 19, 19, 19, 19, 19, 19, 19, 23, 35,
+ 12, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 11, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19
+ }
+#ifdef MORE_LANGUAGES
+ },
+ {
+ { 13, 12, 31, 35, 23, 35, 31, 9, 14, 15, 25, 30, 11, 17,
+ 13, 31, 23, 16, 22, 21, 24, 23, 23, 20, 23, 22, 10,
+ 35, 26, 26, 26, 26, 30, 26, 24, 23, 24, 22, 21, 24,
+ 26, 10, 20, 26, 22, 29, 26, 25, 23, 25, 24, 24, 22,
+ 25, 24, 29, 29, 23, 25, 37, 22, 37, 35, 37, 35, 21,
+ 22, 21, 21, 22, 13, 22, 21, 10, 16, 22, 11, 32, 21,
+ 21, 23, 22, 16, 20, 14, 21, 20, 30, 25, 21, 21, 13,
+ 33, 13, 13, 13, 24, 22, 22, 19, 26, 21, 30, 20, 23,
+ 23, 21, 24, 26, 23, 22, 23, 21, 22, 20, 20, 26, 25,
+ 24, 22, 31, 32, 23, 30, 22, 22, 32, 23, 19, 18, 18,
+ 15, 22, 19, 27, 19, 20, 20, 18, 22, 24, 20, 19, 19,
+ 20, 19, 16, 19, 28, 20, 20, 18, 26, 27, 19, 26, 18,
+ 19, 27, 19, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 18, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 20 },
+ { 13, 9, 21, 35, 23, 35, 35, 11, 35, 35, 25, 35, 11,
+ 17, 13, 33, 28, 14, 22, 21, 24, 23, 23, 21, 23, 22,
+ 10, 35, 13, 35, 13, 33, 5, 25, 22, 23, 24, 21, 21, 24,
+ 24, 9, 20, 24, 21, 27, 25, 25, 22, 25, 23, 20, 23, 23,
+ 23, 31, 23, 23, 23, 37, 33, 37, 35, 37, 35, 21, 19,
+ 19, 21, 19, 17, 21, 21, 8, 17, 18, 14, 24, 21, 21, 20,
+ 22, 19, 20, 20, 19, 20, 26, 21, 20, 21, 33, 33, 33,
+ 33, 35, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 16, },
+ { 15, 14, 16, 25, 19,
+ 26, 22, 11, 18, 18, 27, 26, 13, 19, 9, 27, 19, 18, 19,
+ 19, 22, 19, 20, 18, 19, 20, 12, 32, 15, 32, 15, 35,
+ 15, 19, 19, 19, 19, 19, 16, 19, 20, 9, 19, 20, 14, 29,
+ 19, 20, 19, 19, 19, 19, 21, 19, 20, 32, 20, 19, 19,
+ 33, 31, 39, 37, 39, 37, 21, 21, 21, 23, 21, 19, 23, 23, 10, 19, 20, 16, 26, 23,
+ 21, 21, 20, 20, 22, 21, 22, 22, 26, 22, 22, 23, 35,
+ 35, 35, 35, 37, 19, 19, 19, 19, 19, 19, 29, 19, 19,
+ 19, 20, 22, 31, 19, 19, 19, 19, 19, 29, 19, 29, 19,
+ 21, 19, 30, 31, 21, 29, 19, 19, 29, 19, 21, 23, 32,
+ 21, 21, 30, 31, 22, 21, 32, 33, 23, 32, 21, 21, 32,
+ 21, 19, 19, 30, 31, 22, 22, 21, 32, 33, 23, 32, 21,
+ 21, 32, 21, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 11, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19 },
+ }
+#endif
+};
+
+wchar foreign_table[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 177, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 175,
+ 128, 129, 130, 0, 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
+ 0, 173, 142, 143, 144, 0, 145, 0, 0, 146, 147, 148, 149, 0, 0, 150,
+ 151, 152, 153, 0, 154, 0, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
+ 0, 174, 165, 166, 167, 0, 168, 0, 0, 169, 170, 171, 172, 0, 0, 0,
+};
+
+void
+CFont::Initialise(void)
+{
+ int slot;
+
+ slot = CTxdStore::AddTxdSlot("fonts");
+#ifdef MORE_LANGUAGES
+ Slot = slot;
+ switch (LanguageSet)
+ {
+ case FONT_LANGSET_EFIGS:
+ default:
+ CTxdStore::LoadTxd(slot, "MODELS/FONTS.TXD");
+ break;
+ case FONT_LANGSET_RUSSIAN:
+ CTxdStore::LoadTxd(slot, "MODELS/FONTS_R.TXD");
+ break;
+ }
+#else
+ CTxdStore::LoadTxd(slot, "MODELS/FONTS.TXD");
+#endif
+ CTxdStore::AddRef(slot);
+ CTxdStore::PushCurrentTxd();
+ CTxdStore::SetCurrentTxd(slot);
+ Sprite[0].SetTexture("font2", "font2_mask");
+ Sprite[1].SetTexture("pager", "pager_mask");
+ Sprite[2].SetTexture("font1", "font1_mask");
+ SetScale(1.0f, 1.0f);
+ SetSlantRefPoint(SCREEN_WIDTH, 0.0f);
+ SetSlant(0.0f);
+ SetColor(CRGBA(0xFF, 0xFF, 0xFF, 0));
+ SetJustifyOff();
+ SetCentreOff();
+ SetWrapx(640.0f);
+ SetCentreSize(640.0f);
+ SetBackgroundOff();
+ SetBackgroundColor(CRGBA(0x80, 0x80, 0x80, 0x80));
+ SetBackGroundOnlyTextOff();
+ SetPropOn();
+ SetFontStyle(FONT_BANK);
+ SetRightJustifyWrap(0.0f);
+ SetAlphaFade(255.0f);
+ SetDropShadowPosition(0);
+ CTxdStore::PopCurrentTxd();
+}
+
+#ifdef MORE_LANGUAGES
+void
+CFont::ReloadFonts(uint8 set)
+{
+ if (Slot != -1 && LanguageSet != set) {
+ Sprite[0].Delete();
+ Sprite[1].Delete();
+ Sprite[2].Delete();
+ CTxdStore::PushCurrentTxd();
+ CTxdStore::RemoveTxd(Slot);
+ switch (set)
+ {
+ case FONT_LANGSET_EFIGS:
+ default:
+ CTxdStore::LoadTxd(Slot, "MODELS/FONTS.TXD");
+ break;
+ case FONT_LANGSET_RUSSIAN:
+ CTxdStore::LoadTxd(Slot, "MODELS/FONTS_R.TXD");
+ break;
+ }
+ CTxdStore::SetCurrentTxd(Slot);
+ Sprite[0].SetTexture("font2", "font2_mask");
+ Sprite[1].SetTexture("pager", "pager_mask");
+ Sprite[2].SetTexture("font1", "font1_mask");
+ CTxdStore::PopCurrentTxd();
+ }
+ LanguageSet = set;
+}
+#endif
+
+void
+CFont::Shutdown(void)
+{
+ Sprite[0].Delete();
+ Sprite[1].Delete();
+ Sprite[2].Delete();
+#ifdef MORE_LANGUAGES
+ CTxdStore::RemoveTxdSlot(Slot);
+ Slot = -1;
+#else
+ CTxdStore::RemoveTxdSlot(CTxdStore::FindTxdSlot("fonts"));
+#endif
+}
+
+void
+CFont::InitPerFrame(void)
+{
+ Details.bank = CSprite2d::GetBank(30, Sprite[0].m_pTexture);
+ CSprite2d::GetBank(15, Sprite[1].m_pTexture);
+ CSprite2d::GetBank(15, Sprite[2].m_pTexture);
+ SetDropShadowPosition(0);
+ NewLine = 0;
+}
+
+void
+CFont::PrintChar(float x, float y, wchar c)
+{
+ if(x <= 0.0f || x > SCREEN_WIDTH ||
+ y <= 0.0f || y > SCREEN_HEIGHT) // BUG: game uses SCREENW again
+ return;
+
+ float w = GetCharacterWidth(c) / 32.0f;
+ float xoff = c & 0xF;
+ float yoff = c >> 4;
+
+ if(Details.style == FONT_BANK || Details.style == FONT_HEADING){
+ if(Details.dropShadowPosition != 0){
+ CSprite2d::AddSpriteToBank(Details.bank + Details.style, // BUG: game doesn't add bank
+ CRect(x + SCREEN_SCALE_X(Details.dropShadowPosition),
+ y + SCREEN_SCALE_Y(Details.dropShadowPosition),
+ x + SCREEN_SCALE_X(Details.dropShadowPosition) + 32.0f * Details.scaleX * 1.0f,
+ y + SCREEN_SCALE_Y(Details.dropShadowPosition) + 40.0f * Details.scaleY * 0.5f),
+ Details.dropColor,
+ xoff/16.0f, yoff/12.8f,
+ (xoff+1.0f)/16.0f - 0.001f, yoff/12.8f,
+ xoff/16.0f, (yoff+1.0f)/12.8f,
+ (xoff+1.0f)/16.0f - 0.001f, (yoff+1.0f)/12.8f - 0.0001f);
+ }
+ CSprite2d::AddSpriteToBank(Details.bank + Details.style, // BUG: game doesn't add bank
+ CRect(x, y,
+ x + 32.0f * Details.scaleX * 1.0f,
+ y + 40.0f * Details.scaleY * 0.5f),
+ Details.color,
+ xoff/16.0f, yoff/12.8f,
+ (xoff+1.0f)/16.0f - 0.001f, yoff/12.8f,
+ xoff/16.0f, (yoff+1.0f)/12.8f - 0.002f,
+ (xoff+1.0f)/16.0f - 0.001f, (yoff+1.0f)/12.8f - 0.002f);
+ }else{
+ CSprite2d::AddSpriteToBank(Details.bank + Details.style, // BUG: game doesn't add bank
+ CRect(x, y,
+ x + 32.0f * Details.scaleX * w,
+ y + 32.0f * Details.scaleY * 0.5f),
+ Details.color,
+ xoff/16.0f, yoff/16.0f,
+ (xoff+w)/16.0f, yoff/16.0f,
+ xoff/16.0f, (yoff+1.0f)/16.0f,
+ (xoff+w)/16.0f - 0.0001f, (yoff+1.0f)/16.0f - 0.0001f);
+ }
+}
+
+void
+CFont::PrintString(float xstart, float ystart, wchar *s)
+{
+ CRect rect;
+ int numSpaces;
+ float lineLength;
+ float x, y;
+ bool first;
+ wchar *start, *t;
+
+ if(*s == '*')
+ return;
+
+ if(Details.background){
+ GetNumberLines(xstart, ystart, s); // BUG: result not used
+ GetTextRect(&rect, xstart, ystart, s);
+ CSprite2d::DrawRect(rect, Details.backgroundColor);
+ }
+
+ lineLength = 0.0f;
+ numSpaces = 0;
+ first = true;
+ if(Details.centre || Details.rightJustify)
+ x = 0.0f;
+ else
+ x = xstart;
+ y = ystart;
+ start = s;
+
+ // This is super ugly, I blame R*
+ for(;;){
+ for(;;){
+ for(;;){
+ if(*s == '\0')
+ return;
+ int xend = Details.centre ? Details.centreSize :
+ Details.rightJustify ? xstart - Details.rightJustifyWrap :
+ Details.wrapX;
+ if(x + GetStringWidth(s) > xend && !first){
+ // flush line
+ float spaceWidth = !Details.justify || Details.centre ? 0.0f :
+ (Details.wrapX - lineLength) / numSpaces;
+ float xleft = Details.centre ? xstart - x/2 :
+ Details.rightJustify ? xstart - x :
+ xstart;
+ PrintString(xleft, y, start, s, spaceWidth);
+ // reset things
+ lineLength = 0.0f;
+ numSpaces = 0;
+ first = true;
+ if(Details.centre || Details.rightJustify)
+ x = 0.0f;
+ else
+ x = xstart;
+ y += 32.0f * CFont::Details.scaleY * 0.5f + 2.0f * CFont::Details.scaleY;
+ start = s;
+ }else
+ break;
+ }
+ // advance by one word
+ t = GetNextSpace(s);
+ if(t[0] == '\0' ||
+ t[0] == ' ' && t[1] == '\0')
+ break;
+ if(!first)
+ numSpaces++;
+ first = false;
+ x += GetStringWidth(s) + GetCharacterSize(*t - ' ');
+ lineLength = x;
+ s = t+1;
+ }
+ // print rest
+ if(t[0] == ' ' && t[1] == '\0')
+ t[0] = '\0';
+ x += GetStringWidth(s);
+ s = t;
+ float xleft = Details.centre ? xstart - x/2 :
+ Details.rightJustify ? xstart - x :
+ xstart;
+ PrintString(xleft, y, start, s, 0.0f);
+ }
+}
+
+int
+CFont::GetNumberLines(float xstart, float ystart, wchar *s)
+{
+ int n;
+ float x, y;
+ wchar *t;
+
+ n = 0;
+ if(Details.centre || Details.rightJustify)
+ x = 0.0f;
+ else
+ x = xstart;
+ y = ystart;
+
+ while(*s){
+ if(x + GetStringWidth(s) > (Details.centre ? Details.centreSize : Details.wrapX)){
+ // reached end of line
+ if(Details.centre || Details.rightJustify)
+ x = 0.0f;
+ else
+ x = xstart;
+ n++;
+ // Why even?
+ y += 32.0f * CFont::Details.scaleY * 0.5f + 2.0f * CFont::Details.scaleY;
+ }else{
+ // still space in current line
+ t = GetNextSpace(s);
+ if(*t == '\0'){
+ // end of string
+ x += GetStringWidth(s);
+ n++;
+ s = t;
+ }else{
+ x += GetStringWidth(s);
+ x += GetCharacterSize(*t - ' ');
+ s = t+1;
+ }
+ }
+ }
+
+ return n;
+}
+
+void
+CFont::GetTextRect(CRect *rect, float xstart, float ystart, wchar *s)
+{
+ int numLines;
+ float x, y;
+ int16 maxlength;
+ wchar *t;
+
+ maxlength = 0;
+ numLines = 0;
+ if(Details.centre || Details.rightJustify)
+ x = 0.0f;
+ else
+ x = xstart;
+ y = ystart;
+
+ while(*s){
+ if(x + GetStringWidth(s) > (Details.centre ? Details.centreSize : Details.wrapX)){
+ // reached end of line
+ if(x > maxlength)
+ maxlength = x;
+ if(Details.centre || Details.rightJustify)
+ x = 0.0f;
+ else
+ x = xstart;
+ numLines++;
+ y += 32.0f * CFont::Details.scaleY * 0.5f + 2.0f * CFont::Details.scaleY;
+ }else{
+ // still space in current line
+ t = GetNextSpace(s);
+ if(*t == '\0'){
+ // end of string
+ x += GetStringWidth(s);
+ if(x > maxlength)
+ maxlength = x;
+ numLines++;
+ s = t;
+ }else{
+ x += GetStringWidth(s);
+ x += GetCharacterSize(*t - ' ');
+ s = t+1;
+ }
+ }
+ }
+
+ if(Details.centre){
+ if(Details.backgroundOnlyText){
+ rect->left = xstart - maxlength/2 - 4.0f;
+ rect->right = xstart + maxlength/2 + 4.0f;
+ rect->bottom = (32.0f * CFont::Details.scaleY * 0.5f + 2.0f * CFont::Details.scaleY) * numLines +
+ ystart + 2.0f;
+ rect->top = ystart - 2.0f;
+ }else{
+ rect->left = xstart - Details.centreSize*0.5f - 4.0f;
+ rect->right = xstart + Details.centreSize*0.5f + 4.0f;
+ rect->bottom = (32.0f * CFont::Details.scaleY * 0.5f + 2.0f * CFont::Details.scaleY) * numLines +
+ ystart + 2.0f;
+ rect->top = ystart - 2.0f;
+ }
+ }else{
+ rect->left = xstart - 4.0f;
+ rect->right = Details.wrapX;
+ // WTF?
+ rect->bottom = ystart - 4.0f + 4.0f;
+ rect->top = (32.0f * CFont::Details.scaleY * 0.5f + 2.0f * CFont::Details.scaleY) * numLines +
+ ystart + 2.0f + 2.0f;
+ }
+}
+
+void
+CFont::PrintString(float x, float y, wchar *start, wchar *end, float spwidth)
+{
+ wchar *s, c, unused;
+
+ for(s = start; s < end; s++){
+ if(*s == '~')
+ s = ParseToken(s, &unused);
+ c = *s - ' ';
+ if(Details.slant != 0.0f)
+ y = (Details.slantRefX - x)*Details.slant + Details.slantRefY;
+ PrintChar(x, y, c);
+ x += GetCharacterSize(c);
+ if(c == 0) // space
+ x += spwidth;
+ }
+}
+
+float
+CFont::GetCharacterWidth(wchar c)
+{
+#ifdef MORE_LANGUAGES
+ if (Details.proportional)
+ return Size[LanguageSet][Details.style][c];
+ else
+ return Size[LanguageSet][Details.style][192];
+#else
+ if (Details.proportional)
+ return Size[Details.style][c];
+ else
+ return Size[Details.style][192];
+#endif // MORE_LANGUAGES
+}
+
+float
+CFont::GetCharacterSize(wchar c)
+{
+#ifdef MORE_LANGUAGES
+ if(Details.proportional)
+ return Size[LanguageSet][Details.style][c] * Details.scaleX;
+ else
+ return Size[LanguageSet][Details.style][192] * Details.scaleX;
+#else
+ if (Details.proportional)
+ return Size[Details.style][c] * Details.scaleX;
+ else
+ return Size[Details.style][192] * Details.scaleX;
+#endif // MORE_LANGUAGES
+}
+
+float
+CFont::GetStringWidth(wchar *s, bool spaces)
+{
+ float w;
+
+ w = 0.0f;
+ for(; (*s != ' ' || spaces) && *s != '\0'; s++){
+ if(*s == '~'){
+ s++;
+ while(*s != '~') s++;
+ s++;
+ if(*s == ' ' && !spaces)
+ break;
+ }
+ w += GetCharacterSize(*s - ' ');
+ }
+ return w;
+}
+
+wchar*
+CFont::GetNextSpace(wchar *s)
+{
+ for(; *s != ' ' && *s != '\0'; s++)
+ if(*s == '~'){
+ s++;
+ while(*s != '~') s++;
+ s++;
+ if(*s == ' ')
+ break;
+ }
+ return s;
+}
+
+wchar*
+CFont::ParseToken(wchar *s, wchar*)
+{
+ s++;
+ if(Details.color.r || Details.color.g || Details.color.b)
+ switch(*s){
+ case 'N':
+ case 'n':
+ NewLine = 1;
+ break;
+ case 'b': SetColor(CRGBA(0x80, 0xA7, 0xF3, 0xFF)); break;
+ case 'g': SetColor(CRGBA(0x5F, 0xA0, 0x6A, 0xFF)); break;
+ case 'h': SetColor(CRGBA(0xE1, 0xE1, 0xE1, 0xFF)); break;
+ case 'l': SetColor(CRGBA(0x00, 0x00, 0x00, 0xFF)); break;
+ case 'p': SetColor(CRGBA(0xA8, 0x6E, 0xFC, 0xFF)); break;
+ case 'r': SetColor(CRGBA(0x71, 0x2B, 0x49, 0xFF)); break;
+ case 'w': SetColor(CRGBA(0xAF, 0xAF, 0xAF, 0xFF)); break;
+ case 'y': SetColor(CRGBA(0xD2, 0xC4, 0x6A, 0xFF)); break;
+ }
+ while(*s != '~') s++;
+ return s+1;
+}
+
+void
+CFont::DrawFonts(void)
+{
+ CSprite2d::DrawBank(Details.bank);
+ CSprite2d::DrawBank(Details.bank+1);
+ CSprite2d::DrawBank(Details.bank+2);
+}
+
+wchar
+CFont::character_code(uint8 c)
+{
+ if(c < 128)
+ return c;
+ return foreign_table[c-128];
+}
+
+STARTPATCHES
+
+ InjectHook(0x500A40, CFont::Initialise, PATCH_JUMP);
+ InjectHook(0x500BA0, CFont::Shutdown, PATCH_JUMP);
+ InjectHook(0x500BE0, CFont::InitPerFrame, PATCH_JUMP);
+ InjectHook(0x500C30, CFont::PrintChar, PATCH_JUMP);
+ InjectHook(0x500F50, (void (*)(float, float, wchar*))CFont::PrintString, PATCH_JUMP);
+ InjectHook(0x501260, CFont::GetNumberLines, PATCH_JUMP);
+ InjectHook(0x5013B0, CFont::GetTextRect, PATCH_JUMP);
+ InjectHook(0x501730, (void (*)(float, float, wchar*, wchar*, float))CFont::PrintString, PATCH_JUMP);
+ InjectHook(0x5017E0, CFont::GetCharacterWidth, PATCH_JUMP);
+ InjectHook(0x501840, CFont::GetCharacterSize, PATCH_JUMP);
+ InjectHook(0x5018A0, CFont::GetStringWidth, PATCH_JUMP);
+ InjectHook(0x501960, CFont::GetNextSpace, PATCH_JUMP);
+ InjectHook(0x5019A0, CFont::ParseToken, PATCH_JUMP);
+ InjectHook(0x501B50, CFont::DrawFonts, PATCH_JUMP);
+ InjectHook(0x501E80, CFont::character_code, PATCH_JUMP);
+
+ InjectHook(0x501B80, CFont::SetScale, PATCH_JUMP);
+ InjectHook(0x501BA0, CFont::SetSlantRefPoint, PATCH_JUMP);
+ InjectHook(0x501BC0, CFont::SetSlant, PATCH_JUMP);
+ InjectHook(0x501BD0, CFont::SetColor, PATCH_JUMP);
+ InjectHook(0x501C60, CFont::SetJustifyOn, PATCH_JUMP);
+ InjectHook(0x501C80, CFont::SetJustifyOff, PATCH_JUMP);
+ InjectHook(0x501C90, CFont::SetCentreOn, PATCH_JUMP);
+ InjectHook(0x501CB0, CFont::SetCentreOff, PATCH_JUMP);
+ InjectHook(0x501CC0, CFont::SetWrapx, PATCH_JUMP);
+ InjectHook(0x501CD0, CFont::SetCentreSize, PATCH_JUMP);
+ InjectHook(0x501CE0, CFont::SetBackgroundOn, PATCH_JUMP);
+ InjectHook(0x501CF0, CFont::SetBackgroundOff, PATCH_JUMP);
+ InjectHook(0x501D00, CFont::SetBackgroundColor, PATCH_JUMP);
+ InjectHook(0x501D30, CFont::SetBackGroundOnlyTextOn, PATCH_JUMP);
+ InjectHook(0x501D40, CFont::SetBackGroundOnlyTextOff, PATCH_JUMP);
+ InjectHook(0x501D50, CFont::SetRightJustifyOn, PATCH_JUMP);
+ InjectHook(0x501D70, CFont::SetRightJustifyOff, PATCH_JUMP);
+ InjectHook(0x501D90, CFont::SetPropOff, PATCH_JUMP);
+ InjectHook(0x501DA0, CFont::SetPropOn, PATCH_JUMP);
+ InjectHook(0x501DB0, CFont::SetFontStyle, PATCH_JUMP);
+ InjectHook(0x501DC0, CFont::SetRightJustifyWrap, PATCH_JUMP);
+ InjectHook(0x501DD0, CFont::SetAlphaFade, PATCH_JUMP);
+ InjectHook(0x501DE0, CFont::SetDropColor, PATCH_JUMP);
+ InjectHook(0x501E70, CFont::SetDropShadowPosition, PATCH_JUMP);
+
+ENDPATCHES
diff --git a/src/render/Font.h b/src/render/Font.h
index 132ad168..0659dda1 100644
--- a/src/render/Font.h
+++ b/src/render/Font.h
@@ -39,9 +39,23 @@ enum {
ALIGN_RIGHT,
};
+#ifdef MORE_LANGUAGES
+enum
+{
+ FONT_LANGSET_EFIGS,
+ FONT_LANGSET_RUSSIAN
+};
+#endif
+
class CFont
{
+#ifdef MORE_LANGUAGES
+ static int16 Size[2][3][193];
+ static uint8 LanguageSet;
+ static int32 Slot;
+#else
static int16 Size[3][193];
+#endif
static int16 &NewLine;
static CSprite2d *Sprite; //[3]
public:
@@ -50,18 +64,18 @@ public:
static void Initialise(void);
static void Shutdown(void);
static void InitPerFrame(void);
- static void PrintChar(float x, float y, uint16 c);
- static void PrintString(float x, float y, uint16 *s);
- static int GetNumberLines(float xstart, float ystart, uint16 *s);
- static void GetTextRect(CRect *rect, float xstart, float ystart, uint16 *s);
- static void PrintString(float x, float y, uint16 *start, uint16 *end, float spwidth);
- static float GetCharacterWidth(uint16 c);
- static float GetCharacterSize(uint16 c);
- static float GetStringWidth(uint16 *s, bool spaces = false);
- static uint16 *GetNextSpace(uint16 *s);
- static uint16 *ParseToken(uint16 *s, uint16*);
+ static void PrintChar(float x, float y, wchar c);
+ static void PrintString(float x, float y, wchar *s);
+ static int GetNumberLines(float xstart, float ystart, wchar *s);
+ static void GetTextRect(CRect *rect, float xstart, float ystart, wchar *s);
+ static void PrintString(float x, float y, wchar *start, wchar *end, float spwidth);
+ static float GetCharacterWidth(wchar c);
+ static float GetCharacterSize(wchar c);
+ static float GetStringWidth(wchar *s, bool spaces = false);
+ static wchar *GetNextSpace(wchar *s);
+ static wchar *ParseToken(wchar *s, wchar*);
static void DrawFonts(void);
- static uint16 character_code(uint8 c);
+ static wchar character_code(uint8 c);
static CFontDetails GetDetails() { return Details; }
static void SetScale(float x, float y) { Details.scaleX = x; Details.scaleY = y; }
@@ -136,4 +150,6 @@ public:
if(Details.alphaFade < 255.0f)
Details.dropColor.a *= Details.alphaFade/255.0f;
}
+
+ static void ReloadFonts(uint8 set);
};
diff --git a/src/render/Glass.cpp b/src/render/Glass.cpp
index ac04032b..41d31985 100644
--- a/src/render/Glass.cpp
+++ b/src/render/Glass.cpp
@@ -1,21 +1,721 @@
#include "common.h"
#include "patcher.h"
#include "Glass.h"
+#include "Timer.h"
+#include "Object.h"
+#include "General.h"
+#include "AudioScriptObject.h"
+#include "World.h"
+#include "TimeCycle.h"
+#include "Particle.h"
+#include "Camera.h"
+#include "RenderBuffer.h"
+#include "Shadows.h"
+#include "ModelIndices.h"
+#include "main.h"
-WRAPPER void CGlass::AskForObjectToBeRenderedInGlass(CEntity *ent) { EAXJMP(0x5033F0); }
-WRAPPER void
-CGlass::WindowRespondsToCollision(CEntity *ent, float amount, CVector speed, CVector point, bool foo)
+uint32 CGlass::NumGlassEntities;
+CEntity *CGlass::apEntitiesToBeRendered[NUM_GLASSENTITIES];
+CFallingGlassPane CGlass::aGlassPanes[NUM_GLASSPANES];
+
+
+CVector2D CentersWithTriangle[NUM_GLASSTRIANGLES];
+const CVector2D CoorsWithTriangle[NUM_GLASSTRIANGLES][3] =
+{
+ {
+ CVector2D(0.0f, 0.0f),
+ CVector2D(0.0f, 1.0f),
+ CVector2D(0.4f, 0.5f)
+ },
+
+ {
+ CVector2D(0.0f, 1.0f),
+ CVector2D(1.0f, 1.0f),
+ CVector2D(0.4f, 0.5f)
+ },
+
+ {
+ CVector2D(0.0f, 0.0f),
+ CVector2D(0.4f, 0.5f),
+ CVector2D(0.7f, 0.0f)
+ },
+
+ {
+ CVector2D(0.7f, 0.0f),
+ CVector2D(0.4f, 0.5f),
+ CVector2D(1.0f, 1.0f)
+ },
+
+ {
+ CVector2D(0.7f, 0.0f),
+ CVector2D(1.0f, 1.0f),
+ CVector2D(1.0f, 0.0f)
+ }
+};
+
+#define TEMPBUFFERVERTHILIGHTOFFSET 0
+#define TEMPBUFFERINDEXHILIGHTOFFSET 0
+#define TEMPBUFFERVERTHILIGHTSIZE 128
+#define TEMPBUFFERINDEXHILIGHTSIZE 512
+
+#define TEMPBUFFERVERTSHATTEREDOFFSET TEMPBUFFERVERTHILIGHTSIZE
+#define TEMPBUFFERINDEXSHATTEREDOFFSET TEMPBUFFERINDEXHILIGHTSIZE
+#define TEMPBUFFERVERTSHATTEREDSIZE 192
+#define TEMPBUFFERINDEXSHATTEREDSIZE 768
+
+#define TEMPBUFFERVERTREFLECTIONOFFSET TEMPBUFFERVERTSHATTEREDSIZE
+#define TEMPBUFFERINDEXREFLECTIONOFFSET TEMPBUFFERINDEXSHATTEREDSIZE
+#define TEMPBUFFERVERTREFLECTIONSIZE 256
+#define TEMPBUFFERINDEXREFLECTIONSIZE 1024
+
+int32 TempBufferIndicesStoredHiLight = 0;
+int32 TempBufferVerticesStoredHiLight = 0;
+int32 TempBufferIndicesStoredShattered = 0;
+int32 TempBufferVerticesStoredShattered = 0;
+int32 TempBufferIndicesStoredReflection = 0;
+int32 TempBufferVerticesStoredReflection = 0;
+
+void
+CFallingGlassPane::Update(void)
+{
+ if ( CTimer::GetTimeInMilliseconds() >= m_nTimer )
+ {
+ // Apply MoveSpeed
+ GetPosition() += m_vecMoveSpeed * CTimer::GetTimeStep();
+
+ // Apply Gravity
+ m_vecMoveSpeed.z -= 0.02f * CTimer::GetTimeStep();
+
+ // Apply TurnSpeed
+ GetRight() += CrossProduct(m_vecTurn, GetRight());
+ GetForward() += CrossProduct(m_vecTurn, GetForward());
+ GetUp() += CrossProduct(m_vecTurn, GetUp());
+
+ if ( GetPosition().z < m_fGroundZ )
+ {
+ CVector pos;
+ CVector dir;
+
+ m_bActive = false;
+
+ pos = CVector(GetPosition().x, GetPosition().y, m_fGroundZ);
+
+ PlayOneShotScriptObject(_SCRSOUND_GLASS_SHARD, pos);
+
+ RwRGBA color = { 255, 255, 255, 255 };
+
+ static int32 nFrameGen = 0;
+
+ for ( int32 i = 0; i < 4; i++ )
+ {
+ dir.x = CGeneral::GetRandomNumberInRange(-0.35f, 0.35f);
+ dir.y = CGeneral::GetRandomNumberInRange(-0.35f, 0.35f);
+ dir.z = CGeneral::GetRandomNumberInRange(0.05f, 0.20f);
+
+ CParticle::AddParticle(PARTICLE_CAR_DEBRIS,
+ pos,
+ dir,
+ nil,
+ CGeneral::GetRandomNumberInRange(0.02f, 0.2f),
+ color,
+ CGeneral::GetRandomNumberInRange(-40, 40),
+ 0,
+ ++nFrameGen & 3,
+ 500);
+ }
+ }
+ }
+}
+
+void
+CFallingGlassPane::Render(void)
+{
+ float distToCamera = (TheCamera.GetPosition() - GetPosition()).Magnitude();
+
+ CVector fwdNorm = GetForward();
+ fwdNorm.Normalise();
+ uint8 alpha = CGlass::CalcAlphaWithNormal(&fwdNorm);
+
+ int32 time = clamp(CTimer::GetTimeInMilliseconds() - m_nTimer, 0, 500);
+
+ uint8 color = int32( float(alpha) * (float(time) / 500) );
+
+ if ( TempBufferIndicesStoredHiLight >= TEMPBUFFERINDEXHILIGHTSIZE-7 || TempBufferVerticesStoredHiLight >= TEMPBUFFERVERTHILIGHTSIZE-4 )
+ CGlass::RenderHiLightPolys();
+
+ // HiLight Polys
+
+ RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 0], color, color, color, color);
+ RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 1], color, color, color, color);
+ RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 2], color, color, color, color);
+
+ RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 0], 0.5f);
+ RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 0], 0.5f);
+ RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 1], 0.5f);
+ RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 1], 0.6f);
+ RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 2], 0.6f);
+ RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 2], 0.6f);
+
+ ASSERT(m_nTriIndex < NUM_GLASSTRIANGLES);
+
+ CVector2D p0 = CoorsWithTriangle[m_nTriIndex][0] - CentersWithTriangle[m_nTriIndex];
+ CVector2D p1 = CoorsWithTriangle[m_nTriIndex][1] - CentersWithTriangle[m_nTriIndex];
+ CVector2D p2 = CoorsWithTriangle[m_nTriIndex][2] - CentersWithTriangle[m_nTriIndex];
+ CVector v0 = *this * CVector(p0.x, 0.0f, p0.y);
+ CVector v1 = *this * CVector(p1.x, 0.0f, p1.y);
+ CVector v2 = *this * CVector(p2.x, 0.0f, p2.y);
+
+ RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 0], v0.x, v0.y, v0.z);
+ RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 1], v1.x, v1.y, v1.z);
+ RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 2], v2.x, v2.y, v2.z);
+
+ TempBufferRenderIndexList[TempBufferIndicesStoredHiLight + 0] = TempBufferVerticesStoredHiLight + 0;
+ TempBufferRenderIndexList[TempBufferIndicesStoredHiLight + 1] = TempBufferVerticesStoredHiLight + 1;
+ TempBufferRenderIndexList[TempBufferIndicesStoredHiLight + 2] = TempBufferVerticesStoredHiLight + 2;
+ TempBufferRenderIndexList[TempBufferIndicesStoredHiLight + 3] = TempBufferVerticesStoredHiLight + 0;
+ TempBufferRenderIndexList[TempBufferIndicesStoredHiLight + 4] = TempBufferVerticesStoredHiLight + 2;
+ TempBufferRenderIndexList[TempBufferIndicesStoredHiLight + 5] = TempBufferVerticesStoredHiLight + 1;
+
+ TempBufferVerticesStoredHiLight += 3;
+ TempBufferIndicesStoredHiLight += 6;
+
+ if ( m_bShattered )
+ {
+ if ( TempBufferIndicesStoredShattered >= TEMPBUFFERINDEXSHATTEREDSIZE-7 || TempBufferVerticesStoredShattered >= TEMPBUFFERVERTSHATTEREDSIZE-4 )
+ CGlass::RenderShatteredPolys();
+
+ uint8 shatteredColor = 255;
+ if ( distToCamera > 30.0f )
+ shatteredColor = int32((1.0f - (distToCamera - 30.0f) * 4.0f / 40.0f) * 255);
+
+ RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], shatteredColor, shatteredColor, shatteredColor, shatteredColor);
+ RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], shatteredColor, shatteredColor, shatteredColor, shatteredColor);
+ RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], shatteredColor, shatteredColor, shatteredColor, shatteredColor);
+
+ RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], 4.0f * CoorsWithTriangle[m_nTriIndex][0].x * m_fStep);
+ RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], 4.0f * CoorsWithTriangle[m_nTriIndex][0].y * m_fStep);
+ RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], 4.0f * CoorsWithTriangle[m_nTriIndex][1].x * m_fStep);
+ RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], 4.0f * CoorsWithTriangle[m_nTriIndex][1].y * m_fStep);
+ RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], 4.0f * CoorsWithTriangle[m_nTriIndex][2].x * m_fStep);
+ RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], 4.0f * CoorsWithTriangle[m_nTriIndex][2].y * m_fStep);
+
+ RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], v0.x, v0.y, v0.z);
+ RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], v1.x, v1.y, v1.z);
+ RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], v2.x, v2.y, v2.z);
+
+ TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 0] = TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET + 0;
+ TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 1] = TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET + 1;
+ TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 2] = TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET + 2;
+ TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 3] = TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET + 0;
+ TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 4] = TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET + 2;
+ TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 5] = TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET + 1;
+
+ TempBufferIndicesStoredShattered += 6;
+ TempBufferVerticesStoredShattered += 3;
+ }
+}
+
+void
+CGlass::Init(void)
+{
+ for ( int32 i = 0; i < NUM_GLASSPANES; i++ )
+ aGlassPanes[i].m_bActive = false;
+
+ for ( int32 i = 0; i < NUM_GLASSTRIANGLES; i++ )
+ CentersWithTriangle[i] = (CoorsWithTriangle[i][0] + CoorsWithTriangle[i][1] + CoorsWithTriangle[i][2]) / 3;
+}
+
+void
+CGlass::Update(void)
+{
+ for ( int32 i = 0; i < NUM_GLASSPANES; i++ )
+ {
+ if ( aGlassPanes[i].m_bActive )
+ aGlassPanes[i].Update();
+ }
+}
+
+void
+CGlass::Render(void)
+{
+ TempBufferVerticesStoredHiLight = 0;
+ TempBufferIndicesStoredHiLight = 0;
+
+ TempBufferVerticesStoredShattered = TEMPBUFFERVERTSHATTEREDOFFSET;
+ TempBufferIndicesStoredShattered = TEMPBUFFERINDEXSHATTEREDOFFSET;
+
+ TempBufferVerticesStoredReflection = TEMPBUFFERVERTREFLECTIONOFFSET;
+ TempBufferIndicesStoredReflection = TEMPBUFFERINDEXREFLECTIONOFFSET;
+
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE);
+ RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void *)rwFILTERLINEAR);
+ RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)TRUE);
+ RwRenderStateSet(rwRENDERSTATEFOGCOLOR, (void *)RWRGBALONG(CTimeCycle::GetFogRed(), CTimeCycle::GetFogGreen(), CTimeCycle::GetFogBlue(), 255));
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE);
+
+ for ( int32 i = 0; i < NUM_GLASSPANES; i++ )
+ {
+ if ( aGlassPanes[i].m_bActive )
+ aGlassPanes[i].Render();
+ }
+
+ for ( uint32 i = 0; i < NumGlassEntities; i++ )
+ RenderEntityInGlass(apEntitiesToBeRendered[i]);
+
+ NumGlassEntities = 0;
+
+ RenderHiLightPolys();
+ RenderShatteredPolys();
+ RenderReflectionPolys();
+
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)TRUE);
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void *)TRUE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)FALSE);
+}
+
+CFallingGlassPane *
+CGlass::FindFreePane(void)
+{
+ for ( int32 i = 0; i < NUM_GLASSPANES; i++ )
+ {
+ if ( !aGlassPanes[i].m_bActive )
+ return &aGlassPanes[i];
+ }
+
+ return nil;
+}
+
+void
+CGlass::GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector right, CVector speed, CVector point,
+ float moveSpeed, bool cracked, bool explosion)
+{
+ float upLen = up.Magnitude();
+ float rightLen = right.Magnitude();
+
+ float upSteps = upLen + 0.75f;
+ if ( upSteps < 1.0f ) upSteps = 1.0f;
+
+ float rightSteps = rightLen + 0.75f;
+ if ( rightSteps < 1.0f ) rightSteps = 1.0f;
+
+ uint32 ysteps = (uint32)upSteps;
+ if ( ysteps > 3 ) ysteps = 3;
+
+ uint32 xsteps = (uint32)rightSteps;
+ if ( xsteps > 3 ) xsteps = 3;
+
+ if ( explosion )
+ {
+ if ( ysteps > 1 ) ysteps = 1;
+ if ( xsteps > 1 ) xsteps = 1;
+ }
+
+ float upScl = upLen / float(ysteps);
+ float rightScl = rightLen / float(xsteps);
+
+ bool bZFound;
+ float groundZ = CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z, &bZFound);
+ if ( !bZFound ) groundZ = pos.z - 2.0f;
+
+ for ( uint32 y = 0; y < ysteps; y++ )
+ {
+ for ( uint32 x = 0; x < xsteps; x++ )
+ {
+ float stepy = float(y) * upLen / float(ysteps);
+ float stepx = float(x) * rightLen / float(xsteps);
+
+ for ( int32 i = 0; i < NUM_GLASSTRIANGLES; i++ )
+ {
+ CFallingGlassPane *pane = FindFreePane();
+ if ( pane )
+ {
+ pane->m_nTriIndex = i;
+
+ pane->GetRight() = (right * rightScl) / rightLen;
+#ifdef FIX_BUGS
+ pane->GetUp() = (up * upScl) / upLen;
+#else
+ pane->GetUp() = (up * upScl) / rightLen; // copypaste bug
+#endif
+ CVector fwd = CrossProduct(pane->GetRight(), pane->GetUp());
+ fwd.Normalise();
+
+ pane->GetForward() = fwd;
+
+ pane->GetPosition() = right / rightLen * (rightScl * CentersWithTriangle[i].x + stepx)
+ + up / upLen * (upScl * CentersWithTriangle[i].y + stepy)
+ + pos;
+
+ pane->m_vecMoveSpeed.x = float((CGeneral::GetRandomNumber() & 127) - 64) * 0.0015f + speed.x;
+ pane->m_vecMoveSpeed.y = float((CGeneral::GetRandomNumber() & 127) - 64) * 0.0015f + speed.y;
+ pane->m_vecMoveSpeed.z = 0.0f + speed.z;
+
+ if ( moveSpeed != 0.0f )
+ {
+ CVector dist = pane->GetPosition() - point;
+ dist.Normalise();
+
+ pane->m_vecMoveSpeed += moveSpeed * dist;
+ }
+
+ pane->m_vecTurn.x = float((CGeneral::GetRandomNumber() & 127) - 64) * 0.002f;
+ pane->m_vecTurn.y = float((CGeneral::GetRandomNumber() & 127) - 64) * 0.002f;
+ pane->m_vecTurn.z = float((CGeneral::GetRandomNumber() & 127) - 64) * 0.002f;
+
+ switch ( type )
+ {
+ case 0:
+ pane->m_nTimer = CTimer::GetTimeInMilliseconds();
+ break;
+ case 1:
+ float dist = (pane->GetPosition() - point).Magnitude();
+ pane->m_nTimer = uint32(dist*100 + CTimer::GetTimeInMilliseconds());
+ break;
+ }
+
+ pane->m_fGroundZ = groundZ;
+ pane->m_bShattered = cracked;
+ pane->m_fStep = upLen / float(ysteps);
+ pane->m_bActive = true;
+ }
+ }
+ }
+ }
+}
+
+void
+CGlass::AskForObjectToBeRenderedInGlass(CEntity *entity)
+{
+#ifdef FIX_BUGS
+ if ( NumGlassEntities < NUM_GLASSPANES )
+#else
+ if ( NumGlassEntities < NUM_GLASSPANES-1 )
+#endif
+ {
+ apEntitiesToBeRendered[NumGlassEntities++] = entity;
+ }
+}
+
+void
+CGlass::RenderEntityInGlass(CEntity *entity)
+{
+ CObject *object = (CObject *)entity;
+
+ if ( object->bGlassBroken )
+ return;
+
+ float distToCamera = (TheCamera.GetPosition() - object->GetPosition()).Magnitude();
+
+ if ( distToCamera > 40.0f )
+ return;
+
+ CVector fwdNorm = object->GetForward();
+ fwdNorm.Normalise();
+ uint8 alpha = CalcAlphaWithNormal(&fwdNorm);
+
+ CColModel *col = object->GetColModel();
+
+ if ( col->numTriangles >= 2 )
+ {
+ CVector a = object->GetMatrix() * col->vertices[0];
+ CVector b = object->GetMatrix() * col->vertices[1];
+ CVector c = object->GetMatrix() * col->vertices[2];
+ CVector d = object->GetMatrix() * col->vertices[3];
+
+ if ( object->bGlassCracked )
+ {
+ uint8 color = 255;
+ if ( distToCamera > 30.0f )
+ color = int32((1.0f - (distToCamera - 30.0f) * 4.0f / 40.0f) * 255);
+
+ if ( TempBufferIndicesStoredShattered >= TEMPBUFFERINDEXSHATTEREDSIZE-13 || TempBufferVerticesStoredShattered >= TEMPBUFFERVERTSHATTEREDSIZE-5 )
+ RenderShatteredPolys();
+
+ RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], color, color, color, color);
+ RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], color, color, color, color);
+ RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], color, color, color, color);
+ RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 3], color, color, color, color);
+
+ RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], 0.0f);
+ RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], 0.0f);
+ RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], 16.0f);
+ RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], 0.0f);
+ RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], 0.0f);
+ RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], 16.0f);
+ RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 3], 16.0f);
+ RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 3], 16.0f);
+
+ RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], a.x, a.y, a.z);
+ RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], b.x, b.y, b.z);
+ RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], c.x, c.y, c.z);
+ RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 3], d.x, d.y, d.z);
+
+ TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 0] = col->triangles[0].a + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 1] = col->triangles[0].b + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 2] = col->triangles[0].c + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 3] = col->triangles[1].a + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 4] = col->triangles[1].b + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 5] = col->triangles[1].c + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 6] = col->triangles[0].a + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 7] = col->triangles[0].c + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 8] = col->triangles[0].b + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 9] = col->triangles[1].a + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 10] = col->triangles[1].c + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 11] = col->triangles[1].b + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
+
+ TempBufferIndicesStoredShattered += 12;
+ TempBufferVerticesStoredShattered += 4;
+ }
+
+ if ( TempBufferIndicesStoredReflection >= TEMPBUFFERINDEXREFLECTIONSIZE-13 || TempBufferVerticesStoredReflection >= TEMPBUFFERVERTREFLECTIONSIZE-5 )
+ RenderReflectionPolys();
+
+ uint8 color = 100;
+ if ( distToCamera > 30.0f )
+ color = int32((1.0f - (distToCamera - 30.0f) * 4.0f / 40.0f) * 100);
+
+ RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 0], color, color, color, color);
+ RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 1], color, color, color, color);
+ RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 2], color, color, color, color);
+ RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 3], color, color, color, color);
+
+ float FwdAngle = CGeneral::GetATanOfXY(TheCamera.GetForward().x, TheCamera.GetForward().y);
+ float v = 2.0f * TheCamera.GetForward().z * 0.2f;
+ float u = float(object->m_randomSeed & 15) * 0.02f + (FwdAngle / TWOPI);
+
+ RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 0], u);
+ RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 0], v);
+ RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 1], u+0.2f);
+ RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 1], v);
+ RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 2], u);
+ RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 2], v+0.2f);
+ RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 3], u+0.2f);
+ RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 3], v+0.2f);
+
+ RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 0], a.x, a.y, a.z);
+ RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 1], b.x, b.y, b.z);
+ RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 2], c.x, c.y, c.z);
+ RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 3], d.x, d.y, d.z);
+
+ TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 0] = col->triangles[0].a + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 1] = col->triangles[0].b + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 2] = col->triangles[0].c + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 3] = col->triangles[1].a + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 4] = col->triangles[1].b + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 5] = col->triangles[1].c + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 6] = col->triangles[0].a + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 7] = col->triangles[0].c + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 8] = col->triangles[0].b + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 9] = col->triangles[1].a + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 10] = col->triangles[1].c + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
+ TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 11] = col->triangles[1].b + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
+
+ TempBufferIndicesStoredReflection += 12;
+ TempBufferVerticesStoredReflection += 4;
+ }
+}
+
+int32
+CGlass::CalcAlphaWithNormal(CVector *normal)
{
- EAXJMP(0x503F10);
+ float fwdDir = 2.0f * DotProduct(*normal, TheCamera.GetForward());
+ float fwdDot = DotProduct(TheCamera.GetForward()-fwdDir*(*normal), CVector(0.57f, 0.57f, -0.57f));
+ return int32(lerp(fwdDot*fwdDot*fwdDot*fwdDot*fwdDot*fwdDot, 20.0f, 255.0f));
}
-WRAPPER void
-CGlass::WindowRespondsToSoftCollision(CEntity *ent, float amount)
+void
+CGlass::RenderHiLightPolys(void)
{
- EAXJMP(0x504630);
+ if ( TempBufferVerticesStoredHiLight != TEMPBUFFERVERTHILIGHTOFFSET )
+ {
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)RwTextureGetRaster(gpShadowExplosionTex));
+
+ LittleTest();
+
+ if ( RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStoredHiLight, nil, rwIM3D_VERTEXUV) )
+ {
+ RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStoredHiLight);
+ RwIm3DEnd();
+ }
+
+ TempBufferVerticesStoredHiLight = TEMPBUFFERVERTHILIGHTOFFSET;
+ TempBufferIndicesStoredHiLight = TEMPBUFFERINDEXHILIGHTOFFSET;
+ }
+}
+
+void
+CGlass::RenderShatteredPolys(void)
+{
+ if ( TempBufferVerticesStoredShattered != TEMPBUFFERVERTSHATTEREDOFFSET )
+ {
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)RwTextureGetRaster(gpCrackedGlassTex));
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA);
+
+ LittleTest();
+
+ if ( RwIm3DTransform(&TempBufferRenderVertices[TEMPBUFFERVERTSHATTEREDOFFSET], TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET, nil, rwIM3D_VERTEXUV) )
+ {
+ RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, &TempBufferRenderIndexList[TEMPBUFFERINDEXSHATTEREDOFFSET], TempBufferIndicesStoredShattered - TEMPBUFFERINDEXSHATTEREDOFFSET);
+ RwIm3DEnd();
+ }
+
+ TempBufferIndicesStoredShattered = TEMPBUFFERINDEXSHATTEREDOFFSET;
+ TempBufferVerticesStoredShattered = TEMPBUFFERVERTSHATTEREDOFFSET;
+ }
+}
+
+void
+CGlass::RenderReflectionPolys(void)
+{
+ if ( TempBufferVerticesStoredReflection != TEMPBUFFERVERTREFLECTIONOFFSET )
+ {
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)RwTextureGetRaster(gpShadowHeadLightsTex));
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA);
+
+ LittleTest();
+
+ if ( RwIm3DTransform(&TempBufferRenderVertices[TEMPBUFFERVERTREFLECTIONOFFSET], TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET, nil, rwIM3D_VERTEXUV) )
+ {
+ RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, &TempBufferRenderIndexList[TEMPBUFFERINDEXREFLECTIONOFFSET], TempBufferIndicesStoredReflection - TEMPBUFFERINDEXREFLECTIONOFFSET);
+ RwIm3DEnd();
+ }
+
+ TempBufferIndicesStoredReflection = TEMPBUFFERINDEXREFLECTIONOFFSET;
+ TempBufferVerticesStoredReflection = TEMPBUFFERVERTREFLECTIONOFFSET;
+ }
+}
+
+void
+CGlass::WindowRespondsToCollision(CEntity *entity, float amount, CVector speed, CVector point, bool explosion)
+{
+ CObject *object = (CObject *)entity;
+
+ if ( object->bGlassBroken )
+ return;
+
+ object->bGlassCracked = true;
+
+ CColModel *col = object->GetColModel();
+
+ CVector a = object->GetMatrix() * col->vertices[0];
+ CVector b = object->GetMatrix() * col->vertices[1];
+ CVector c = object->GetMatrix() * col->vertices[2];
+ CVector d = object->GetMatrix() * col->vertices[3];
+
+ float minx = min(min(a.x, b.x), min(c.x, d.x));
+ float maxx = max(max(a.x, b.x), max(c.x, d.x));
+ float miny = min(min(a.y, b.y), min(c.y, d.y));
+ float maxy = max(max(a.y, b.y), max(c.y, d.y));
+ float minz = min(min(a.z, b.z), min(c.z, d.z));
+ float maxz = max(max(a.z, b.z), max(c.z, d.z));
+
+
+ if ( amount > 300.0f )
+ {
+ PlayOneShotScriptObject(_SCRSOUND_GLASS_SMASH_1, object->GetPosition());
+
+ GeneratePanesForWindow(0,
+ CVector(minx, miny, minz),
+ CVector(0.0f, 0.0f, maxz-minz),
+ CVector(maxx-minx, maxy-miny, 0.0f),
+ speed, point, 0.1f, !!object->bGlassCracked, explosion);
+ }
+ else
+ {
+ PlayOneShotScriptObject(_SCRSOUND_GLASS_SMASH_2, object->GetPosition());
+
+ GeneratePanesForWindow(1,
+ CVector(minx, miny, minz),
+ CVector(0.0f, 0.0f, maxz-minz),
+ CVector(maxx-minx, maxy-miny, 0.0f),
+ speed, point, 0.1f, !!object->bGlassCracked, explosion);
+ }
+
+ object->bGlassBroken = true;
+ object->GetPosition().z = -100.0f;
+}
+
+void
+CGlass::WindowRespondsToSoftCollision(CEntity *entity, float amount)
+{
+ CObject *object = (CObject *)entity;
+
+ if ( amount > 50.0f && !object->bGlassCracked )
+ {
+ PlayOneShotScriptObject(_SCRSOUND_GLASS_CRACK, object->GetPosition());
+ object->bGlassCracked = true;
+ }
+}
+
+void
+CGlass::WasGlassHitByBullet(CEntity *entity, CVector point)
+{
+ CObject *object = (CObject *)entity;
+
+ if ( IsGlass(object->GetModelIndex()) )
+ {
+ if ( !object->bGlassCracked )
+ {
+ PlayOneShotScriptObject(_SCRSOUND_GLASS_CRACK, object->GetPosition());
+ object->bGlassCracked = true;
+ }
+ else
+ {
+ if ( (CGeneral::GetRandomNumber() & 3) == 2 )
+ WindowRespondsToCollision(object, 0.0f, CVector(0.0f, 0.0f, 0.0f), point, false);
+ }
+ }
+}
+
+void
+CGlass::WindowRespondsToExplosion(CEntity *entity, CVector point)
+{
+ CObject *object = (CObject *)entity;
+
+ CVector distToGlass = object->GetPosition() - point;
+
+ float fDistToGlass = distToGlass.Magnitude();
+
+ if ( fDistToGlass < 10.0f )
+ {
+ distToGlass.Normalise(0.3f);
+ WindowRespondsToCollision(object, 10000.0f, distToGlass, object->GetPosition(), true);
+ }
+ else
+ {
+ if ( fDistToGlass < 30.0f )
+ object->bGlassCracked = true;
+ }
}
-WRAPPER void CGlass::Render(void) { EAXJMP(0x502350); }
-WRAPPER void CGlass::Update(void) { EAXJMP(0x502050); }
-WRAPPER void CGlass::Init(void) { EAXJMP(0x501F20); }
+STARTPATCHES
+ InjectHook(0x501F20, CGlass::Init, PATCH_JUMP);
+ InjectHook(0x502050, CGlass::Update, PATCH_JUMP);
+ InjectHook(0x502080, &CFallingGlassPane::Update, PATCH_JUMP);
+ InjectHook(0x502350, CGlass::Render, PATCH_JUMP);
+ InjectHook(0x502490, CGlass::FindFreePane, PATCH_JUMP);
+ InjectHook(0x5024C0, &CFallingGlassPane::Render, PATCH_JUMP);
+ InjectHook(0x502AC0, CGlass::GeneratePanesForWindow, PATCH_JUMP);
+ InjectHook(0x5033F0, CGlass::AskForObjectToBeRenderedInGlass, PATCH_JUMP);
+ InjectHook(0x503420, CGlass::RenderEntityInGlass, PATCH_JUMP);
+ InjectHook(0x503C90, CGlass::CalcAlphaWithNormal, PATCH_JUMP);
+ InjectHook(0x503D60, CGlass::RenderHiLightPolys, PATCH_JUMP);
+ InjectHook(0x503DE0, CGlass::RenderShatteredPolys, PATCH_JUMP);
+ InjectHook(0x503E70, CGlass::RenderReflectionPolys, PATCH_JUMP);
+ InjectHook(0x503F10, CGlass::WindowRespondsToCollision, PATCH_JUMP);
+ InjectHook(0x504630, CGlass::WindowRespondsToSoftCollision, PATCH_JUMP);
+ InjectHook(0x504670, CGlass::WasGlassHitByBullet, PATCH_JUMP);
+ InjectHook(0x504790, CGlass::WindowRespondsToExplosion, PATCH_JUMP);
+ //InjectHook(0x504880, `global constructor keyed to'glass.cpp, PATCH_JUMP);
+ //InjectHook(0x5048D0, CFallingGlassPane::~CFallingGlassPane, PATCH_JUMP);
+ //InjectHook(0x5048E0, CFallingGlassPane::CFallingGlassPane, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/render/Glass.h b/src/render/Glass.h
index ad4d50f2..dccd9d3d 100644
--- a/src/render/Glass.h
+++ b/src/render/Glass.h
@@ -2,13 +2,52 @@
class CEntity;
+class CFallingGlassPane : public CMatrix
+{
+public:
+ CVector m_vecMoveSpeed;
+ CVector m_vecTurn;
+ uint32 m_nTimer;
+ float m_fGroundZ;
+ float m_fStep;
+ uint8 m_nTriIndex;
+ bool m_bActive;
+ bool m_bShattered;
+ char _pad0[1];
+
+ CFallingGlassPane() { }
+ ~CFallingGlassPane() { }
+
+ void Update(void);
+ void Render(void);
+};
+
+VALIDATE_SIZE(CFallingGlassPane, 0x70);
+
+enum
+{
+ NUM_GLASSTRIANGLES = 5,
+};
+
class CGlass
{
+ static uint32 NumGlassEntities;
+ static CEntity *apEntitiesToBeRendered[NUM_GLASSENTITIES];
+ static CFallingGlassPane aGlassPanes[NUM_GLASSPANES];
public:
- static void AskForObjectToBeRenderedInGlass(CEntity *ent);
- static void WindowRespondsToCollision(CEntity *ent, float amount, CVector speed, CVector point, bool foo);
- static void WindowRespondsToSoftCollision(CEntity *ent, float amount);
- static void Render(void);
- static void Update(void);
static void Init(void);
-};
+ static void Update(void);
+ static void Render(void);
+ static CFallingGlassPane *FindFreePane(void);
+ static void GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector right, CVector speed, CVector point, float moveSpeed, bool cracked, bool explosion);
+ static void AskForObjectToBeRenderedInGlass(CEntity *entity);
+ static void RenderEntityInGlass(CEntity *entity);
+ static int32 CalcAlphaWithNormal(CVector *normal);
+ static void RenderHiLightPolys(void);
+ static void RenderShatteredPolys(void);
+ static void RenderReflectionPolys(void);
+ static void WindowRespondsToCollision(CEntity *entity, float amount, CVector speed, CVector point, bool explosion);
+ static void WindowRespondsToSoftCollision(CEntity *entity, float amount);
+ static void WasGlassHitByBullet(CEntity *entity, CVector point);
+ static void WindowRespondsToExplosion(CEntity *entity, CVector point);
+}; \ No newline at end of file
diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp
index f0134062..c4aca8e4 100644
--- a/src/render/Hud.cpp
+++ b/src/render/Hud.cpp
@@ -11,6 +11,7 @@
#include "Pad.h"
#include "Radar.h"
#include "Replay.h"
+#include "Wanted.h"
#include "Sprite.h"
#include "Sprite2d.h"
#include "Text.h"
@@ -102,9 +103,6 @@ struct
RwTexture *&gpSniperSightTex = *(RwTexture**)0x8F5834;
RwTexture *&gpRocketSightTex = *(RwTexture**)0x8E2C20;
-#if 0
-WRAPPER void CHud::Draw(void) { EAXJMP(0x5052A0); }
-#else
void CHud::Draw()
{
// disable hud via second controller
@@ -115,47 +113,43 @@ void CHud::Draw()
return;
if (m_Wants_To_Draw_Hud && !TheCamera.m_WideScreenOn) {
- bool Mode_RunAround = 0;
- bool Mode_FirstPerson = 0;
+ bool DrawCrossHair = 0;
+ bool DrawCrossHairPC = 0;
int32 WeaponType = FindPlayerPed()->m_weapons[FindPlayerPed()->m_currentWeapon].m_eWeaponType;
int32 Mode = TheCamera.Cams[TheCamera.ActiveCam].Mode;
- if (Mode == CCam::MODE_SNIPER || Mode == CCam::MODE_ROCKETLAUNCHER || Mode == CCam::MODE_M16_1STPERSON || Mode == CCam::MODE_EDITOR)
- Mode_FirstPerson = 1;
- if (Mode == CCam::MODE_M16_1STPERSON_RUNABOUT || Mode == CCam::MODE_SNIPER_RUNABOUT)
- Mode_RunAround = 1;
+ if (Mode == CCam::MODE_SNIPER || Mode == CCam::MODE_ROCKETLAUNCHER || Mode == CCam::MODE_M16_1STPERSON || Mode == CCam::MODE_HELICANNON_1STPERSON)
+ DrawCrossHair = 1;
+ if (Mode == CCam::MODE_M16_1STPERSON_RUNABOUT || Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT || Mode == CCam::MODE_SNIPER_RUNABOUT)
+ DrawCrossHairPC = 1;
/*
Draw Crosshairs
*/
- if (TheCamera.Cams->Using3rdPersonMouseCam() && (!CPad::GetPad(0)->GetLookBehindForPed() || TheCamera.m_bPlayerIsInGarage) || Mode == CCam::MODE_1STPERSON_RUNABOUT) {
+ if (TheCamera.Cams[TheCamera.ActiveCam].Using3rdPersonMouseCam() &&
+ (!CPad::GetPad(0)->GetLookBehindForPed() || TheCamera.m_bPlayerIsInGarage) || Mode == CCam::MODE_1STPERSON_RUNABOUT) {
if (FindPlayerPed() && !FindPlayerPed()->EnteringCar()) {
if ((WeaponType >= WEAPONTYPE_COLT45 && WeaponType <= WEAPONTYPE_M16) || WeaponType == WEAPONTYPE_FLAMETHROWER)
- Mode_RunAround = 1;
+ DrawCrossHairPC = 1;
}
}
- if (Mode_FirstPerson || Mode_RunAround) {
+ if (DrawCrossHair || DrawCrossHairPC) {
RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void *)rwFILTERLINEAR);
- int32 SpriteBrightLikeADiamond = SpriteBrightness + 1;
- if (SpriteBrightLikeADiamond > 30)
- SpriteBrightLikeADiamond = 30;
-
- SpriteBrightness = SpriteBrightLikeADiamond;
+ SpriteBrightness = min(SpriteBrightness+1, 30);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
- float fStep = Sin((CTimer::GetTimeInMilliseconds() & 1023) * 0.0061328127);
+ float fStep = Sin((CTimer::GetTimeInMilliseconds() & 1023)/1024.0f * 6.28f);
float fMultBright = SpriteBrightness * 0.03f * (0.25f * fStep + 0.75f);
CRect rect;
+ if (DrawCrossHairPC && TheCamera.Cams[TheCamera.ActiveCam].Using3rdPersonMouseCam()) {
#ifndef ASPECT_RATIO_SCALE
- if (Mode_RunAround && TheCamera.Cams->Using3rdPersonMouseCam()) {
float f3rdX = SCREEN_WIDTH * TheCamera.m_f3rdPersonCHairMultX;
float f3rdY = SCREEN_HEIGHT * TheCamera.m_f3rdPersonCHairMultY;
#else
- if (Mode_RunAround && TheCamera.Cams->Using3rdPersonMouseCam()) {
float f3rdX = (((TheCamera.m_f3rdPersonCHairMultX - 0.5f) / ((CDraw::GetAspectRatio()) / (DEFAULT_ASPECT_RATIO))) + 0.5f) * SCREEN_WIDTH;
float f3rdY = SCREEN_HEIGHT * TheCamera.m_f3rdPersonCHairMultY + SCREEN_SCALE_Y(-2.0f);
#endif
@@ -179,14 +173,14 @@ void CHud::Draw()
else {
if (Mode == CCam::MODE_M16_1STPERSON ||
Mode == CCam::MODE_M16_1STPERSON_RUNABOUT ||
- Mode == CCam::MODE_EDITOR) {
+ Mode == CCam::MODE_HELICANNON_1STPERSON) {
rect.left = (SCREEN_WIDTH / 2) - SCREEN_SCALE_X(32.0f);
rect.top = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(32.0f);
rect.right = (SCREEN_WIDTH / 2) + SCREEN_SCALE_X(32.0f);
rect.bottom = (SCREEN_HEIGHT / 2) + SCREEN_SCALE_Y(32.0f);
Sprites[HUD_SITEM16].Draw(CRect(rect), CRGBA(255, 255, 255, 255));
}
- else if (Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT) {
+ else if (Mode == CCam::MODE_1STPERSON_RUNABOUT) {
rect.left = (SCREEN_WIDTH / 2) - SCREEN_SCALE_X(32.0f * 0.7f);
rect.top = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(32.0f * 0.7f);
rect.right = (SCREEN_WIDTH / 2) + SCREEN_SCALE_X(32.0f * 0.7f);
@@ -194,17 +188,18 @@ void CHud::Draw()
Sprites[HUD_SITEM16].Draw(CRect(rect), CRGBA(255, 255, 255, 255));
}
- else if (Mode == CCam::MODE_ROCKETLAUNCHER || Mode == CCam::MODE_SNIPER_RUNABOUT) {
+ else if (Mode == CCam::MODE_ROCKETLAUNCHER || Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT) {
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
- RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpRocketSightTex->raster);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpRocketSightTex));
CSprite::RenderOneXLUSprite(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 1.0f, SCREEN_SCALE_X(40.0f), SCREEN_SCALE_Y(40.0f), (100.0f * fMultBright), (200.0f * fMultBright), (100.0f * fMultBright), 255, 1.0f, 255);
}
else {
+ // Sniper
rect.left = (SCREEN_WIDTH / 2) - SCREEN_SCALE_X(210.0f);
rect.top = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(210.0f);
rect.right = SCREEN_WIDTH / 2;
@@ -798,8 +793,11 @@ void CHud::Draw()
if (m_ItemToFlash == ITEM_RADAR && CTimer::GetFrameCounter() & 8 || m_ItemToFlash != ITEM_RADAR) {
CRadar::DrawMap();
CRect rect(0.0f, 0.0f, SCREEN_SCALE_X(RADAR_WIDTH), SCREEN_SCALE_Y(RADAR_HEIGHT));
- // FIX? scale RADAR_LEFT here somehow
+#ifdef FIX_BUGS
+ rect.Translate(SCREEN_SCALE_X(RADAR_LEFT), SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT));
+#else
rect.Translate(RADAR_LEFT, SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT));
+#endif
rect.Grow(4.0f);
Sprites[HUD_RADARDISC].Draw(rect, CRGBA(0, 0, 0, 255));
CRadar::DrawBlips();
@@ -1006,12 +1004,7 @@ void CHud::Draw()
}
}
}
-#endif
-
-#if 0
-WRAPPER void CHud::DrawAfterFade(void) { EAXJMP(0x509030); }
-#else
void CHud::DrawAfterFade()
{
if (CTimer::GetIsUserPaused() || CReplay::IsPlayingBack())
@@ -1104,7 +1097,6 @@ void CHud::DrawAfterFade()
CFont::SetColor(CRGBA(175, 175, 175, 255));
CFont::PrintString(SCREEN_SCALE_X(26.0f), SCREEN_SCALE_Y(28.0f + (150.0f - PagerXOffset) * 0.6f), CHud::m_HelpMessageToPrint);
CFont::SetAlphaFade(255.0f);
- CFont::DrawFonts();
}
}
else
@@ -1263,11 +1255,7 @@ void CHud::DrawAfterFade()
BigMessageInUse[1] = 0.0f;
}
}
-#endif
-#if 0
-WRAPPER void CHud::GetRidOfAllHudMessages(void) { EAXJMP(0x504F90); }
-#else
void CHud::GetRidOfAllHudMessages()
{
m_ZoneState = 0;
@@ -1303,7 +1291,6 @@ void CHud::GetRidOfAllHudMessages()
m_BigMessage[i][j] = 0;
}
}
-#endif
void CHud::Initialise()
{
@@ -1345,9 +1332,6 @@ void CHud::Initialise()
CTxdStore::PopCurrentTxd();
}
-#if 0
-WRAPPER void CHud::ReInitialise(void) { EAXJMP(0x504CC0); }
-#else
void CHud::ReInitialise() {
m_Wants_To_Draw_Hud = true;
m_Wants_To_Draw_3dMarkers = true;
@@ -1369,12 +1353,9 @@ void CHud::ReInitialise() {
PagerSoundPlayed = 0;
PagerXOffset = 150.0f;
}
-#endif
wchar LastBigMessage[6][128];
-#if 0
-WRAPPER void CHud::SetBigMessage(wchar *message, int16 style) { EAXJMP(0x50A250); }
-#else
+
void CHud::SetBigMessage(wchar *message, int16 style)
{
int i = 0;
@@ -1402,11 +1383,7 @@ void CHud::SetBigMessage(wchar *message, int16 style)
LastBigMessage[style][i] = 0;
m_BigMessage[style][i] = 0;
}
-#endif
-#if 0
-WRAPPER void CHud::SetHelpMessage(wchar *message, bool quick) { EAXJMP(0x5051E0); }
-#else
void CHud::SetHelpMessage(wchar *message, bool quick)
{
if (!CReplay::IsPlayingBack()) {
@@ -1421,11 +1398,7 @@ void CHud::SetHelpMessage(wchar *message, bool quick)
m_HelpMessageQuick = quick;
}
}
-#endif
-#if 0
-WRAPPER void CHud::SetMessage(wchar *message) { EAXJMP(0x50A210); }
-#else
void CHud::SetMessage(wchar *message)
{
int i = 0;
@@ -1437,11 +1410,7 @@ void CHud::SetMessage(wchar *message)
}
m_Message[i] = 0;
}
-#endif
-#if 0
-WRAPPER void CHud::SetPagerMessage(wchar *message) { EAXJMP(0x50A320); }
-#else
void CHud::SetPagerMessage(wchar *message)
{
int i = 0;
@@ -1453,25 +1422,16 @@ void CHud::SetPagerMessage(wchar *message)
}
m_PagerMessage[i] = 0;
}
-#endif
-#if 0
-WRAPPER void CHud::SetVehicleName(wchar *name) { EAXJMP(0x505290); }
-#else
void CHud::SetVehicleName(wchar *name)
{
m_VehicleName = name;
}
-#endif
-#if 0
-WRAPPER void CHud::SetZoneName(wchar *name) { EAXJMP(0x5051D0); }
-#else
void CHud::SetZoneName(wchar *name)
{
m_pZoneName = name;
}
-#endif
void CHud::Shutdown()
{
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index ff9f5755..d7834065 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -645,6 +645,9 @@ CRenderer::ScanWorld(void)
m_loadingPriority = false;
if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN ||
+#ifdef FIX_BUGS
+ TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_GTACLASSIC ||
+#endif
TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED){
CRect rect;
int x1, x2, y1, y2;
@@ -756,6 +759,9 @@ CRenderer::RequestObjectsInFrustum(void)
RwV3dTransformPoints((RwV3d*)vectors, (RwV3d*)vectors, 9, cammatrix);
if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN ||
+#ifdef FIX_BUGS
+ TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_GTACLASSIC ||
+#endif
TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED){
CRect rect;
int x1, x2, y1, y2;
diff --git a/src/render/Rubbish.cpp b/src/render/Rubbish.cpp
index c336eb47..a52e59a0 100644
--- a/src/render/Rubbish.cpp
+++ b/src/render/Rubbish.cpp
@@ -7,3 +7,4 @@ WRAPPER void CRubbish::StirUp(CVehicle *veh) { EAXJMP(0x512690); }
WRAPPER void CRubbish::Update(void) { EAXJMP(0x511B90); }
WRAPPER void CRubbish::SetVisibility(bool) { EAXJMP(0x512AA0); }
WRAPPER void CRubbish::Init(void) { EAXJMP(0x511940); }
+WRAPPER void CRubbish::Shutdown(void) { EAXJMP(0x511B50); }
diff --git a/src/render/Rubbish.h b/src/render/Rubbish.h
index c94ff303..17323694 100644
--- a/src/render/Rubbish.h
+++ b/src/render/Rubbish.h
@@ -10,4 +10,5 @@ public:
static void Update(void);
static void SetVisibility(bool);
static void Init(void);
+ static void Shutdown(void);
};
diff --git a/src/render/Shadows.h b/src/render/Shadows.h
index 66df0273..982cc463 100644
--- a/src/render/Shadows.h
+++ b/src/render/Shadows.h
@@ -182,3 +182,4 @@ extern RwTexture *&gpGoalTex;
extern RwTexture *&gpOutline1Tex;
extern RwTexture *&gpOutline2Tex;
extern RwTexture *&gpOutline3Tex;
+extern RwTexture *&gpCrackedGlassTex;
diff --git a/src/render/Skidmarks.cpp b/src/render/Skidmarks.cpp
index deb5a648..c2725ed6 100644
--- a/src/render/Skidmarks.cpp
+++ b/src/render/Skidmarks.cpp
@@ -9,3 +9,4 @@ WRAPPER void CSkidmarks::Render(void) { EAXJMP(0x5182E0); }
WRAPPER void CSkidmarks::RegisterOne(uint32 id, CVector pos, float fwdx, float fwdY, bool *isMuddy, bool *isBloddy) { EAXJMP(0x5185C0); }
WRAPPER void CSkidmarks::Init(void) { EAXJMP(0x517D70); }
+WRAPPER void CSkidmarks::Shutdown(void) { EAXJMP(0x518100); }
diff --git a/src/render/Skidmarks.h b/src/render/Skidmarks.h
index 2f669575..bf2da7e4 100644
--- a/src/render/Skidmarks.h
+++ b/src/render/Skidmarks.h
@@ -8,4 +8,5 @@ public:
static void Render(void);
static void RegisterOne(uint32 id, CVector pos, float fwdx, float fwdY, bool *isMuddy, bool *isBloddy);
static void Init(void);
+ static void Shutdown(void);
};
diff --git a/src/render/SpecialFX.cpp b/src/render/SpecialFX.cpp
index 8ec2d9a1..301ae265 100644
--- a/src/render/SpecialFX.cpp
+++ b/src/render/SpecialFX.cpp
@@ -20,6 +20,7 @@
WRAPPER void CSpecialFX::Render(void) { EAXJMP(0x518DC0); }
WRAPPER void CSpecialFX::Update(void) { EAXJMP(0x518D40); }
WRAPPER void CSpecialFX::Init(void) { EAXJMP(0x5189E0); }
+WRAPPER void CSpecialFX::Shutdown(void) { EAXJMP(0x518BE0); }
WRAPPER void CMotionBlurStreaks::RegisterStreak(int32 id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2) { EAXJMP(0x519460); }
diff --git a/src/render/SpecialFX.h b/src/render/SpecialFX.h
index 701b89a0..fc155a53 100644
--- a/src/render/SpecialFX.h
+++ b/src/render/SpecialFX.h
@@ -6,6 +6,7 @@ public:
static void Render(void);
static void Update(void);
static void Init(void);
+ static void Shutdown(void);
};
class CMotionBlurStreaks
diff --git a/src/render/WaterCannon.cpp b/src/render/WaterCannon.cpp
index 7a9aa4d9..e848fb43 100644
--- a/src/render/WaterCannon.cpp
+++ b/src/render/WaterCannon.cpp
@@ -1,10 +1,320 @@
#include "common.h"
#include "patcher.h"
#include "WaterCannon.h"
+#include "Vector.h"
+#include "General.h"
+#include "main.h"
+#include "Timer.h"
+#include "Pools.h"
+#include "Ped.h"
+#include "AnimManager.h"
+#include "Fire.h"
+#include "WaterLevel.h"
+#include "Camera.h"
-CWaterCannon (&aCannons)[NUM_WATERCANNONS] = *(CWaterCannon(*)[NUM_WATERCANNONS])*(uintptr*)0x8F2CA8;
+#define WATERCANNONVERTS 4
+#define WATERCANNONINDEXES 12
-WRAPPER void CWaterCannons::Update(void) { EAXJMP(0x522510); }
-WRAPPER void CWaterCannons::UpdateOne(uint32 id, CVector *pos, CVector *dir) { EAXJMP(0x522470); }
-WRAPPER void CWaterCannons::Render(void) { EAXJMP(0x522550); }
-WRAPPER void CWaterCannons::Init(void) { EAXJMP(0x522440); }
+RwIm3DVertex WaterCannonVertices[WATERCANNONVERTS];
+RwImVertexIndex WaterCannonIndexList[WATERCANNONINDEXES];
+
+CWaterCannon CWaterCannons::aCannons[NUM_WATERCANNONS];
+
+void CWaterCannon::Init(void)
+{
+ m_nId = 0;
+ m_nCur = 0;
+ m_nTimeCreated = CTimer::GetTimeInMilliseconds();
+
+ for ( int32 i = 0; i < NUM_SEGMENTPOINTS; i++ )
+ m_abUsed[i] = false;
+
+ RwIm3DVertexSetU(&WaterCannonVertices[0], 0.0f);
+ RwIm3DVertexSetV(&WaterCannonVertices[0], 0.0f);
+
+ RwIm3DVertexSetU(&WaterCannonVertices[1], 1.0f);
+ RwIm3DVertexSetV(&WaterCannonVertices[1], 0.0f);
+
+ RwIm3DVertexSetU(&WaterCannonVertices[2], 0.0f);
+ RwIm3DVertexSetV(&WaterCannonVertices[2], 0.0f);
+
+ RwIm3DVertexSetU(&WaterCannonVertices[3], 1.0f);
+ RwIm3DVertexSetV(&WaterCannonVertices[3], 0.0f);
+
+ WaterCannonIndexList[0] = 0;
+ WaterCannonIndexList[1] = 1;
+ WaterCannonIndexList[2] = 2;
+
+ WaterCannonIndexList[3] = 1;
+ WaterCannonIndexList[4] = 3;
+ WaterCannonIndexList[5] = 2;
+
+ WaterCannonIndexList[6] = 0;
+ WaterCannonIndexList[7] = 2;
+ WaterCannonIndexList[8] = 1;
+
+ WaterCannonIndexList[9] = 1;
+ WaterCannonIndexList[10] = 2;
+ WaterCannonIndexList[11] = 3;
+}
+
+void CWaterCannon::Update_OncePerFrame(int16 index)
+{
+ ASSERT(index < NUM_WATERCANNONS);
+
+ if (CTimer::GetTimeInMilliseconds() > m_nTimeCreated + WATERCANNON_LIFETIME )
+ {
+ m_nCur = (m_nCur + 1) % -NUM_SEGMENTPOINTS;
+ m_abUsed[m_nCur] = false;
+ }
+
+ for ( int32 i = 0; i < NUM_SEGMENTPOINTS; i++ )
+ {
+ if ( m_abUsed[i] )
+ {
+ m_avecVelocity[i].z += -WATERCANNON_GRAVITY * CTimer::GetTimeStep();
+ m_avecPos[i] += m_avecVelocity[i] * CTimer::GetTimeStep();
+ }
+ }
+
+ int32 extinguishingPoint = CGeneral::GetRandomNumber() & (NUM_SEGMENTPOINTS - 1);
+ if ( m_abUsed[extinguishingPoint] )
+ gFireManager.ExtinguishPoint(m_avecPos[extinguishingPoint], 3.0f);
+
+ if ( ((index + CTimer::GetFrameCounter()) & 3) == 0 )
+ PushPeds();
+
+ // free if unused
+
+ int32 i = 0;
+ while ( 1 )
+ {
+ if ( m_abUsed[i] )
+ break;
+
+ if ( ++i >= NUM_SEGMENTPOINTS )
+ {
+ m_nId = 0;
+ return;
+ }
+ }
+}
+
+void CWaterCannon::Update_NewInput(CVector *pos, CVector *dir)
+{
+ ASSERT(pos != NULL);
+ ASSERT(dir != NULL);
+
+ m_avecPos[m_nCur] = *pos;
+ m_avecVelocity[m_nCur] = *dir;
+ m_abUsed[m_nCur] = true;
+}
+
+void CWaterCannon::Render(void)
+{
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE);
+ RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)TRUE);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)gpWaterRaster);
+
+ float v = float(CGeneral::GetRandomNumber() & 255) / 256;
+
+ RwIm3DVertexSetV(&WaterCannonVertices[0], v);
+ RwIm3DVertexSetV(&WaterCannonVertices[1], v);
+ RwIm3DVertexSetV(&WaterCannonVertices[2], v);
+ RwIm3DVertexSetV(&WaterCannonVertices[3], v);
+
+ int16 pointA = m_nCur % -NUM_SEGMENTPOINTS;
+
+ int16 pointB = pointA - 1;
+ if ( (pointA - 1) < 0 )
+ pointB += NUM_SEGMENTPOINTS;
+
+ bool bInit = false;
+ CVector norm;
+
+ for ( int32 i = 0; i < NUM_SEGMENTPOINTS - 1; i++ )
+ {
+ if ( m_abUsed[pointA] && m_abUsed[pointB] )
+ {
+ if ( !bInit )
+ {
+ CVector cp = CrossProduct(m_avecPos[pointB] - m_avecPos[pointA], TheCamera.GetForward());
+ cp.Normalise(0.05f);
+ norm = cp;
+ bInit = true;
+ }
+
+ float dist = float(i*i*i) / 300.0f + 1.0f;
+ float brightness = float(i) / NUM_SEGMENTPOINTS;
+
+ int32 color = (int32)((1.0f - brightness*brightness) * 255.0f);
+ CVector offset = dist * norm;
+
+ RwIm3DVertexSetRGBA(&WaterCannonVertices[0], color, color, color, color);
+ RwIm3DVertexSetPos (&WaterCannonVertices[0], m_avecPos[pointA].x - offset.x, m_avecPos[pointA].y - offset.y, m_avecPos[pointA].z - offset.z);
+
+ RwIm3DVertexSetRGBA(&WaterCannonVertices[1], color, color, color, color);
+ RwIm3DVertexSetPos (&WaterCannonVertices[1], m_avecPos[pointA].x + offset.x, m_avecPos[pointA].y + offset.y, m_avecPos[pointA].z + offset.z);
+
+ RwIm3DVertexSetRGBA(&WaterCannonVertices[2], color, color, color, color);
+ RwIm3DVertexSetPos (&WaterCannonVertices[2], m_avecPos[pointB].x - offset.x, m_avecPos[pointB].y - offset.y, m_avecPos[pointB].z - offset.z);
+
+ RwIm3DVertexSetRGBA(&WaterCannonVertices[3], color, color, color, color);
+ RwIm3DVertexSetPos (&WaterCannonVertices[3], m_avecPos[pointB].x + offset.x, m_avecPos[pointB].y + offset.y, m_avecPos[pointB].z + offset.z);
+
+ LittleTest();
+
+ if ( RwIm3DTransform(WaterCannonVertices, WATERCANNONVERTS, NULL, rwIM3D_VERTEXUV) )
+ {
+ RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, WaterCannonIndexList, WATERCANNONINDEXES);
+ RwIm3DEnd();
+ }
+ }
+
+ pointA = pointB--;
+ if ( pointB < 0 )
+ pointB += NUM_SEGMENTPOINTS;
+ }
+
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)TRUE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)FALSE);
+ RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)FALSE);
+}
+
+void CWaterCannon::PushPeds(void)
+{
+ float minx = 10000.0f;
+ float maxx = -10000.0f;
+ float miny = 10000.0f;
+ float maxy = -10000.0f;
+ float minz = 10000.0f;
+ float maxz = -10000.0f;
+
+ for ( int32 i = 0; i < NUM_SEGMENTPOINTS; i++ )
+ {
+ if ( m_abUsed[i] )
+ {
+ minx = min(minx, m_avecPos[i].x);
+ maxx = max(maxx, m_avecPos[i].x);
+
+ miny = min(miny, m_avecPos[i].y);
+ maxy = max(maxy, m_avecPos[i].y);
+
+ minz = min(minz, m_avecPos[i].z);
+ maxz = max(maxz, m_avecPos[i].z);
+ }
+ }
+
+ for ( int32 i = CPools::GetPedPool()->GetSize() - 1; i >= 0; i--)
+ {
+ CPed *ped = CPools::GetPedPool()->GetSlot(i);
+ if ( ped )
+ {
+ if ( ped->GetPosition().x > minx && ped->GetPosition().x < maxx
+ && ped->GetPosition().y > miny && ped->GetPosition().y < maxy
+ && ped->GetPosition().z > minz && ped->GetPosition().z < maxz )
+ {
+ for ( int32 j = 0; j < NUM_SEGMENTPOINTS; j++ )
+ {
+ if ( m_abUsed[j] )
+ {
+ CVector dist = m_avecPos[j] - ped->GetPosition();
+
+ if ( dist.MagnitudeSqr() < 5.0f )
+ {
+ int32 localDir = ped->GetLocalDirection(CVector2D(1.0f, 0.0f));
+
+ ped->bIsStanding = false;
+
+ ped->ApplyMoveForce(0.0f, 0.0f, 2.0f * CTimer::GetTimeStep());
+
+ ped->m_vecMoveSpeed.x = (0.6f * m_avecVelocity[j].x + ped->m_vecMoveSpeed.x) * 0.5f;
+ ped->m_vecMoveSpeed.y = (0.6f * m_avecVelocity[j].y + ped->m_vecMoveSpeed.y) * 0.5f;
+
+ ped->SetFall(2000, AnimationId(ANIM_KO_SKID_FRONT + localDir), 0);
+
+ CFire *fire = ped->m_pFire;
+ if ( fire )
+ fire->Extinguish();
+
+ j = NUM_SEGMENTPOINTS;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void CWaterCannons::Init(void)
+{
+ for ( int32 i = 0; i < NUM_WATERCANNONS; i++ )
+ aCannons[i].Init();
+}
+
+void CWaterCannons::UpdateOne(uint32 id, CVector *pos, CVector *dir)
+{
+ ASSERT(pos != NULL);
+ ASSERT(dir != NULL);
+
+ // find the one by id
+ {
+ int32 n = 0;
+ while ( n < NUM_WATERCANNONS && id != aCannons[n].m_nId )
+ n++;
+
+ if ( n < NUM_WATERCANNONS )
+ {
+ aCannons[n].Update_NewInput(pos, dir);
+ return;
+ }
+ }
+
+ // if no luck then find a free one
+ {
+ int32 n = 0;
+ while ( n < NUM_WATERCANNONS && 0 != aCannons[n].m_nId )
+ n++;
+
+ if ( n < NUM_WATERCANNONS )
+ {
+ aCannons[n].Init();
+ aCannons[n].m_nId = id;
+ aCannons[n].Update_NewInput(pos, dir);
+ return;
+ }
+ }
+}
+
+void CWaterCannons::Update(void)
+{
+ for ( int32 i = 0; i < NUM_WATERCANNONS; i++ )
+ {
+ if ( aCannons[i].m_nId != 0 )
+ aCannons[i].Update_OncePerFrame(i);
+ }
+}
+
+void CWaterCannons::Render(void)
+{
+ for ( int32 i = 0; i < NUM_WATERCANNONS; i++ )
+ {
+ if ( aCannons[i].m_nId != 0 )
+ aCannons[i].Render();
+ }
+}
+
+STARTPATCHES
+ InjectHook(0x521A30, &CWaterCannon::Init, PATCH_JUMP);
+ InjectHook(0x521B80, &CWaterCannon::Update_OncePerFrame, PATCH_JUMP);
+ InjectHook(0x521CC0, &CWaterCannon::Update_NewInput, PATCH_JUMP);
+ InjectHook(0x521D30, &CWaterCannon::Render, PATCH_JUMP);
+ InjectHook(0x5220B0, &CWaterCannon::PushPeds, PATCH_JUMP);
+ InjectHook(0x522440, CWaterCannons::Init, PATCH_JUMP);
+ InjectHook(0x522470, CWaterCannons::UpdateOne, PATCH_JUMP);
+ InjectHook(0x522510, CWaterCannons::Update, PATCH_JUMP);
+ InjectHook(0x522550, CWaterCannons::Render, PATCH_JUMP);
+ //InjectHook(0x522B40, `global constructor keyed to'watercannon.cpp, PATCH_JUMP);
+ //InjectHook(0x522B60, CWaterCannon::CWaterCannon, PATCH_JUMP);
+ENDPATCHES \ No newline at end of file
diff --git a/src/render/WaterCannon.h b/src/render/WaterCannon.h
index c2b288f2..826dc78e 100644
--- a/src/render/WaterCannon.h
+++ b/src/render/WaterCannon.h
@@ -1,15 +1,29 @@
#pragma once
+#define WATERCANNON_GRAVITY (0.009f)
+#define WATERCANNON_LIFETIME (150)
+
class CWaterCannon
{
public:
+ enum
+ {
+ NUM_SEGMENTPOINTS = 16,
+ };
+
int32 m_nId;
- int16 m_wIndex;
- char gap_6[2];
- int32 m_nTimeCreated;
- CVector m_avecPos[16];
- CVector m_avecVelocity[16];
- char m_abUsed[16];
+ int16 m_nCur;
+ char _pad0[2];
+ uint32 m_nTimeCreated;
+ CVector m_avecPos[NUM_SEGMENTPOINTS];
+ CVector m_avecVelocity[NUM_SEGMENTPOINTS];
+ bool m_abUsed[NUM_SEGMENTPOINTS];
+
+ void Init(void);
+ void Update_OncePerFrame(int16 index);
+ void Update_NewInput(CVector *pos, CVector *dir);
+ void Render(void);
+ void PushPeds(void);
};
static_assert(sizeof(CWaterCannon) == 412, "CWaterCannon: error");
@@ -17,11 +31,10 @@ static_assert(sizeof(CWaterCannon) == 412, "CWaterCannon: error");
class CWaterCannons
{
public:
- static void Update();
+ static CWaterCannon aCannons[NUM_WATERCANNONS];
+
+ static void Init(void);
static void UpdateOne(uint32 id, CVector *pos, CVector *dir);
+ static void Update();
static void Render(void);
- static void Init(void);
-};
-
-extern CWaterCannon (&aCannons)[NUM_WATERCANNONS];
-
+}; \ No newline at end of file
diff --git a/src/render/WeaponEffects.cpp b/src/render/WeaponEffects.cpp
index 932c661e..2ed9e662 100644
--- a/src/render/WeaponEffects.cpp
+++ b/src/render/WeaponEffects.cpp
@@ -1,45 +1,106 @@
#include "common.h"
#include "patcher.h"
#include "WeaponEffects.h"
-
#include "TxdStore.h"
+#include "Sprite.h"
-WRAPPER void CWeaponEffects::Render(void) { EAXJMP(0x564D70); }
+RwTexture *gpCrossHairTex;
+RwRaster *gpCrossHairRaster;
-CWeaponEffects &gCrossHair = *(CWeaponEffects*)0x6503BC;
+CWeaponEffects gCrossHair;
+
+CWeaponEffects::CWeaponEffects()
+{
+
+}
+
+CWeaponEffects::~CWeaponEffects()
+{
+
+}
void
-CWeaponEffects::ClearCrossHair()
+CWeaponEffects::Init(void)
{
- gCrossHair.m_bCrosshair = false;
+ gCrossHair.m_bActive = false;
+ gCrossHair.m_vecPos = CVector(0.0f, 0.0f, 0.0f);
+ gCrossHair.m_nRed = 0;
+ gCrossHair.m_nGreen = 0;
+ gCrossHair.m_nBlue = 0;
+ gCrossHair.m_nAlpha = 255;
+ gCrossHair.m_fSize = 1.0f;
+ gCrossHair.m_fRotation = 0.0f;
+
+
+ CTxdStore::PushCurrentTxd();
+ int32 slot = CTxdStore::FindTxdSlot("particle");
+ CTxdStore::SetCurrentTxd(slot);
+
+ gpCrossHairTex = RwTextureRead("crosshair", nil);
+ gpCrossHairRaster = RwTextureGetRaster(gpCrossHairTex);
+
+ CTxdStore::PopCurrentTxd();
+}
+
+void
+CWeaponEffects::Shutdown(void)
+{
+ RwTextureDestroy(gpCrossHairTex);
}
void
CWeaponEffects::MarkTarget(CVector pos, uint8 red, uint8 green, uint8 blue, uint8 alpha, float size)
{
- gCrossHair.m_bCrosshair = true;
- gCrossHair.m_vecPos = pos;
- gCrossHair.m_red = red;
- gCrossHair.m_green = green;
- gCrossHair.m_blue = blue;
- gCrossHair.m_alpha = alpha;
- gCrossHair.m_size = size;
+ gCrossHair.m_bActive = true;
+ gCrossHair.m_vecPos = pos;
+ gCrossHair.m_nRed = red;
+ gCrossHair.m_nGreen = green;
+ gCrossHair.m_nBlue = blue;
+ gCrossHair.m_nAlpha = alpha;
+ gCrossHair.m_fSize = size;
+}
+
+void
+CWeaponEffects::ClearCrossHair(void)
+{
+ gCrossHair.m_bActive = false;
}
void
-CWeaponEffects::Init()
+CWeaponEffects::Render(void)
{
- gCrossHair.m_bCrosshair = false;
- gCrossHair.m_vecPos = CVector(0.0f, 0.0f, 0.0f);
- gCrossHair.m_red = 0;
- gCrossHair.m_green = 0;
- gCrossHair.m_blue = 0;
- gCrossHair.m_alpha = 255;
- gCrossHair.m_size = 1.0f;
- gCrossHair.field_24 = 0;
- CTxdStore::PushCurrentTxd();
- CTxdStore::SetCurrentTxd(CTxdStore::FindTxdSlot("particle"));
- gCrossHair.m_pTexture = RwTextureRead("crosshair", nil);
- gCrossHair.m_pRaster = gCrossHair.m_pTexture->raster;
- CTxdStore::PopCurrentTxd();
+ if ( gCrossHair.m_bActive )
+ {
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)gpCrossHairRaster);
+
+ RwV3d pos;
+ float w, h;
+ if ( CSprite::CalcScreenCoors(gCrossHair.m_vecPos, &pos, &w, &h, true) )
+ {
+ float recipz = 1.0f / pos.z;
+ CSprite::RenderOneXLUSprite(pos.x, pos.y, pos.z,
+ gCrossHair.m_fSize * w, gCrossHair.m_fSize * h,
+ gCrossHair.m_nRed, gCrossHair.m_nGreen, gCrossHair.m_nBlue, 255,
+ recipz, 255);
+ }
+
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)FALSE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA);
+ }
}
+
+STARTPATCHES
+ //InjectHook(0x564C40, CWeaponEffects::CWeaponEffects, PATCH_JUMP);
+ //InjectHook(0x564C50, CWeaponEffects::~CWeaponEffects, PATCH_JUMP);
+ InjectHook(0x564C60, CWeaponEffects::Init, PATCH_JUMP);
+ InjectHook(0x564CF0, CWeaponEffects::Shutdown, PATCH_JUMP);
+ InjectHook(0x564D00, CWeaponEffects::MarkTarget, PATCH_JUMP);
+ InjectHook(0x564D60, CWeaponEffects::ClearCrossHair, PATCH_JUMP);
+ InjectHook(0x564D70, CWeaponEffects::Render, PATCH_JUMP);
+ENDPATCHES \ No newline at end of file
diff --git a/src/render/WeaponEffects.h b/src/render/WeaponEffects.h
index e4d0461a..31c5a309 100644
--- a/src/render/WeaponEffects.h
+++ b/src/render/WeaponEffects.h
@@ -3,21 +3,25 @@
class CWeaponEffects
{
public:
- bool m_bCrosshair;
- int8 gap_1[3];
+ bool m_bActive;
+ char _pad[3];
CVector m_vecPos;
- uint8 m_red;
- uint8 m_green;
- uint8 m_blue;
- uint8 m_alpha;
- float m_size;
- int32 field_24;
- RwTexture *m_pTexture;
- RwRaster *m_pRaster;
+ uint8 m_nRed;
+ uint8 m_nGreen;
+ uint8 m_nBlue;
+ uint8 m_nAlpha;
+ float m_fSize;
+ float m_fRotation;
public:
- static void Render(void);
- static void ClearCrossHair();
- static void MarkTarget(CVector, uint8, uint8, uint8, uint8, float);
+ CWeaponEffects();
+ ~CWeaponEffects();
+
static void Init(void);
+ static void Shutdown(void);
+ static void MarkTarget(CVector pos, uint8 red, uint8 green, uint8 blue, uint8 alpha, float size);
+ static void ClearCrossHair(void);
+ static void Render(void);
};
+
+VALIDATE_SIZE(CWeaponEffects, 0x1C); \ No newline at end of file
diff --git a/src/save/GenericGameStorage.cpp b/src/save/GenericGameStorage.cpp
index 8c851686..d71b0c22 100644
--- a/src/save/GenericGameStorage.cpp
+++ b/src/save/GenericGameStorage.cpp
@@ -1,3 +1,4 @@
+#define WITHWINDOWS
#include "common.h"
#include "main.h"
#include "patcher.h"
@@ -50,7 +51,6 @@ CDate &CompileDateAndTime = *(CDate*)0x72BCB8;
#define ReadDataFromBufferPointer(buf, to) memcpy(&to, buf, sizeof(to)); buf += align4bytes(sizeof(to));
#define WriteDataToBufferPointer(buf, from) memcpy(buf, &from, sizeof(from)); buf += align4bytes(sizeof(from));
-//WRAPPER bool GenericSave(int file) { EAXJMP(0x58F8D0); }
WRAPPER bool GenericLoad() { EAXJMP(0x590A00); }
@@ -61,9 +61,9 @@ do {\
MakeSpaceForSizeInBufferPointer(presize, buf, postsize);\
save_func(buf, &size);\
CopySizeAndPreparePointer(presize, buf, postsize, reserved, size);\
- if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, size + 4))\
+ if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, buf - work_buff))\
return false;\
- totalSize += size;\
+ totalSize += buf - work_buff;\
} while (0)
bool
@@ -74,7 +74,6 @@ GenericSave(int file)
uint32 reserved;
uint32 totalSize;
- uint32 i;
wchar *lastMissionPassed;
wchar suffix[6];
@@ -85,13 +84,11 @@ GenericSave(int file)
CheckSum = 0;
buf = work_buff;
reserved = 0;
- totalSize = 0;
// Save simple vars
-INITSAVEBUF
lastMissionPassed = TheText.Get(CStats::LastMissionPassedName);
if (*lastMissionPassed) {
- AsciiToUnicode("'...", suffix);
+ AsciiToUnicode("...'", suffix);
TextCopy(saveName, lastMissionPassed);
int len = UnicodeStrlen(saveName);
saveName[len] = '\0';
@@ -104,20 +101,20 @@ INITSAVEBUF
WriteDataToBufferPointer(buf, saveTime);
WriteDataToBufferPointer(buf, SIZE_OF_ONE_GAME_IN_BYTES);
WriteDataToBufferPointer(buf, CGame::currLevel);
- WriteDataToBufferPointer(buf, TheCamera.m_matrix.m_matrix.pos.x);
- WriteDataToBufferPointer(buf, TheCamera.m_matrix.m_matrix.pos.y);
- WriteDataToBufferPointer(buf, TheCamera.m_matrix.m_matrix.pos.z);
+ WriteDataToBufferPointer(buf, TheCamera.GetPosition().x);
+ WriteDataToBufferPointer(buf, TheCamera.GetPosition().y);
+ WriteDataToBufferPointer(buf, TheCamera.GetPosition().z);
WriteDataToBufferPointer(buf, CClock::ms_nMillisecondsPerGameMinute);
WriteDataToBufferPointer(buf, CClock::ms_nLastClockTick);
WriteDataToBufferPointer(buf, CClock::ms_nGameClockHours);
WriteDataToBufferPointer(buf, CClock::ms_nGameClockMinutes);
currPad = CPad::GetPad(0);
WriteDataToBufferPointer(buf, currPad->Mode);
- WriteDataToBufferPointer(buf, CTimer::m_snTimeInMilliseconds);
- WriteDataToBufferPointer(buf, CTimer::ms_fTimeScale);
- WriteDataToBufferPointer(buf, CTimer::ms_fTimeStep);
- WriteDataToBufferPointer(buf, CTimer::ms_fTimeStepNonClipped);
- WriteDataToBufferPointer(buf, CTimer::m_FrameCounter);
+ WriteDataToBufferPointer(buf, CTimer::GetTimeInMilliseconds());
+ WriteDataToBufferPointer(buf, CTimer::GetTimeScale());
+ WriteDataToBufferPointer(buf, CTimer::GetTimeStep());
+ WriteDataToBufferPointer(buf, CTimer::GetTimeStepNonClipped());
+ WriteDataToBufferPointer(buf, CTimer::GetFrameCounter());
WriteDataToBufferPointer(buf, CTimeStep::ms_fTimeStep);
WriteDataToBufferPointer(buf, CTimeStep::ms_fFramesPerUpdate);
WriteDataToBufferPointer(buf, CTimeStep::ms_fTimeScale);
@@ -134,10 +131,8 @@ INITSAVEBUF
WriteDataToBufferPointer(buf, CWeather::WeatherTypeInList);
WriteDataToBufferPointer(buf, TheCamera.CarZoomIndicator);
WriteDataToBufferPointer(buf, TheCamera.PedZoomIndicator);
-#ifdef VALIDATE_SAVE_SIZE
- _saveBufCount = buf - work_buff;
-#endif
-VALIDATESAVEBUF(SIZE_OF_SIMPLEVARS);
+
+ assert(buf - work_buff == SIZE_OF_SIMPLEVARS);
// Save scripts, block is nested within the same block as simple vars for some reason
presize = buf;
@@ -145,9 +140,10 @@ VALIDATESAVEBUF(SIZE_OF_SIMPLEVARS);
postsize = buf;
CTheScripts::SaveAllScripts(buf, &size);
CopySizeAndPreparePointer(presize, buf, postsize, reserved, size);
- if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, size + SIZE_OF_SIMPLEVARS + 4))
+ if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, buf - work_buff))
return false;
- totalSize += size + SIZE_OF_SIMPLEVARS;
+
+ totalSize = buf - work_buff;
// Save the rest
WRITE_BLOCK(CPools::SavePedPool);
@@ -171,8 +167,7 @@ VALIDATESAVEBUF(SIZE_OF_SIMPLEVARS);
WRITE_BLOCK(CPedType::Save);
// Write padding
- i = 0;
- do {
+ for (int i = 0; i < 4; i++) {
size = align4bytes(SIZE_OF_ONE_GAME_IN_BYTES - totalSize - 4);
if (size > sizeof(work_buff))
size = sizeof(work_buff);
@@ -181,15 +176,15 @@ VALIDATESAVEBUF(SIZE_OF_SIMPLEVARS);
return false;
totalSize += size;
}
- i++;
- } while (i < 4);
+ }
// Write checksum and close
CFileMgr::Write(file, (const char *) &CheckSum, sizeof(CheckSum));
if (CFileMgr::GetErrorReadWrite(file)) {
PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_WRITE;
- if (CloseFile(file))
+ if (!CloseFile(file))
PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE;
+
return false;
}
diff --git a/src/save/PCSave.cpp b/src/save/PCSave.cpp
index 2702bd6e..744f5e0d 100644
--- a/src/save/PCSave.cpp
+++ b/src/save/PCSave.cpp
@@ -1,3 +1,4 @@
+#define WITHWINDOWS
#include "common.h"
#include "patcher.h"
#include "FileMgr.h"
@@ -38,7 +39,7 @@ C_PcSave::SaveSlot(int32 slot)
if (file != 0) {
DoGameSpecificStuffBeforeSave();
if (GenericSave(file)) {
- if (CFileMgr::CloseFile(file) != 0)
+ if (!!CFileMgr::CloseFile(file))
nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE;
return true;
}
@@ -55,21 +56,21 @@ C_PcSave::PcClassSaveRoutine(int32 file, uint8 *data, uint32 size)
CFileMgr::Write(file, (const char*)&size, sizeof(size));
if (CFileMgr::GetErrorReadWrite(file)) {
nErrorCode = SAVESTATUS_ERR_SAVE_WRITE;
- strncpy(SaveFileNameJustSaved, ValidSaveName, 259);
+ strncpy(SaveFileNameJustSaved, ValidSaveName, sizeof(ValidSaveName) - 1);
return false;
}
CFileMgr::Write(file, (const char*)data, align4bytes(size));
- CheckSum += ((uint8*)&size)[0];
- CheckSum += ((uint8*)&size)[1];
- CheckSum += ((uint8*)&size)[2];
- CheckSum += ((uint8*)&size)[3];
+ CheckSum += (uint8) size;
+ CheckSum += (uint8) (size >> 8);
+ CheckSum += (uint8) (size >> 16);
+ CheckSum += (uint8) (size >> 24);
for (int i = 0; i < align4bytes(size); i++) {
CheckSum += *data++;
}
if (CFileMgr::GetErrorReadWrite(file)) {
nErrorCode = SAVESTATUS_ERR_SAVE_WRITE;
- strncpy(SaveFileNameJustSaved, ValidSaveName, 259);
+ strncpy(SaveFileNameJustSaved, ValidSaveName, sizeof(ValidSaveName) - 1);
return false;
}
diff --git a/src/skel/win/resource.h b/src/skel/win/resource.h
index 2fb3dc50..84dffb95 100644
--- a/src/skel/win/resource.h
+++ b/src/skel/win/resource.h
@@ -8,6 +8,7 @@
#define IDEXIT 1002
#define IDC_SELECTDEVICE 1005
+#define IDI_MAIN_ICON 1042
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp
index f05580cd..7993426a 100644
--- a/src/skel/win/win.cpp
+++ b/src/skel/win/win.cpp
@@ -2056,7 +2056,7 @@ _WinMain(HINSTANCE instance,
{
GetWindowPlacement(PSGLOBAL(window), &wp);
- if ( wp.showCmd != SW_SHOWMINIMIZED )
+ if (wp.showCmd != SW_SHOWMINIMIZED)
RsEventHandler(rsFRONTENDIDLE, nil);
if ( !FrontEndMenuManager.m_bMenuActive || FrontEndMenuManager.m_bLoadingSavedGame )
diff --git a/src/skel/win/win.rc b/src/skel/win/win.rc
index 676b8ef7..379c473d 100644
--- a/src/skel/win/win.rc
+++ b/src/skel/win/win.rc
@@ -30,8 +30,18 @@ BEGIN
WS_TABSTOP
DEFPUSHBUTTON "EXIT",IDEXIT,103,69,52,14
DEFPUSHBUTTON "OK",IDOK,28,69,50,14
- LTEXT "Please select the device to use:",IDC_SELECTDEVICE,7,7,
+ LTEXT "Please select the Device To Use:",IDC_SELECTDEVICE,7,7,
137,8
END
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_MAIN_ICON ICON DISCARDABLE "gta3.ico"
+
+///////////////////////////////////////////////////////////////////////////// \ No newline at end of file
diff --git a/src/text/Pager.h b/src/text/Pager.h
index 727eeb24..1719e726 100644
--- a/src/text/Pager.h
+++ b/src/text/Pager.h
@@ -1,5 +1,5 @@
#pragma once
-
+
struct PagerMessage {
wchar *m_pText;
uint16 m_nSpeedMs;
@@ -9,20 +9,20 @@ struct PagerMessage {
uint32 m_nTimeToChangePosition;
int16 field_10;
int32 m_nNumber[6];
-};
-
-#define NUMPAGERMESSAGES 8
-
-class CPager
-{
+};
+
+#define NUMPAGERMESSAGES 8
+
+class CPager
+{
int16 m_nNumDisplayLetters;
- PagerMessage m_messages[NUMPAGERMESSAGES];
+ PagerMessage m_messages[NUMPAGERMESSAGES];
public:
- void Init();
- void Process();
- void Display();
+ void Init();
+ void Process();
+ void Display();
void AddMessage(wchar*, uint16, uint16, uint16);
- void AddMessageWithNumber(wchar *str, int32 n1, int32 n2, int32 n3, int32 n4, int32 n5, int32 n6, uint16 speed, uint16 priority, uint16 a11);
- void ClearMessages();
- void RestartCurrentMessage();
+ void AddMessageWithNumber(wchar *str, int32 n1, int32 n2, int32 n3, int32 n4, int32 n5, int32 n6, uint16 speed, uint16 priority, uint16 a11);
+ void ClearMessages();
+ void RestartCurrentMessage();
}; \ No newline at end of file
diff --git a/src/text/Text.cpp b/src/text/Text.cpp
index 40717ed5..d0cdb310 100644
--- a/src/text/Text.cpp
+++ b/src/text/Text.cpp
@@ -1,92 +1,97 @@
-#include "common.h"
-#include "patcher.h"
-#include "FileMgr.h"
-#include "Frontend.h"
-#include "Messages.h"
-#include "Text.h"
-
-static wchar WideErrorString[25];
-
-CText &TheText = *(CText*)0x941520;
-
-CText::CText(void)
-{
- encoding = 'e';
- memset(WideErrorString, 0, sizeof(WideErrorString));
-}
-
-void
-CText::Load(void)
-{
- uint8 *filedata;
- char filename[32], type[4];
- int length;
- int offset, sectlen;
-
- Unload();
- filedata = new uint8[0x40000];
-
- CFileMgr::SetDir("TEXT");
- switch(CMenuManager::m_PrefsLanguage){
- case LANGUAGE_AMERICAN:
- sprintf(filename, "AMERICAN.GXT");
- break;
- case LANGUAGE_FRENCH:
- sprintf(filename, "FRENCH.GXT");
- break;
- case LANGUAGE_GERMAN:
- sprintf(filename, "GERMAN.GXT");
- break;
- case LANGUAGE_ITALIAN:
- sprintf(filename, "ITALIAN.GXT");
- break;
- case LANGUAGE_SPANISH:
- sprintf(filename, "SPANISH.GXT");
- break;
- }
-
- length = CFileMgr::LoadFile(filename, filedata, 0x40000, "rb");
- CFileMgr::SetDir("");
-
- offset = 0;
- while(offset < length){
- type[0] = filedata[offset++];
- type[1] = filedata[offset++];
- type[2] = filedata[offset++];
- type[3] = filedata[offset++];
- sectlen = (int)filedata[offset+3]<<24 | (int)filedata[offset+2]<<16 |
- (int)filedata[offset+1]<<8 | (int)filedata[offset+0];
- offset += 4;
- if(sectlen != 0){
- if(strncmp(type, "TKEY", 4) == 0)
- keyArray.Load(sectlen, filedata, &offset);
- else if(strncmp(type, "TDAT", 4) == 0)
- data.Load(sectlen, filedata, &offset);
- else
- offset += sectlen;
- }
- }
-
- keyArray.Update(data.chars);
-
- delete[] filedata;
-}
-
-void
-CText::Unload(void)
-{
- CMessages::ClearAllMessagesDisplayedByGame();
- data.Unload();
- keyArray.Unload();
-}
-
-wchar*
-CText::Get(const char *key)
-{
- return keyArray.Search(key);
-}
-
-wchar UpperCaseTable[128] = {
+#include "common.h"
+#include "patcher.h"
+#include "FileMgr.h"
+#include "Frontend.h"
+#include "Messages.h"
+#include "Text.h"
+
+static wchar WideErrorString[25];
+
+CText &TheText = *(CText*)0x941520;
+
+CText::CText(void)
+{
+ encoding = 'e';
+ memset(WideErrorString, 0, sizeof(WideErrorString));
+}
+
+void
+CText::Load(void)
+{
+ uint8 *filedata;
+ char filename[32], type[4];
+ int length;
+ int offset, sectlen;
+
+ Unload();
+ filedata = new uint8[0x40000];
+
+ CFileMgr::SetDir("TEXT");
+ switch(CMenuManager::m_PrefsLanguage){
+ case LANGUAGE_AMERICAN:
+ sprintf(filename, "AMERICAN.GXT");
+ break;
+ case LANGUAGE_FRENCH:
+ sprintf(filename, "FRENCH.GXT");
+ break;
+ case LANGUAGE_GERMAN:
+ sprintf(filename, "GERMAN.GXT");
+ break;
+ case LANGUAGE_ITALIAN:
+ sprintf(filename, "ITALIAN.GXT");
+ break;
+ case LANGUAGE_SPANISH:
+ sprintf(filename, "SPANISH.GXT");
+ break;
+#ifdef MORE_LANGUAGES
+ case LANGUAGE_RUSSIAN:
+ sprintf(filename, "RUSSIAN.GXT");
+ break;
+#endif
+ }
+
+ length = CFileMgr::LoadFile(filename, filedata, 0x40000, "rb");
+ CFileMgr::SetDir("");
+
+ offset = 0;
+ while(offset < length){
+ type[0] = filedata[offset++];
+ type[1] = filedata[offset++];
+ type[2] = filedata[offset++];
+ type[3] = filedata[offset++];
+ sectlen = (int)filedata[offset+3]<<24 | (int)filedata[offset+2]<<16 |
+ (int)filedata[offset+1]<<8 | (int)filedata[offset+0];
+ offset += 4;
+ if(sectlen != 0){
+ if(strncmp(type, "TKEY", 4) == 0)
+ keyArray.Load(sectlen, filedata, &offset);
+ else if(strncmp(type, "TDAT", 4) == 0)
+ data.Load(sectlen, filedata, &offset);
+ else
+ offset += sectlen;
+ }
+ }
+
+ keyArray.Update(data.chars);
+
+ delete[] filedata;
+}
+
+void
+CText::Unload(void)
+{
+ CMessages::ClearAllMessagesDisplayedByGame();
+ data.Unload();
+ keyArray.Unload();
+}
+
+wchar*
+CText::Get(const char *key)
+{
+ return keyArray.Search(key);
+}
+
+wchar UpperCaseTable[128] = {
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
150, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137,
@@ -98,10 +103,10 @@ wchar UpperCaseTable[128] = {
216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226,
227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237,
238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248,
- 249, 250, 251, 252, 253, 254, 255
-};
-
-wchar FrenchUpperCaseTable[128] = {
+ 249, 250, 251, 252, 253, 254, 255
+};
+
+wchar FrenchUpperCaseTable[128] = {
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
150, 65, 65, 65, 65, 132, 133, 69, 69, 69, 69, 73, 73,
@@ -113,11 +118,11 @@ wchar FrenchUpperCaseTable[128] = {
220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230,
231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252,
- 253, 254, 255
-};
-
-wchar
-CText::GetUpperCase(wchar c)
+ 253, 254, 255
+};
+
+wchar
+CText::GetUpperCase(wchar c)
{
switch (encoding)
{
@@ -144,176 +149,176 @@ CText::GetUpperCase(wchar c)
default:
break;
}
- return c;
-}
-
-void
-CText::UpperCase(wchar *s)
-{
- while(*s){
- *s = GetUpperCase(*s);
- s++;
- }
-}
-
-
-void
-CKeyArray::Load(uint32 length, uint8 *data, int *offset)
-{
- uint32 i;
- uint8 *rawbytes;
-
- numEntries = length / sizeof(CKeyEntry);
- entries = new CKeyEntry[numEntries];
- rawbytes = (uint8*)entries;
-
- for(i = 0; i < length; i++)
- rawbytes[i] = data[(*offset)++];
-}
-
-void
-CKeyArray::Unload(void)
-{
- delete[] entries;
- entries = nil;
- numEntries = 0;
-}
-
-void
-CKeyArray::Update(wchar *chars)
-{
- int i;
- for(i = 0; i < numEntries; i++)
- entries[i].value = (wchar*)((uint8*)chars + (uintptr)entries[i].value);
-}
-
-CKeyEntry*
-CKeyArray::BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high)
-{
- int mid;
- int diff;
-
- if(low > high)
- return nil;
-
- mid = (low + high)/2;
- diff = strcmp(key, entries[mid].key);
- if(diff == 0)
- return &entries[mid];
- if(diff < 0)
- return BinarySearch(key, entries, low, mid-1);
- if(diff > 0)
- return BinarySearch(key, entries, mid+1, high);
- return nil;
-}
-
-wchar*
-CKeyArray::Search(const char *key)
-{
- CKeyEntry *found;
- char errstr[25];
- int i;
-
- found = BinarySearch(key, entries, 0, numEntries-1);
- if(found)
- return found->value;
- sprintf(errstr, "%s missing", key);
- for(i = 0; i < 25; i++)
- WideErrorString[i] = errstr[i];
- return WideErrorString;
-}
-
-
-void
-CData::Load(uint32 length, uint8 *data, int *offset)
-{
- uint32 i;
- uint8 *rawbytes;
-
- numChars = length / sizeof(wchar);
- chars = new wchar[numChars];
- rawbytes = (uint8*)chars;
-
- for(i = 0; i < length; i++)
- rawbytes[i] = data[(*offset)++];
-}
-
-void
-CData::Unload(void)
-{
- delete[] chars;
- chars = nil;
- numChars = 0;
-}
-
-void
-AsciiToUnicode(const char *src, wchar *dst)
-{
- while((*dst++ = *src++) != '\0');
-}
-
-char*
-UnicodeToAscii(wchar *src)
-{
- static char aStr[256];
- int len;
- for(len = 0; *src != '\0' && len < 256-1; len++, src++)
- if(*src < 128)
- aStr[len] = *src;
- else
- aStr[len] = '#';
- aStr[len] = '\0';
- return aStr;
-}
-
-char*
-UnicodeToAsciiForSaveLoad(wchar *src)
-{
- static char aStr[256];
- int len;
- for(len = 0; *src != '\0' && len < 256-1; len++, src++)
- if(*src < 256)
- aStr[len] = *src;
- else
- aStr[len] = '#';
- aStr[len] = '\0';
- return aStr;
-}
-
-void
-UnicodeStrcpy(wchar *dst, const wchar *src)
-{
- while((*dst++ = *src++) != '\0');
-}
-
-int
-UnicodeStrlen(const wchar *str)
-{
- int len;
- for(len = 0; *str != '\0'; len++, str++);
- return len;
-}
-
-void
-TextCopy(wchar *dst, const wchar *src)
-{
- while((*dst++ = *src++) != '\0');
-}
-
-
-STARTPATCHES
- InjectHook(0x52C3C0, &CText::Load, PATCH_JUMP);
- InjectHook(0x52C580, &CText::Unload, PATCH_JUMP);
- InjectHook(0x52C5A0, &CText::Get, PATCH_JUMP);
- InjectHook(0x52C220, &CText::GetUpperCase, PATCH_JUMP);
- InjectHook(0x52C2C0, &CText::UpperCase, PATCH_JUMP);
-
- InjectHook(0x52BE70, &CKeyArray::Load, PATCH_JUMP);
- InjectHook(0x52BF60, &CKeyArray::Unload, PATCH_JUMP);
- InjectHook(0x52BF80, &CKeyArray::Update, PATCH_JUMP);
- InjectHook(0x52C060, &CKeyArray::BinarySearch, PATCH_JUMP);
- InjectHook(0x52BFB0, &CKeyArray::Search, PATCH_JUMP);
-
- InjectHook(0x52C120, &CData::Load, PATCH_JUMP);
- InjectHook(0x52C200, &CData::Unload, PATCH_JUMP);
-ENDPATCHES
+ return c;
+}
+
+void
+CText::UpperCase(wchar *s)
+{
+ while(*s){
+ *s = GetUpperCase(*s);
+ s++;
+ }
+}
+
+
+void
+CKeyArray::Load(uint32 length, uint8 *data, int *offset)
+{
+ uint32 i;
+ uint8 *rawbytes;
+
+ numEntries = length / sizeof(CKeyEntry);
+ entries = new CKeyEntry[numEntries];
+ rawbytes = (uint8*)entries;
+
+ for(i = 0; i < length; i++)
+ rawbytes[i] = data[(*offset)++];
+}
+
+void
+CKeyArray::Unload(void)
+{
+ delete[] entries;
+ entries = nil;
+ numEntries = 0;
+}
+
+void
+CKeyArray::Update(wchar *chars)
+{
+ int i;
+ for(i = 0; i < numEntries; i++)
+ entries[i].value = (wchar*)((uint8*)chars + (uintptr)entries[i].value);
+}
+
+CKeyEntry*
+CKeyArray::BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high)
+{
+ int mid;
+ int diff;
+
+ if(low > high)
+ return nil;
+
+ mid = (low + high)/2;
+ diff = strcmp(key, entries[mid].key);
+ if(diff == 0)
+ return &entries[mid];
+ if(diff < 0)
+ return BinarySearch(key, entries, low, mid-1);
+ if(diff > 0)
+ return BinarySearch(key, entries, mid+1, high);
+ return nil;
+}
+
+wchar*
+CKeyArray::Search(const char *key)
+{
+ CKeyEntry *found;
+ char errstr[25];
+ int i;
+
+ found = BinarySearch(key, entries, 0, numEntries-1);
+ if(found)
+ return found->value;
+ sprintf(errstr, "%s missing", key);
+ for(i = 0; i < 25; i++)
+ WideErrorString[i] = errstr[i];
+ return WideErrorString;
+}
+
+
+void
+CData::Load(uint32 length, uint8 *data, int *offset)
+{
+ uint32 i;
+ uint8 *rawbytes;
+
+ numChars = length / sizeof(wchar);
+ chars = new wchar[numChars];
+ rawbytes = (uint8*)chars;
+
+ for(i = 0; i < length; i++)
+ rawbytes[i] = data[(*offset)++];
+}
+
+void
+CData::Unload(void)
+{
+ delete[] chars;
+ chars = nil;
+ numChars = 0;
+}
+
+void
+AsciiToUnicode(const char *src, wchar *dst)
+{
+ while((*dst++ = *src++) != '\0');
+}
+
+char*
+UnicodeToAscii(wchar *src)
+{
+ static char aStr[256];
+ int len;
+ for(len = 0; *src != '\0' && len < 256-1; len++, src++)
+ if(*src < 128)
+ aStr[len] = *src;
+ else
+ aStr[len] = '#';
+ aStr[len] = '\0';
+ return aStr;
+}
+
+char*
+UnicodeToAsciiForSaveLoad(wchar *src)
+{
+ static char aStr[256];
+ int len;
+ for(len = 0; *src != '\0' && len < 256-1; len++, src++)
+ if(*src < 256)
+ aStr[len] = *src;
+ else
+ aStr[len] = '#';
+ aStr[len] = '\0';
+ return aStr;
+}
+
+void
+UnicodeStrcpy(wchar *dst, const wchar *src)
+{
+ while((*dst++ = *src++) != '\0');
+}
+
+int
+UnicodeStrlen(const wchar *str)
+{
+ int len;
+ for(len = 0; *str != '\0'; len++, str++);
+ return len;
+}
+
+void
+TextCopy(wchar *dst, const wchar *src)
+{
+ while((*dst++ = *src++) != '\0');
+}
+
+
+STARTPATCHES
+ InjectHook(0x52C3C0, &CText::Load, PATCH_JUMP);
+ InjectHook(0x52C580, &CText::Unload, PATCH_JUMP);
+ InjectHook(0x52C5A0, &CText::Get, PATCH_JUMP);
+ InjectHook(0x52C220, &CText::GetUpperCase, PATCH_JUMP);
+ InjectHook(0x52C2C0, &CText::UpperCase, PATCH_JUMP);
+
+ InjectHook(0x52BE70, &CKeyArray::Load, PATCH_JUMP);
+ InjectHook(0x52BF60, &CKeyArray::Unload, PATCH_JUMP);
+ InjectHook(0x52BF80, &CKeyArray::Update, PATCH_JUMP);
+ InjectHook(0x52C060, &CKeyArray::BinarySearch, PATCH_JUMP);
+ InjectHook(0x52BFB0, &CKeyArray::Search, PATCH_JUMP);
+
+ InjectHook(0x52C120, &CData::Load, PATCH_JUMP);
+ InjectHook(0x52C200, &CData::Unload, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp
index a05a1236..e6b936f6 100644
--- a/src/vehicles/Automobile.cpp
+++ b/src/vehicles/Automobile.cpp
@@ -39,6 +39,7 @@
#include "PathFind.h"
#include "AnimManager.h"
#include "RpAnimBlend.h"
+#include "AnimBlendAssociation.h"
#include "Ped.h"
#include "PlayerPed.h"
#include "Object.h"
@@ -2338,10 +2339,16 @@ 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();
+#ifdef FREE_CAM
+ if (!CCamera::bFreeCam)
+#endif
+ {
+ 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(
@@ -2407,7 +2414,11 @@ CAutomobile::TankControl(void)
// Rotate turret
float prevAngle = m_fCarGunLR;
- m_fCarGunLR -= CPad::GetPad(0)->GetCarGunLeftRight() * 0.00015f * CTimer::GetTimeStep();
+#ifdef FREE_CAM
+ if(!CCamera::bFreeCam)
+#endif
+ m_fCarGunLR -= CPad::GetPad(0)->GetCarGunLeftRight() * 0.00015f * CTimer::GetTimeStep();
+
if(m_fCarGunLR < 0.0f)
m_fCarGunLR += TWOPI;
if(m_fCarGunLR > TWOPI)
@@ -2822,13 +2833,13 @@ CAutomobile::ProcessBuoyancy(void)
if(pDriver){
pDriver->bIsInWater = true;
if(pDriver->IsPlayer() || !bWaterTight)
- pDriver->InflictDamage(nil, WEAPONTYPE_WATER, CTimer::GetTimeStep(), PEDPIECE_TORSO, 0);
+ pDriver->InflictDamage(nil, WEAPONTYPE_DROWNING, 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);
+ pPassengers[i]->InflictDamage(nil, WEAPONTYPE_DROWNING, CTimer::GetTimeStep(), PEDPIECE_TORSO, 0);
}
}else
bIsInWater = false;
@@ -4483,6 +4494,8 @@ CAutomobile::SetAllTaxiLights(bool set)
m_sAllTaxiLights = set;
}
+#include <new>
+
class CAutomobile_ : public CAutomobile
{
public:
diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp
index 7dbd7080..6d584017 100644
--- a/src/vehicles/Boat.cpp
+++ b/src/vehicles/Boat.cpp
@@ -299,6 +299,8 @@ CBoat::FillBoatList()
}
}
+#include <new>
+
class CBoat_ : public CBoat
{
public:
diff --git a/src/vehicles/Heli.cpp b/src/vehicles/Heli.cpp
index aab9dd0d..3dc1deeb 100644
--- a/src/vehicles/Heli.cpp
+++ b/src/vehicles/Heli.cpp
@@ -19,6 +19,8 @@
#include "World.h"
#include "WaterLevel.h"
#include "PlayerPed.h"
+#include "Wanted.h"
+#include "DMAudio.h"
#include "Object.h"
#include "HandlingMgr.h"
#include "Heli.h"
@@ -1034,6 +1036,7 @@ bool CHeli::HasCatalinaBeenShotDown(void) { return CatalinaHasBeenShotDown; }
void CHeli::ActivateHeli(bool activate) { ScriptHeliOn = activate; }
+#include <new>
class CHeli_ : public CHeli
{
diff --git a/src/vehicles/Plane.cpp b/src/vehicles/Plane.cpp
index b4d80581..c2b9e493 100644
--- a/src/vehicles/Plane.cpp
+++ b/src/vehicles/Plane.cpp
@@ -7,6 +7,8 @@
#include "Streaming.h"
#include "Replay.h"
#include "Camera.h"
+#include "DMAudio.h"
+#include "Wanted.h"
#include "Coronas.h"
#include "Particle.h"
#include "Explosion.h"
@@ -964,6 +966,7 @@ bool CPlane::HasCesnaLanded(void) { return CesnaMissionStatus == CESNA_STATUS_LA
bool CPlane::HasCesnaBeenDestroyed(void) { return CesnaMissionStatus == CESNA_STATUS_DESTROYED; }
bool CPlane::HasDropOffCesnaBeenShotDown(void) { return DropOffCesnaMissionStatus == CESNA_STATUS_DESTROYED; }
+#include <new>
class CPlane_ : public CPlane
{
diff --git a/src/vehicles/Train.cpp b/src/vehicles/Train.cpp
index 1c73ed05..7d81fd57 100644
--- a/src/vehicles/Train.cpp
+++ b/src/vehicles/Train.cpp
@@ -10,6 +10,7 @@
#include "Coronas.h"
#include "World.h"
#include "Ped.h"
+#include "DMAudio.h"
#include "HandlingMgr.h"
#include "Train.h"
@@ -691,6 +692,8 @@ CTrain::UpdateTrains(void)
}
}
+#include <new>
+
class CTrain_ : public CTrain
{
public:
diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp
index 90848d6c..adeba19e 100644
--- a/src/vehicles/Vehicle.cpp
+++ b/src/vehicles/Vehicle.cpp
@@ -16,6 +16,8 @@
#include "Renderer.h"
#include "DMAudio.h"
#include "Radar.h"
+#include "Fire.h"
+#include "Darkel.h"
bool &CVehicle::bWheelsOnlyCheat = *(bool *)0x95CD78;
bool &CVehicle::bAllDodosCheat = *(bool *)0x95CD75;
@@ -29,9 +31,17 @@ void *CVehicle::operator new(size_t sz, int handle) { return CPools::GetVehicleP
void CVehicle::operator delete(void *p, size_t sz) { CPools::GetVehiclePool()->Delete((CVehicle*)p); }
void CVehicle::operator delete(void *p, int handle) { CPools::GetVehiclePool()->Delete((CVehicle*)p); }
-WRAPPER bool CVehicle::ShufflePassengersToMakeSpace(void) { EAXJMP(0x5528A0); }
-// or Weapon.cpp?
-WRAPPER void FireOneInstantHitRound(CVector *shotSource, CVector *shotTarget, int32 damage) { EAXJMP(0x563B00); }
+#ifdef FIX_BUGS
+// I think they meant that
+#define DAMAGE_FLEE_IN_CAR_PROBABILITY_VALUE (MYRAND_MAX * 35 / 100)
+#define DAMAGE_FLEE_ON_FOOT_PROBABILITY_VALUE (MYRAND_MAX * 70 / 100)
+#else
+#define DAMAGE_FLEE_IN_CAR_PROBABILITY_VALUE (35000)
+#define DAMAGE_FLEE_ON_FOOT_PROBABILITY_VALUE (70000)
+#endif
+#define DAMAGE_HEALTH_TO_FLEE_ALWAYS (200.0f)
+#define DAMAGE_HEALTH_TO_CATCH_FIRE (250.0f)
+
CVehicle::CVehicle(uint8 CreatedBy)
{
@@ -359,6 +369,119 @@ CVehicle::ProcessWheelRotation(tWheelState state, const CVector &fwd, const CVec
}
void
+CVehicle::InflictDamage(CEntity* damagedBy, eWeaponType weaponType, float damage)
+{
+ if (!bCanBeDamaged)
+ return;
+ if (bOnlyDamagedByPlayer && (damagedBy != FindPlayerPed() && damagedBy != FindPlayerVehicle()))
+ return;
+ bool bFrightensDriver = false;
+ switch (weaponType) {
+ case WEAPONTYPE_UNARMED:
+ case WEAPONTYPE_BASEBALLBAT:
+ if (bMeleeProof)
+ return;
+ break;
+ case WEAPONTYPE_COLT45:
+ case WEAPONTYPE_UZI:
+ case WEAPONTYPE_SHOTGUN:
+ case WEAPONTYPE_AK47:
+ case WEAPONTYPE_M16:
+ case WEAPONTYPE_SNIPERRIFLE:
+ case WEAPONTYPE_TOTAL_INVENTORY_WEAPONS:
+ case WEAPONTYPE_UZI_DRIVEBY:
+ if (bBulletProof)
+ return;
+ bFrightensDriver = true;
+ break;
+ case WEAPONTYPE_ROCKETLAUNCHER:
+ case WEAPONTYPE_MOLOTOV:
+ case WEAPONTYPE_GRENADE:
+ case WEAPONTYPE_EXPLOSION:
+ if (bExplosionProof)
+ return;
+ bFrightensDriver = true;
+ break;
+ case WEAPONTYPE_FLAMETHROWER:
+ if (bFireProof)
+ return;
+ break;
+ case WEAPONTYPE_RAMMEDBYCAR:
+ if (bCollisionProof)
+ return;
+ break;
+ default:
+ break;
+ }
+ if (m_fHealth > 0.0f) {
+ if (VehicleCreatedBy == RANDOM_VEHICLE && pDriver &&
+ (m_status == STATUS_SIMPLE || m_status == STATUS_PHYSICS) &&
+ AutoPilot.m_nCarMission == MISSION_CRUISE) {
+ if (m_randomSeed < DAMAGE_FLEE_IN_CAR_PROBABILITY_VALUE) {
+ CCarCtrl::SwitchVehicleToRealPhysics(this);
+ AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS;
+ AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * pHandling->Transmission.fUnkMaxVelocity;
+ m_status = STATUS_PHYSICS;
+ }
+ }
+ m_nLastWeaponDamage = weaponType;
+ float oldHealth = m_fHealth;
+ if (m_fHealth > damage) {
+ m_fHealth -= damage;
+ if (VehicleCreatedBy == RANDOM_VEHICLE &&
+ (m_fHealth < DAMAGE_HEALTH_TO_FLEE_ALWAYS ||
+ bFrightensDriver && m_randomSeed > DAMAGE_FLEE_ON_FOOT_PROBABILITY_VALUE)) {
+ switch (m_status) {
+ case STATUS_SIMPLE:
+ case STATUS_PHYSICS:
+ if (pDriver) {
+ m_status = STATUS_ABANDONED;
+ pDriver->bFleeAfterExitingCar = true;
+ pDriver->SetObjective(OBJECTIVE_LEAVE_VEHICLE, this);
+ }
+ for (int i = 0; i < m_nNumMaxPassengers; i++) {
+ if (pPassengers[i]) {
+ pPassengers[i]->bFleeAfterExitingCar = true;
+ pPassengers[i]->SetObjective(OBJECTIVE_LEAVE_VEHICLE, this);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (oldHealth > DAMAGE_HEALTH_TO_CATCH_FIRE && m_fHealth < DAMAGE_HEALTH_TO_CATCH_FIRE) {
+ if (IsCar()) {
+ CAutomobile* pThisCar = (CAutomobile*)this;
+ pThisCar->Damage.SetEngineStatus(ENGINE_STATUS_ON_FIRE);
+ pThisCar->m_pSetOnFireEntity = damagedBy;
+ if (damagedBy)
+ damagedBy->RegisterReference((CEntity**)&pThisCar->m_pSetOnFireEntity);
+ }
+ }
+ }
+ else {
+ m_fHealth = 0.0f;
+ if (weaponType == WEAPONTYPE_EXPLOSION) {
+ // between 1000 and 3047. Also not very nice: can't be saved by respray or cheat
+ m_nBombTimer = 1000 + CGeneral::GetRandomNumber() & 0x7FF;
+ m_pBlowUpEntity = damagedBy;
+ if (damagedBy)
+ damagedBy->RegisterReference((CEntity**)&m_pBlowUpEntity);
+ }
+ else
+ BlowUpCar(damagedBy);
+ }
+ }
+#ifdef FIX_BUGS // removing dumb case when shooting police car in player's own garage gives wanted level
+ if (GetModelIndex() == MI_POLICE && damagedBy == FindPlayerPed() && !bHasBeenOwnedByPlayer)
+#else
+ if (GetModelIndex() == MI_POLICE && damagedBy == FindPlayerPed())
+#endif
+ FindPlayerPed()->SetWantedLevelNoDrop(1);
+}
+
+void
CVehicle::ExtinguishCarFire(void)
{
m_fHealth = max(m_fHealth, 300.0f);
@@ -372,6 +495,65 @@ CVehicle::ExtinguishCarFire(void)
}
}
+bool
+CVehicle::ShufflePassengersToMakeSpace(void)
+{
+ if (m_nNumPassengers >= m_nNumMaxPassengers)
+ return false;
+ if (pPassengers[1] &&
+ !(m_nGettingInFlags & CAR_DOOR_FLAG_LR) &&
+ IsRoomForPedToLeaveCar(COMPONENT_DOOR_REAR_LEFT, nil)) {
+ if (!pPassengers[2] && !(m_nGettingInFlags & CAR_DOOR_FLAG_RR)) {
+ pPassengers[2] = pPassengers[1];
+ pPassengers[1] = nil;
+ pPassengers[2]->m_vehEnterType = CAR_DOOR_RR;
+ return true;
+ }
+ if (!pPassengers[0] && !(m_nGettingInFlags & CAR_DOOR_FLAG_RF)) {
+ pPassengers[0] = pPassengers[1];
+ pPassengers[1] = nil;
+ pPassengers[0]->m_vehEnterType = CAR_DOOR_RF;
+ return true;
+ }
+ return false;
+ }
+ if (pPassengers[2] &&
+ !(m_nGettingInFlags & CAR_DOOR_FLAG_RR) &&
+ IsRoomForPedToLeaveCar(COMPONENT_DOOR_REAR_RIGHT, nil)) {
+ if (!pPassengers[1] && !(m_nGettingInFlags & CAR_DOOR_FLAG_LR)) {
+ pPassengers[1] = pPassengers[2];
+ pPassengers[2] = nil;
+ pPassengers[1]->m_vehEnterType = CAR_DOOR_LR;
+ return true;
+ }
+ if (!pPassengers[0] && !(m_nGettingInFlags & CAR_DOOR_FLAG_RF)) {
+ pPassengers[0] = pPassengers[2];
+ pPassengers[2] = nil;
+ pPassengers[0]->m_vehEnterType = CAR_DOOR_RF;
+ return true;
+ }
+ return false;
+ }
+ if (pPassengers[0] &&
+ !(m_nGettingInFlags & CAR_DOOR_FLAG_RF) &&
+ IsRoomForPedToLeaveCar(COMPONENT_DOOR_FRONT_RIGHT, nil)) {
+ if (!pPassengers[1] && !(m_nGettingInFlags & CAR_DOOR_FLAG_LR)) {
+ pPassengers[1] = pPassengers[0];
+ pPassengers[0] = nil;
+ pPassengers[1]->m_vehEnterType = CAR_DOOR_LR;
+ return true;
+ }
+ if (!pPassengers[2] && !(m_nGettingInFlags & CAR_DOOR_FLAG_RR)) {
+ pPassengers[2] = pPassengers[0];
+ pPassengers[0] = nil;
+ pPassengers[2]->m_vehEnterType = CAR_DOOR_RR;
+ return true;
+ }
+ return false;
+ }
+ return false;
+}
+
void
CVehicle::ProcessDelayedExplosion(void)
{
@@ -763,6 +945,29 @@ CVehicle::IsSphereTouchingVehicle(float sx, float sy, float sz, float radius)
return true;
}
+void
+DestroyVehicleAndDriverAndPassengers(CVehicle* pVehicle)
+{
+ if (pVehicle->pDriver) {
+#ifndef FIX_BUGS
+ // this just isn't fair
+ CDarkel::RegisterKillByPlayer(pVehicle->pDriver, WEAPONTYPE_UNIDENTIFIED);
+#endif
+ pVehicle->pDriver->FlagToDestroyWhenNextProcessed();
+ }
+ for (int i = 0; i < pVehicle->m_nNumMaxPassengers; i++) {
+ if (pVehicle->pPassengers[i]) {
+#ifndef FIX_BUGS
+ // this just isn't fair
+ CDarkel::RegisterKillByPlayer(pVehicle->pPassengers[i], WEAPONTYPE_UNIDENTIFIED);
+#endif
+ pVehicle->pPassengers[i]->FlagToDestroyWhenNextProcessed();
+ }
+ }
+ CWorld::Remove(pVehicle);
+ delete pVehicle;
+}
+
class CVehicle_ : public CVehicle
{
@@ -805,4 +1010,5 @@ STARTPATCHES
InjectHook(0x551EB0, &CVehicle::RemovePassenger, PATCH_JUMP);
InjectHook(0x5525A0, &CVehicle::ProcessCarAlarm, PATCH_JUMP);
InjectHook(0x552620, &CVehicle::IsSphereTouchingVehicle, PATCH_JUMP);
+ InjectHook(0x551950, &CVehicle::InflictDamage, PATCH_JUMP);
ENDPATCHES
diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h
index bd8df694..4639f3e1 100644
--- a/src/vehicles/Vehicle.h
+++ b/src/vehicles/Vehicle.h
@@ -4,6 +4,7 @@
#include "AutoPilot.h"
#include "ModelIndices.h"
#include "AnimManager.h"
+#include "Weapon.h"
class CPed;
class CFire;
@@ -266,6 +267,7 @@ public:
void ProcessCarAlarm(void);
bool IsSphereTouchingVehicle(float sx, float sy, float sz, float radius);
bool ShufflePassengersToMakeSpace(void);
+ void InflictDamage(CEntity *damagedBy, eWeaponType weaponType, float damage);
bool IsAlarmOn(void) { return m_nAlarmState != 0 && m_nAlarmState != -1; }
CVehicleModelInfo* GetModelInfo() { return (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()); }
@@ -300,3 +302,5 @@ public:
};
static_assert(sizeof(cVehicleParams) == 0x18, "cVehicleParams: error");
+
+void DestroyVehicleAndDriverAndPassengers(CVehicle* pVehicle);
diff --git a/src/weapons/Explosion.cpp b/src/weapons/Explosion.cpp
index 05087335..e99dc918 100644
--- a/src/weapons/Explosion.cpp
+++ b/src/weapons/Explosion.cpp
@@ -6,8 +6,6 @@
CExplosion(&gaExplosion)[48] = *(CExplosion(*)[48])*(uintptr*)0x64E208;
WRAPPER void CExplosion::AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type, const CVector &pos, uint32) { EAXJMP(0x5591C0); }
-//WRAPPER void CExplosion::RemoveAllExplosionsInArea(CVector, float) { EAXJMP(0x55AD40); }
-//WRAPPER bool CExplosion::TestForExplosionInArea(eExplosionType, float, float, float, float, float, float) { EAXJMP(0x55AC80); }
int AudioHandle = AEHANDLE_NONE;
diff --git a/src/weapons/ShotInfo.cpp b/src/weapons/ShotInfo.cpp
new file mode 100644
index 00000000..43d0579d
--- /dev/null
+++ b/src/weapons/ShotInfo.cpp
@@ -0,0 +1,140 @@
+#include "common.h"
+#include "patcher.h"
+#include "ShotInfo.h"
+#include "Entity.h"
+#include "Weapon.h"
+#include "World.h"
+#include "WeaponInfo.h"
+#include "General.h"
+#include "Timer.h"
+#include "Ped.h"
+#include "Fire.h"
+
+CShotInfo gaShotInfo[NUMSHOTINFOS];
+float CShotInfo::ms_afRandTable[20];
+
+// CShotInfo (&gaShotInfo)[100] = *(CShotInfo(*)[100])*(uintptr*)0x64F0D0;
+// float (&CShotInfo::ms_afRandTable)[20] = *(float(*)[20])*(uintptr*)0x6E9878;
+
+/*
+ Used for flamethrower. I don't know why it's name is CShotInfo.
+ Has no relation with any visual, just calculates the area fire affects
+ (including spreading and slowing of fire) and make entities burn/flee.
+*/
+
+void
+CShotInfo::Initialise()
+{
+ debug("Initialising CShotInfo...\n");
+ for(int i=0; i<ARRAY_SIZE(gaShotInfo); i++) {
+ gaShotInfo[i].m_inUse = false;
+ gaShotInfo[i].m_weapon = WEAPONTYPE_COLT45;
+ gaShotInfo[i].m_startPos = CVector(0.0f, 0.0f, 0.0f);
+ gaShotInfo[i].m_areaAffected = CVector(0.0f, 0.0f, 0.0f);
+ gaShotInfo[i].m_radius = 1.0f;
+ gaShotInfo[i].m_sourceEntity = nil;
+ gaShotInfo[i].m_timeout = 0;
+ }
+
+ // Not random for sure
+ float nextVal = -0.05f;
+ for (int i = 0; i < ARRAY_SIZE(ms_afRandTable); i++) {
+ ms_afRandTable[i] = nextVal;
+ nextVal += 0.005f;
+ }
+ debug("CShotInfo ready\n");
+}
+
+bool
+CShotInfo::AddShot(CEntity *sourceEntity, eWeaponType weapon, CVector startPos, CVector endPos)
+{
+ CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(weapon);
+
+ int slot;
+ for (slot = 0; slot < ARRAY_SIZE(gaShotInfo) && gaShotInfo[slot].m_inUse; slot++);
+
+ if (slot == ARRAY_SIZE(gaShotInfo))
+ return false;
+
+ gaShotInfo[slot].m_inUse = true;
+ gaShotInfo[slot].m_weapon = weapon;
+ gaShotInfo[slot].m_startPos = startPos;
+ gaShotInfo[slot].m_areaAffected = endPos - startPos;
+ gaShotInfo[slot].m_radius = weaponInfo->m_fRadius;
+
+ if (weaponInfo->m_fSpread != 0.0f) {
+ gaShotInfo[slot].m_areaAffected.x += CShotInfo::ms_afRandTable[CGeneral::GetRandomNumber() % ARRAY_SIZE(ms_afRandTable)] * weaponInfo->m_fSpread;
+ gaShotInfo[slot].m_areaAffected.y += CShotInfo::ms_afRandTable[CGeneral::GetRandomNumber() % ARRAY_SIZE(ms_afRandTable)] * weaponInfo->m_fSpread;
+ gaShotInfo[slot].m_areaAffected.z += CShotInfo::ms_afRandTable[CGeneral::GetRandomNumber() % ARRAY_SIZE(ms_afRandTable)];
+ }
+ gaShotInfo[slot].m_areaAffected.Normalise();
+ if (weaponInfo->m_bRandSpeed)
+ gaShotInfo[slot].m_areaAffected *= CShotInfo::ms_afRandTable[CGeneral::GetRandomNumber() % ARRAY_SIZE(ms_afRandTable)] + weaponInfo->m_fSpeed;
+ else
+ gaShotInfo[slot].m_areaAffected *= weaponInfo->m_fSpeed;
+
+ gaShotInfo[slot].m_sourceEntity = sourceEntity;
+ gaShotInfo[slot].m_timeout = CTimer::GetTimeInMilliseconds() + weaponInfo->m_fLifespan;
+
+ return true;
+}
+
+void
+CShotInfo::Shutdown()
+{
+ debug("Shutting down CShotInfo...\n");
+ debug("CShotInfo shut down\n");
+}
+
+void
+CShotInfo::Update()
+{
+ for (int slot = 0; slot < ARRAY_SIZE(gaShotInfo); slot++) {
+ CShotInfo &shot = gaShotInfo[slot];
+ if (shot.m_sourceEntity && shot.m_sourceEntity->IsPed() && !((CPed*)shot.m_sourceEntity)->IsPointerValid())
+ shot.m_sourceEntity = nil;
+
+ if (!shot.m_inUse)
+ continue;
+
+ CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(shot.m_weapon);
+ if (CTimer::GetTimeInMilliseconds() > shot.m_timeout)
+ shot.m_inUse = false;
+
+ if (weaponInfo->m_bSlowsDown)
+ shot.m_areaAffected *= pow(0.96, CTimer::GetTimeStep()); // FRAMERATE
+
+ if (weaponInfo->m_bExpands)
+ shot.m_radius += 0.075f * CTimer::GetTimeStep();
+
+ shot.m_startPos += CTimer::GetTimeStep() * shot.m_areaAffected;
+ if (shot.m_sourceEntity) {
+ assert(shot.m_sourceEntity->IsPed());
+ CPed *ped = (CPed*) shot.m_sourceEntity;
+ float radius = max(1.0f, shot.m_radius);
+
+ for (int i = 0; i < ped->m_numNearPeds; ++i) {
+ CPed *nearPed = ped->m_nearPeds[i];
+ if (nearPed->IsPointerValid()) {
+ if (nearPed->IsPedInControl() && (nearPed->GetPosition() - shot.m_startPos).MagnitudeSqr() < radius && !nearPed->bFireProof) {
+
+ if (!nearPed->IsPlayer()) {
+ nearPed->SetFindPathAndFlee(shot.m_sourceEntity, 10000);
+ nearPed->SetMoveState(PEDMOVE_SPRINT);
+ }
+ gFireManager.StartFire(nearPed, shot.m_sourceEntity, 0.8f, true);
+ }
+ }
+ }
+ }
+ if (!((CTimer::GetFrameCounter() + slot) & 3))
+ CWorld::SetCarsOnFire(shot.m_startPos.x, shot.m_startPos.y, shot.m_startPos.z, 4.0f, shot.m_sourceEntity);
+ }
+}
+
+STARTPATCHES
+ InjectHook(0x55BFF0, &CShotInfo::Update, PATCH_JUMP);
+ InjectHook(0x55BD70, &CShotInfo::AddShot, PATCH_JUMP);
+ InjectHook(0x55BC60, &CShotInfo::Initialise, PATCH_JUMP);
+ InjectHook(0x55BD50, &CShotInfo::Shutdown, PATCH_JUMP);
+ENDPATCHES \ No newline at end of file
diff --git a/src/weapons/ShotInfo.h b/src/weapons/ShotInfo.h
new file mode 100644
index 00000000..a5e5fd35
--- /dev/null
+++ b/src/weapons/ShotInfo.h
@@ -0,0 +1,23 @@
+#pragma once
+
+class CEntity;
+enum eWeaponType;
+
+class CShotInfo
+{
+public:
+ eWeaponType m_weapon;
+ CVector m_startPos;
+ CVector m_areaAffected;
+ float m_radius;
+ CEntity *m_sourceEntity;
+ float m_timeout;
+ bool m_inUse;
+
+ static float ms_afRandTable[20];
+
+ static void Initialise(void);
+ static bool AddShot(CEntity*, eWeaponType, CVector, CVector);
+ static void Shutdown(void);
+ static void Update(void);
+};
diff --git a/src/weapons/Weapon.cpp b/src/weapons/Weapon.cpp
index 8019a1cf..0f41264f 100644
--- a/src/weapons/Weapon.cpp
+++ b/src/weapons/Weapon.cpp
@@ -6,6 +6,7 @@
#include "Ped.h"
#include "World.h"
+WRAPPER void CWeapon::ShutdownWeapons(void) { EAXJMP(0x55C2F0); }
WRAPPER void CWeapon::UpdateWeapons(void) { EAXJMP(0x55C310); }
WRAPPER bool CWeapon::Fire(CEntity*, CVector*) { EAXJMP(0x55C380); }
WRAPPER void CWeapon::FireFromCar(CAutomobile *car, bool left) { EAXJMP(0x55C940); }
@@ -13,6 +14,7 @@ WRAPPER void CWeapon::AddGunshell(CEntity*, CVector const&, CVector2D const&, fl
WRAPPER void CWeapon::Update(int32 audioEntity) { EAXJMP(0x563A10); }
WRAPPER void CWeapon::DoTankDoomAiming(CEntity *playerVehicle, CEntity *playerPed, CVector *start, CVector *end) { EAXJMP(0x563200); }
WRAPPER void CWeapon::InitialiseWeapons(void) { EAXJMP(0x55C2D0); }
+WRAPPER void FireOneInstantHitRound(CVector* shotSource, CVector* shotTarget, int32 damage) { EAXJMP(0x563B00); }
void
CWeapon::Initialise(eWeaponType type, int ammo)
diff --git a/src/weapons/Weapon.h b/src/weapons/Weapon.h
index 1db66720..84760550 100644
--- a/src/weapons/Weapon.h
+++ b/src/weapons/Weapon.h
@@ -15,17 +15,19 @@ enum eWeaponType
WEAPONTYPE_MOLOTOV,
WEAPONTYPE_GRENADE,
WEAPONTYPE_DETONATOR,
- WEAPONTYPE_TOTAL_INVENTORY_WEAPONS = 13,
- WEAPONTYPE_HELICANNON = 13,
- WEAPONTYPE_TOTALWEAPONS,
+ WEAPONTYPE_HELICANNON,
+ WEAPONTYPE_LAST_WEAPONTYPE,
WEAPONTYPE_ARMOUR,
WEAPONTYPE_RAMMEDBYCAR,
WEAPONTYPE_RUNOVERBYCAR,
WEAPONTYPE_EXPLOSION,
WEAPONTYPE_UZI_DRIVEBY,
- WEAPONTYPE_WATER,
- WEAPONTYPE_FALL_DAMAGE,
+ WEAPONTYPE_DROWNING,
+ WEAPONTYPE_FALL,
WEAPONTYPE_UNIDENTIFIED,
+
+ WEAPONTYPE_TOTALWEAPONS = WEAPONTYPE_LAST_WEAPONTYPE,
+ WEAPONTYPE_TOTAL_INVENTORY_WEAPONS = 13,
};
enum eWeaponFire {
@@ -63,6 +65,7 @@ public:
m_bAddRotOffset = false;
}
+ static void ShutdownWeapons(void);
void Initialise(eWeaponType type, int ammo);
void Update(int32 audioEntity);
void Reload(void);
@@ -78,3 +81,5 @@ public:
static void UpdateWeapons(void);
};
static_assert(sizeof(CWeapon) == 0x18, "CWeapon: error");
+
+void FireOneInstantHitRound(CVector* shotSource, CVector* shotTarget, int32 damage); \ No newline at end of file
diff --git a/src/weapons/WeaponInfo.cpp b/src/weapons/WeaponInfo.cpp
index 6884d347..a4a1a085 100644
--- a/src/weapons/WeaponInfo.cpp
+++ b/src/weapons/WeaponInfo.cpp
@@ -3,7 +3,9 @@
#include "main.h"
#include "FileMgr.h"
#include "WeaponInfo.h"
+#include "AnimManager.h"
#include "AnimBlendAssociation.h"
+#include "Weapon.h"
//CWeaponInfo (&CWeaponInfo::ms_apWeaponInfos)[14] = * (CWeaponInfo(*)[14]) * (uintptr*)0x6503EC;
CWeaponInfo CWeaponInfo::ms_apWeaponInfos[WEAPONTYPE_TOTALWEAPONS];
diff --git a/src/weapons/WeaponInfo.h b/src/weapons/WeaponInfo.h
index faa8bf7b..e2e71d23 100644
--- a/src/weapons/WeaponInfo.h
+++ b/src/weapons/WeaponInfo.h
@@ -1,7 +1,8 @@
#pragma once
-#include "common.h"
-#include "Weapon.h"
-#include "AnimManager.h"
+
+enum AnimationId;
+enum eWeaponFire;
+enum eWeaponType;
class CWeaponInfo {
// static CWeaponInfo(&ms_apWeaponInfos)[14];