summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorFire_Head <Fire-Head@users.noreply.github.com>2019-07-24 20:00:08 +0200
committerGitHub <noreply@github.com>2019-07-24 20:00:08 +0200
commit81ee1c509a8d05189901dd59c268bf47a6188eb8 (patch)
treed836f70678f2ce7b5d86a6745f34b45232ff71d0 /src
parentupdate (diff)
parentMerge branch 'master' into master (diff)
downloadre3-81ee1c509a8d05189901dd59c268bf47a6188eb8.tar
re3-81ee1c509a8d05189901dd59c268bf47a6188eb8.tar.gz
re3-81ee1c509a8d05189901dd59c268bf47a6188eb8.tar.bz2
re3-81ee1c509a8d05189901dd59c268bf47a6188eb8.tar.lz
re3-81ee1c509a8d05189901dd59c268bf47a6188eb8.tar.xz
re3-81ee1c509a8d05189901dd59c268bf47a6188eb8.tar.zst
re3-81ee1c509a8d05189901dd59c268bf47a6188eb8.zip
Diffstat (limited to 'src')
-rw-r--r--src/animation/AnimBlendAssocGroup.cpp13
-rw-r--r--src/animation/AnimBlendAssociation.h2
-rw-r--r--src/animation/AnimBlendSequence.h2
-rw-r--r--src/audio/AudioManager.cpp3186
-rw-r--r--src/audio/AudioManager.h365
-rw-r--r--src/audio/AudioSamples.h130
-rw-r--r--src/audio/DMAudio.cpp9
-rw-r--r--src/audio/DMAudio.h22
-rw-r--r--src/audio/MusicManager.cpp14
-rw-r--r--src/audio/MusicManager.h3
-rw-r--r--src/audio/SampleManager.cpp62
-rw-r--r--src/audio/SampleManager.h26
-rw-r--r--src/control/AutoPilot.h7
-rw-r--r--src/control/Bridge.cpp49
-rw-r--r--src/control/CarAI.cpp6
-rw-r--r--src/control/CarAI.h10
-rw-r--r--src/control/CarCtrl.cpp13
-rw-r--r--src/control/CarCtrl.h6
-rw-r--r--src/control/Darkel.cpp4
-rw-r--r--src/control/Darkel.h2
-rw-r--r--src/control/Garages.cpp2
-rw-r--r--src/control/Garages.h1
-rw-r--r--src/control/PathFind.cpp2
-rw-r--r--src/control/PathFind.h1
-rw-r--r--src/control/Phones.cpp161
-rw-r--r--src/control/Phones.h21
-rw-r--r--src/control/Population.cpp2
-rw-r--r--src/control/Population.h3
-rw-r--r--src/control/Remote.cpp5
-rw-r--r--src/control/Remote.h7
-rw-r--r--src/control/Replay.cpp56
-rw-r--r--src/control/Replay.h2
-rw-r--r--src/control/Script.cpp831
-rw-r--r--src/control/Script.h2
-rw-r--r--src/core/Camera.cpp10
-rw-r--r--src/core/Camera.h5
-rw-r--r--src/core/Clock.cpp7
-rw-r--r--src/core/Clock.h2
-rw-r--r--src/core/Collision.cpp243
-rw-r--r--src/core/EventList.cpp238
-rw-r--r--src/core/EventList.h67
-rw-r--r--src/core/FileLoader.cpp8
-rw-r--r--src/core/Frontend.cpp636
-rw-r--r--src/core/Frontend.h51
-rw-r--r--src/core/General.h16
-rw-r--r--src/core/MenuScreens.h118
-rw-r--r--src/core/Messages.cpp5
-rw-r--r--src/core/Messages.h5
-rw-r--r--src/core/Pad.cpp70
-rw-r--r--src/core/Pad.h31
-rw-r--r--src/core/Pools.cpp10
-rw-r--r--src/core/Pools.h11
-rw-r--r--src/core/Stats.cpp1
-rw-r--r--src/core/Stats.h1
-rw-r--r--src/core/Streaming.cpp2
-rw-r--r--src/core/SurfaceTable.h2
-rw-r--r--src/core/Wanted.cpp306
-rw-r--r--src/core/Wanted.h73
-rw-r--r--src/core/World.cpp163
-rw-r--r--src/core/World.h4
-rw-r--r--src/core/common.h16
-rw-r--r--src/core/config.h1
-rw-r--r--src/core/main.cpp2
-rw-r--r--src/core/main.h3
-rw-r--r--src/core/re3.cpp127
-rw-r--r--src/entities/Entity.cpp8
-rw-r--r--src/entities/Entity.h20
-rw-r--r--src/math/Matrix.h1
-rw-r--r--src/math/Vector.h1
-rw-r--r--src/modelinfo/ModelIndices.h23
-rw-r--r--src/modelinfo/ModelInfo.cpp7
-rw-r--r--src/modelinfo/ModelInfo.h1
-rw-r--r--src/modelinfo/PedModelInfo.cpp20
-rw-r--r--src/modelinfo/PedModelInfo.h4
-rw-r--r--src/objects/ObjectData.cpp2
-rw-r--r--src/peds/CivilianPed.cpp26
-rw-r--r--src/peds/CivilianPed.h1
-rw-r--r--src/peds/CopPed.cpp60
-rw-r--r--src/peds/CopPed.h35
-rw-r--r--src/peds/EmergencyPed.cpp25
-rw-r--r--src/peds/EmergencyPed.h11
-rw-r--r--src/peds/Ped.cpp1673
-rw-r--r--src/peds/Ped.h72
-rw-r--r--src/peds/PedIK.cpp55
-rw-r--r--src/peds/PedIK.h13
-rw-r--r--src/peds/PedPlacement.cpp7
-rw-r--r--src/peds/PedPlacement.h2
-rw-r--r--src/peds/PlayerPed.cpp19
-rw-r--r--src/peds/PlayerPed.h4
-rw-r--r--src/render/Draw.h5
-rw-r--r--src/render/Fluff.cpp827
-rw-r--r--src/render/Fluff.h86
-rw-r--r--src/render/Hud.cpp2
-rw-r--r--src/render/Lines.cpp74
-rw-r--r--src/render/Lines.h7
-rw-r--r--src/render/Renderer.cpp21
-rw-r--r--src/render/Renderer.h6
-rw-r--r--src/render/Rubbish.cpp1
-rw-r--r--src/render/Rubbish.h3
-rw-r--r--src/render/WaterLevel.cpp8
-rw-r--r--src/render/WaterLevel.h1
-rw-r--r--src/skel/events.cpp2
-rw-r--r--src/skel/win/win.rc8
-rw-r--r--src/vehicles/Automobile.cpp1812
-rw-r--r--src/vehicles/Automobile.h67
-rw-r--r--src/vehicles/DamageManager.cpp25
-rw-r--r--src/vehicles/DamageManager.h12
-rw-r--r--src/vehicles/Door.h6
-rw-r--r--src/vehicles/Floater.cpp195
-rw-r--r--src/vehicles/Floater.h45
-rw-r--r--src/vehicles/HandlingMgr.cpp40
-rw-r--r--src/vehicles/HandlingMgr.h6
-rw-r--r--src/vehicles/Plane.h12
-rw-r--r--src/vehicles/Transmission.cpp106
-rw-r--r--src/vehicles/Transmission.h4
-rw-r--r--src/vehicles/Vehicle.cpp69
-rw-r--r--src/vehicles/Vehicle.h65
-rw-r--r--src/weapons/Weapon.cpp8
-rw-r--r--src/weapons/Weapon.h7
119 files changed, 11359 insertions, 1522 deletions
diff --git a/src/animation/AnimBlendAssocGroup.cpp b/src/animation/AnimBlendAssocGroup.cpp
index fbca92b7..05f9a06a 100644
--- a/src/animation/AnimBlendAssocGroup.cpp
+++ b/src/animation/AnimBlendAssocGroup.cpp
@@ -116,14 +116,13 @@ CAnimBlendAssocGroup::CreateAssociations(const char *name)
for(i = 0; i < animBlock->numAnims; i++){
CAnimBlendHierarchy *anim = CAnimManager::GetAnimation(animBlock->firstIndex + i);
CBaseModelInfo *model = GetModelFromName(anim->name);
+ assert(model);
printf("Associated anim %s with model %s\n", anim->name, model->GetName());
- if(model){
- RpClump *clump = (RpClump*)model->CreateInstance();
- RpAnimBlendClumpInit(clump);
- assocList[i].Init(clump, anim);
- RpClumpDestroy(clump);
- assocList[i].animId = i;
- }
+ RpClump *clump = (RpClump*)model->CreateInstance();
+ RpAnimBlendClumpInit(clump);
+ assocList[i].Init(clump, anim);
+ RpClumpDestroy(clump);
+ assocList[i].animId = i;
}
numAssociations = animBlock->numAnims;
}
diff --git a/src/animation/AnimBlendAssociation.h b/src/animation/AnimBlendAssociation.h
index a7e127f7..cd61636f 100644
--- a/src/animation/AnimBlendAssociation.h
+++ b/src/animation/AnimBlendAssociation.h
@@ -77,6 +77,8 @@ public:
void UpdateTime(float timeDelta, float relSpeed);
bool UpdateBlend(float timeDelta);
+ void SetRun(void) { flags |= ASSOC_RUNNING; }
+
inline float GetTimeLeft() { return hierarchy->totalLength - currentTime; }
static CAnimBlendAssociation *FromLink(CAnimBlendLink *l) {
diff --git a/src/animation/AnimBlendSequence.h b/src/animation/AnimBlendSequence.h
index 7538cf56..1246d7b4 100644
--- a/src/animation/AnimBlendSequence.h
+++ b/src/animation/AnimBlendSequence.h
@@ -1,6 +1,6 @@
#pragma once
-#include "math/Quaternion.h"
+#include "Quaternion.h"
// TODO: put them somewhere else?
struct KeyFrame {
diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp
index 51f45e16..c0479002 100644
--- a/src/audio/AudioManager.cpp
+++ b/src/audio/AudioManager.cpp
@@ -3,19 +3,26 @@
#include "AudioManager.h"
+#include "Automobile.h"
+#include "Camera.h"
#include "DMAudio.h"
+#include "Garages.h"
#include "ModelIndices.h"
#include "MusicManager.h"
#include "Ped.h"
#include "Physical.h"
+#include "Plane.h"
#include "PlayerPed.h"
+#include "Pools.h"
#include "SampleManager.h"
+#include "Stats.h"
#include "Vehicle.h"
#include "World.h"
+uint32 *audioLogicTimers = (uint32 *)0x6508A0;
+
// TODO: where is this used? Is this the right file?
-enum eVehicleModel
-{
+enum eVehicleModel {
LANDSTAL,
IDAHO,
STINGER,
@@ -88,6 +95,11 @@ enum eVehicleModel
CAR159,
};
+void *cAudioScriptObject::operator new(size_t sz) { return CPools::GetAudioScriptObjectPool()->New(); }
+void *cAudioScriptObject::operator new(size_t sz, int handle) { return CPools::GetAudioScriptObjectPool()->New(handle); }
+void cAudioScriptObject::operator delete(void *p, size_t sz) { CPools::GetAudioScriptObjectPool()->Delete((cAudioScriptObject*)p); }
+void cAudioScriptObject::operator delete(void *p, int handle) { CPools::GetAudioScriptObjectPool()->Delete((cAudioScriptObject*)p); }
+
cAudioManager &AudioManager = *(cAudioManager *)0x880FC0;
constexpr int totalAudioEntitiesSlots = 200;
@@ -96,21 +108,187 @@ constexpr int maxVolume = 127;
char &g_nMissionAudioPlayingStatus = *(char *)0x60ED88;
void
+cAudioManager::AddDetailsToRequestedOrderList(uint8 sample)
+{
+ uint32 i = 0;
+ if(sample != 0) {
+ for(; i < sample; i++) {
+ if(m_asSamples[m_bActiveSampleQueue]
+ [m_abSampleQueueIndexTable[m_bActiveSampleQueue][i]]
+ .calculatedVolume >
+ m_asSamples[m_bActiveSampleQueue][sample].calculatedVolume)
+ break;
+ }
+ if(i < sample) {
+ memmove(&m_abSampleQueueIndexTable[m_bActiveSampleQueue][i + 1],
+ &m_abSampleQueueIndexTable[m_bActiveSampleQueue][i],
+ m_bActiveSamples - i - 1);
+ }
+ }
+ m_abSampleQueueIndexTable[m_bActiveSampleQueue][i] = sample;
+}
+
+void
+cAudioManager::AddPlayerCarSample(uint8 emittingVolume, int32 freq, uint32 sample, uint8 unk1,
+ uint8 unk2, bool notLooping)
+{
+ m_sQueueSample.m_bVolume = ComputeVolume(emittingVolume, 50.f, m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.field_4 = unk2;
+ m_sQueueSample.m_nSampleIndex = sample;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_16 = 0;
+ m_sQueueSample.m_nFrequency = freq;
+ if(notLooping) {
+ m_sQueueSample.m_nLoopCount = 0;
+ m_sQueueSample.field_76 = 8;
+ } else {
+ m_sQueueSample.m_nLoopCount = 1;
+ }
+ m_sQueueSample.m_bEmittingVolume = emittingVolume;
+ m_sQueueSample.m_nLoopStart =
+ cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nLoopEnd =
+ cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.field_48 = 6.0f;
+ m_sQueueSample.m_fSoundIntensity = 50.0f;
+ m_sQueueSample.field_56 = 0;
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ }
+}
+
+void
+cAudioManager::AddReflectionsToRequestedQueue()
+{
+ float reflectionDistance;
+ int32 noise;
+ uint8 emittingVolume = emittingVolume =
+ (m_sQueueSample.m_bVolume >> 1) + (m_sQueueSample.m_bVolume >> 3);
+
+ for(uint32 i = 0; i < 5u; i++) {
+ reflectionDistance = m_afReflectionsDistances[i];
+ if(reflectionDistance > 0.0f && reflectionDistance < 100.f &&
+ reflectionDistance < m_sQueueSample.m_fSoundIntensity) {
+ m_sQueueSample.m_bLoopsRemaining = (reflectionDistance * 500.f / 1029.f);
+ if(m_sQueueSample.m_bLoopsRemaining > 5u) {
+ m_sQueueSample.m_fDistance = m_afReflectionsDistances[i];
+ m_sQueueSample.m_bEmittingVolume = emittingVolume;
+ m_sQueueSample.m_bVolume =
+ ComputeVolume(emittingVolume, m_sQueueSample.m_fSoundIntensity,
+ m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume > emittingVolume >> 4) {
+ m_sQueueSample.field_4 += ((i + 1) << 8);
+ if(m_sQueueSample.m_nLoopCount) {
+ noise = RandomDisplacement(
+ m_sQueueSample.m_nFrequency >> 5);
+ if(noise <= 0)
+ m_sQueueSample.m_nFrequency += noise;
+ else
+ m_sQueueSample.m_nFrequency -= noise;
+ }
+ m_sQueueSample.field_16 += 20;
+ m_sQueueSample.m_vecPos.x = m_avecReflectionsPos[i].x;
+ m_sQueueSample.m_vecPos.y = m_avecReflectionsPos[i].y;
+ m_sQueueSample.m_vecPos.z = m_avecReflectionsPos[i].z;
+ AddSampleToRequestedQueue();
+ }
+ }
+ }
+ }
+}
+
+#if 1
+WRAPPER void
+cAudioManager::AddReleasingSounds()
+{
+ EAXJMP(0x57B8D0);
+}
+#else
+void
+cAudioManager::AddReleasingSounds()
+{
+ bool isFirstSampleQueue;
+ int32 calculatedIndex;
+ tActiveSample *sample;
+ uint8 field_76;
+ uint8 field_88;
+ int sampleQueue;
+ bool toProcess[44];
+ isFirstSampleQueue = m_bActiveSampleQueue == 0;
+
+ cAudioManager *s = (this + 2484 * isFirstSampleQueue); // wtf
+
+ for(uint32 i = 0; i < m_bSampleRequestQueuesStatus[isFirstSampleQueue]; i++) {
+ calculatedIndex = i + 27 * isFirstSampleQueue;
+ sample = &s->m_asSamples[m_abSampleQueueIndexTable[calculatedIndex]];
+ if(!s->m_asSamples[m_abSampleQueueIndexTable[calculatedIndex]].m_bLoopEnded) {
+ toProcess[i] = 0;
+ sampleQueue = m_bActiveSampleQueue;
+ for(uint8 j = 0; j < m_bSampleRequestQueuesStatus[m_bActiveSampleQueue];
+ j++) {
+ if(sample->m_nEntityIndex ==
+ m_asSamples[27 * sampleQueue +
+ m_abSampleQueueIndexTable[27 * sampleQueue + j]]
+ .m_nEntityIndex &&
+ sample->field_4 ==
+ m_asSamples[27 * sampleQueue +
+ m_abSampleQueueIndexTable[27 * sampleQueue + j]]
+ .field_4) {
+ toProcess[i] = 1;
+ break;
+ }
+ }
+ if(!toProcess[i]) {
+ if(sample->field_4 <= 255u || !sample->m_bLoopsRemaining) {
+ field_76 = sample->field_76;
+ if(!field_76) continue;
+ if(!sample->m_nLoopCount) {
+ uint8 &vol = sample->m_bVolume;
+ if(sample->field_88 == -1) {
+ sample->field_88 = vol / field_76;
+ if(sample->field_88 <= 0)
+ sample->field_88 = 1;
+ }
+ field_88 = sample->field_88;
+ if(vol <= field_88) {
+ sample->field_76 = 0;
+ continue;
+ }
+ vol -= field_88;
+ }
+ --sample->field_76;
+ if(field_2) {
+ if(sample->field_16 < 20u) ++sample->field_16;
+ }
+ sample->field_56 = 0;
+ }
+ memcpy(&m_sQueueSample, sample, 92);
+ AddSampleToRequestedQueue();
+ }
+ }
+ }
+}
+#endif
+
+void
cAudioManager::AddSampleToRequestedQueue()
{
int32 calculatedVolume;
tActiveSample *sample;
- int32 unknown1;
- uint8 unknown2;
+ uint8 sampleIndex;
bool bReflections;
if(m_sQueueSample.m_nSampleIndex < TOTAL_AUDIO_SAMPLES) {
calculatedVolume = m_sQueueSample.field_16 * (maxVolume - m_sQueueSample.m_bVolume);
- unknown2 = m_bSampleRequestQueuesStatus[m_bActiveSampleQueue];
- if(unknown2 >= m_bActiveSamples) {
- unknown1 = 27 * m_bActiveSampleQueue;
- unknown2 = *(&m_asSamples[53].field_91 + m_bActiveSamples + unknown1);
- if(m_asSamples[unknown1 + unknown2].calculatedVolume <= calculatedVolume)
+ sampleIndex = m_bSampleRequestQueuesStatus[m_bActiveSampleQueue];
+ if(sampleIndex >= m_bActiveSamples) {
+ sampleIndex =
+ m_abSampleQueueIndexTable[m_bActiveSampleQueue][m_bActiveSamples - 1];
+ if(m_asSamples[m_bActiveSampleQueue][sampleIndex].calculatedVolume <=
+ calculatedVolume)
return;
} else {
++m_bSampleRequestQueuesStatus[m_bActiveSampleQueue];
@@ -131,7 +309,7 @@ cAudioManager::AddSampleToRequestedQueue()
if(!m_bDynamicAcousticModelingStatus) m_sQueueSample.m_bReverbFlag = 0;
- sample = &m_asSamples[27 * m_bActiveSampleQueue + unknown2];
+ sample = &m_asSamples[m_bActiveSampleQueue][sampleIndex];
sample->m_nEntityIndex = m_sQueueSample.m_nEntityIndex;
sample->field_4 = m_sQueueSample.field_4;
sample->m_nSampleIndex = m_sQueueSample.m_nSampleIndex;
@@ -159,69 +337,91 @@ cAudioManager::AddSampleToRequestedQueue()
sample->calculatedVolume = m_sQueueSample.calculatedVolume;
sample->field_88 = m_sQueueSample.field_88;
- AddDetailsToRequestedOrderList(unknown2);
+ AddDetailsToRequestedOrderList(sampleIndex);
if(bReflections) AddReflectionsToRequestedQueue();
}
}
+WRAPPER
void
-cAudioManager::AddDetailsToRequestedOrderList(uint8 sample)
+cAudioManager::AgeCrimes()
{
- int32 offset;
- uint32 i = 0;
- if(sample != 0) {
- for(; i < sample; i++) {
- offset = 27 * m_bActiveSampleQueue;
- if(m_asSamples[offset + m_abSampleQueueIndexTable[i + offset]]
- .calculatedVolume > m_asSamples[offset + sample].calculatedVolume)
- break;
- }
- if(i < sample) {
- memmove(&m_abSampleQueueIndexTable[offset + 1 + i],
- &m_abSampleQueueIndexTable[offset + i], m_bActiveSamples - i - 1);
- }
+ EAXJMP(0x580AF0);
+}
+
+int8
+cAudioManager::AutoDetect3DProviders()
+{
+ if(m_bIsInitialised) return cSampleManager.AutoDetect3DProviders();
+
+ return -1;
+}
+
+void
+cAudioManager::CalculateDistance(bool *ptr, float dist)
+{
+ if(*ptr == false) {
+ m_sQueueSample.m_fDistance = sqrt(dist);
+ *ptr = true;
}
- m_abSampleQueueIndexTable[27 * m_bActiveSampleQueue + i] = sample;
+}
+
+bool
+cAudioManager::CheckForAnAudioFileOnCD()
+{
+ return cSampleManager.CheckForAnAudioFileOnCD();
}
void
-cAudioManager::AddReflectionsToRequestedQueue()
+cAudioManager::ClearMissionAudio()
{
- float reflectionDistance;
- int32 noise;
- uint8 emittingVolume = emittingVolume =
- (m_sQueueSample.m_bVolume >> 1) + (m_sQueueSample.m_bVolume >> 3);
+ if(m_bIsInitialised) {
+ m_sMissionAudio.m_nSampleIndex = NO_SAMPLE;
+ m_sMissionAudio.m_bLoadingStatus = 0;
+ m_sMissionAudio.m_bPlayStatus = 0;
+ m_sMissionAudio.field_22 = 0;
+ m_sMissionAudio.m_bIsPlayed = false;
+ m_sMissionAudio.field_12 = 1;
+ m_sMissionAudio.field_24 = 0;
+ }
+}
- for(uint32 i = 0; i < 5u; i++) {
- reflectionDistance = m_afReflectionsDistances[i];
- if(reflectionDistance > 0.0f && reflectionDistance < 100.f &&
- reflectionDistance < m_sQueueSample.m_fSoundIntensity) {
- m_sQueueSample.m_bLoopsRemaining = (reflectionDistance * 0.38873f); // @todo assert value
- if(m_sQueueSample.m_bLoopsRemaining > 5u) {
- m_sQueueSample.m_fDistance = m_afReflectionsDistances[i];
- m_sQueueSample.m_bEmittingVolume = emittingVolume;
- m_sQueueSample.m_bVolume =
- ComputeVolume(emittingVolume, m_sQueueSample.m_fSoundIntensity,
- m_sQueueSample.m_fDistance);
- if(m_sQueueSample.m_bVolume > emittingVolume >> 4) {
- m_sQueueSample.field_4 += ((i + 1) << 8);
- if(m_sQueueSample.m_nLoopCount) {
- noise = RandomDisplacement(
- m_sQueueSample.m_nFrequency >> 5);
- if(noise <= 0)
- m_sQueueSample.m_nFrequency += noise;
- else
- m_sQueueSample.m_nFrequency -= noise;
- }
- m_sQueueSample.field_16 += 20;
- m_sQueueSample.m_vecPos.x = m_avecReflectionsPos[i].x;
- m_sQueueSample.m_vecPos.y = m_avecReflectionsPos[i].y;
- m_sQueueSample.m_vecPos.z = m_avecReflectionsPos[i].z;
- AddSampleToRequestedQueue();
+void
+cAudioManager::ClearRequestedQueue()
+{
+ for(int32 i = 0; i < m_bActiveSamples; i++) {
+ m_abSampleQueueIndexTable[m_bActiveSampleQueue][i] = m_bActiveSamples;
+ }
+ m_bSampleRequestQueuesStatus[m_bActiveSampleQueue] = 0;
+}
+
+int32
+cAudioManager::ComputeDopplerEffectedFrequency(uint32 oldFreq, float position1, float position2,
+ float speedMultiplier)
+{
+ uint32 newFreq = oldFreq;
+ if(!TheCamera.Get_Just_Switched_Status() && speedMultiplier != 0.0f) {
+ float dist = position2 - position1;
+ if(dist != 0.0f) {
+ float speedOfSource = (dist / field_19195) * speedMultiplier;
+ if(speedOfSound > fabsf(speedOfSource)) {
+ if(speedOfSource < 0.0f) {
+ speedOfSource = max(speedOfSource, -1.5f);
+ } else {
+ speedOfSource = min(speedOfSource, 1.5f);
}
+ newFreq = (oldFreq * speedOfSound) / (speedOfSource + speedOfSound);
}
}
}
+ return newFreq;
+}
+
+WRAPPER
+int32
+cAudioManager::ComputePan(float, CVector *)
+{
+ EAXJMP(0x57AD20);
}
uint32
@@ -238,6 +438,131 @@ cAudioManager::ComputeVolume(int emittingVolume, float soundIntensity, float dis
return emittingVolume;
}
+int32
+cAudioManager::CreateEntity(int32 type, CPhysical *entity)
+{
+ if(!m_bIsInitialised) return -4;
+ if(!entity) return -2;
+ if(type >= TOTAL_AUDIO_TYPES) return -1;
+ for(uint32 i = 0; i < 200; i++) {
+ if(!m_asAudioEntities[i].m_bIsUsed) {
+ m_asAudioEntities[i].m_bIsUsed = true;
+ m_asAudioEntities[i].m_bStatus = 0;
+ m_asAudioEntities[i].m_nType = (eAudioType)type;
+ m_asAudioEntities[i].m_pEntity = entity;
+ m_asAudioEntities[i].m_awAudioEvent[0] = SOUND_TOTAL_PED_SOUNDS;
+ m_asAudioEntities[i].m_awAudioEvent[1] = SOUND_TOTAL_PED_SOUNDS;
+ m_asAudioEntities[i].m_awAudioEvent[2] = SOUND_TOTAL_PED_SOUNDS;
+ m_asAudioEntities[i].m_awAudioEvent[3] = SOUND_TOTAL_PED_SOUNDS;
+ m_asAudioEntities[i].field_24 = 0;
+ m_anAudioEntityIndices[m_nAudioEntitiesTotal++] = i;
+ return i;
+ }
+ }
+ return -3;
+}
+
+void
+cAudioManager::DestroyAllGameCreatedEntities()
+{
+ cAudioScriptObject *entity;
+
+ if(m_bIsInitialised) {
+ for(uint32 i = 0; i < 200; i++) {
+ if(m_asAudioEntities[i].m_bIsUsed) {
+ switch(m_asAudioEntities[i].m_nType) {
+ case AUDIOTYPE_PHYSICAL:
+ case AUDIOTYPE_EXPLOSION:
+ case AUDIOTYPE_WEATHER:
+ case AUDIOTYPE_CRANE:
+ case AUDIOTYPE_GARAGE:
+ case AUDIOTYPE_HYDRANT: cAudioManager::DestroyEntity(i); break;
+ case AUDIOTYPE_ONE_SHOT:
+ entity =
+ (cAudioScriptObject *)m_asAudioEntities[i].m_pEntity;
+ if(entity) { delete entity; }
+ DestroyEntity(i);
+ break;
+ default: break;
+ }
+ }
+ }
+ m_nScriptObjectEntityTotal = 0;
+ }
+}
+
+void
+cAudioManager::DestroyEntity(int32 id)
+{
+ if(m_bIsInitialised && id >= 0 && id < totalAudioEntitiesSlots &&
+ m_asAudioEntities[id].m_bIsUsed) {
+ m_asAudioEntities[id].m_bIsUsed = 0;
+ for(int32 i = 0; i < m_nAudioEntitiesTotal; ++i) {
+ if(id == m_anAudioEntityIndices[i]) {
+ if(i < totalAudioEntitiesSlots - 1)
+ memmove(&m_anAudioEntityIndices[i],
+ &m_anAudioEntityIndices[i + 1],
+ 4 * (m_nAudioEntitiesTotal - (i + 1)));
+ m_anAudioEntityIndices[--m_nAudioEntitiesTotal] =
+ totalAudioEntitiesSlots;
+ return;
+ }
+ }
+ }
+}
+
+void
+cAudioManager::DoPoliceRadioCrackle()
+{
+ m_sQueueSample.m_nEntityIndex = m_nPoliceChannelEntity;
+ m_sQueueSample.field_4 = 0;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_POLICE_SCANNER_CRACKLE;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_bIsDistant = 1;
+ m_sQueueSample.field_16 = 10;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_POLICE_SCANNER_CRACKLE);
+ m_sQueueSample.m_bVolume = m_anRandomTable[2] % 20u + 15;
+ m_sQueueSample.m_nLoopCount = 0;
+ m_sQueueSample.m_bEmittingVolume = m_sQueueSample.m_bVolume;
+ m_sQueueSample.m_nLoopStart = cSampleManager.GetSampleLoopStartOffset(188);
+ m_sQueueSample.m_nLoopEnd = cSampleManager.GetSampleLoopEndOffset(188);
+ m_sQueueSample.field_56 = 0;
+ m_sQueueSample.m_bReverbFlag = 0;
+ m_sQueueSample.m_bOffset = 63;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+}
+
+void
+cAudioManager::GenerateIntegerRandomNumberTable()
+{
+ for(int32 i = 0; i < 5; i++) { m_anRandomTable[i] = rand(); }
+}
+
+float
+cAudioManager::GetDistanceSquared(CVector *v)
+{
+ const CVector &c = TheCamera.GetPosition();
+ return sq(v->x - c.x) + sq(v->y - c.y) + sq((v->z - c.z) * 0.2f);
+}
+
+void
+cAudioManager::TranslateEntity(CVector *v1, CVector *v2)
+{
+ const RwMatrix &cM = TheCamera.GetMatrix().m_matrix;
+ const CVector &cV = TheCamera.GetPosition();
+
+ float a = v1->z - cV.z;
+ float b = v1->y - cV.y;
+ float c = v1->x - cV.x;
+
+ v2->x = cM.right.y * b + cM.right.x * c + cM.right.z * a;
+ v2->y = cM.up.y * b + cM.up.x * c + cM.up.z * a;
+ v2->z = cM.at.y * b + cM.at.x * c + cM.at.z * a;
+}
+
void
cAudioManager::Initialise()
{
@@ -262,27 +587,28 @@ cAudioManager::Initialise()
void
cAudioManager::PostInitialiseGameSpecificSetup()
{
- m_nFireAudioEntity = CreateEntity(
- AUDIOTYPE_FIRE, (CPhysical *)0x8F31D0); // last is addr of firemanager @todo change
- if(m_nFireAudioEntity >= 0) cAudioManager::SetEntityStatus(m_nFireAudioEntity, 1);
+ m_nFireAudioEntity =
+ CreateEntity(AUDIOTYPE_FIRE,
+ (CPhysical *)0x8F31D0); // last is addr of firemanager @todo change
+ if(m_nFireAudioEntity >= 0) SetEntityStatus(m_nFireAudioEntity, 1);
m_nCollisionEntity = CreateEntity(AUDIOTYPE_COLLISION, (CPhysical *)1);
- if(m_nCollisionEntity >= 0) cAudioManager::SetEntityStatus(m_nCollisionEntity, 1);
+ if(m_nCollisionEntity >= 0) SetEntityStatus(m_nCollisionEntity, 1);
m_nFrontEndEntity = CreateEntity(AUDIOTYPE_FRONTEND, (CPhysical *)1);
- if(m_nFrontEndEntity >= 0) cAudioManager::SetEntityStatus(m_nFrontEndEntity, 1);
+ if(m_nFrontEndEntity >= 0) SetEntityStatus(m_nFrontEndEntity, 1);
m_nProjectileEntity = CreateEntity(AUDIOTYPE_PROJECTILE, (CPhysical *)1);
- if(m_nProjectileEntity >= 0) cAudioManager::SetEntityStatus(m_nProjectileEntity, 1);
+ if(m_nProjectileEntity >= 0) SetEntityStatus(m_nProjectileEntity, 1);
m_nWaterCannonEntity = CreateEntity(AUDIOTYPE_WATER_CANNON, (CPhysical *)1);
- if(m_nWaterCannonEntity >= 0) cAudioManager::SetEntityStatus(m_nWaterCannonEntity, 1);
+ if(m_nWaterCannonEntity >= 0) SetEntityStatus(m_nWaterCannonEntity, 1);
m_nPoliceChannelEntity = CreateEntity(AUDIOTYPE_D, (CPhysical *)1);
- if(m_nPoliceChannelEntity >= 0) cAudioManager::SetEntityStatus(m_nPoliceChannelEntity, 1);
+ if(m_nPoliceChannelEntity >= 0) SetEntityStatus(m_nPoliceChannelEntity, 1);
m_nBridgeEntity = CreateEntity(AUDIOTYPE_BRIDGE, (CPhysical *)1);
- if(m_nBridgeEntity >= 0) cAudioManager::SetEntityStatus(m_nBridgeEntity, 1);
+ if(m_nBridgeEntity >= 0) SetEntityStatus(m_nBridgeEntity, 1);
m_sMissionAudio.m_nSampleIndex = NO_SAMPLE;
m_sMissionAudio.m_bLoadingStatus = 0;
@@ -348,7 +674,6 @@ cAudioManager::GetMissionAudioLoadingStatus()
return true;
}
-
uint8
cAudioManager::GetNum3DProvidersAvailable()
{
@@ -356,14 +681,6 @@ cAudioManager::GetNum3DProvidersAvailable()
return 0;
}
-int8
-cAudioManager::AutoDetect3DProviders()
-{
- if(m_bIsInitialised) return cSampleManager.AutoDetect3DProviders();
-
- return -1;
-}
-
bool
cAudioManager::IsMP3RadioChannelAvailable()
{
@@ -410,12 +727,6 @@ cAudioManager::SetSpeakerConfig(int32 conf)
cSampleManager.SetSpeakerConfig(conf);
}
-void
-cAudioManager::ProcessJumboFlying()
-{
- if(SetupJumboFlySound(127u)) SetupJumboEngineSound(63u, 22050);
-}
-
WRAPPER
bool cAudioManager::SetupJumboEngineSound(uint8, int32) { EAXJMP(0x56F140); }
@@ -441,15 +752,6 @@ cAudioManager::SetMissionScriptPoliceAudio(int32 sfx)
}
}
-void
-cAudioManager::CalculateDistance(bool *ptr, float dist)
-{
- if(*ptr == false) {
- m_sQueueSample.m_fDistance = Sqrt(dist);
- *ptr = true;
- }
-}
-
bool
cAudioManager::UsesSiren(int32 model)
{
@@ -496,30 +798,154 @@ cAudioManager::MissionScriptAudioUsesPoliceChannel(int32 soundMission)
}
}
-uint8
+char *
cAudioManager::Get3DProviderName(uint8 id)
{
- if(m_bIsInitialised) return 0;
+ if(!m_bIsInitialised) return 0;
if(id >= num3DProvidersAvailable) return 0;
return asName3DProviders[id];
}
-void
-cAudioManager::ProcessJumboTaxi()
-{
- if(SetupJumboFlySound(20u)) {
- if(SetupJumboTaxiSound(75u)) SetupJumboWhineSound(18u, 29500);
+bool
+cAudioManager::SetupJumboFlySound(uint8 emittingVol)
+{
+ int32 vol;
+
+ if(m_sQueueSample.m_fDistance >= 440.0) return 0;
+
+ vol = ComputeVolume(emittingVol, 440.0f, m_sQueueSample.m_fDistance);
+ m_sQueueSample.m_bVolume = vol;
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_JUMBO_FLY_SOUND;
+ m_sQueueSample.field_4 = 0;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_16 = 1;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_nLoopCount = 0;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_JUMBO_FLY_SOUND);
+ m_sQueueSample.m_nLoopStart =
+ cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_fSoundIntensity = 440.0f;
+ m_sQueueSample.field_56 = 0;
+ m_sQueueSample.field_48 = 4.0;
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.field_76 = 5;
+ m_sQueueSample.m_nLoopEnd =
+ cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+ AddSampleToRequestedQueue();
}
+ return 1;
}
-WRAPPER
-bool cAudioManager::SetupJumboFlySound(uint8) { EAXJMP(0x56F230); }
+bool
+cAudioManager::SetupJumboRumbleSound(uint8 emittingVol)
+{
+ if(m_sQueueSample.m_fDistance >= 240.f) return 0;
+
+ m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 240.f, m_sQueueSample.m_fDistance);
+
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.field_4 = 5;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_JUMBO_RUMBLE_SOUND;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_bIsDistant = 1;
+ m_sQueueSample.field_16 = 1;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_JUMBO_RUMBLE_SOUND);
+ m_sQueueSample.m_nLoopCount = 0;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_nLoopStart =
+ cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nLoopEnd =
+ cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.field_48 = 4.0;
+ m_sQueueSample.m_fSoundIntensity = 240.0;
+ m_sQueueSample.field_56 = 0;
+ m_sQueueSample.field_76 = 12;
+ m_sQueueSample.m_bOffset = 0;
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ m_sQueueSample.field_4 = 6;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_JUMBO_RUMBLE_SOUND;
+ m_sQueueSample.m_nFrequency += 200;
+ m_sQueueSample.m_bOffset = 127;
+ AddSampleToRequestedQueue();
+ }
+ return 1;
+}
-WRAPPER
-bool cAudioManager::SetupJumboTaxiSound(uint8) { EAXJMP(0x56EF20); }
+uint8 &gJumboVolOffsetPercentage = *(uint8 *)0x6508ED;
-WRAPPER
-bool cAudioManager::SetupJumboWhineSound(uint8, int32) { EAXJMP(0x56F070); }
+bool
+cAudioManager::SetupJumboTaxiSound(uint8 vol)
+{
+ uint8 emittingVol;
+
+ if(m_sQueueSample.m_fDistance >= 180.f) return 0;
+
+ emittingVol = (vol >> 1) + ((vol >> 1) * m_sQueueSample.m_fDistance * 0.0055556f);
+
+ if(m_sQueueSample.m_fDistance * 0.0055556f < 0.7f)
+ emittingVol -= emittingVol * gJumboVolOffsetPercentage / 100;
+ m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 180.f, m_sQueueSample.m_fDistance);
+
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.field_4 = 1;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_JUMBO_TAXI_SOUND;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_16 = 1;
+ m_sQueueSample.m_nFrequency = GetJumboTaxiFreq();
+ m_sQueueSample.m_nLoopCount = 0;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_nLoopStart =
+ cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nLoopEnd =
+ cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.field_48 = 4.0f;
+ m_sQueueSample.m_fSoundIntensity = 180.0f;
+ m_sQueueSample.field_56 = 0;
+ m_sQueueSample.field_76 = 4;
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ }
+ return 1;
+}
+
+bool
+cAudioManager::SetupJumboWhineSound(uint8 emittingVol, int32 freq)
+{
+ if(m_sQueueSample.m_fDistance >= 170.f) return 0;
+
+ m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 170.f, m_sQueueSample.m_fDistance);
+
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.field_4 = 2;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_JUMBO_WHINE_SOUND;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_16 = 1;
+ m_sQueueSample.m_nFrequency = freq;
+ m_sQueueSample.m_nLoopCount = 0;
+ m_sQueueSample.m_bEmittingVolume = emittingVol;
+ m_sQueueSample.m_nLoopStart =
+ cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nLoopEnd =
+ cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.field_48 = 4.0f;
+ m_sQueueSample.m_fSoundIntensity = 170.0f;
+ m_sQueueSample.field_56 = 0;
+ m_sQueueSample.field_76 = 4;
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ }
+ return 1;
+}
void
cAudioManager::PlayLoadedMissionAudio()
@@ -559,20 +985,6 @@ cAudioManager::InterrogateAudioEntities()
}
}
-void
-cAudioManager::ClearRequestedQueue()
-{
- for(int32 i = 0; i < m_bActiveSamples; i++) {
- m_abSampleQueueIndexTable[i + 27 * m_bActiveSampleQueue] = m_bActiveSamples;
- }
- m_bSampleRequestQueuesStatus[m_bActiveSampleQueue] = 0;
-}
-
-// void cAudioManager::AgeCrimes()
-//{
-
-//}
-
bool
cAudioManager::UsesReverseWarning(int32 model)
{
@@ -593,59 +1005,6 @@ cAudioManager::GetJumboTaxiFreq()
return (60.833f * m_sQueueSample.m_fDistance) + 22050;
}
-void
-cAudioManager::ProcessPhysical(int32 id)
-{
- CPhysical *entity = m_asAudioEntities[id].m_pEntity;
- if(entity) {
- switch(entity->m_type & 7) {
- case ENTITY_TYPE_VEHICLE: ProcessVehicle(m_asAudioEntities[id].m_pEntity); break;
- case ENTITY_TYPE_PED: ProcessPed(m_asAudioEntities[id].m_pEntity); break;
- default: return;
- }
- }
-}
-
-WRAPPER
-void
-cAudioManager::ProcessVehicle(CPhysical *)
-{
- EAXJMP(0x569A00);
-}
-
-WRAPPER
-void
-cAudioManager::ProcessPed(CPhysical *)
-{
- EAXJMP(0x56F450);
-}
-
-WRAPPER
-void
-cAudioManager::ProcessPlane(void *ptr)
-{
- EAXJMP(0x56E860);
-}
-
-void
-cAudioManager::ClearMissionAudio()
-{
- if(m_bIsInitialised) {
- m_sMissionAudio.m_nSampleIndex = NO_SAMPLE;
- m_sMissionAudio.m_bLoadingStatus = 0;
- m_sMissionAudio.m_bPlayStatus = 0;
- m_sMissionAudio.field_22 = 0;
- m_sMissionAudio.m_bIsPlayed = false;
- m_sMissionAudio.field_12 = 1;
- m_sMissionAudio.field_24 = 0;
- }
-}
-
-// void
-// cAudioManager::ProcessReverb()
-//{
-//}
-
bool
cAudioManager::IsMissionAudioSampleFinished()
{
@@ -657,9 +1016,6 @@ cAudioManager::IsMissionAudioSampleFinished()
}
WRAPPER
-void cAudioManager::ProcessEntity(int32) { EAXJMP(0x569870); }
-
-WRAPPER
void
cAudioManager::InitialisePoliceRadio()
{
@@ -708,50 +1064,6 @@ cAudioManager::IsAudioInitialised() const
return m_bIsInitialised;
}
-int32
-cAudioManager::CreateEntity(int32 type, CPhysical *entity)
-{
- if(!m_bIsInitialised) return -4;
- if(!entity) return -2;
- if(type >= TOTAL_AUDIO_TYPES) return -1;
- for(uint32 i = 0; i < 200; i++) {
- if(!m_asAudioEntities[i].m_bIsUsed) {
- m_asAudioEntities[i].m_bIsUsed = true;
- m_asAudioEntities[i].m_bStatus = 0;
- m_asAudioEntities[i].m_nType = (eAudioType)type;
- m_asAudioEntities[i].m_pEntity = entity;
- m_asAudioEntities[i].m_awAudioEvent[0] = SOUND_TOTAL_PED_SOUNDS;
- m_asAudioEntities[i].m_awAudioEvent[1] = SOUND_TOTAL_PED_SOUNDS;
- m_asAudioEntities[i].m_awAudioEvent[2] = SOUND_TOTAL_PED_SOUNDS;
- m_asAudioEntities[i].m_awAudioEvent[3] = SOUND_TOTAL_PED_SOUNDS;
- m_asAudioEntities[i].field_24 = 0;
- m_anAudioEntityIndices[m_nAudioEntitiesTotal++] = i;
- return i;
- }
- }
- return -3;
-}
-
-void
-cAudioManager::DestroyEntity(int32 id)
-{
- if(m_bIsInitialised && id >= 0 && id < totalAudioEntitiesSlots &&
- m_asAudioEntities[id].m_bIsUsed) {
- m_asAudioEntities[id].m_bIsUsed = 0;
- for(int32 i = 0; i < m_nAudioEntitiesTotal; ++i) {
- if(id == m_anAudioEntityIndices[i]) {
- if(i < totalAudioEntitiesSlots - 1)
- memmove(&m_anAudioEntityIndices[i],
- &m_anAudioEntityIndices[i + 1],
- 4 * (m_nAudioEntitiesTotal - (i + 1)));
- m_anAudioEntityIndices[--m_nAudioEntitiesTotal] =
- totalAudioEntitiesSlots;
- return;
- }
- }
- }
-}
-
void
cAudioManager::SetEntityStatus(int32 id, bool status)
{
@@ -799,12 +1111,6 @@ cAudioManager::PostTerminateGameSpecificShutdown()
;
}
-void
-cAudioManager::GenerateIntegerRandomNumberTable()
-{
- for(int32 i = 0; i < 5; i++) { m_anRandomTable[i] = rand(); }
-}
-
bool &bPlayerJustEnteredCar = *(bool *)0x6508C4;
void
@@ -830,6 +1136,107 @@ cAudioManager::GetPhrase(uint32 *phrase, uint32 *prevPhrase, uint32 sample, uint
*prevPhrase = *phrase;
}
+uint8 &jumboVolOffset = *(uint8 *)0x6508ED;
+
+void
+cAudioManager::DoJumboVolOffset()
+{
+ if(!(m_nTimeOfRecentCrime % (m_anRandomTable[0] % 6u + 3)))
+ jumboVolOffset = m_anRandomTable[1] % 60u;
+}
+
+int32
+cAudioManager::GetPedCommentSfx(CPed *ped, int32 sound)
+{
+ if(ped->IsPlayer()) return GetPlayerTalkSfx(sound);
+
+ switch(ped->m_modelIndex) {
+ case MI_COP: return GetCopTalkSfx(sound);
+ case MI_SWAT: return GetSwatTalkSfx(sound);
+ case MI_FBI: return GetFBITalkSfx(sound);
+ case MI_ARMY: return GetArmyTalkSfx(sound);
+ case MI_MEDIC: return GetMedicTalkSfx(sound);
+ case MI_FIREMAN: return GetFiremanTalkSfx(sound);
+ case MI_MALE01: return GetNormalMaleTalkSfx(sound);
+ case MI_TAXI_D: return GetTaxiDriverTalkSfx(sound);
+ case MI_PIMP: return GetPimpTalkSfx(sound);
+ case MI_GANG01:
+ case MI_GANG02: return GetMafiaTalkSfx(sound);
+ case MI_GANG03:
+ case MI_GANG04: return GetTriadTalkSfx(sound);
+ case MI_GANG05:
+ case MI_GANG06: return GetDiabloTalkSfx(sound);
+ case MI_GANG07:
+ case MI_GANG08: return GetYakuzaTalkSfx(sound);
+ case MI_GANG09:
+ case MI_GANG10: return GetYardieTalkSfx(sound);
+ case MI_GANG11:
+ case MI_GANG12: return GetColumbianTalkSfx(sound);
+ case MI_GANG13:
+ case MI_GANG14: return GetHoodTalkSfx(sound);
+ case MI_CRIMINAL01: return GetBlackCriminalTalkSfx(sound);
+ case MI_CRIMINAL02: return GetWhiteCriminalTalkSfx(sound);
+ case MI_SPECIAL01:
+ case MI_SPECIAL02:
+ case MI_SPECIAL03:
+ case MI_SPECIAL04: return GetSpecialCharacterTalkSfx(ped->m_modelIndex, sound);
+ case MI_MALE02: return GetMaleNo2TalkSfx(sound);
+ case MI_MALE03:
+ case MI_P_MAN1:
+ case MI_P_MAN2: return GetBlackProjectMaleTalkSfx(sound, ped->m_modelIndex);
+ case MI_FATMALE01: return GetWhiteFatMaleTalkSfx(sound);
+ case MI_FATMALE02: return GetBlackFatMaleTalkSfx(sound);
+ case MI_FEMALE01: return GetBlackCasualFemaleTalkSfx(sound);
+ case MI_FEMALE02:
+ case MI_CAS_WOM: return GetWhiteCasualFemaleTalkSfx(sound);
+ case MI_FEMALE03: return GetFemaleNo3TalkSfx(sound);
+ case MI_FATFEMALE01: return GetBlackFatFemaleTalkSfx(sound);
+ case MI_FATFEMALE02: return GetWhiteFatFemaleTalkSfx(sound);
+ case MI_PROSTITUTE: return GetBlackFemaleProstituteTalkSfx(sound);
+ case MI_PROSTITUTE2: return GetWhiteFemaleProstituteTalkSfx(sound);
+ case MI_P_WOM1: return GetBlackProjectFemaleOldTalkSfx(sound);
+ case MI_P_WOM2: return GetBlackProjectFemaleYoungTalkSfx(sound);
+ case MI_CT_MAN1: return GetChinatownMaleOldTalkSfx(sound);
+ case MI_CT_MAN2: return GetChinatownMaleYoungTalkSfx(sound);
+ case MI_CT_WOM1: return GetChinatownFemaleOldTalkSfx(sound);
+ case MI_CT_WOM2: return GetChinatownFemaleYoungTalkSfx(sound);
+ case MI_LI_MAN1:
+ case MI_LI_MAN2: return GetLittleItalyMaleTalkSfx(sound);
+ case MI_LI_WOM1: return GetLittleItalyFemaleOldTalkSfx(sound);
+ case MI_LI_WOM2: return GetLittleItalyFemaleYoungTalkSfx(sound);
+ case MI_DOCKER1: return GetWhiteDockerMaleTalkSfx(sound);
+ case MI_DOCKER2: return GetBlackDockerMaleTalkSfx(sound);
+ case MI_SCUM_MAN: return GetScumMaleTalkSfx(sound);
+ case MI_SCUM_WOM: return GetScumFemaleTalkSfx(sound);
+ case MI_WORKER1: return GetWhiteWorkerMaleTalkSfx(sound);
+ case MI_WORKER2: return GetBlackWorkerMaleTalkSfx(sound);
+ case MI_B_MAN1:
+ case MI_B_MAN3: return GetBusinessMaleYoungTalkSfx(sound, ped->m_modelIndex);
+ case MI_B_MAN2: return GetBusinessMaleOldTalkSfx(sound);
+ case MI_B_WOM1:
+ case MI_B_WOM2: return GetWhiteBusinessFemaleTalkSfx(sound, ped->m_modelIndex);
+ case MI_B_WOM3: return GetBlackBusinessFemaleTalkSfx(sound);
+ case MI_MOD_MAN: return GetSupermodelMaleTalkSfx(sound);
+ case MI_MOD_WOM: return GetSupermodelFemaleTalkSfx(sound);
+ case MI_ST_MAN: return GetStewardMaleTalkSfx(sound);
+ case MI_ST_WOM: return GetStewardFemaleTalkSfx(sound);
+ case MI_FAN_MAN1:
+ case MI_FAN_MAN2: return GetFanMaleTalkSfx(sound, ped->m_modelIndex);
+ case MI_FAN_WOM: return GetFanFemaleTalkSfx(sound);
+ case MI_HOS_MAN: return GetHospitalMaleTalkSfx(sound);
+ case MI_HOS_WOM: return GetHospitalFemaleTalkSfx(sound);
+ case MI_CONST1: return GetWhiteConstructionWorkerTalkSfx(sound);
+ case MI_CONST2: return GetBlackConstructionWorkerTalkSfx(sound);
+ case MI_SHOPPER1:
+ case MI_SHOPPER2:
+ case MI_SHOPPER3: return GetShopperFemaleTalkSfx(sound, ped->m_modelIndex);
+ case MI_STUD_MAN: return GetStudentMaleTalkSfx(sound);
+ case MI_STUD_WOM: return GetStudentFemaleTalkSfx(sound);
+ case MI_CAS_MAN: return GetCasualMaleOldTalkSfx(sound);
+ default: return GetGenericMaleTalkSfx(sound);
+ }
+}
+
uint32
cAudioManager::GetPlayerTalkSfx(int16 sound)
{
@@ -2953,6 +3360,2260 @@ cAudioManager::GetGenericFemaleTalkSfx(int16 sound)
return sfx;
}
+#if 1
+
+WRAPPER
+void
+cAudioManager::ProcessActiveQueues()
+{
+ EAXJMP(0x57BA60);
+}
+
+#else
+void
+cAudioManager::ProcessActiveQueues()
+{
+ int v3; // ecx
+ cAudioManager *v4; // edx
+ tActiveSample *v5; // ebx
+ cAudioManager *v6; // edi
+ tActiveSample *v7; // esi
+ char v8; // al
+ unsigned __int8 v9; // dl
+ double v10; // st7
+ double v11; // st6
+ float a4; // ST08_4
+ float a3; // ST04_4
+ int activeSampleFreq; // ecx
+ int freq; // edi
+ int newFreq; // ecx
+ int v17; // eax
+ char v18; // al
+ unsigned __int8 v19; // al
+ float v20; // ST0C_4
+ int v21; // edx
+ unsigned __int8 v22; // bl
+ cAudioManager *v23; // ebp
+ int v24; // ecx
+ cAudioManager *v25; // edx
+ tActiveSample *v26; // ebx
+ cAudioManager *v27; // ebp
+ unsigned int v28; // edi
+ unsigned int v29; // eax
+ unsigned __int8 v30; // cl
+ double v31; // st4
+ double v32; // st7
+ double v33; // st6
+ double v34; // st5
+ float v35; // ST0C_4
+ float v36; // ST08_4
+ float v37; // ST04_4
+ float v38; // ST0C_4
+ int v39; // edx
+ int v40; // [esp+Ch] [ebp-58h]
+ int v41; // [esp+Ch] [ebp-58h]
+ unsigned int v42; // [esp+10h] [ebp-54h]
+ int v43; // [esp+10h] [ebp-54h]
+ char v44; // [esp+14h] [ebp-50h]
+ unsigned __int8 v45; // [esp+14h] [ebp-50h]
+ unsigned __int8 l; // [esp+24h] [ebp-40h]
+ unsigned __int8 j; // [esp+28h] [ebp-3Ch]
+ unsigned __int8 k; // [esp+34h] [ebp-30h]
+ unsigned __int8 i; // [esp+38h] [ebp-2Ch]
+ CVector a2; // [esp+48h] [ebp-1Ch]
+
+ for(uint32 i = 0; i < m_bActiveSamples; i++) {
+ m_asSamples[m_bActiveSampleQueue][i].m_bIsProcessed = 0;
+ m_asActiveSamples[i].m_bIsProcessed = 0;
+ }
+
+ for(i = 0;; ++i) {
+ v21 = m_bActiveSampleQueue;
+ if(i >= m_bSampleRequestQueuesStatus[v21]) break;
+ v3 = i + 27 * v21;
+ v4 = (this + 2484 * v21);
+ v5 = &v4->m_asSamples[m_abSampleQueueIndexTable[v3]];
+ if(v4->m_asSamples[m_abSampleQueueIndexTable[v3]].m_nSampleIndex != NO_SAMPLE) {
+ v6 = this;
+ for(j = 0;; ++j) {
+ if(j >= m_bActiveSamples) goto LABEL_58;
+ v7 = m_asActiveSamples;
+ if(v5->m_nEntityIndex == m_asActiveSamples[0].m_nEntityIndex &&
+ v5->field_4 == m_asActiveSamples[0].field_4 &&
+ v5->m_nSampleIndex == m_asActiveSamples[0].m_nSampleIndex) {
+ break;
+ }
+ LABEL_56:
+ v6 = (v6 + 92);
+ }
+ if(v5->m_nLoopCount) {
+ if(m_nTimeOfRecentCrime & 1) {
+ if(!(j & 1)) {
+ v8 = 0;
+ goto LABEL_17;
+ }
+ LABEL_16:
+ v8 = 1;
+ } else {
+ if(!(j & 1)) goto LABEL_16;
+ v8 = 0;
+ }
+ LABEL_17:
+ if(v8 && !cSampleManager.GetChannelUsedFlag(j)) {
+ v5->m_bLoopEnded = 1;
+ m_asActiveSamples[0].m_bLoopEnded = 1;
+ m_asActiveSamples[0].m_nSampleIndex = NO_SAMPLE;
+ v7->m_nEntityIndex = -5;
+ goto LABEL_56;
+ }
+ }
+ v5->m_bIsProcessed = 1;
+ m_asActiveSamples[0].m_bIsProcessed = 1;
+ v5->field_88 = -1;
+ if(!v5->field_56) {
+ if(v5->m_bIsDistant) {
+ if(field_4) {
+ v9 = v5->m_bEmittingVolume;
+ if(v9 >= 63u)
+ v42 = 63;
+ else
+ v42 = v9;
+ v43 = 2 * v42;
+ } else {
+ v43 = v5->m_bEmittingVolume;
+ }
+ cSampleManager.SetChannelFrequency(j, v5->m_nFrequency);
+ cSampleManager.SetChannelEmittingVolume(j, v43);
+ } else {
+ v10 = m_asActiveSamples[0].m_fDistance;
+ v11 = v5->m_fDistance;
+ m_asActiveSamples[0].m_fDistance = v5->m_fDistance;
+ a4 = v11;
+ a3 = v10;
+ v5->m_nFrequency = ComputeDopplerEffectedFrequency(
+ v5->m_nFrequency, a3, a4, v5->field_48);
+ activeSampleFreq = m_asActiveSamples[0].m_nFrequency;
+ freq = v5->m_nFrequency;
+ if(freq != activeSampleFreq) {
+ if(freq <= activeSampleFreq) {
+ if(activeSampleFreq - 6000 > freq)
+ freq = activeSampleFreq - 6000;
+ newFreq = freq;
+ } else if(activeSampleFreq + 6000 >= freq) {
+ newFreq = v5->m_nFrequency;
+ } else {
+ newFreq = activeSampleFreq + 6000;
+ }
+ v7->m_nFrequency = newFreq;
+ cSampleManager.SetChannelFrequency(j, newFreq);
+ }
+ v40 = v7->m_bEmittingVolume;
+ v17 = v5->m_bEmittingVolume;
+ if(v17 != v40) {
+ if(v17 <= v40) {
+ if(v40 - 10 > v17) v17 = v40 - 10;
+ v41 = v17;
+ } else if(v40 + 10 >= v17) {
+ v41 = v5->m_bEmittingVolume;
+ } else {
+ v41 = v40 + 10;
+ }
+ if(field_4) {
+ if(v41 >= 63)
+ v18 = 63;
+ else
+ v18 = v41;
+ v19 = 2 * v18;
+ } else {
+ v19 = v41;
+ }
+ cSampleManager.SetChannelEmittingVolume(j, v19);
+ v7->m_bEmittingVolume = v41;
+ }
+ TranslateEntity(&v5->m_vecPos, &a2);
+ cSampleManager.SetChannel3DPosition(j, a2.x, a2.y, a2.z);
+ v20 = 0.25f * v5->m_fSoundIntensity;
+ cSampleManager.SetChannel3DDistances(
+ j, v5->m_fSoundIntensity, v20);
+ }
+ cSampleManager.SetChannelReverbFlag(j, v5->m_bReverbFlag);
+ continue;
+ }
+ v5->m_bIsProcessed = 0;
+ m_asActiveSamples[0].m_bIsProcessed = 0;
+ goto LABEL_56;
+ }
+ LABEL_58:;
+ }
+ v22 = 0;
+ v23 = this;
+ for(uint32 i = 0; v22 < m_bActiveSamples; i++) {
+ if(v23->m_asActiveSamples[0].m_nSampleIndex != NO_SAMPLE &&
+ !v23->m_asActiveSamples[0].m_bIsProcessed) {
+ cSampleManager.StopChannel(i);
+ v23->m_asActiveSamples[0].m_nSampleIndex = NO_SAMPLE;
+ v23->m_asActiveSamples[0].m_nEntityIndex = -5;
+ }
+ v23 = (v23 + 92);
+ }
+ for(k = 0; k < m_bSampleRequestQueuesStatus[m_bActiveSampleQueue]; ++k) {
+ v24 = k + 27 * v39;
+ v25 = (this + 2484 * v39);
+ v26 = &v25->m_asSamples[m_abSampleQueueIndexTable[v24]];
+ if(!v25->m_asSamples[m_abSampleQueueIndexTable[v24]].m_bIsProcessed &&
+ !v25->m_asSamples[m_abSampleQueueIndexTable[v24]].m_bLoopEnded &&
+ m_asAudioEntities[v26->m_nEntityIndex].m_bIsUsed &&
+ v25->m_asSamples[m_abSampleQueueIndexTable[v24]].m_nSampleIndex < NO_SAMPLE) {
+ if(v25->m_asSamples[m_abSampleQueueIndexTable[v24]].field_4 > 255u &&
+ v25->m_asSamples[m_abSampleQueueIndexTable[v24]].m_nLoopCount &&
+ v25->m_asSamples[m_abSampleQueueIndexTable[v24]].m_bLoopsRemaining) {
+ --v25->m_asSamples[m_abSampleQueueIndexTable[v24]]
+ .m_bLoopsRemaining;
+ v26->field_76 = 1;
+ } else {
+ v27 = this;
+ for(l = 0; l < m_bActiveSamples; ++l) {
+ if(!v27->m_asActiveSamples[0].m_bIsProcessed) {
+ if(!v26->m_nLoopCount) goto LABEL_80;
+ v28 = v26->m_nFrequency / field_19192;
+ v29 = v26->m_nLoopCount *
+ cSampleManager.GetSampleLength(
+ v26->m_nSampleIndex);
+ if(v28) {
+ v26->field_76 = v29 / v28 + 1;
+ LABEL_80:
+ memcpy(v27->m_asActiveSamples, v26, 92);
+ if(!v27->m_asActiveSamples[0].m_bIsDistant)
+ TranslateEntity(
+ &v27->m_asActiveSamples[0]
+ .m_vecPos,
+ &a2);
+ if(field_4) {
+ if(v27->m_asActiveSamples[0]
+ .m_bEmittingVolume >= 63u)
+ v44 = 63;
+ else
+ v44 =
+ v27
+ ->m_asActiveSamples
+ [0]
+ .m_bEmittingVolume;
+ v45 = 2 * v44;
+ } else {
+ v45 = v27->m_asActiveSamples[0]
+ .m_bEmittingVolume;
+ }
+ if(cSampleManager.InitialiseChannel(
+ l,
+ v27->m_asActiveSamples[0]
+ .m_nSampleIndex,
+ v27->m_asActiveSamples[0]
+ .m_bBankIndex)) {
+ cSampleManager.SetChannelFrequency(
+ l, v27->m_asActiveSamples[0]
+ .m_nFrequency);
+ cSampleManager
+ .SetChannelEmittingVolume(l,
+ v45);
+ cSampleManager.SetChannelLoopPoints(
+ l,
+ v27->m_asActiveSamples[0]
+ .m_nLoopStart,
+ v27->m_asActiveSamples[0]
+ .m_nLoopEnd);
+ cSampleManager.SetChannelLoopCount(
+ l, v27->m_asActiveSamples[0]
+ .m_nLoopCount);
+ cSampleManager.SetChannelReverbFlag(
+ l, v27->m_asActiveSamples[0]
+ .m_bReverbFlag);
+ if(v27->m_asActiveSamples[0]
+ .m_bIsDistant) {
+ v30 = v27->m_asActiveSamples
+ [0]
+ .m_bOffset;
+ if(v30 == 63) {
+ v31 = 0.0f;
+ } else if(v30 >= 63u) {
+ v31 = (v30 - 63) *
+ 15.873f;
+ } else {
+ v31 = -((63 - v30) *
+ 15.873f);
+ }
+ v32 = v31;
+ v33 = 0.0f;
+ v34 = 0.0f;
+ v27->m_asActiveSamples[0]
+ .m_fSoundIntensity =
+ 100000.0f;
+ } else {
+ v32 = a2.x;
+ v33 = a2.y;
+ v34 = a2.z;
+ }
+ v35 = v34;
+ v36 = v33;
+ v37 = v32;
+ cSampleManager.SetChannel3DPosition(
+ l, v37, v36, v35);
+ v38 = 0.25f *
+ v27->m_asActiveSamples[0]
+ .m_fSoundIntensity;
+ cSampleManager
+ .SetChannel3DDistances(
+ l,
+ v27->m_asActiveSamples[0]
+ .m_fSoundIntensity,
+ v38);
+ cSampleManager.StartChannel(l);
+ }
+ v27->m_asActiveSamples[0].m_bIsProcessed =
+ 1;
+ v26->m_bIsProcessed = 1;
+ v26->field_88 = -1;
+ break;
+ }
+ }
+ v27 = (v27 + 92);
+ }
+ }
+ }
+ }
+}
+#endif
+
+bool
+cAudioManager::ProcessAirBrakes(cVehicleParams *params)
+{
+ CAutomobile *automobile;
+ uint8 rand;
+
+ if(params->m_fDistance > 900.0f) return 0;
+ automobile = (CAutomobile *)params->m_pVehicle;
+ if(!automobile->bEngineOn) return 1;
+
+ if((automobile->m_fVelocityChangeForAudio < 0.025f ||
+ params->m_fVelocityChange >= 0.025f) &&
+ (automobile->m_fVelocityChangeForAudio > -0.025f || params->m_fVelocityChange <= 0.025f))
+ return 1;
+
+ CalculateDistance((bool *)params, params->m_fDistance);
+ rand = m_anRandomTable[0] % 10u + 70;
+ m_sQueueSample.m_bVolume = ComputeVolume(rand, 30.0f, m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.field_4 = 13;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_VEHICLE_AIR_BRAKES;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_VEHICLE_AIR_BRAKES);
+ m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency >> 4);
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_16 = 10;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.m_bEmittingVolume = rand;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.field_56 = 1;
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ }
+
+ return 1;
+}
+
+void
+cAudioManager::ProcessAirportScriptObject(uint8 sound)
+{
+
+ float dist;
+ float distSquared;
+ float maxDist;
+
+ static uint8 counter = 0;
+
+ uint32 time = CTimer::GetTimeInMilliseconds();
+ if(time > audioLogicTimers[3]) {
+ switch(sound) {
+ case SCRIPT_SOUND_AIRPORT_LOOP_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ break;
+ case SCRIPT_SOUND_AIRPORT_LOOP_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ break;
+ default: break;
+ }
+ distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
+ if(distSquared < maxDist) {
+ dist = sqrt(distSquared);
+ m_sQueueSample.m_fDistance = dist;
+ m_sQueueSample.m_bVolume = ComputeVolume(
+ 110u, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.m_nSampleIndex =
+ (m_anRandomTable[1] & 3) + AUDIO_SAMPLE_AIRPORT_1;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.field_4 = counter++;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.field_56 = 1;
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ m_sQueueSample.m_bEmittingVolume = 110;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ audioLogicTimers[3] = time + 10000 + m_anRandomTable[3] % 20000u;
+ }
+ }
+ }
+}
+
+WRAPPER
+bool
+cAudioManager::ProcessBoatEngine(cVehicleParams *params)
+{
+ EAXJMP(0x56DE80);
+}
+
+WRAPPER
+bool
+cAudioManager::ProcessBoatMovingOverWater(cVehicleParams *params)
+{
+ EAXJMP(0x56E500);
+}
+
+WRAPPER
+void
+cAudioManager::ProcessBridge()
+{
+ EAXJMP(0x5790D0);
+}
+
+void
+cAudioManager::ProcessBridgeMotor()
+{
+ if(m_sQueueSample.m_fDistance < 400.f) {
+ m_sQueueSample.m_bVolume = ComputeVolume(127, 400.f, m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.field_4 = 1;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_MOTOR;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_16 = 1;
+ m_sQueueSample.m_nFrequency = 5500;
+ m_sQueueSample.m_nLoopCount = 0;
+ m_sQueueSample.m_bEmittingVolume = 127;
+ m_sQueueSample.m_nLoopStart =
+ cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nLoopEnd =
+ cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.field_48 = 2.0f;
+ m_sQueueSample.m_fSoundIntensity = 400.0f;
+ m_sQueueSample.field_56 = 0;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.m_bReverbFlag = 0;
+ AddSampleToRequestedQueue();
+ }
+ }
+}
+
+WRAPPER
+void
+cAudioManager::ProcessBridgeOneShots()
+{
+ EAXJMP(0x579310);
+}
+
+void
+cAudioManager::ProcessBridgeWarning()
+{
+ if(CStats::CommercialPassed && m_sQueueSample.m_fDistance < 450.f) {
+ m_sQueueSample.m_bVolume = ComputeVolume(100u, 450.f, m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.field_4 = 0;
+ m_sQueueSample.m_nSampleIndex = 457;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_16 = 1;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_BRIDGE_WARNING);
+ m_sQueueSample.m_nLoopCount = 0;
+ m_sQueueSample.m_bEmittingVolume = 100;
+ m_sQueueSample.m_nLoopStart =
+ cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nLoopEnd =
+ cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.field_48 = 2.0f;
+ m_sQueueSample.m_fSoundIntensity = 450.0f;
+ m_sQueueSample.field_56 = 0;
+ m_sQueueSample.field_76 = 8;
+ m_sQueueSample.m_bReverbFlag = 0;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ }
+ }
+}
+
+WRAPPER
+bool
+cAudioManager::ProcessCarBombTick(void *)
+{
+ EAXJMP(0x56CC20);
+}
+
+WRAPPER
+void
+cAudioManager::ProcessCesna(void *)
+{
+ EAXJMP(0x56ADF0);
+}
+
+void
+cAudioManager::ProcessCinemaScriptObject(uint8 sound)
+{
+ uint8 rand;
+ float distSquared;
+ float maxDist;
+
+ static uint8 counter = 0;
+
+ uint32 time = CTimer::GetTimeInMilliseconds();
+ if(time > audioLogicTimers[4]) {
+ switch(sound) {
+ case SCRIPT_SOUND_CINEMA_LOOP_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ break;
+ case SCRIPT_SOUND_CINEMA_LOOP_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ break;
+ default: break;
+ }
+ distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
+ if(distSquared < maxDist) {
+ m_sQueueSample.m_fDistance = sqrt(distSquared);
+ rand = m_anRandomTable[0] % 90u + 30;
+ m_sQueueSample.m_bVolume = ComputeVolume(
+ rand, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.m_nSampleIndex = counter % 3 + AUDIO_SAMPLE_CINEMA_1;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nFrequency +=
+ RandomDisplacement(m_sQueueSample.m_nFrequency >> 2);
+ m_sQueueSample.field_4 = counter++;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.field_56 = 1;
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ m_sQueueSample.m_bEmittingVolume = rand;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ audioLogicTimers[4] = time + 1000 + m_anRandomTable[3] % 4000u;
+ }
+ }
+ }
+}
+
+WRAPPER
+void
+cAudioManager::ProcessCrane()
+{
+ EAXJMP(0x578910);
+}
+
+void
+cAudioManager::ProcessDocksScriptObject(uint8 sound)
+{
+ uint32 time;
+ uint8 rand;
+ float distSquared;
+ float maxDist;
+
+ static uint32 counter = 0;
+
+ time = CTimer::GetTimeInMilliseconds();
+ if(time > audioLogicTimers[5]) {
+ switch(sound) {
+ case SCRIPT_SOUND_DOCKS_LOOP_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ break;
+ case SCRIPT_SOUND_DOCKS_LOOP_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ break;
+ default: break;
+ }
+ distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
+ if(distSquared < maxDist) {
+ m_sQueueSample.m_fDistance = sqrt(distSquared);
+ rand = m_anRandomTable[0] % 60u + 40;
+ m_sQueueSample.m_bVolume = ComputeVolume(
+ rand, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_DOCKS;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_DOCKS);
+ m_sQueueSample.m_nFrequency +=
+ RandomDisplacement(m_sQueueSample.m_nFrequency >> 3);
+ m_sQueueSample.field_4 = counter++;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.field_56 = 1;
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ m_sQueueSample.m_bEmittingVolume = rand;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ audioLogicTimers[5] = time + 10000 + m_anRandomTable[3] % 40000u;
+ }
+ }
+ }
+}
+
+void
+cAudioManager::ProcessEntity(int32 id)
+{
+ if(m_asAudioEntities[id].m_bStatus) {
+ m_sQueueSample.m_nEntityIndex = id;
+ switch(m_asAudioEntities[id].m_nType) {
+ case AUDIOTYPE_PHYSICAL:
+ if(!m_bUserPause) {
+ m_sQueueSample.m_bReverbFlag = 1;
+ cAudioManager::ProcessPhysical(id);
+ }
+ break;
+ case AUDIOTYPE_EXPLOSION:
+ if(!m_bUserPause) {
+ m_sQueueSample.m_bReverbFlag = 1;
+ cAudioManager::ProcessExplosions(id);
+ }
+ break;
+ case AUDIOTYPE_FIRE:
+ if(!m_bUserPause) {
+ m_sQueueSample.m_bReverbFlag = 1;
+ cAudioManager::ProcessFires(id);
+ }
+ break;
+ case AUDIOTYPE_WEATHER:
+ if(!m_bUserPause) {
+ m_sQueueSample.m_bReverbFlag = 1;
+ cAudioManager::ProcessWeather(id);
+ }
+ break;
+ case AUDIOTYPE_CRANE:
+ if(!m_bUserPause) {
+ m_sQueueSample.m_bReverbFlag = 1;
+ cAudioManager::ProcessCrane();
+ }
+ break;
+ case AUDIOTYPE_ONE_SHOT:
+ if(!m_bUserPause) {
+ m_sQueueSample.m_bReverbFlag = 1;
+ cAudioManager::ProcessScriptObject(id);
+ }
+ break;
+ case AUDIOTYPE_BRIDGE:
+ if(!m_bUserPause) {
+ m_sQueueSample.m_bReverbFlag = 1;
+ cAudioManager::ProcessBridgeOneShots();
+ }
+ break;
+ case AUDIOTYPE_FRONTEND:
+ m_sQueueSample.m_bReverbFlag = 0;
+ cAudioManager::ProcessFrontEnd();
+ break;
+ case AUDIOTYPE_PROJECTILE:
+ if(!m_bUserPause) {
+ m_sQueueSample.m_bReverbFlag = 1;
+ cAudioManager::ProcessProjectiles();
+ }
+ break;
+ case AUDIOTYPE_GARAGE:
+ if(!m_bUserPause) cAudioManager::ProcessGarages();
+ break;
+ case AUDIOTYPE_HYDRANT:
+ if(!m_bUserPause) {
+ m_sQueueSample.m_bReverbFlag = 1;
+ cAudioManager::ProcessFireHydrant();
+ }
+ break;
+ case AUDIOTYPE_WATER_CANNON:
+ if(!m_bUserPause) {
+ m_sQueueSample.m_bReverbFlag = 1;
+ cAudioManager::ProcessWaterCannon(id);
+ }
+ break;
+ default: return;
+ }
+ }
+}
+
+WRAPPER
+void
+cAudioManager::ProcessExplosions(int32 explosion)
+{
+ EAXJMP(0x575AC0);
+}
+
+void
+cAudioManager::ProcessFireHydrant()
+{
+ float distSquared;
+ bool something = false;
+
+ m_sQueueSample.m_vecPos =
+ *(CVector *)((size_t)m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_pEntity + 52);
+ distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
+ if(distSquared < 1225.f) {
+ CalculateDistance(&something, distSquared);
+ m_sQueueSample.m_bVolume = ComputeVolume(40u, 35.f, m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.field_4 = 0;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_JUMBO_TAXI_SOUND;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.field_16 = 4;
+ m_sQueueSample.m_nFrequency = 15591;
+ m_sQueueSample.m_nLoopCount = 0;
+ m_sQueueSample.m_bEmittingVolume = 40;
+ m_sQueueSample.m_nLoopStart =
+ cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nLoopEnd =
+ cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.field_48 = 2.0f;
+ m_sQueueSample.m_fSoundIntensity = 35.0f;
+ m_sQueueSample.field_56 = 0;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ }
+ }
+}
+
+WRAPPER
+void
+cAudioManager::ProcessFires(int32 entity)
+{
+ EAXJMP(0x575CD0);
+}
+
+void
+cAudioManager::ProcessFrontEnd()
+{
+ bool processed;
+ int16 sample;
+
+ static uint32 counter = 0;
+
+ for(uint32 i = 0; i < m_asAudioEntities[m_sQueueSample.m_nEntityIndex].field_24; i++) {
+ processed = 0;
+ switch(
+ m_asAudioEntities[0].m_awAudioEvent[i + 20 * m_sQueueSample.m_nEntityIndex]) {
+ case SOUND_WEAPON_SNIPER_SHOT_NO_ZOOM:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_SNIPER_NO_ZOOM;
+ break;
+ case SOUND_WEAPON_ROCKET_SHOT_NO_ZOOM:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_ROCKET_NO_ZOOM;
+ break;
+ case SOUND_GARAGE_NO_MONEY:
+ case SOUND_GARAGE_BAD_VEHICLE:
+ case SOUND_3C:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PICKUP_FAIL_1;
+ processed = 1;
+ break;
+ case SOUND_GARAGE_OPENING:
+ case SOUND_GARAGE_BOMB1_SET:
+ case SOUND_GARAGE_BOMB2_SET:
+ case SOUND_GARAGE_BOMB3_SET:
+ case SOUND_41:
+ case SOUND_GARAGE_VEHICLE_DECLINED:
+ case SOUND_GARAGE_VEHICLE_ACCEPTED:
+ case SOUND_PICKUP_HEALTH:
+ case SOUND_4B:
+ case SOUND_PICKUP_ADRENALINE:
+ case SOUND_PICKUP_ARMOUR:
+ case SOUND_EVIDENCE_PICKUP:
+ case SOUND_UNLOAD_GOLD:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PICKUP_SUCCESS_1;
+ processed = 1;
+ break;
+ case SOUND_PICKUP_WEAPON_BOUGHT:
+ case SOUND_PICKUP_WEAPON:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PICKUP_NEUTRAL_1;
+ processed = 1;
+ break;
+ case SOUND_4A:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PICKUP_FAIL_1;
+ processed = 1;
+ break;
+ case SOUND_PICKUP_BONUS:
+ case SOUND_PICKUP_MONEY:
+ case SOUND_PICKUP_HIDDEN_PACKAGE:
+ case SOUND_PICKUP_PACMAN_PILL:
+ case SOUND_PICKUP_PACMAN_PACKAGE:
+ case SOUND_PICKUP_FLOAT_PACKAGE:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PICKUP_SUCCESS_3;
+ processed = 1;
+ break;
+ case SOUND_PAGER: m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PAGER; break;
+ case SOUND_RACE_START_3:
+ case SOUND_RACE_START_2:
+ case SOUND_RACE_START_1:
+ case SOUND_CLOCK_TICK:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FRONTEND_CLOCK_TICK;
+ break;
+ case SOUND_RACE_START_GO:
+ m_sQueueSample.m_nSampleIndex =
+ AUDIO_SAMPLE_FRONTEND_PART_MISSION_COMPLETED;
+ break;
+ case SOUND_PART_MISSION_COMPLETE:
+ m_sQueueSample.m_nSampleIndex =
+ AUDIO_SAMPLE_FRONTEND_PART_MISSION_COMPLETED;
+ break;
+ case SOUND_FRONTEND_MENU_STARTING:
+ processed = 1;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FRONTEND_MENU_STARTING_1;
+ break;
+ case SOUND_FRONTEND_MENU_COMPLETED:
+ processed = 1;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FRONTEND_MENU_COMPLETED_1;
+ break;
+ case SOUND_FRONTEND_MENU_DENIED:
+ processed = 1;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FRONTEND_MENU_DENIED_1;
+ break;
+ case SOUND_FRONTEND_MENU_SUCCESS:
+ processed = 1;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FRONTEND_MENU_SUCCESS_1;
+ break;
+ case SOUND_FRONTEND_EXIT:
+ processed = 1;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FRONTEND_MENU_EXIT_1;
+ break;
+ case SOUND_9A:
+ processed = 1;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_380;
+ break;
+ case SOUND_9B: m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_382; break;
+ case SOUND_FRONTEND_AUDIO_TEST:
+ m_sQueueSample.m_nSampleIndex =
+ m_anRandomTable[0] % 3u + AUDIO_SAMPLE_FRONTEND_MENU_AUDIO_TEST_1;
+ break;
+ case SOUND_FRONTEND_FAIL:
+ processed = 1;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FRONTEND_MENU_FAIL_1;
+ break;
+ case SOUND_FRONTEND_NO_RADIO:
+ case SOUND_FRONTEND_RADIO_CHANGE:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FRONTEND_GAMEPLAY_FAIL;
+ break;
+ case SOUND_A0:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FRONTEND_GAMEPLAY_SUCCESS;
+ break;
+ default: continue;
+ }
+
+ sample =
+ m_asAudioEntities[0].m_awAudioEvent[i + 20 * m_sQueueSample.m_nEntityIndex];
+ if(sample == AUDIO_SAMPLE_COLLISION_LOOPING_GRASS) {
+ m_sQueueSample.m_nFrequency = 28509;
+ } else if(sample == AUDIO_SAMPLE_PICKUP_NEUTRAL_1) {
+ if(1.f ==
+ m_asAudioEntities[0].m_afVolume[i + 10 * m_sQueueSample.m_nEntityIndex])
+ m_sQueueSample.m_nFrequency = 32000;
+ else
+ m_sQueueSample.m_nFrequency = 48000;
+ } else {
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
+ }
+ m_sQueueSample.m_bVolume = 110;
+ m_sQueueSample.field_4 = counter++;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.field_56 = 1;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.field_16 = 0;
+ m_sQueueSample.m_bIsDistant = 1;
+ m_sQueueSample.m_bEmittingVolume = m_sQueueSample.m_bVolume;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ if(processed)
+ m_sQueueSample.m_bOffset = m_anRandomTable[0] & 0x1F;
+ else
+ m_sQueueSample.m_bOffset = 63;
+ m_sQueueSample.m_bReverbFlag = 0;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ if(processed) {
+ ++m_sQueueSample.m_nSampleIndex;
+ m_sQueueSample.field_4 = counter++;
+ m_sQueueSample.m_bOffset = 127 - m_sQueueSample.m_bOffset;
+ AddSampleToRequestedQueue();
+ }
+ }
+}
+
+WRAPPER
+void
+cAudioManager::ProcessGarages()
+{
+ EAXJMP(0x578C20);
+}
+
+void
+cAudioManager::ProcessHomeScriptObject(uint8 sound)
+{
+ uint32 time;
+ uint8 rand;
+ float dist;
+ float maxDist;
+
+ static uint8 counter = 0;
+
+ time = CTimer::GetTimeInMilliseconds();
+ if(time > audioLogicTimers[6]) {
+ switch(sound) {
+ case SCRIPT_SOUND_HOME_LOOP_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ break;
+ case SCRIPT_SOUND_HOME_LOOP_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ break;
+ default: break;
+ }
+ dist = GetDistanceSquared(&m_sQueueSample.m_vecPos);
+ if(dist < maxDist) {
+ m_sQueueSample.m_fDistance = sqrt(dist);
+ rand = m_anRandomTable[0] % 30u + 40;
+ m_sQueueSample.m_bVolume = ComputeVolume(
+ rand, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.m_nSampleIndex =
+ m_anRandomTable[0] % 5u + AUDIO_SAMPLE_HOME_1;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nFrequency +=
+ RandomDisplacement(m_sQueueSample.m_nFrequency >> 4);
+ m_sQueueSample.field_4 = counter++;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.field_56 = 1;
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_bEmittingVolume = rand;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 1;
+ AddSampleToRequestedQueue();
+ audioLogicTimers[6] = time + 1000 + m_anRandomTable[3] % 4000u;
+ }
+ }
+ }
+}
+
+float *PlanePathPosition = (float *)0x8F5FC8;
+float &LandingPoint = *(float *)0x8F2C7C;
+float &TakeOffPoint = *(float *)0x8E28A4;
+
+void
+cAudioManager::ProcessJumbo(cVehicleParams *params)
+{
+ CPlane *plane;
+ float position;
+
+ if(params->m_fDistance < 193600.0f) {
+ CalculateDistance((bool *)params, params->m_fDistance);
+ plane = (CPlane *)params->m_pVehicle;
+ DoJumboVolOffset();
+ position = PlanePathPosition[plane->m_wIndex];
+ if(position <= TakeOffPoint) {
+ if(plane->field_656 <= 0.10334f) {
+ ProcessJumboTaxi();
+ return;
+ }
+
+ ProcessJumboAccel(plane);
+ } else if(300.0f + TakeOffPoint >= position) {
+ ProcessJumboTakeOff(plane);
+ } else if(LandingPoint - 350.0f >= position) {
+ ProcessJumboFlying();
+ } else {
+ if(position > LandingPoint) {
+ if(plane->field_656 > 0.10334f) {
+ ProcessJumboDecel(plane);
+ return;
+ }
+ ProcessJumboTaxi();
+ return;
+ }
+ ProcessJumboLanding(plane);
+ }
+ }
+}
+
+void
+cAudioManager::ProcessJumboAccel(CPlane *plane)
+{
+ int32 engineFreq;
+ int32 vol;
+ float whineSoundFreq;
+ float modificator;
+
+ if(SetupJumboFlySound(20u)) {
+ modificator = (plane->field_656 - 0.10334f) * 1.676f;
+ if(modificator > 1.0f) modificator = 1.0f;
+ if(cAudioManager::SetupJumboRumbleSound(maxVolume * modificator) &&
+ SetupJumboTaxiSound((1.0f - modificator) * 75.f)) {
+ if(modificator < 0.2f) {
+ whineSoundFreq = modificator * 5.f * 14600.0f + 29500;
+ vol = modificator * 5.f * maxVolume;
+ engineFreq = modificator * 5.f * 6050.f + 16000;
+ } else {
+ whineSoundFreq = 44100;
+ engineFreq = 22050;
+ vol = maxVolume;
+ }
+ SetupJumboEngineSound(vol, engineFreq);
+ SetupJumboWhineSound(18u, whineSoundFreq);
+ }
+ }
+}
+
+void
+cAudioManager::ProcessJumboDecel(CPlane *plane)
+{
+ float modificator;
+
+ if(SetupJumboFlySound(20u) && SetupJumboTaxiSound(75u)) {
+ modificator = (plane->field_656 - 0.10334f) * 1.676f;
+ if(modificator > 1.0f) modificator = 1.0f;
+ SetupJumboEngineSound(maxVolume * modificator, 6050.f * modificator + 16000);
+ SetupJumboWhineSound(18u, 29500);
+ }
+}
+
+void
+cAudioManager::ProcessJumboFlying()
+{
+ if(SetupJumboFlySound(127u)) SetupJumboEngineSound(63u, 22050);
+}
+
+void
+cAudioManager::ProcessJumboLanding(CPlane *plane)
+{
+ float modificator = (LandingPoint - PlanePathPosition[plane->m_wIndex]) * 0.0028571f;
+ if(SetupJumboFlySound(107.f * modificator + 20)) {
+ if(SetupJumboTaxiSound(75.f * (1.f - modificator))) {
+ SetupJumboEngineSound(maxVolume, 22050);
+ SetupJumboWhineSound(18.f * (1.f - modificator),
+ 14600.f * modificator + 29500);
+ }
+ }
+}
+
+void
+cAudioManager::ProcessJumboTakeOff(CPlane *plane)
+{
+ double modificator = (PlanePathPosition[plane->m_wIndex] - TakeOffPoint) * 0.0033333f;
+
+ if(cAudioManager::SetupJumboFlySound((107.f * modificator) + 20) &&
+ cAudioManager::SetupJumboRumbleSound(maxVolume * (1.f - modificator))) {
+ if(cAudioManager::SetupJumboEngineSound(127u, 22050))
+ cAudioManager::SetupJumboWhineSound(18.f * (1.f - modificator), 44100);
+ }
+}
+
+void
+cAudioManager::ProcessJumboTaxi()
+{
+ if(SetupJumboFlySound(20u)) {
+ if(SetupJumboTaxiSound(75u)) SetupJumboWhineSound(18u, 29500);
+ }
+}
+
+void
+cAudioManager::ProcessLaunderetteScriptObject(uint8 sound)
+{
+ float maxDist;
+ float distSquared;
+
+ switch(sound) {
+ case SCRIPT_SOUND_LAUNDERETTE_LOOP_S:
+ case SCRIPT_SOUND_LAUNDERETTE_LOOP_L:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ break;
+ default: break;
+ }
+ distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
+ if(distSquared < maxDist) {
+ m_sQueueSample.m_fDistance = sqrt(distSquared);
+ m_sQueueSample.m_bVolume = ComputeVolume(45u, m_sQueueSample.m_fSoundIntensity,
+ m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_LAUNDERETTE_1;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_LAUNDERETTE_1);
+ m_sQueueSample.field_4 = 0;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_nLoopCount = 0;
+ m_sQueueSample.field_56 = 0;
+ m_sQueueSample.field_16 = 5;
+ m_sQueueSample.field_48 = 2.0f;
+ m_sQueueSample.m_bEmittingVolume = 45;
+ m_sQueueSample.m_nLoopStart =
+ cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nLoopEnd =
+ cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ }
+ m_sQueueSample.m_bVolume = ComputeVolume(110u, m_sQueueSample.m_fSoundIntensity,
+ m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_LAUNDERETTE_2;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_LAUNDERETTE_2);
+ m_sQueueSample.field_4 = 1;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_nLoopCount = 0;
+ m_sQueueSample.field_56 = 0;
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ m_sQueueSample.m_bEmittingVolume = 110;
+ m_sQueueSample.m_nLoopStart =
+ cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nLoopEnd =
+ cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ }
+ }
+}
+
+void
+cAudioManager::ProcessLoopingScriptObject(uint8 sound)
+{
+ uint8 emittingVolume;
+ float maxDist;
+ float distSquared;
+
+ switch(sound) {
+ case SCRIPT_SOUND_PARTY_1_LOOP_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_1;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_1);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_1_LOOP_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_1;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_1);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_2_LOOP_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_2;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_2);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_2_LOOP_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_2;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_2);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_3_LOOP_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_3;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_3);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_3_LOOP_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_3;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_3);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_4_LOOP_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_4;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_4);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_4_LOOP_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_4;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_4);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_5_LOOP_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_5;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_5);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_5_LOOP_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_5;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_5);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_6_LOOP_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_6;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_6);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_6_LOOP_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_6;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_6);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_7_LOOP_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_7;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_7);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_7_LOOP_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_7;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_7);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_8_LOOP_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_8;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_8);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_8_LOOP_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_8;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_8);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_9_LOOP_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_9;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_9);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_9_LOOP_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_9;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_9);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_10_LOOP_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_10;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_10);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_10_LOOP_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_10;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_10);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_11_LOOP_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_11;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_11);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_11_LOOP_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_11;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_11);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_12_LOOP_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_12;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_12);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_12_LOOP_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_12;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_12);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_13_LOOP_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_13;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_13);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_13_LOOP_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_13;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_13);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_STRIP_CLUB_LOOP_1_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_STRIP_CLUB_1;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_STRIP_CLUB_1);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_STRIP_CLUB_LOOP_1_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_STRIP_CLUB_1;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_STRIP_CLUB_1);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_STRIP_CLUB_LOOP_2_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_STRIP_CLUB_2;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_STRIP_CLUB_2);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_STRIP_CLUB_LOOP_2_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_STRIP_CLUB_2;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_STRIP_CLUB_2);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_WORK_SHOP_LOOP_S:
+ case SCRIPT_SOUND_WORK_SHOP_LOOP_L:
+ cAudioManager::ProcessWorkShopScriptObject(sound);
+ return;
+ case SCRIPT_SOUND_SAWMILL_LOOP_S:
+ case SCRIPT_SOUND_SAWMILL_LOOP_L: cAudioManager::ProcessSawMillScriptObject(sound); return;
+ case SCRIPT_SOUND_38:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_409;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 110;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_409);
+ m_sQueueSample.field_16 = 6;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_39:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_409;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 110;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_409);
+ m_sQueueSample.field_16 = 6;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_LAUNDERETTE_LOOP_S:
+ case SCRIPT_SOUND_LAUNDERETTE_LOOP_L: ProcessLaunderetteScriptObject(sound); return;
+ case SCRIPT_SOUND_CHINATOWN_RESTAURANT_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_CHINATOWN_RESTAURANT;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 110;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_CHINATOWN_RESTAURANT);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_CHINATOWN_RESTAURANT_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_CHINATOWN_RESTAURANT;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 110;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_CHINATOWN_RESTAURANT);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_CIPRIANI_RESAURANT_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_CIPRIANI_RESTAURANT;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 110;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_CIPRIANI_RESTAURANT);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_CIPRIANI_RESAURANT_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_CIPRIANI_RESTAURANT;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 110;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_CIPRIANI_RESTAURANT);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_46:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_414;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 110;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_414);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_47:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_414;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 110;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_414);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_MARCO_BISTRO_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_MARCO_BISTRO;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 110;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_MARCO_BISTRO);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_MARCO_BISTRO_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_MARCO_BISTRO;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 110;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_MARCO_BISTRO);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_AIRPORT_LOOP_S:
+ case SCRIPT_SOUND_AIRPORT_LOOP_L: ProcessAirportScriptObject(sound); return;
+ case SCRIPT_SOUND_SHOP_LOOP_S:
+ case SCRIPT_SOUND_SHOP_LOOP_L: ProcessShopScriptObject(sound); return;
+ case SCRIPT_SOUND_CINEMA_LOOP_S:
+ case SCRIPT_SOUND_CINEMA_LOOP_L: ProcessCinemaScriptObject(sound); return;
+ case SCRIPT_SOUND_DOCKS_LOOP_S:
+ case SCRIPT_SOUND_DOCKS_LOOP_L: cAudioManager::ProcessDocksScriptObject(sound); return;
+ case SCRIPT_SOUND_HOME_LOOP_S:
+ case SCRIPT_SOUND_HOME_LOOP_L: cAudioManager::ProcessHomeScriptObject(sound); return;
+ case SCRIPT_SOUND_FRANKIE_PIANO:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FRANKIE_PIANO;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_FRANKIE_PIANO);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PARTY_1_LOOP:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_1;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_1);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PORN_CINEMA_1_S:
+ case SCRIPT_SOUND_PORN_CINEMA_1_L:
+ case SCRIPT_SOUND_PORN_CINEMA_2_S:
+ case SCRIPT_SOUND_PORN_CINEMA_2_L:
+ case SCRIPT_SOUND_PORN_CINEMA_3_S:
+ case SCRIPT_SOUND_PORN_CINEMA_3_L:
+ case SCRIPT_SOUND_MISTY_SEX_S:
+ case SCRIPT_SOUND_MISTY_SEX_L: ProcessPornCinema(sound); return;
+ case SCRIPT_SOUND_BANK_ALARM_LOOP_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_BANK_ALARM;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 90;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_BANK_ALARM);
+ m_sQueueSample.field_16 = 2;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_BANK_ALARM_LOOP_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_BANK_ALARM;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 90;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_BANK_ALARM);
+ m_sQueueSample.field_16 = 2;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_POLICE_BALL_LOOP_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_POLICE_BALL;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_POLICE_BALL);
+ m_sQueueSample.field_16 = 2;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_POLICE_BALL_LOOP_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_POLICE_BALL;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_POLICE_BALL);
+ m_sQueueSample.field_16 = 2;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_RAVE_LOOP_INDUSTRIAL_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_RAVE_INDUSTRIAL;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_RAVE_INDUSTRIAL);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_RAVE_LOOP_INDUSTRIAL_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_RAVE_INDUSTRIAL;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_RAVE_INDUSTRIAL);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_POLICE_CELL_BEATING_LOOP_S:
+ case SCRIPT_SOUND_POLICE_CELL_BEATING_LOOP_L:
+ cAudioManager::ProcessPoliceCellBeatingScriptObject(sound);
+ return;
+ case SCRIPT_SOUND_RAVE_1_LOOP_S:
+ case SCRIPT_SOUND_RAVE_2_LOOP_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_RAVE_1;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_RAVE_1_LOOP_L:
+ case SCRIPT_SOUND_RAVE_2_LOOP_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_RAVE_1;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_RAVE_3_LOOP_S:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_RAVE_2;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_RAVE_2);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_RAVE_3_LOOP_L:
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_RAVE_2;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 127;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_RAVE_2);
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_76 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ case SCRIPT_SOUND_PRETEND_FIRE_LOOP:
+ maxDist = 2500.f;
+ m_sQueueSample.m_fSoundIntensity = 50.0f;
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FIRE_ENTITY;
+ m_sQueueSample.m_bBankIndex = 0;
+ emittingVolume = 80;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_FIRE_ENTITY);
+ m_sQueueSample.field_16 = 8;
+ m_sQueueSample.field_76 = 10;
+ m_sQueueSample.field_48 = 2.0f;
+ break;
+ default: return;
+ }
+
+ distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
+ if(distSquared < maxDist) {
+ m_sQueueSample.m_fDistance = Sqrt(distSquared);
+ m_sQueueSample.m_bVolume = ComputeVolume(
+ emittingVolume, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.field_4 = 0;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_nLoopCount = 0;
+ m_sQueueSample.field_56 = 0;
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bEmittingVolume = emittingVolume;
+ m_sQueueSample.m_nLoopStart =
+ cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nLoopEnd =
+ cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ }
+ }
+}
+
+WRAPPER
+void
+cAudioManager::ProcessPed(CPhysical *)
+{
+ EAXJMP(0x56F450);
+}
+
+void
+cAudioManager::ProcessPhysical(int32 id)
+{
+ CPhysical *entity = (CPhysical *)m_asAudioEntities[id].m_pEntity;
+ if(entity) {
+ switch(entity->m_type & 7) {
+ case ENTITY_TYPE_VEHICLE:
+ ProcessVehicle((CVehicle *)m_asAudioEntities[id].m_pEntity);
+ break;
+ case ENTITY_TYPE_PED:
+ ProcessPed((CPhysical *)m_asAudioEntities[id].m_pEntity);
+ break;
+ default: return;
+ }
+ }
+}
+
+WRAPPER
+void
+cAudioManager::ProcessPlane(void *ptr)
+{
+ EAXJMP(0x56E860);
+}
+
+WRAPPER
+void
+cAudioManager::ProcessPoliceCellBeatingScriptObject(uint8 sound)
+{
+ EAXJMP(0x578190);
+}
+
+void
+cAudioManager::ProcessPornCinema(uint8 sound)
+{
+
+ eAudioSamples sample;
+ uint32 time;
+ int32 rand;
+ float distSquared;
+ float maxDist;
+
+ switch(sound) {
+ case SCRIPT_SOUND_PORN_CINEMA_1_S:
+ case SCRIPT_SOUND_MISTY_SEX_S:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PORN_CINEMA_1_BACKGROUND_1;
+ m_sQueueSample.m_bBankIndex = 0;
+ maxDist = 400.f;
+ sample = AUDIO_SAMPLE_PORN_CINEMA_1_SEX_1;
+ m_sQueueSample.m_fSoundIntensity = 20.0f;
+ break;
+ case SCRIPT_SOUND_PORN_CINEMA_1_L:
+ case SCRIPT_SOUND_MISTY_SEX_L:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PORN_CINEMA_1_BACKGROUND_1;
+ m_sQueueSample.m_bBankIndex = 0;
+ maxDist = 6400.f;
+ sample = AUDIO_SAMPLE_PORN_CINEMA_1_SEX_1;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ break;
+ case SCRIPT_SOUND_PORN_CINEMA_2_S:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PORN_CINEMA_2_BACKGROUND_2;
+ m_sQueueSample.m_bBankIndex = 0;
+ maxDist = 400.f;
+ sample = AUDIO_SAMPLE_PORN_CINEMA_2_SEX_1;
+ m_sQueueSample.m_fSoundIntensity = 20.0f;
+ break;
+ case SCRIPT_SOUND_PORN_CINEMA_2_L:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PORN_CINEMA_2_BACKGROUND_2;
+ m_sQueueSample.m_bBankIndex = 0;
+ maxDist = 6400.f;
+ sample = AUDIO_SAMPLE_PORN_CINEMA_2_SEX_1;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ break;
+ case SCRIPT_SOUND_PORN_CINEMA_3_S:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PORN_CINEMA_3_BACKGROUND_3;
+ m_sQueueSample.m_bBankIndex = 0;
+ maxDist = 400.f;
+ m_sQueueSample.m_fSoundIntensity = 20.0f;
+ sample = AUDIO_SAMPLE_PORN_CINEMA_3_SEX_1;
+ break;
+ case SCRIPT_SOUND_PORN_CINEMA_3_L:
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PORN_CINEMA_3_BACKGROUND_3;
+ m_sQueueSample.m_bBankIndex = 0;
+ maxDist = 6400.f;
+ m_sQueueSample.m_fSoundIntensity = 80.0f;
+ sample = AUDIO_SAMPLE_PORN_CINEMA_3_SEX_1;
+ break;
+ default: break;
+ }
+ distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
+ if(distSquared < maxDist) {
+ m_sQueueSample.m_fDistance = sqrt(distSquared);
+ if(sound != SCRIPT_SOUND_MISTY_SEX_S && sound != SCRIPT_SOUND_MISTY_SEX_L) {
+ m_sQueueSample.m_bVolume =
+ ComputeVolume(maxVolume, m_sQueueSample.m_fSoundIntensity,
+ m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.field_4 = 0;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_nLoopCount = 0;
+ m_sQueueSample.field_56 = 0;
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ m_sQueueSample.m_bEmittingVolume = maxVolume;
+ m_sQueueSample.m_nLoopStart =
+ cSampleManager.GetSampleLoopStartOffset(
+ m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nLoopEnd = cSampleManager.GetSampleLoopEndOffset(
+ m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ }
+ }
+
+ time = CTimer::GetTimeInMilliseconds();
+ if(time > audioLogicTimers[0]) {
+ m_sQueueSample.m_bVolume = ComputeVolume(
+ 90u, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ rand = m_anRandomTable[1] & 1;
+ m_sQueueSample.m_nSampleIndex = rand + sample;
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nFrequency +=
+ RandomDisplacement(m_sQueueSample.m_nFrequency >> 4);
+ m_sQueueSample.field_4 = rand + 1;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.field_56 = 1;
+ m_sQueueSample.field_16 = 6;
+ m_sQueueSample.field_48 = 0.0f;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ audioLogicTimers[0] = time + 2000 + m_anRandomTable[3] % 6000u;
+ }
+ }
+ }
+}
+
+WRAPPER
+void
+cAudioManager::ProcessProjectiles()
+{
+ EAXJMP(0x578A80);
+}
+
+void
+cAudioManager::ProcessSawMillScriptObject(uint8 sound)
+{
+ uint32 time;
+ float distSquared;
+ float maxDist;
+
+ switch(sound) {
+ case SCRIPT_SOUND_SAWMILL_LOOP_S:
+ case SCRIPT_SOUND_SAWMILL_LOOP_L:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ break;
+ default: break;
+ }
+ distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
+ if(distSquared < maxDist) {
+ m_sQueueSample.m_fDistance = sqrt(distSquared);
+ m_sQueueSample.m_bVolume = cAudioManager::ComputeVolume(
+ 30u, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_SAWMILL_1;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_SAWMILL_1);
+ m_sQueueSample.field_4 = 0;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_nLoopCount = 0;
+ m_sQueueSample.field_56 = 0;
+ m_sQueueSample.field_16 = 5;
+ m_sQueueSample.field_48 = 2.0f;
+ m_sQueueSample.m_bEmittingVolume = 30;
+ m_sQueueSample.m_nLoopStart =
+ cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nLoopEnd =
+ cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ }
+ time = CTimer::GetTimeInMilliseconds();
+ if(time > audioLogicTimers[1]) {
+ m_sQueueSample.m_bVolume = cAudioManager::ComputeVolume(
+ 70u, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_SAWMILL_2;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.field_4 = 1;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.field_56 = 1;
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ audioLogicTimers[1] = time + 2000 + m_anRandomTable[3] % 4000u;
+ }
+ }
+ }
+}
+
+WRAPPER
+void
+cAudioManager::ProcessScriptObject(int32 id)
+{
+ EAXJMP(0x576070);
+}
+
+void
+cAudioManager::ProcessShopScriptObject(uint8 sound)
+{
+ uint32 time;
+ int32 rand;
+ float distSquared;
+ float maxDist;
+
+ switch(sound) {
+ case SCRIPT_SOUND_SHOP_LOOP_S:
+ case SCRIPT_SOUND_SHOP_LOOP_L:
+ maxDist = 900.f;
+ m_sQueueSample.m_fSoundIntensity = 30.0f;
+ break;
+ default: break;
+ }
+ distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
+ if(distSquared < maxDist) {
+ m_sQueueSample.m_fDistance = sqrt(distSquared);
+ m_sQueueSample.m_bVolume = ComputeVolume(30u, m_sQueueSample.m_fSoundIntensity,
+ m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_SHOP_1;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_SHOP_1);
+ m_sQueueSample.field_4 = 0;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_nLoopCount = 0;
+ m_sQueueSample.field_56 = 0;
+ m_sQueueSample.field_16 = 5;
+ m_sQueueSample.field_48 = 2.0f;
+ m_sQueueSample.m_bEmittingVolume = 30;
+ m_sQueueSample.m_nLoopStart =
+ cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nLoopEnd =
+ cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ cAudioManager::AddSampleToRequestedQueue();
+ }
+ time = CTimer::GetTimeInMilliseconds();
+ if(time > audioLogicTimers[2]) {
+ m_sQueueSample.m_bVolume = ComputeVolume(
+ 70u, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ rand = m_anRandomTable[1] & 1;
+ m_sQueueSample.m_nSampleIndex = rand + AUDIO_SAMPLE_SHOP_2;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency(
+ m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.field_4 = rand + 1;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_nLoopCount = 1;
+ m_sQueueSample.field_56 = 1;
+ m_sQueueSample.field_16 = 3;
+ m_sQueueSample.field_48 = 2.0f;
+ m_sQueueSample.m_bEmittingVolume = 70;
+ m_sQueueSample.m_nLoopStart = 0;
+ m_sQueueSample.m_nLoopEnd = -1;
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ audioLogicTimers[2] = time + 3000 + m_anRandomTable[3] % 7000u;
+ }
+ }
+ }
+}
+
+void
+cAudioManager::ProcessSpecial()
+{
+ if(m_bUserPause) {
+ if(!m_bPreviousUserPause) {
+ MusicManager.ChangeMusicMode(0);
+ cSampleManager.SetEffectsFadeVol(maxVolume);
+ cSampleManager.SetMusicFadeVol(maxVolume);
+ }
+ } else {
+ if(m_bPreviousUserPause) {
+ MusicManager.StopFrontEndTrack();
+ MusicManager.ChangeMusicMode(1u);
+ }
+ CPlayerPed *playerPed = FindPlayerPed();
+ if(playerPed) {
+ const PedState &state = playerPed->m_nPedState;
+ if(state != PED_ENTER_CAR && state != PED_STEAL_CAR &&
+ !playerPed->bInVehicle)
+ cSampleManager.StopChannel(m_bActiveSamples);
+ }
+ }
+}
+
+#if 1
+WRAPPER
+void
+cAudioManager::ProcessVehicle(CVehicle *)
+{
+ EAXJMP(0x569A00);
+}
+#else
+void
+cAudioManager::ProcessVehicle(CVehicle *)
+{
+ EAXJMP(0x569A00);
+}
+#endif
+
+WRAPPER
+void cAudioManager::ProcessWaterCannon(int32) { EAXJMP(0x575F30); }
+
+WRAPPER
+void
+cAudioManager::ProcessWeather(int32 id)
+{
+ EAXJMP(0x578370);
+}
+
+void
+cAudioManager::ProcessWorkShopScriptObject(uint8 sound)
+{
+ float distSquared;
+ float maxDist;
+
+ switch(sound) {
+ case SCRIPT_SOUND_WORK_SHOP_LOOP_S:
+ case SCRIPT_SOUND_WORK_SHOP_LOOP_L:
+ maxDist = 400.f;
+ m_sQueueSample.m_fSoundIntensity = 20.0;
+ break;
+ default: break;
+ }
+ distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
+ if(distSquared < maxDist) {
+ m_sQueueSample.m_fDistance = sqrt(distSquared);
+ m_sQueueSample.m_bVolume = ComputeVolume(30u, m_sQueueSample.m_fSoundIntensity,
+ m_sQueueSample.m_fDistance);
+ if(m_sQueueSample.m_bVolume) {
+ m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_WORK_SHOP;
+ m_sQueueSample.m_bBankIndex = 0;
+ m_sQueueSample.m_nFrequency =
+ cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_WORK_SHOP);
+ m_sQueueSample.field_4 = 0;
+ m_sQueueSample.m_bIsDistant = 0;
+ m_sQueueSample.m_nLoopCount = 0;
+ m_sQueueSample.field_56 = 0;
+ m_sQueueSample.field_16 = 5;
+ m_sQueueSample.field_48 = 2.0;
+ m_sQueueSample.m_bEmittingVolume = 30;
+ m_sQueueSample.m_nLoopStart =
+ cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_nLoopEnd =
+ cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+ m_sQueueSample.m_bReverbFlag = 1;
+ m_sQueueSample.m_bRequireReflection = 0;
+ AddSampleToRequestedQueue();
+ }
+ }
+}
+
WRAPPER void
cAudioManager::Service()
{
@@ -2960,22 +5621,40 @@ cAudioManager::Service()
}
STARTPATCHES
-InjectHook(0x57B070, &cAudioManager::AddSampleToRequestedQueue, PATCH_JUMP);
InjectHook(0x57B210, &cAudioManager::AddDetailsToRequestedOrderList, PATCH_JUMP);
+InjectHook(0x56AD30, &cAudioManager::AddPlayerCarSample, PATCH_JUMP);
InjectHook(0x57B300, &cAudioManager::AddReflectionsToRequestedQueue, PATCH_JUMP);
+// InjectHook(0x57B8D0, &cAudioManager::AddReleasingSounds, PATCH_JUMP);
+InjectHook(0x57B070, &cAudioManager::AddSampleToRequestedQueue, PATCH_JUMP);
+InjectHook(0x57A8F0, &cAudioManager::AutoDetect3DProviders, PATCH_JUMP);
+// InjectHook(0x580AF0, &cAudioManager::AgeCrimes, PATCH_JUMP);
+
+InjectHook(0x5697A0, &cAudioManager::CalculateDistance, PATCH_JUMP);
+InjectHook(0x57AA10, &cAudioManager::CheckForAnAudioFileOnCD, PATCH_JUMP);
+InjectHook(0x5796A0, &cAudioManager::ClearMissionAudio, PATCH_JUMP);
+InjectHook(0x57C120, &cAudioManager::ClearRequestedQueue, PATCH_JUMP);
+InjectHook(0x57AE00, &cAudioManager::ComputeDopplerEffectedFrequency, PATCH_JUMP);
InjectHook(0x57ABB0, &cAudioManager::ComputeVolume, PATCH_JUMP);
+InjectHook(0x57A310, &cAudioManager::CreateEntity, PATCH_JUMP);
+
+InjectHook(0x57A830, &cAudioManager::DestroyAllGameCreatedEntities, PATCH_JUMP);
+InjectHook(0x57A400, &cAudioManager::DestroyEntity, PATCH_JUMP);
+InjectHook(0x57F060, &cAudioManager::DoPoliceRadioCrackle, PATCH_JUMP);
+
+InjectHook(0x57C290, &cAudioManager::GenerateIntegerRandomNumberTable, PATCH_JUMP);
+InjectHook(0x569750, &cAudioManager::GetDistanceSquared, PATCH_JUMP);
+InjectHook(0x57AC60, &cAudioManager::TranslateEntity, PATCH_JUMP);
InjectHook(0x57A0E0, &cAudioManager::Initialise, PATCH_JUMP);
InjectHook(0x569420, &cAudioManager::PostInitialiseGameSpecificSetup, PATCH_JUMP);
-//InjectHook(0x57EAC0, &cAudioManager::InitialisePoliceRadioZones, PATCH_JUMP);
-//InjectHook(0x569650, &cAudioManager::ResetAudioLogicTimers, PATCH_JUMP);
+// InjectHook(0x57EAC0, &cAudioManager::InitialisePoliceRadioZones, PATCH_JUMP);
+// InjectHook(0x569650, &cAudioManager::ResetAudioLogicTimers, PATCH_JUMP);
InjectHook(0x57A150, &cAudioManager::Terminate, PATCH_JUMP);
InjectHook(0x57F050, &cAudioManager::GetMissionScriptPoliceAudioPlayingStatus, PATCH_JUMP);
InjectHook(0x5795D0, &cAudioManager::GetMissionAudioLoadingStatus, PATCH_JUMP);
InjectHook(0x57A8A0, &cAudioManager::GetNum3DProvidersAvailable, PATCH_JUMP);
-InjectHook(0x57A8F0, &cAudioManager::AutoDetect3DProviders, PATCH_JUMP);
InjectHook(0x57A9C0, &cAudioManager::IsMP3RadioChannelAvailable, PATCH_JUMP);
InjectHook(0x57AA30, &cAudioManager::GetCDAudioDriveLetter, PATCH_JUMP);
@@ -2986,20 +5665,20 @@ InjectHook(0x57A790, &cAudioManager::SetMusicFadeVol, PATCH_JUMP);
InjectHook(0x57A9A0, &cAudioManager::SetSpeakerConfig, PATCH_JUMP);
-InjectHook(0x56ECF0, &cAudioManager::ProcessJumboFlying, PATCH_JUMP);
InjectHook(0x569400, &cAudioManager::PreInitialiseGameSpecificSetup, PATCH_JUMP);
InjectHook(0x57F020, &cAudioManager::SetMissionScriptPoliceAudio, PATCH_JUMP);
-InjectHook(0x5697A0, &cAudioManager::CalculateDistance, PATCH_JUMP);
-
InjectHook(0x56C3C0, &cAudioManager::UsesSiren, PATCH_JUMP);
InjectHook(0x56C3F0, &cAudioManager::UsesSirenSwitching, PATCH_JUMP);
InjectHook(0x579520, &cAudioManager::MissionScriptAudioUsesPoliceChannel, PATCH_JUMP);
InjectHook(0x57A8C0, &cAudioManager::Get3DProviderName, PATCH_JUMP);
-InjectHook(0x56EA10, &cAudioManager::ProcessJumboTaxi, PATCH_JUMP);
+InjectHook(0x56F230, &cAudioManager::SetupJumboFlySound, PATCH_JUMP);
+InjectHook(0x56F310, &cAudioManager::SetupJumboRumbleSound, PATCH_JUMP);
+InjectHook(0x56EF20, &cAudioManager::SetupJumboTaxiSound, PATCH_JUMP);
+InjectHook(0x56F070, &cAudioManager::SetupJumboWhineSound, PATCH_JUMP);
InjectHook(0x579620, &cAudioManager::PlayLoadedMissionAudio, PATCH_JUMP);
@@ -3009,22 +5688,12 @@ InjectHook(0x57EFF0, &cAudioManager::ResetPoliceRadio, PATCH_JUMP);
InjectHook(0x57B030, &cAudioManager::InterrogateAudioEntities, PATCH_JUMP);
-InjectHook(0x57C120, &cAudioManager::ClearRequestedQueue, PATCH_JUMP);
-// InjectHook(0x580AF0, &cAudioManager::AgeCrimes, PATCH_JUMP);
-
InjectHook(0x56C600, &cAudioManager::UsesReverseWarning, PATCH_JUMP);
InjectHook(0x56CAB0, &cAudioManager::HasAirBrakes, PATCH_JUMP);
InjectHook(0x56F410, &cAudioManager::GetJumboTaxiFreq, PATCH_JUMP);
-InjectHook(0x5699C0, &cAudioManager::ProcessPhysical, PATCH_JUMP);
-// InjectHook(0x56E860, &cAudioManager::ProcessPlane, PATCH_JUMP);
-
-InjectHook(0x5796A0, &cAudioManager::ClearMissionAudio, PATCH_JUMP);
-// InjectHook(0x569700, &cAudioManager::ProcessReverb, PATCH_JUMP);
-
InjectHook(0x579650, &cAudioManager::IsMissionAudioSampleFinished, PATCH_JUMP);
-// done
InjectHook(0x57AF90, &cAudioManager::RandomDisplacement, PATCH_JUMP);
InjectHook(0x57A9E0, &cAudioManager::ReleaseDigitalHandle, PATCH_JUMP);
@@ -3033,19 +5702,18 @@ InjectHook(0x57AA00, &cAudioManager::SetDynamicAcousticModelingStatus, PATCH_JUM
InjectHook(0x57AA50, &cAudioManager::IsAudioInitialised, PATCH_JUMP);
-InjectHook(0x57A310, &cAudioManager::CreateEntity, PATCH_JUMP);
-InjectHook(0x57A400, &cAudioManager::DestroyEntity, PATCH_JUMP);
InjectHook(0x57A4C0, &cAudioManager::SetEntityStatus, PATCH_JUMP);
InjectHook(0x569570, &cAudioManager::PreTerminateGameSpecificShutdown, PATCH_JUMP);
InjectHook(0x569640, &cAudioManager::PostTerminateGameSpecificShutdown, PATCH_JUMP);
-InjectHook(0x57C290, &cAudioManager::GenerateIntegerRandomNumberTable, PATCH_JUMP);
-
InjectHook(0x56AD10, &cAudioManager::PlayerJustGotInCar, PATCH_JUMP);
InjectHook(0x56AD20, &cAudioManager::PlayerJustLeftCar, PATCH_JUMP);
InjectHook(0x570DB0, &cAudioManager::GetPhrase, PATCH_JUMP);
+// Get ped sfx stuff
+InjectHook(0x570960, &cAudioManager::GetPedCommentSfx, PATCH_JUMP);
+
InjectHook(0x570E00, &cAudioManager::GetPlayerTalkSfx, PATCH_JUMP);
InjectHook(0x570EA0, &cAudioManager::GetCopTalkSfx, PATCH_JUMP);
InjectHook(0x570F80, &cAudioManager::GetSwatTalkSfx, PATCH_JUMP);
@@ -3122,4 +5790,32 @@ InjectHook(0x575120, &cAudioManager::GetChunkyTalkSfx, PATCH_JUMP);
InjectHook(0x575460, &cAudioManager::GetGenericMaleTalkSfx, PATCH_JUMP);
InjectHook(0x575510, &cAudioManager::GetGenericFemaleTalkSfx, PATCH_JUMP);
+
+// Process stuff
+// InjectHook(0x57BA60, &cAudioManager::ProcessActiveQueues, PATCH_JUMP);
+InjectHook(0x56C940, &cAudioManager::ProcessAirBrakes, PATCH_JUMP);
+InjectHook(0x577B30, &cAudioManager::ProcessAirportScriptObject, PATCH_JUMP);
+InjectHook(0x579250, &cAudioManager::ProcessBridgeMotor, PATCH_JUMP);
+InjectHook(0x579170, &cAudioManager::ProcessBridgeWarning, PATCH_JUMP);
+InjectHook(0x577CA0, &cAudioManager::ProcessCinemaScriptObject, PATCH_JUMP);
+InjectHook(0x577E50, &cAudioManager::ProcessDocksScriptObject, PATCH_JUMP);
+InjectHook(0x569870, &cAudioManager::ProcessEntity, PATCH_JUMP);
+InjectHook(0x578FD0, &cAudioManager::ProcessFireHydrant, PATCH_JUMP);
+InjectHook(0x5785E0, &cAudioManager::ProcessFrontEnd, PATCH_JUMP);
+InjectHook(0x577FE0, &cAudioManager::ProcessHomeScriptObject, PATCH_JUMP);
+InjectHook(0x56E8F0, &cAudioManager::ProcessJumbo, PATCH_JUMP);
+InjectHook(0x56EA40, &cAudioManager::ProcessJumboAccel, PATCH_JUMP);
+InjectHook(0x56EE40, &cAudioManager::ProcessJumboDecel, PATCH_JUMP);
+InjectHook(0x56ECF0, &cAudioManager::ProcessJumboFlying, PATCH_JUMP);
+InjectHook(0x56ED10, &cAudioManager::ProcessJumboLanding, PATCH_JUMP);
+InjectHook(0x56EC00, &cAudioManager::ProcessJumboTakeOff, PATCH_JUMP);
+InjectHook(0x56EA10, &cAudioManager::ProcessJumboTaxi, PATCH_JUMP);
+InjectHook(0x5777E0, &cAudioManager::ProcessLaunderetteScriptObject, PATCH_JUMP);
+InjectHook(0x576770, &cAudioManager::ProcessLoopingScriptObject, PATCH_JUMP);
+InjectHook(0x5699C0, &cAudioManager::ProcessPhysical, PATCH_JUMP);
+InjectHook(0x577280, &cAudioManager::ProcessPornCinema, PATCH_JUMP);
+InjectHook(0x577630, &cAudioManager::ProcessSawMillScriptObject, PATCH_JUMP);
+InjectHook(0x577970, &cAudioManager::ProcessShopScriptObject, PATCH_JUMP);
+InjectHook(0x5697D0, &cAudioManager::ProcessSpecial, PATCH_JUMP);
+InjectHook(0x577530, &cAudioManager::ProcessWorkShopScriptObject, PATCH_JUMP);
ENDPATCHES
diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h
index 7a2dc9c5..1ae50b2f 100644
--- a/src/audio/AudioManager.h
+++ b/src/audio/AudioManager.h
@@ -7,48 +7,48 @@
class tActiveSample
{
public:
- int m_nEntityIndex;
- int field_4;
- int m_nSampleIndex;
- char m_bBankIndex;
- char m_bIsDistant;
- char field_14;
- char field_15;
- int field_16;
- int m_nFrequency;
+ int32 m_nEntityIndex;
+ int32 field_4;
+ int32 m_nSampleIndex;
+ uint8 m_bBankIndex;
+ uint8 m_bIsDistant;
+ uint8 field_14;
+ uint8 field_15;
+ int32 field_16;
+ int32 m_nFrequency;
uint8 m_bVolume;
- char field_25;
- char field_26;
- char field_27;
+ uint8 field_25;
+ uint8 field_26;
+ uint8 field_27;
float m_fDistance;
- int m_nLoopCount;
- int m_nLoopStart;
- int m_nLoopEnd;
+ int32 m_nLoopCount;
+ int32 m_nLoopStart;
+ int32 m_nLoopEnd;
uint8 m_bEmittingVolume;
- char field_45;
- char field_46;
- char field_47;
+ uint8 field_45;
+ uint8 field_46;
+ uint8 field_47;
float field_48;
float m_fSoundIntensity;
- char field_56;
- char field_57;
- char field_58;
- char field_59;
+ uint8 field_56;
+ uint8 field_57;
+ uint8 field_58;
+ uint8 field_59;
CVector m_vecPos;
- char m_bReverbFlag;
- char m_bLoopsRemaining;
- char m_bRequireReflection;
+ uint8 m_bReverbFlag;
+ uint8 m_bLoopsRemaining;
+ uint8 m_bRequireReflection;
uint8 m_bOffset;
- int field_76;
- char m_bIsProcessed;
- char m_bLoopEnded;
- char field_82;
- char field_83;
- int calculatedVolume;
- char field_88;
- char field_89;
- char field_90;
- char field_91;
+ int32 field_76;
+ uint8 m_bIsProcessed;
+ uint8 m_bLoopEnded;
+ uint8 field_82;
+ uint8 field_83;
+ int32 calculatedVolume;
+ uint8 field_88;
+ uint8 field_89;
+ uint8 field_90;
+ uint8 field_91;
};
static_assert(sizeof(tActiveSample) == 0x5c, "tActiveSample: error");
@@ -77,14 +77,14 @@ class tAudioEntity
{
public:
eAudioType m_nType;
- CPhysical *m_pEntity;
+ void *m_pEntity;
bool m_bIsUsed;
- char m_bStatus;
+ uint8 m_bStatus;
int16 m_awAudioEvent[4];
- char gap_18[2];
+ uint8 gap_18[2];
float m_afVolume[4];
- char field_24;
- char field_25[3];
+ uint8 field_24;
+ uint8 field_25[3];
};
static_assert(sizeof(tAudioEntity) == 0x28, "tAudioEntity: error");
@@ -96,9 +96,9 @@ public:
int field_4;
CVector m_vecPos;
float m_fDistance;
- char m_bVolume;
- char field_25;
- char gap_26[2];
+ uint8 m_bVolume;
+ uint8 field_25;
+ uint8 gap_26[2];
};
static_assert(sizeof(tPedComment) == 0x1c, "tPedComment: error");
@@ -107,10 +107,10 @@ class cPedComments
{
public:
tPedComment m_asPedComments[40];
- char field_1120[40];
- char field_1160[2];
- char field_1162;
- char gap_1163[1];
+ uint8 field_1120[40];
+ uint8 field_1160[2];
+ uint8 field_1162;
+ uint8 gap_1163[1];
};
static_assert(sizeof(cPedComments) == 0x48c, "cPedComments: error");
@@ -122,15 +122,15 @@ class cAudioCollision
public:
CEntity *m_pEntity1;
CEntity *m_pEntity2;
- char m_bSurface1;
- char m_bSurface2;
- char field_10;
- char field_11;
+ uint8 m_bSurface1;
+ uint8 m_bSurface2;
+ uint8 field_10;
+ uint8 field_11;
float m_fIntensity1;
float m_fIntensity2;
CVector m_vecPosition;
float m_fDistance;
- int m_nBaseVolume;
+ int32 m_nBaseVolume;
};
static_assert(sizeof(cAudioCollision) == 0x28, "cAudioCollision: error");
@@ -140,95 +140,137 @@ class cAudioCollisionManager
public:
cAudioCollision m_asCollisions1[10];
cAudioCollision m_asCollisions2[10];
- char m_bIndicesTable[10];
- char m_bCollisionsInQueue;
- char gap_811;
+ uint8 m_bIndicesTable[10];
+ uint8 m_bCollisionsInQueue;
+ uint8 gap_811;
cAudioCollision m_sQueue;
};
-static_assert(sizeof(cAudioCollisionManager) == 0x354,
- "cAudioCollisionManager: error");
+static_assert(sizeof(cAudioCollisionManager) == 0x354, "cAudioCollisionManager: error");
class cMissionAudio
{
public:
CVector m_vecPos;
- char field_12;
- char gap_13[3];
+ uint8 field_12;
+ uint8 gap_13[3];
int m_nSampleIndex;
- char m_bLoadingStatus;
- char m_bPlayStatus;
- char field_22;
- char field_23;
+ uint8 m_bLoadingStatus;
+ uint8 m_bPlayStatus;
+ uint8 field_22;
+ uint8 field_23;
int field_24;
bool m_bIsPlayed;
- char field_29;
- char field_30;
- char field_31;
+ uint8 field_29;
+ uint8 field_30;
+ uint8 field_31;
};
static_assert(sizeof(cMissionAudio) == 0x20, "cMissionAudio: error");
+class cVehicleParams;
+class CPlane;
+class CVehicle;
+class CPed;
+
+struct cAudioScriptObject {
+ int16 m_wSound;
+ char gap_2[2];
+ CVector m_vecPos;
+ int m_nAudioEntityId;
+
+ static void *operator new(size_t);
+ static void *operator new(size_t, int);
+ static void operator delete(void*, size_t);
+ static void operator delete(void*, int);
+};
+
+static_assert(sizeof(cAudioScriptObject) == 0x14, "cAudioScriptObject: error");
+
class cAudioManager
{
public:
bool m_bIsInitialised;
- char field_1;
- char field_2;
- char m_bActiveSamples;
- char field_4;
+ uint8 field_1;
+ uint8 field_2;
+ uint8 m_bActiveSamples;
+ uint8 field_4;
bool m_bDynamicAcousticModelingStatus;
- char field_6;
- char field_7;
- float field_8;
+ uint8 field_6;
+ uint8 field_7;
+ float speedOfSound;
bool m_bTimerJustReset;
- char field_13;
- char field_14;
- char field_15;
- int m_nTimer;
+ uint8 field_13;
+ uint8 field_14;
+ uint8 field_15;
+ int32 m_nTimer;
tActiveSample m_sQueueSample;
uint8 m_bActiveSampleQueue;
- char gap_109[3];
- tActiveSample m_asSamples[54];
- char m_abSampleQueueIndexTable[54];
- char m_bSampleRequestQueuesStatus[2];
+ uint8 gap_109[3];
+ tActiveSample m_asSamples[2][27];
+ uint8 m_abSampleQueueIndexTable[2][27];
+ uint8 m_bSampleRequestQueuesStatus[2];
tActiveSample m_asActiveSamples[27];
tAudioEntity m_asAudioEntities[200];
- int m_anAudioEntityIndices[200];
- int m_nAudioEntitiesTotal;
+ int32 m_anAudioEntityIndices[200];
+ int32 m_nAudioEntitiesTotal;
CVector m_avecReflectionsPos[5];
float m_afReflectionsDistances[5];
- int m_anScriptObjectEntityIndices[40];
- int m_nScriptObjectEntityTotal;
+ int32 m_anScriptObjectEntityIndices[40];
+ int32 m_nScriptObjectEntityTotal;
cPedComments m_sPedComments;
- int m_nFireAudioEntity;
- int m_nWaterCannonEntity;
- int m_nPoliceChannelEntity;
- char gap45B8[444];
- int m_nFrontEndEntity;
- int m_nCollisionEntity;
+ int32 m_nFireAudioEntity;
+ int32 m_nWaterCannonEntity;
+ int32 m_nPoliceChannelEntity;
+ uint8 gap45B8[444];
+ int32 m_nFrontEndEntity;
+ int32 m_nCollisionEntity;
cAudioCollisionManager m_sCollisionManager;
- int m_nProjectileEntity;
- int m_nBridgeEntity;
+ int32 m_nProjectileEntity;
+ int32 m_nBridgeEntity;
cMissionAudio m_sMissionAudio;
- int m_anRandomTable[5];
- char field_19192;
- char m_bUserPause;
- char m_bPreviousUserPause;
- char field_19195;
- int m_nTimeOfRecentCrime;
-
- void AddSampleToRequestedQueue();
-
- void AddDetailsToRequestedOrderList(uint8 sample);
- void AddReflectionsToRequestedQueue();
-
- uint32 ComputeVolume(int emittingVolume, float soundIntensity, float distance);
+ int32 m_anRandomTable[5];
+ uint8 field_19192;
+ uint8 m_bUserPause;
+ uint8 m_bPreviousUserPause;
+ uint8 field_19195;
+ int32 m_nTimeOfRecentCrime;
+
+ void AddDetailsToRequestedOrderList(uint8 sample); /// ok
+ void AddPlayerCarSample(uint8 emittingVolume, int32 freq, uint32 sample, uint8 unk1,
+ uint8 unk2, bool notLooping); /// ok
+ void AddReflectionsToRequestedQueue(); /// ok (check value)
+ void AddReleasingSounds(); // todo (difficult)
+ void AddSampleToRequestedQueue(); /// ok
+ void AgeCrimes(); // todo
+ int8 AutoDetect3DProviders(); /// ok
+
+ void CalculateDistance(bool *ptr, float dist); /// ok
+ bool CheckForAnAudioFileOnCD(); /// ok
+ void ClearMissionAudio(); /// ok
+ void ClearRequestedQueue(); /// ok
+ int32 ComputeDopplerEffectedFrequency(uint32 oldFreq, float position1, float position2,
+ float speedMultiplier); /// ok
+ int32 ComputePan(float, CVector *); // todo
+ uint32 ComputeVolume(int emittingVolume, float soundIntensity, float distance); /// ok
+ int32 CreateEntity(int32 type, CPhysical *entity); /// ok
+
+ void DestroyAllGameCreatedEntities(); /// ok
+ void DestroyEntity(int32 id); /// ok
+ void DoPoliceRadioCrackle(); /// ok
+
+ void GenerateIntegerRandomNumberTable(); /// ok
+
+ float GetDistanceSquared(CVector *v); /// ok
+
+ void TranslateEntity(CVector *v1, CVector *v2); /// ok
+
+ // done
void Initialise();
void PostInitialiseGameSpecificSetup();
- void InitialisePoliceRadioZones(); // @todo
- void ResetAudioLogicTimers(int32 timer); // @todo
+ void InitialisePoliceRadioZones(); // todo
+ void ResetAudioLogicTimers(int32 timer); // todo
void Terminate();
@@ -236,7 +278,6 @@ public:
bool GetMissionAudioLoadingStatus();
uint8 GetNum3DProvidersAvailable();
- int8 AutoDetect3DProviders();
bool IsMP3RadioChannelAvailable();
uint8 GetCDAudioDriveLetter();
@@ -247,24 +288,21 @@ public:
void SetSpeakerConfig(int32 conf);
- void ProcessJumboFlying();
bool SetupJumboEngineSound(uint8, int32); // todo
void PreInitialiseGameSpecificSetup();
void SetMissionScriptPoliceAudio(int32 sfx);
- void CalculateDistance(bool *ptr, float dist);
-
bool UsesSiren(int32 model);
bool UsesSirenSwitching(int32 model);
bool MissionScriptAudioUsesPoliceChannel(int32 soundMission);
- uint8 Get3DProviderName(uint8 id);
+ char* Get3DProviderName(uint8 id);
- void ProcessJumboTaxi();
- bool SetupJumboFlySound(uint8); // todo
- bool SetupJumboTaxiSound(uint8); // todo
- bool SetupJumboWhineSound(uint8, int32); // todo
+ bool SetupJumboFlySound(uint8 emittingVol); /// ok
+ bool SetupJumboRumbleSound(uint8 emittingVol); /// ok
+ bool SetupJumboTaxiSound(uint8 vol); /// ok
+ bool SetupJumboWhineSound(uint8 emittingVol, int32 freq); /// ok
void PlayLoadedMissionAudio();
@@ -274,27 +312,14 @@ public:
void InterrogateAudioEntities();
- void ClearRequestedQueue();
- // void AgeCrimes(); //todo
-
bool UsesReverseWarning(int32 model);
bool HasAirBrakes(int32 model);
int32 GetJumboTaxiFreq();
- void ProcessPhysical(int32 id);
- void ProcessVehicle(CPhysical *); // todo
- void ProcessPed(CPhysical *); // todo
- void ProcessPlane(void *); // todo
-
- void ClearMissionAudio();
- // void ProcessReverb(); // todo
-
bool IsMissionAudioSampleFinished();
- void ProcessEntity(int32);
-
- void InitialisePoliceRadio();
+ void InitialisePoliceRadio(); // todo
int32 RandomDisplacement(uint32 seed);
@@ -304,21 +329,20 @@ public:
bool IsAudioInitialised() const;
- int32 CreateEntity(int32 type, CPhysical *entity);
- void DestroyEntity(int32 id);
void SetEntityStatus(int32 id, bool status);
void PreTerminateGameSpecificShutdown();
void PostTerminateGameSpecificShutdown();
- void GenerateIntegerRandomNumberTable();
-
void PlayerJustGotInCar();
void PlayerJustLeftCar();
void Service();
- void GetPhrase(uint32 *phrase, uint32 *prevPhrase, uint32 sample,
- uint32 maxOffset);
+ void GetPhrase(uint32 *phrase, uint32 *prevPhrase, uint32 sample, uint32 maxOffset);
+
+ void DoJumboVolOffset();
+
+ int32 GetPedCommentSfx(CPed *ped, int32 sound);
uint32 GetPlayerTalkSfx(int16 sound);
uint32 GetCopTalkSfx(int16 sound);
@@ -396,9 +420,74 @@ public:
uint32 GetGenericMaleTalkSfx(int16 sound);
uint32 GetGenericFemaleTalkSfx(int16 sound);
+
+ void ProcessActiveQueues(); // todo
+ bool ProcessAirBrakes(cVehicleParams *params); /// ok
+ void ProcessAirportScriptObject(uint8 sound); /// ok
+ bool ProcessBoatEngine(cVehicleParams *params); // todo requires CBoat
+ bool ProcessBoatMovingOverWater(cVehicleParams *params); // todo requires CBoat
+ void ProcessBridge(); // todo requires CBridge
+ void ProcessBridgeMotor(); /// ok
+ void ProcessBridgeOneShots(); // todo requires CBridge
+ void ProcessBridgeWarning(); /// ok
+ bool ProcessCarBombTick(void *); // todo requires CVehicle
+ void ProcessCesna(void *); // todo requires CPlane
+ void ProcessCinemaScriptObject(uint8 sound); /// ok
+ void ProcessCrane(); // todo requires CCrane
+ void ProcessDocksScriptObject(uint8 sound); /// ok
+ // bool ProcessEngineDamage(void *); //todo requires CVehicle
+ void ProcessEntity(int32 sound); /// ok
+ void ProcessExplosions(int32 explosion); // todo requires CExplosion
+ void ProcessFireHydrant(); /// ok
+ void ProcessFires(int32 entity); // todo requires gFireManager
+ void ProcessFrontEnd(); /// ok
+ void ProcessGarages(); // todo requires CGarages::aGarages
+ // bool ProcessHelicopter(void *); // todo requires CVehicle
+ void ProcessHomeScriptObject(uint8 sound); /// ok
+ void ProcessJumbo(cVehicleParams *); /// ok
+ void ProcessJumboAccel(CPlane *plane); /// ok
+ void ProcessJumboDecel(CPlane *plane); /// ok
+ void ProcessJumboFlying(); /// ok
+ void ProcessJumboLanding(CPlane *plane); /// ok
+ void ProcessJumboTakeOff(CPlane *plane); /// ok
+ void ProcessJumboTaxi(); /// ok
+ void ProcessLaunderetteScriptObject(uint8 sound); /// ok
+ void ProcessLoopingScriptObject(uint8 sound); /// ok
+ // void ProcessMissionAudio();
+ // void ProcessModelVehicle(void *);
+ // void ProcessOneShotScriptObject(uint8 sound);
+ void ProcessPed(CPhysical *p); // todo
+ // void ProcessPedHeadphones(void *);
+ // void ProcessPedOneShots(void *);
+ void ProcessPhysical(int32 id); /// ok
+ void ProcessPlane(void *); // todo
+ // void ProcessPlayersVehicleEngine(void *, void *);
+ void ProcessPoliceCellBeatingScriptObject(uint8 sound); // todo
+ void ProcessPornCinema(uint8 sound); /// ok
+ void ProcessProjectiles(); // todo
+ // void ProcessRainOnVehicle(void *);
+ // void ProcessReverb();
+ // bool ProcessReverseGear(void *);
+ void ProcessSawMillScriptObject(uint8 sound); /// ok
+ void ProcessScriptObject(int32 id); // todo
+ void ProcessShopScriptObject(uint8 sound); /// ok
+ void ProcessSpecial(); /// ok
+ // bool ProcessTrainNoise(void *);
+ void ProcessVehicle(CVehicle *); // todo
+ // bool ProcessVehicleDoors(void *);
+ // bool ProcessVehicleEngine(void *);
+ // void ProcessVehicleHorn(void *);
+ // void ProcessVehicleOneShots(void *);
+ // bool ProcessVehicleReverseWarning(void *);
+ // bool ProcessVehicleRoadNoise(void *);
+ // void ProcessVehicleSirenOrAlarm(void *);
+ // void ProcessVehicleSkidding(void *);
+ void ProcessWaterCannon(int32); // todo
+ void ProcessWeather(int32 id); // todo
+ // bool ProcessWetRoadNoise(void *);
+ void ProcessWorkShopScriptObject(uint8 sound); /// ok
};
static_assert(sizeof(cAudioManager) == 0x4B14, "cAudioManager: error");
extern cAudioManager &AudioManager;
-extern cAudioManager &Players;
diff --git a/src/audio/AudioSamples.h b/src/audio/AudioSamples.h
index 26fffe63..ba7bf7a8 100644
--- a/src/audio/AudioSamples.h
+++ b/src/audio/AudioSamples.h
@@ -3037,4 +3037,132 @@ enum eAudioSamples : uint32 {
AUDIO_SAMPLE_AMMUNATION_WELCOME_3 = 3031,
TOTAL_AUDIO_SAMPLES = 3032,
NO_SAMPLE = 3033,
-}; \ No newline at end of file
+};
+
+enum eScriptSounds : int16
+{
+ SCRIPT_SOUND_0 = 0,
+ SCRIPT_SOUND_1 = 1,
+ SCRIPT_SOUND_2 = 2,
+ SCRIPT_SOUND_3 = 3,
+ SCRIPT_SOUND_PARTY_1_LOOP_S = 4,
+ SCRIPT_SOUND_PARTY_1_LOOP_L = 5,
+ SCRIPT_SOUND_PARTY_2_LOOP_S = 6,
+ SCRIPT_SOUND_PARTY_2_LOOP_L = 7,
+ SCRIPT_SOUND_PARTY_3_LOOP_S = 8,
+ SCRIPT_SOUND_PARTY_3_LOOP_L = 9,
+ SCRIPT_SOUND_PARTY_4_LOOP_S = 10,
+ SCRIPT_SOUND_PARTY_4_LOOP_L = 11,
+ SCRIPT_SOUND_PARTY_5_LOOP_S = 12,
+ SCRIPT_SOUND_PARTY_5_LOOP_L = 13,
+ SCRIPT_SOUND_PARTY_6_LOOP_S = 14,
+ SCRIPT_SOUND_PARTY_6_LOOP_L = 15,
+ SCRIPT_SOUND_PARTY_7_LOOP_S = 16,
+ SCRIPT_SOUND_PARTY_7_LOOP_L = 17,
+ SCRIPT_SOUND_PARTY_8_LOOP_S = 18,
+ SCRIPT_SOUND_PARTY_8_LOOP_L = 19,
+ SCRIPT_SOUND_PARTY_9_LOOP_S = 20,
+ SCRIPT_SOUND_PARTY_9_LOOP_L = 21,
+ SCRIPT_SOUND_PARTY_10_LOOP_S = 22,
+ SCRIPT_SOUND_PARTY_10_LOOP_L = 23,
+ SCRIPT_SOUND_PARTY_11_LOOP_S = 24,
+ SCRIPT_SOUND_PARTY_11_LOOP_L = 25,
+ SCRIPT_SOUND_PARTY_12_LOOP_S = 26,
+ SCRIPT_SOUND_PARTY_12_LOOP_L = 27,
+ SCRIPT_SOUND_PARTY_13_LOOP_S = 28,
+ SCRIPT_SOUND_PARTY_13_LOOP_L = 29,
+ SCRIPT_SOUND_STRIP_CLUB_LOOP_1_S = 30,
+ SCRIPT_SOUND_STRIP_CLUB_LOOP_1_L = 31,
+ SCRIPT_SOUND_STRIP_CLUB_LOOP_2_S = 32,
+ SCRIPT_SOUND_STRIP_CLUB_LOOP_2_L = 33,
+ SCRIPT_SOUND_WORK_SHOP_LOOP_S = 34,
+ SCRIPT_SOUND_WORK_SHOP_LOOP_L = 35,
+ SCRIPT_SOUND_SAWMILL_LOOP_S = 36,
+ SCRIPT_SOUND_SAWMILL_LOOP_L = 37,
+ SCRIPT_SOUND_38 = 38,
+ SCRIPT_SOUND_39 = 39,
+ SCRIPT_SOUND_LAUNDERETTE_LOOP_S = 40,
+ SCRIPT_SOUND_LAUNDERETTE_LOOP_L = 41,
+ SCRIPT_SOUND_CHINATOWN_RESTAURANT_S = 42,
+ SCRIPT_SOUND_CHINATOWN_RESTAURANT_L = 43,
+ SCRIPT_SOUND_CIPRIANI_RESAURANT_S = 44,
+ SCRIPT_SOUND_CIPRIANI_RESAURANT_L = 45,
+ SCRIPT_SOUND_46 = 46,
+ SCRIPT_SOUND_47 = 47,
+ SCRIPT_SOUND_MARCO_BISTRO_S = 48,
+ SCRIPT_SOUND_MARCO_BISTRO_L = 49,
+ SCRIPT_SOUND_AIRPORT_LOOP_S = 50,
+ SCRIPT_SOUND_AIRPORT_LOOP_L = 51,
+ SCRIPT_SOUND_SHOP_LOOP_S = 52,
+ SCRIPT_SOUND_SHOP_LOOP_L = 53,
+ SCRIPT_SOUND_CINEMA_LOOP_S = 54,
+ SCRIPT_SOUND_CINEMA_LOOP_L = 55,
+ SCRIPT_SOUND_DOCKS_LOOP_S = 56,
+ SCRIPT_SOUND_DOCKS_LOOP_L = 57,
+ SCRIPT_SOUND_HOME_LOOP_S = 58,
+ SCRIPT_SOUND_HOME_LOOP_L = 59,
+ SCRIPT_SOUND_FRANKIE_PIANO = 60,
+ SCRIPT_SOUND_PARTY_1_LOOP = 61,
+ SCRIPT_SOUND_PORN_CINEMA_1_S = 62,
+ SCRIPT_SOUND_PORN_CINEMA_1_L = 63,
+ SCRIPT_SOUND_PORN_CINEMA_2_S = 64,
+ SCRIPT_SOUND_PORN_CINEMA_2_L = 65,
+ SCRIPT_SOUND_PORN_CINEMA_3_S = 66,
+ SCRIPT_SOUND_PORN_CINEMA_3_L = 67,
+ SCRIPT_SOUND_BANK_ALARM_LOOP_S = 68,
+ SCRIPT_SOUND_BANK_ALARM_LOOP_L = 69,
+ SCRIPT_SOUND_POLICE_BALL_LOOP_S = 70,
+ SCRIPT_SOUND_POLICE_BALL_LOOP_L = 71,
+ SCRIPT_SOUND_RAVE_LOOP_INDUSTRIAL_S = 72,
+ SCRIPT_SOUND_RAVE_LOOP_INDUSTRIAL_L = 73,
+ SCRIPT_SOUND_74 = 74,
+ SCRIPT_SOUND_75 = 75,
+ SCRIPT_SOUND_POLICE_CELL_BEATING_LOOP_S = 76,
+ SCRIPT_SOUND_POLICE_CELL_BEATING_LOOP_L = 77,
+ SCRIPT_SOUND_INJURED_PED_MALE_OUCH_S = 78,
+ SCRIPT_SOUND_INJURED_PED_MALE_OUCH_L = 79,
+ SCRIPT_SOUND_INJURED_PED_FEMALE_OUCH_S = 80,
+ SCRIPT_SOUND_INJURED_PED_FEMALE_OUCH_L = 81,
+ SCRIPT_SOUND_EVIDENCE_PICKUP = 82,
+ SCRIPT_SOUND_UNLOAD_GOLD = 83,
+ SCRIPT_SOUND_RAVE_1_LOOP_S = 84,
+ SCRIPT_SOUND_RAVE_1_LOOP_L = 85,
+ SCRIPT_SOUND_RAVE_2_LOOP_S = 86,
+ SCRIPT_SOUND_RAVE_2_LOOP_L = 87,
+ SCRIPT_SOUND_RAVE_3_LOOP_S = 88,
+ SCRIPT_SOUND_RAVE_3_LOOP_L = 89,
+ SCRIPT_SOUND_MISTY_SEX_S = 90,
+ SCRIPT_SOUND_MISTY_SEX_L = 91,
+ SCRIPT_SOUND_GATE_START_CLUNK = 92,
+ SCRIPT_SOUND_GATE_STOP_CLUNK = 93,
+ SCRIPT_SOUND_PART_MISSION_COMPLETE = 94,
+ SCRIPT_SOUND_CHUNKY_RUN_SHOUT = 95,
+ SCRIPT_SOUND_SECURITY_GUARD_AWAY_SHOUT = 96,
+ SCRIPT_SOUND_RACE_START_3 = 97,
+ SCRIPT_SOUND_RACE_START_2 = 98,
+ SCRIPT_SOUND_RACE_START_1 = 99,
+ SCRIPT_SOUND_RACE_START_GO = 100,
+ SCRIPT_SOUND_SWAT_PED_SHOUT = 101,
+ SCRIPT_SOUND_PRETEND_FIRE_LOOP = 102,
+ SCRIPT_SOUND_AMMUNATION_CHAT_1 = 103,
+ SCRIPT_SOUND_AMMUNATION_CHAT_2 = 104,
+ SCRIPT_SOUND_AMMUNATION_CHAT_3 = 105,
+ SCRIPT_SOUND_BULLET_HIT_GROUND_1 = 106,
+ SCRIPT_SOUND_BULLET_HIT_GROUND_2 = 107,
+ SCRIPT_SOUND_BULLET_HIT_GROUND_3 = 108,
+ SCRIPT_SOUND_109 = 109,
+ SCRIPT_SOUND_110 = 110,
+ SCRIPT_SOUND_111 = 111,
+ SCRIPT_SOUND_PAYPHONE_RINGING = 112,
+ SCRIPT_SOUND_113 = 113,
+ SCRIPT_SOUND_GLASS_BREAK_L = 114,
+ SCRIPT_SOUND_GLASS_BREAK_S = 115,
+ SCRIPT_SOUND_GLASS_CRACK = 116,
+ SCRIPT_SOUND_GLASS_LIGHT_BREAK = 117,
+ SCRIPT_SOUND_BOX_DESTROYED_1 = 118,
+ SCRIPT_SOUND_BOX_DESTROYED_2 = 119,
+ SCRIPT_SOUND_METAL_COLLISION = 120,
+ SCRIPT_SOUND_TIRE_COLLISION = 121,
+ SCRIPT_SOUND_GUNSHELL_DROP = 122,
+ SCRIPT_SOUND_GUNSHELL_DROP_SOFT = 123,
+};
diff --git a/src/audio/DMAudio.cpp b/src/audio/DMAudio.cpp
index b4fee67f..2019c394 100644
--- a/src/audio/DMAudio.cpp
+++ b/src/audio/DMAudio.cpp
@@ -20,9 +20,9 @@ WRAPPER void cDMAudio::PlayFrontEndSound(uint32, uint32) { EAXJMP(0x57CC20); }
WRAPPER void cDMAudio::PlayFrontEndTrack(uint32, uint32) { EAXJMP(0x57CC80); }
WRAPPER void cDMAudio::StopFrontEndTrack() { EAXJMP(0x57CCB0); }
WRAPPER void cDMAudio::PlayOneShot(int32 audioentity, uint16 sound/*eSound*/, float) { EAXJMP(0x57C840); }
-WRAPPER void cDMAudio::SetMusicMasterVolume(int8) { EAXJMP(0x57C8C0); }
-WRAPPER void cDMAudio::SetEffectsMasterVolume(int8) { EAXJMP(0x57C890); }
-WRAPPER int8 cDMAudio::SetCurrent3DProvider(int8) { EAXJMP(0x57C9B0); }
+WRAPPER void cDMAudio::SetMusicMasterVolume(uint8) { EAXJMP(0x57C8C0); }
+WRAPPER void cDMAudio::SetEffectsMasterVolume(uint8) { EAXJMP(0x57C890); }
+WRAPPER uint8 cDMAudio::SetCurrent3DProvider(uint8) { EAXJMP(0x57C9B0); }
WRAPPER int32 cDMAudio::SetSpeakerConfig(int32) { EAXJMP(0x57C9D0); }
WRAPPER int32 cDMAudio::GetRadioInCar() { EAXJMP(0x57CE40); }
@@ -33,4 +33,5 @@ WRAPPER int32 cDMAudio::CreateEntity(int, void*) { EAXJMP(0x57C7C0); }
WRAPPER void cDMAudio::SetEntityStatus(int32 id, uint8 enable) { EAXJMP(0x57C810); }
WRAPPER void cDMAudio::SetRadioInCar(int32) { EAXJMP(0x57CE60); }
WRAPPER void cDMAudio::DestroyEntity(int32) { EAXJMP(0x57C7F0); }
-WRAPPER void cDMAudio::ClearMissionAudio(void) { EAXJMP(0x57CE20); } \ No newline at end of file
+WRAPPER void cDMAudio::ClearMissionAudio(void) { EAXJMP(0x57CE20); }
+WRAPPER void cDMAudio::ReportCrime(eCrimeType crime, const CVector &pos) { EAXJMP(0x57CAD0); }
diff --git a/src/audio/DMAudio.h b/src/audio/DMAudio.h
index 8be09ac6..da20dc31 100644
--- a/src/audio/DMAudio.h
+++ b/src/audio/DMAudio.h
@@ -96,8 +96,8 @@ enum eSound : int16
SOUND_RAMPAGE_FAILED = 91,
SOUND_RAMPAGE_KILL = 92,
SOUND_RAMPAGE_CAR_BLOWN = 93,
- _SOUND_EVIDENCE_PICKUP = 94,
- _SOUND_UNLOAD_GOLD = 95,
+ SOUND_EVIDENCE_PICKUP = 94,
+ SOUND_UNLOAD_GOLD = 95,
SOUND_PAGER = 96,
SOUND_PED_DEATH = 97,
SOUND_PED_DAMAGE = 98,
@@ -141,16 +141,16 @@ enum eSound : int16
SOUND_INJURED_PED_MALE_OUCH = 136,
SOUND_INJURED_PED_FEMALE = 137,
SOUND_8A = 138,
- _SOUND_RACE_START_3 = 139,
- _SOUND_RACE_START_2 = 140,
- _SOUND_RACE_START_1 = 141,
- _SOUND_RACE_START_GO = 142,
+ SOUND_RACE_START_3 = 139,
+ SOUND_RACE_START_2 = 140,
+ SOUND_RACE_START_1 = 141,
+ SOUND_RACE_START_GO = 142,
SOUND_SPLASH = 143,
SOUND_WATER_FALL = 144,
SOUND_SPLATTER = 145,
SOUND_CAR_PED_COLLISION = 146,
SOUND_CLOCK_TICK = 147,
- _SOUND_PART_MISSION_COMPLETE = 148,
+ SOUND_PART_MISSION_COMPLETE = 148,
SOUND_FRONTEND_MENU_STARTING = 149,
SOUND_FRONTEND_MENU_COMPLETED = 150,
SOUND_FRONTEND_MENU_DENIED = 151,
@@ -173,6 +173,7 @@ enum eSound : int16
};
class CEntity;
+enum eCrimeType;
class cDMAudio
{
@@ -191,9 +192,9 @@ public:
void PlayFrontEndTrack(uint32, uint32);
void StopFrontEndTrack();
void PlayOneShot(int32 audioentity, uint16 sound/*eSound*/, float);
- void SetMusicMasterVolume(int8);
- void SetEffectsMasterVolume(int8);
- int8 SetCurrent3DProvider(int8);
+ void SetMusicMasterVolume(uint8);
+ void SetEffectsMasterVolume(uint8);
+ uint8 SetCurrent3DProvider(uint8);
int32 SetSpeakerConfig(int32);
int32 GetRadioInCar(void);
void SetEffectsFadeVol(uint8);
@@ -204,5 +205,6 @@ public:
uint8 IsMP3RadioChannelAvailable();
void DestroyEntity(int32);
void ClearMissionAudio(void);
+ void ReportCrime(eCrimeType crime, const CVector &pos);
};
extern cDMAudio &DMAudio;
diff --git a/src/audio/MusicManager.cpp b/src/audio/MusicManager.cpp
index dcd4ae93..71cc594b 100644
--- a/src/audio/MusicManager.cpp
+++ b/src/audio/MusicManager.cpp
@@ -188,3 +188,17 @@ cMusicManager::Terminate()
{
EAXJMP(0x57D140);
}
+
+WRAPPER
+void
+cMusicManager::ChangeMusicMode(int32 mode)
+{
+ EAXJMP(0x57D310);
+}
+
+WRAPPER
+void
+cMusicManager::StopFrontEndTrack()
+{
+ EAXJMP(0x57E3D0);
+}
diff --git a/src/audio/MusicManager.h b/src/audio/MusicManager.h
index 944fd16e..6a08882f 100644
--- a/src/audio/MusicManager.h
+++ b/src/audio/MusicManager.h
@@ -267,6 +267,9 @@ public:
void Initialise();
void Terminate();
+ void ChangeMusicMode(int32 mode);
+ void StopFrontEndTrack();
+
char *Get3DProviderName(char);
bool PlayerInCar();
void DisplayRadioStationName();
diff --git a/src/audio/SampleManager.cpp b/src/audio/SampleManager.cpp
index fbeb49ed..b2f0cf35 100644
--- a/src/audio/SampleManager.cpp
+++ b/src/audio/SampleManager.cpp
@@ -1,18 +1,67 @@
+#include "SampleManager.h"
#include "common.h"
#include "patcher.h"
-#include "SampleManager.h"
CSampleManager &cSampleManager = *(CSampleManager *)0x7341E0;
uint32 &nNumOfMp3Files = *(uint32 *)0x95CC00;
uint8 &num3DProvidersAvailable = *(uint8 *)0x734237;
-uint32 *asName3DProviders = (uint32 *)0x734238;
+char **asName3DProviders = (char **)0x734238;
-bool CSampleManager::IsMP3RadioChannelAvailable() {
+bool
+CSampleManager::IsMP3RadioChannelAvailable()
+{
return nNumOfMp3Files != 0;
}
WRAPPER
+void CSampleManager::SetChannelFrequency(int32, int32) { EAXJMP(0x5679D0); }
+
+WRAPPER
+void CSampleManager::SetChannelEmittingVolume(int32, uint32) { EAXJMP(0x567820); }
+
+WRAPPER
+void
+CSampleManager::SetChannel3DPosition(int32, float, float, float)
+{
+ EAXJMP(0x567890);
+}
+
+WRAPPER
+void CSampleManager::SetChannelLoopCount(int32, int32) { EAXJMP(0x567AA0); }
+
+WRAPPER
+void CSampleManager::SetChannel3DDistances(int32, int32, int32) { EAXJMP(0x5678D0); }
+
+WRAPPER
+void CSampleManager::SetChannelReverbFlag(int32, uint8) { EAXJMP(0x567630); }
+
+WRAPPER
+int32 CSampleManager::GetSampleLength(int32) { EAXJMP(0x567300); }
+
+WRAPPER
+bool CSampleManager::InitialiseChannel(int32, int32, uint32, uint32) { EAXJMP(0x5676A0); }
+
+WRAPPER
+void CSampleManager::SetChannelLoopPoints(int32, int32, int32) { EAXJMP(0x567A30); }
+
+WRAPPER
+bool
+CSampleManager::CheckForAnAudioFileOnCD()
+{
+ EAXJMP(0x566EA0);
+}
+
+WRAPPER
+int32 CSampleManager::GetSampleBaseFrequency(int32) { EAXJMP(0x5672A0); }
+
+WRAPPER
+int32 CSampleManager::GetSampleLoopStartOffset(int32) { EAXJMP(0x5672C0); }
+
+WRAPPER
+int32 CSampleManager::GetSampleLoopEndOffset(int32) { EAXJMP(0x5672E0); }
+
+WRAPPER
bool CSampleManager::IsSampleBankLoaded(uint8) { EAXJMP(0x567130); }
WRAPPER
@@ -110,6 +159,13 @@ CSampleManager::GetChannelUsedFlag(int32 id)
WRAPPER
void
+CSampleManager::StartChannel(int32 id)
+{
+ EAXJMP(0x567B80);
+}
+
+WRAPPER
+void
CSampleManager::StopChannel(int32 id)
{
EAXJMP(0x567BE0);
diff --git a/src/audio/SampleManager.h b/src/audio/SampleManager.h
index f0245d4e..dc46e7ec 100644
--- a/src/audio/SampleManager.h
+++ b/src/audio/SampleManager.h
@@ -1,5 +1,7 @@
#pragma once
+#include "common.h"
+
struct tSample {
int m_nOffset;
unsigned int m_nSize;
@@ -11,6 +13,26 @@ struct tSample {
class CSampleManager
{
public:
+ void SetChannelFrequency(int32, int32);
+ void SetChannelEmittingVolume(int32, uint32);
+ void SetChannel3DPosition(int32, float, float, float);
+ void SetChannelLoopCount(int32, int32);
+
+ void SetChannel3DDistances(int32, int32, int32);
+ void SetChannelReverbFlag(int32, uint8);
+
+ int32 GetSampleLength(int32);
+
+ bool InitialiseChannel(int32, int32, uint32, uint32 something = 0);
+
+ void SetChannelLoopPoints(int32, int32, int32);
+
+ bool CheckForAnAudioFileOnCD();
+
+ int32 GetSampleBaseFrequency(int32);
+ int32 GetSampleLoopStartOffset(int32);
+ int32 GetSampleLoopEndOffset(int32);
+
bool IsSampleBankLoaded(uint8);
void UnloadSampleBank(uint8);
void Terminate();
@@ -32,6 +54,8 @@ public:
void SetSpeakerConfig(uint32 config);
bool GetChannelUsedFlag(int32 id);
+
+ void StartChannel(int32 id);
void StopChannel(int32 id);
static bool IsMP3RadioChannelAvailable();
@@ -39,6 +63,6 @@ public:
extern uint32 &nNumOfMp3Files;
extern uint8 &num3DProvidersAvailable;
-extern uint32* asName3DProviders;
+extern char **asName3DProviders;
extern CSampleManager &cSampleManager; \ No newline at end of file
diff --git a/src/control/AutoPilot.h b/src/control/AutoPilot.h
index 364cb633..b1c824d8 100644
--- a/src/control/AutoPilot.h
+++ b/src/control/AutoPilot.h
@@ -72,8 +72,8 @@ public:
int8 m_nPreviousDirection;
int8 m_nCurrentDirecton;
int8 m_nNextDirection;
- int8 m_nPreviousPathDirection;
- int8 m_nCurrentPathDirection;
+ int8 m_nPreviousLane;
+ int8 m_nCurrentLane;
eCarDrivingStyle m_nDrivingStyle;
eCarMission m_nCarMission;
eCarTempAction m_nAnimationId;
@@ -101,8 +101,7 @@ public:
m_nCurrentPathNodeInfo = m_nNextPathNodeInfo;
m_nNextDirection = 1;
m_nCurrentDirecton = m_nNextDirection;
- m_nCurrentPathDirection = 0;
- m_nPreviousPathDirection = m_nCurrentPathDirection;
+ m_nPreviousLane = m_nCurrentLane = 0;
m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS;
m_nCarMission = MISSION_NONE;
m_nAnimationId = TEMPACT_NONE;
diff --git a/src/control/Bridge.cpp b/src/control/Bridge.cpp
index 3215ea2d..81f43f32 100644
--- a/src/control/Bridge.cpp
+++ b/src/control/Bridge.cpp
@@ -46,6 +46,7 @@ void CBridge::Update()
float liftHeight;
+ // Set bridge height and state
if (CStats::CommercialPassed)
{
if (TimeOfBridgeBecomingOperational == 0)
@@ -81,30 +82,6 @@ void CBridge::Update()
liftHeight = 25.0;
State = STATE_LIFT_PART_IS_UP;
}
-
- // Move bridge part
- if (liftHeight != OldLift)
- {
- pLiftPart->GetPosition().z = DefaultZLiftPart + liftHeight;
- pLiftPart->GetMatrix().UpdateRW();
- pLiftPart->UpdateRwFrame();
- if (pLiftRoad)
- {
- pLiftRoad->GetPosition().z = DefaultZLiftRoad + liftHeight;
- pLiftRoad->GetMatrix().UpdateRW();
- pLiftRoad->UpdateRwFrame();
- }
- pWeight->GetPosition().z = DefaultZLiftWeight - liftHeight;
- pWeight->GetMatrix().UpdateRW();
- pWeight->UpdateRwFrame();
-
- OldLift = liftHeight;
- }
-
- if (State == STATE_LIFT_PART_ABOUT_TO_MOVE_UP && OldState == STATE_LIFT_PART_IS_DOWN)
- ThePaths.SetLinksBridgeLights(-330.0, -230.0, -700.0, -588.0, true);
- else if (State == STATE_LIFT_PART_IS_DOWN && OldState == STATE_LIFT_PART_MOVING_DOWN)
- ThePaths.SetLinksBridgeLights(-330.0, -230.0, -700.0, -588.0, false);
}
else
{
@@ -112,6 +89,30 @@ void CBridge::Update()
TimeOfBridgeBecomingOperational = 0;
State = STATE_BRIDGE_LOCKED;
}
+
+ // Move bridge part
+ if (liftHeight != OldLift)
+ {
+ pLiftPart->GetPosition().z = DefaultZLiftPart + liftHeight;
+ pLiftPart->GetMatrix().UpdateRW();
+ pLiftPart->UpdateRwFrame();
+ if (pLiftRoad)
+ {
+ pLiftRoad->GetPosition().z = DefaultZLiftRoad + liftHeight;
+ pLiftRoad->GetMatrix().UpdateRW();
+ pLiftRoad->UpdateRwFrame();
+ }
+ pWeight->GetPosition().z = DefaultZLiftWeight - liftHeight;
+ pWeight->GetMatrix().UpdateRW();
+ pWeight->UpdateRwFrame();
+
+ OldLift = liftHeight;
+ }
+
+ if (State == STATE_LIFT_PART_ABOUT_TO_MOVE_UP && OldState == STATE_LIFT_PART_IS_DOWN)
+ ThePaths.SetLinksBridgeLights(-330.0, -230.0, -700.0, -588.0, true);
+ else if (State == STATE_LIFT_PART_IS_DOWN && OldState == STATE_LIFT_PART_MOVING_DOWN)
+ ThePaths.SetLinksBridgeLights(-330.0, -230.0, -700.0, -588.0, false);
}
bool CBridge::ShouldLightsBeFlashing() { return State != STATE_LIFT_PART_IS_DOWN; }
diff --git a/src/control/CarAI.cpp b/src/control/CarAI.cpp
new file mode 100644
index 00000000..faf27788
--- /dev/null
+++ b/src/control/CarAI.cpp
@@ -0,0 +1,6 @@
+#include "common.h"
+#include "patcher.h"
+#include "CarAI.h"
+
+WRAPPER void CCarAI::UpdateCarAI(CVehicle*) { EAXJMP(0x413E50); }
+WRAPPER void CCarAI::MakeWayForCarWithSiren(CVehicle *veh) { EAXJMP(0x416280); }
diff --git a/src/control/CarAI.h b/src/control/CarAI.h
new file mode 100644
index 00000000..5112f769
--- /dev/null
+++ b/src/control/CarAI.h
@@ -0,0 +1,10 @@
+#pragma once
+
+class CVehicle;
+
+class CCarAI
+{
+public:
+ static void UpdateCarAI(CVehicle*);
+ static void MakeWayForCarWithSiren(CVehicle *veh);
+};
diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp
index b0f4c1ed..5e436c84 100644
--- a/src/control/CarCtrl.cpp
+++ b/src/control/CarCtrl.cpp
@@ -12,3 +12,16 @@ WRAPPER void CCarCtrl::SwitchVehicleToRealPhysics(CVehicle*) { EAXJMP(0x41F7F0);
WRAPPER void CCarCtrl::AddToCarArray(int32 id, int32 vehclass) { EAXJMP(0x4182F0); }
WRAPPER void CCarCtrl::UpdateCarCount(CVehicle*, bool) { EAXJMP(0x4202E0); }
WRAPPER int32 CCarCtrl::ChooseCarModel(int32 vehclass) { EAXJMP(0x418110); }
+WRAPPER bool CCarCtrl::JoinCarWithRoadSystemGotoCoors(CVehicle*, CVector, bool) { EAXJMP(0x41FA00); }
+WRAPPER void CCarCtrl::JoinCarWithRoadSystem(CVehicle*) { EAXJMP(0x41F820); }
+WRAPPER void CCarCtrl::SteerAICarWithPhysics(CVehicle*) { EAXJMP(0x41DA60); }
+WRAPPER void CCarCtrl::UpdateCarOnRails(CVehicle*) { EAXJMP(0x418880); }
+WRAPPER void CCarCtrl::ScanForPedDanger(CVehicle *veh) { EAXJMP(0x418F40); }
+
+bool
+CCarCtrl::MapCouldMoveInThisArea(float x, float y)
+{
+ // bridge moves up and down
+ return x > -342.0f && x < -219.0f &&
+ y > -677.0f && y < -580.0f;
+}
diff --git a/src/control/CarCtrl.h b/src/control/CarCtrl.h
index c54f747f..677dcf36 100644
--- a/src/control/CarCtrl.h
+++ b/src/control/CarCtrl.h
@@ -9,6 +9,12 @@ public:
static void AddToCarArray(int32 id, int32 vehclass);
static void UpdateCarCount(CVehicle*, bool);
static int32 ChooseCarModel(int32 vehclass);
+ static bool JoinCarWithRoadSystemGotoCoors(CVehicle*, CVector, bool);
+ static void JoinCarWithRoadSystem(CVehicle*);
+ static void SteerAICarWithPhysics(CVehicle*);
+ static void UpdateCarOnRails(CVehicle*);
+ static bool MapCouldMoveInThisArea(float x, float y);
+ static void ScanForPedDanger(CVehicle *veh);
static int32 &NumLawEnforcerCars;
static int32 &NumAmbulancesOnDuty;
diff --git a/src/control/Darkel.cpp b/src/control/Darkel.cpp
index ab28f96e..ad8d1176 100644
--- a/src/control/Darkel.cpp
+++ b/src/control/Darkel.cpp
@@ -141,7 +141,7 @@ void CDarkel::RegisterKillByPlayer(CPed *victim, eWeaponType weapontype, bool he
}
#endif
-void CDarkel::RegisterKillNotByPlayer()
+void CDarkel::RegisterKillNotByPlayer(CPed* victim, eWeaponType weapontype)
{
++CStats::NumberKillFrenziesPassed;
}
@@ -300,7 +300,7 @@ void CDarkel::Update()
TimeOfFrenzyStart = CTimer::GetTimeInMilliseconds();
- FindPlayerPed()->m_pWanted->SetWantedLevel(NOTWANTED);
+ FindPlayerPed()->m_pWanted->SetWantedLevel(0);
if (WeaponType == WEAPONTYPE_UZI_DRIVEBY)
WeaponType = WEAPONTYPE_UZI;
diff --git a/src/control/Darkel.h b/src/control/Darkel.h
index 35d849d2..77a14bb8 100644
--- a/src/control/Darkel.h
+++ b/src/control/Darkel.h
@@ -42,7 +42,7 @@ public:
static eKillFrenzyStatus ReadStatus();
static void RegisterCarBlownUpByPlayer(CVehicle *vehicle);
static void RegisterKillByPlayer(CPed *victim, eWeaponType weapontype, bool headshot = false);
- static void RegisterKillNotByPlayer();
+ static void RegisterKillNotByPlayer(CPed* victim, eWeaponType weapontype);
static void ResetModelsKilledByPlayer();
static void ResetOnPlayerDeath();
static void StartFrenzy(eWeaponType weaponType, int32 time, int16 kill, int32 modelId0, wchar *text, int32 modelId2, int32 modelId3, int32 modelId4, bool standardSound, bool needHeadShot);
diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp
index d601db8e..acc2b459 100644
--- a/src/control/Garages.cpp
+++ b/src/control/Garages.cpp
@@ -63,6 +63,8 @@ CGarages::IsModelIndexADoor(uint32 id)
id == MI_CRUSHERLID;
}
+WRAPPER void CGarages::TriggerMessage(char *text, int16, uint16 time, int16) { EAXJMP(0x426B20); }
+
#if 0
WRAPPER void CGarages::PrintMessages(void) { EAXJMP(0x426310); }
#else
diff --git a/src/control/Garages.h b/src/control/Garages.h
index f018401c..69f9d256 100644
--- a/src/control/Garages.h
+++ b/src/control/Garages.h
@@ -22,5 +22,6 @@ public:
public:
static bool IsModelIndexADoor(uint32 id);
+ static void TriggerMessage(char *text, int16, uint16 time, int16);
static void PrintMessages(void);
};
diff --git a/src/control/PathFind.cpp b/src/control/PathFind.cpp
index a92882db..f90e0c8f 100644
--- a/src/control/PathFind.cpp
+++ b/src/control/PathFind.cpp
@@ -5,7 +5,7 @@
CPathFind &ThePaths = *(CPathFind*)0x8F6754;
WRAPPER int32 CPathFind::FindNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bool disabled, bool betweenLevels) { EAXJMP(0x42CC30); }
-
+WRAPPER CPathNode** CPathFind::FindNextNodeWandering(uint8, CVector, CPathNode**, CPathNode**, uint8, uint8*) { EAXJMP(0x42B9F0); }
int TempListLength;
enum
diff --git a/src/control/PathFind.h b/src/control/PathFind.h
index 9b6be573..9d97de3f 100644
--- a/src/control/PathFind.h
+++ b/src/control/PathFind.h
@@ -129,6 +129,7 @@ public:
void StoreNodeInfoCar(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, int16 width, int8 numLeft, int8 numRight);
void RegisterMapObject(CTreadable *mapObject);
int32 FindNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bool disabled, bool betweenLevels);
+ CPathNode** FindNextNodeWandering(uint8, CVector, CPathNode**, CPathNode**, uint8, uint8*);
bool IsPathObject(int id) { return id < PATHNODESIZE && (InfoForTileCars[id*12].type != 0 || InfoForTilePeds[id*12].type != 0); }
diff --git a/src/control/Phones.cpp b/src/control/Phones.cpp
index 028d80a9..376e2757 100644
--- a/src/control/Phones.cpp
+++ b/src/control/Phones.cpp
@@ -2,12 +2,18 @@
#include "patcher.h"
#include "Phones.h"
#include "Pools.h"
+#include "ModelIndices.h"
+#include "Ped.h"
+#include "Pad.h"
+#include "Messages.h"
CPhoneInfo &gPhoneInfo = *(CPhoneInfo*)0x732A20;
bool &CPhoneInfo::isPhonePickedUp = *(bool*)0x6283AC;
-bool &CPhoneInfo::isPhoneBeingPickedUp = *(bool*)0x6283B4;
+uint32 &CPhoneInfo::phoneMessagesTimer = *(uint32*)0x6283A8;
CPhone *&CPhoneInfo::pickedUpPhone = *(CPhone**)0x6283B0;
+bool &CPhoneInfo::isPhoneBeingPickedUp = *(bool*)0x6283B4;
+CPed *&CPhoneInfo::pedWhoPickingUpPhone = *(CPed**)0x6283B8;
int
CPhoneInfo::FindNearestFreePhone(CVector *pos)
@@ -69,21 +75,20 @@ CPhoneInfo::Load(CPhoneInfo *source, uint8 buffer)
CPhone *phone = &source->m_aPhones[phoneId];
m_aPhones[phoneId].m_vecPos = phone->m_vecPos;
- memcpy(m_aPhones[phoneId].m_apMessages, phone->m_apMessages, sizeof(uint16*) * 6);
+ memcpy(m_aPhones[phoneId].m_apMessages, phone->m_apMessages, sizeof(wchar*) * 6);
m_aPhones[phoneId].m_pEntity = phone->m_pEntity;
m_aPhones[phoneId].m_nState = phone->m_nState;
m_aPhones[phoneId].field_30 = phone->field_30;
+ // It's saved as building pool index in save file, convert it to true entity
if (phone->m_pEntity) {
- // It's saved as building pool index in save file, convert it to true entity
- CBuilding *actualEntity = CPools::GetBuildingPool()->GetSlot((int)phone->m_pEntity - 1);
- m_aPhones[phoneId].m_pEntity = actualEntity;
+ m_aPhones[phoneId].m_pEntity = CPools::GetBuildingPool()->GetSlot((int)phone->m_pEntity - 1);
}
}
}
void
-CPhoneInfo::SetPhoneMessage_JustOnce(int phoneId, uint16 *msg1, uint16 *msg2, uint16 *msg3, uint16 *msg4, uint16 *msg5, uint16 *msg6)
+CPhoneInfo::SetPhoneMessage_JustOnce(int phoneId, wchar *msg1, wchar *msg2, wchar *msg3, wchar *msg4, wchar *msg5, wchar *msg6)
{
// If there is at least one message, it should be msg1.
if (msg1) {
@@ -100,7 +105,7 @@ CPhoneInfo::SetPhoneMessage_JustOnce(int phoneId, uint16 *msg1, uint16 *msg2, ui
}
void
-CPhoneInfo::SetPhoneMessage_Repeatedly(int phoneId, uint16 *msg1, uint16 *msg2, uint16 *msg3, uint16 *msg4, uint16 *msg5, uint16 *msg6)
+CPhoneInfo::SetPhoneMessage_Repeatedly(int phoneId, wchar *msg1, wchar *msg2, wchar *msg3, wchar *msg4, wchar *msg5, wchar *msg6)
{
// If there is at least one message, it should be msg1.
if (msg1) {
@@ -116,6 +121,137 @@ CPhoneInfo::SetPhoneMessage_Repeatedly(int phoneId, uint16 *msg1, uint16 *msg2,
}
}
+int
+CPhoneInfo::GrabPhone(float xPos, float yPos)
+{
+ // "Grab" doesn't mean picking up the phone, it means allocating some particular phone to
+ // whoever called the 024A opcode first with the position parameters closest to phone.
+ // Same phone won't be available on next run of this function.
+
+ int nearestPhoneId = -1;
+ CVector pos(xPos, yPos, 0.0f);
+ float nearestPhoneDist = 100.0f;
+
+ for (int phoneId = m_nNum; phoneId < m_nMax; phoneId++) {
+ float phoneDistance = (m_aPhones[phoneId].m_vecPos - pos).Magnitude2D();
+ if (phoneDistance < nearestPhoneDist) {
+ nearestPhoneDist = phoneDistance;
+ nearestPhoneId = phoneId;
+ }
+ }
+ m_aPhones[nearestPhoneId].m_nState = PHONE_STATE_MESSAGE_REMOVED;
+
+ CPhone oldFirstPhone = m_aPhones[m_nNum];
+ m_aPhones[m_nNum] = m_aPhones[nearestPhoneId];
+ m_aPhones[nearestPhoneId] = oldFirstPhone;
+ m_nNum++;
+ return m_nNum - 1;
+}
+
+void
+CPhoneInfo::Initialise(void)
+{
+ CBuildingPool *pool = CPools::GetBuildingPool();
+ pedWhoPickingUpPhone = nil;
+ isPhonePickedUp = false;
+ isPhoneBeingPickedUp = false;
+ pickedUpPhone = nil;
+ m_nMax = 0;
+ m_nNum = 0;
+ for (int v5 = pool->GetSize() - 1; v5 >= 0; v5--) {
+ CBuilding *building = pool->GetSlot(v5);
+ if (building) {
+ if (building->m_modelIndex == MI_PHONEBOOTH1) {
+ CPhone *maxPhone = &m_aPhones[m_nMax];
+ maxPhone->m_nState = PHONE_STATE_FREE;
+ maxPhone->m_vecPos = *(building->GetPosition());
+ maxPhone->m_pEntity = building;
+ m_nMax++;
+ }
+ }
+ }
+}
+
+void
+CPhoneInfo::Save(CPhoneInfo *destination, uint32 *size)
+{
+ *size = sizeof(CPhoneInfo);
+ destination->m_nMax = this->m_nMax;
+ destination->m_nNum = m_nNum;
+ for(int phoneId = 0; phoneId < 50; phoneId++) {
+ CPhone* phone = &destination->m_aPhones[phoneId];
+
+ phone->m_vecPos = m_aPhones[phoneId].m_vecPos;
+ memcpy(phone->m_apMessages, m_aPhones[phoneId].m_apMessages, sizeof(wchar*) * 6);
+ phone->m_pEntity = m_aPhones[phoneId].m_pEntity;
+ phone->m_nState = m_aPhones[phoneId].m_nState;
+ phone->field_30 = m_aPhones[phoneId].field_30;
+
+ // Convert entity pointer to building pool index while saving
+ if (phone->m_pEntity) {
+ phone->m_pEntity = (CEntity*) CPools::GetBuildingPool()->GetJustIndex((CBuilding*)phone->m_pEntity) + 1;
+ }
+ }
+}
+
+void
+CPhoneInfo::Shutdown(void)
+{
+ m_nMax = 0;
+ m_nNum = 0;
+}
+
+void
+PhonePutDownCB(CAnimBlendAssociation *assoc, void *arg)
+{
+ assoc->flags |= ASSOC_DELETEFADEDOUT;
+ assoc->blendDelta = -1000.0f;
+ CPad::GetPad(0)->DisablePlayerControls &= ~PLAYERCONTROL_DISABLED_40;
+ CPed *ped = (CPed*)arg;
+
+ if (assoc->blendAmount > 0.5f)
+ ped->m_ped_flagC10 = true;
+
+ if (ped->m_nPedState == PED_MAKE_CALL)
+ ped->m_nPedState = PED_IDLE;
+}
+
+void
+PhonePickUpCB(CAnimBlendAssociation *assoc, void *arg)
+{
+ CPhone *phone = (CPhone*)arg;
+ int messagesDisplayTime = 0;
+
+ for(int i=0; i < 6; i++) {
+ wchar *msg = phone->m_apMessages[i];
+ if (msg) {
+ CMessages::AddMessage(msg, 3000, 0);
+ messagesDisplayTime += 3000;
+ }
+ }
+
+ CPhoneInfo::isPhoneBeingPickedUp = false;
+ CPhoneInfo::isPhonePickedUp = true;
+ CPhoneInfo::pickedUpPhone = phone;
+ CPhoneInfo::phoneMessagesTimer = CTimer::GetTimeInMilliseconds() + messagesDisplayTime;
+
+ if (phone->m_nState == PHONE_STATE_ONETIME_MESSAGE_SET) {
+ phone->m_nState = PHONE_STATE_ONETIME_MESSAGE_SHOWN;
+ } else {
+ phone->m_nState = PHONE_STATE_REPEATED_MESSAGE_SHOWN;
+ phone->m_lastTimeRepeatedMsgShown = CTimer::GetTimeInMilliseconds();
+ }
+
+ CPed *ped = CPhoneInfo::pedWhoPickingUpPhone;
+ ped->m_nMoveState = PEDMOVE_STILL;
+ CAnimManager::BlendAnimation((RpClump*)ped->m_rwObject, ASSOCGRP_STD, ANIM_IDLE_STANCE, 8.0f);
+
+ if (assoc->blendAmount > 0.5f && ped)
+ CAnimManager::BlendAnimation((RpClump*)ped->m_rwObject, ASSOCGRP_STD, ANIM_PHONE_TALK, 8.0f);
+
+ CPhoneInfo::pedWhoPickingUpPhone = nil;
+}
+
STARTPATCHES
InjectHook(0x42F720, &CPhoneInfo::FindNearestFreePhone, PATCH_JUMP);
InjectHook(0x42FD50, &CPhoneInfo::PhoneAtThisPosition, PATCH_JUMP);
@@ -124,7 +260,10 @@ STARTPATCHES
InjectHook(0x430120, &CPhoneInfo::Load, PATCH_JUMP);
InjectHook(0x42FF90, &CPhoneInfo::SetPhoneMessage_JustOnce, PATCH_JUMP);
InjectHook(0x42FF30, &CPhoneInfo::SetPhoneMessage_Repeatedly, PATCH_JUMP);
-ENDPATCHES
-
-WRAPPER void PhonePutDownCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x42F570); }
-WRAPPER void PhonePickUpCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x42F470); }
+ InjectHook(0x430060, &CPhoneInfo::Save, PATCH_JUMP);
+ InjectHook(0x42F710, &CPhoneInfo::Shutdown, PATCH_JUMP);
+ InjectHook(0x42F640, &CPhoneInfo::Initialise, PATCH_JUMP);
+ InjectHook(0x42FDB0, &CPhoneInfo::GrabPhone, PATCH_JUMP);
+ InjectHook(0x42F570, &PhonePutDownCB, PATCH_JUMP);
+ InjectHook(0x42F470, &PhonePickUpCB, PATCH_JUMP);
+ENDPATCHES \ No newline at end of file
diff --git a/src/control/Phones.h b/src/control/Phones.h
index 74f24d25..35389f3f 100644
--- a/src/control/Phones.h
+++ b/src/control/Phones.h
@@ -1,7 +1,9 @@
#pragma once
#include "Physical.h"
-#include "AnimBlendAssociation.h"
+
+class CPed;
+class CAnimBlendAssociation;
enum {
PHONE_STATE_FREE,
@@ -19,7 +21,7 @@ enum {
struct CPhone
{
CVector m_vecPos;
- uint16 *m_apMessages[6];
+ wchar *m_apMessages[6];
uint32 m_lastTimeRepeatedMsgShown;
CEntity *m_pEntity; // it's building pool index in save files
int32 m_nState;
@@ -29,10 +31,13 @@ struct CPhone
static_assert(sizeof(CPhone) == 0x34, "CPhone: error");
class CPhoneInfo {
+public:
static bool &isPhonePickedUp;
- static bool &isPhoneBeingPickedUp;
+ static uint32 &phoneMessagesTimer;
static CPhone *&pickedUpPhone;
-public:
+ static bool &isPhoneBeingPickedUp;
+ static CPed *&pedWhoPickingUpPhone;
+
int32 m_nMax;
int32 m_nNum;
CPhone m_aPhones[50];
@@ -45,8 +50,12 @@ public:
bool HasMessageBeenDisplayed(int);
bool IsMessageBeingDisplayed(int);
void Load(CPhoneInfo *source, uint8 buffer);
- void SetPhoneMessage_JustOnce(int phoneId, uint16 *msg1, uint16 *msg2, uint16 *msg3, uint16 *msg4, uint16 *msg5, uint16 *msg6);
- void SetPhoneMessage_Repeatedly(int phoneId, uint16 *msg1, uint16 *msg2, uint16 *msg3, uint16 *msg4, uint16 *msg5, uint16 *msg6);
+ void SetPhoneMessage_JustOnce(int phoneId, wchar *msg1, wchar *msg2, wchar *msg3, wchar *msg4, wchar *msg5, wchar *msg6);
+ void SetPhoneMessage_Repeatedly(int phoneId, wchar *msg1, wchar *msg2, wchar *msg3, wchar *msg4, wchar *msg5, wchar *msg6);
+ int GrabPhone(float, float);
+ void Initialise(void);
+ void Save(CPhoneInfo*, uint32*);
+ void Shutdown(void);
};
extern CPhoneInfo &gPhoneInfo;
diff --git a/src/control/Population.cpp b/src/control/Population.cpp
index 1ae5962d..31c475f0 100644
--- a/src/control/Population.cpp
+++ b/src/control/Population.cpp
@@ -7,7 +7,9 @@ PedGroup *CPopulation::ms_pPedGroups = (PedGroup*)0x6E9248;
bool &CPopulation::ms_bGivePedsWeapons = *(bool*)0x95CCF6;
int32 &CPopulation::m_AllRandomPedsThisType = *(int32*)0x5FA570;
float &CPopulation::PedDensityMultiplier = *(float*)0x5FA56C;
+uint32 &CPopulation::ms_nTotalMissionPeds = *(uint32*)0x8F5F70;
WRAPPER void CPopulation::UpdatePedCount(uint32, bool) { EAXJMP(0x4F5A60); }
WRAPPER void CPopulation::DealWithZoneChange(eLevelName oldLevel, eLevelName newLevel, bool) { EAXJMP(0x4F6200); }
WRAPPER CPed *CPopulation::AddPedInCar(CVehicle *vehicle) { EAXJMP(0x4F5800); }
+WRAPPER bool CPopulation::IsPointInSafeZone(CVector *coors) { EAXJMP(0x4F60C0); }
diff --git a/src/control/Population.h b/src/control/Population.h
index 6bd2e3ae..e067562a 100644
--- a/src/control/Population.h
+++ b/src/control/Population.h
@@ -2,6 +2,7 @@
class CPed;
class CVehicle;
+enum eLevelName;
struct PedGroup
{
@@ -15,8 +16,10 @@ public:
static bool &ms_bGivePedsWeapons;
static int32 &m_AllRandomPedsThisType;
static float &PedDensityMultiplier;
+ static uint32 &ms_nTotalMissionPeds;
static void UpdatePedCount(uint32, bool);
static void DealWithZoneChange(eLevelName oldLevel, eLevelName newLevel, bool);
static CPed *AddPedInCar(CVehicle *vehicle);
+ static bool IsPointInSafeZone(CVector *coors);
};
diff --git a/src/control/Remote.cpp b/src/control/Remote.cpp
new file mode 100644
index 00000000..8d8d08f2
--- /dev/null
+++ b/src/control/Remote.cpp
@@ -0,0 +1,5 @@
+#include "common.h"
+#include "patcher.h"
+#include "Remote.h"
+
+WRAPPER void CRemote::TakeRemoteControlledCarFromPlayer(void) { EAXJMP(0x435DA0); }
diff --git a/src/control/Remote.h b/src/control/Remote.h
new file mode 100644
index 00000000..f8ef96bf
--- /dev/null
+++ b/src/control/Remote.h
@@ -0,0 +1,7 @@
+#pragma once
+
+class CRemote
+{
+public:
+ static void TakeRemoteControlledCarFromPlayer(void);
+};
diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp
index 3ce9085f..d9453ad6 100644
--- a/src/control/Replay.cpp
+++ b/src/control/Replay.cpp
@@ -11,7 +11,7 @@
#include "FileMgr.h"
#include "Heli.h"
#include "main.h"
-#include "math/Matrix.h"
+#include "Matrix.h"
#include "ModelIndices.h"
#include "ModelInfo.h"
#include "Object.h"
@@ -25,7 +25,7 @@
#include "RpAnimBlend.h"
#include "RwHelper.h"
#include "CutsceneMgr.h"
-#include "render/Skidmarks.h"
+#include "Skidmarks.h"
#include "Streaming.h"
#include "Timer.h"
#include "Train.h"
@@ -625,9 +625,9 @@ void CReplay::StoreCarUpdate(CVehicle *vehicle, int id)
vp->health = vehicle->m_fHealth / 4.0f; /* Not anticipated that health can be > 1000. */
vp->acceleration = vehicle->m_fGasPedal * 100.0f;
vp->panels = vehicle->IsCar() ? ((CAutomobile*)vehicle)->Damage.m_panelStatus : 0;
- vp->velocityX = 8000.0f * max(-4.0f, min(4.0f, vehicle->GetSpeed().x)); /* 8000!? */
- vp->velocityY = 8000.0f * max(-4.0f, min(4.0f, vehicle->GetSpeed().y));
- vp->velocityZ = 8000.0f * max(-4.0f, min(4.0f, vehicle->GetSpeed().z));
+ vp->velocityX = 8000.0f * max(-4.0f, min(4.0f, vehicle->GetMoveSpeed().x)); /* 8000!? */
+ vp->velocityY = 8000.0f * max(-4.0f, min(4.0f, vehicle->GetMoveSpeed().y));
+ vp->velocityZ = 8000.0f * max(-4.0f, min(4.0f, vehicle->GetMoveSpeed().z));
vp->mi = vehicle->GetModelIndex();
vp->primary_color = vehicle->m_currentColour1;
vp->secondary_color = vehicle->m_currentColour2;
@@ -718,7 +718,7 @@ void CReplay::ProcessCarUpdate(CVehicle *vehicle, float interpolation, CAddressI
}
vehicle->bEngineOn = true;
if (vehicle->IsCar())
- ((CAutomobile*)vehicle)->m_nWheelsOnGround = 4;
+ ((CAutomobile*)vehicle)->m_nDriveWheelsOnGround = 4;
CWorld::Remove(vehicle);
CWorld::Add(vehicle);
if (vehicle->IsBoat())
@@ -850,10 +850,10 @@ bool CReplay::PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, flo
TheCamera.GetMatrix().GetPosition() *= split;
TheCamera.GetMatrix() += CMatrix(interpolation) * pg->camera_pos;
RwMatrix* pm = RwFrameGetMatrix(RwCameraGetFrame(TheCamera.m_pRwCamera));
- pm->pos = *(RwV3d*)TheCamera.GetMatrix().GetPosition();
- pm->at = *(RwV3d*)TheCamera.GetMatrix().GetForward();
- pm->up = *(RwV3d*)TheCamera.GetMatrix().GetUp();
- pm->right = *(RwV3d*)TheCamera.GetMatrix().GetRight();
+ pm->pos = *(RwV3d*)TheCamera.GetPosition();
+ pm->at = *(RwV3d*)TheCamera.GetForward();
+ pm->up = *(RwV3d*)TheCamera.GetUp();
+ pm->right = *(RwV3d*)TheCamera.GetRight();
CameraFocusX = split * CameraFocusX + interpolation * pg->player_pos.x;
CameraFocusY = split * CameraFocusY + interpolation * pg->player_pos.y;
CameraFocusZ = split * CameraFocusZ + interpolation * pg->player_pos.z;
@@ -979,15 +979,15 @@ void CReplay::ProcessReplayCamera(void)
switch (CameraMode) {
case REPLAYCAMMODE_TOPDOWN:
{
- TheCamera.GetMatrix().GetPosition() = CVector(CameraFocusX, CameraFocusY, CameraFocusZ + 15.0f);
- TheCamera.GetMatrix().GetForward() = CVector(0.0f, 0.0f, -1.0f);
- TheCamera.GetMatrix().GetUp() = CVector(0.0f, 1.0f, 0.0f);
- TheCamera.GetMatrix().GetRight() = CVector(1.0f, 0.0f, 0.0f);
+ TheCamera.GetPosition() = CVector(CameraFocusX, CameraFocusY, CameraFocusZ + 15.0f);
+ TheCamera.GetForward() = CVector(0.0f, 0.0f, -1.0f);
+ TheCamera.GetUp() = CVector(0.0f, 1.0f, 0.0f);
+ TheCamera.GetRight() = CVector(1.0f, 0.0f, 0.0f);
RwMatrix* pm = RwFrameGetMatrix(RwCameraGetFrame(TheCamera.m_pRwCamera));
- pm->pos = *(RwV3d*)&TheCamera.GetMatrix().GetPosition();
- pm->at = *(RwV3d*)&TheCamera.GetMatrix().GetForward();
- pm->up = *(RwV3d*)&TheCamera.GetMatrix().GetUp();
- pm->right = *(RwV3d*)&TheCamera.GetMatrix().GetRight();
+ pm->pos = *(RwV3d*)&TheCamera.GetPosition();
+ pm->at = *(RwV3d*)&TheCamera.GetForward();
+ pm->up = *(RwV3d*)&TheCamera.GetUp();
+ pm->right = *(RwV3d*)&TheCamera.GetRight();
break;
}
case REPLAYCAMMODE_FIXED:
@@ -1113,7 +1113,7 @@ void CReplay::StoreStuffInMem(void)
TimeStep = CTimer::GetTimeStep();
TimeScale = CTimer::GetTimeScale();
int size = CPools::GetPedPool()->GetSize();
- pPedAnims = (CStoredDetailedAnimationState*)malloc(size * sizeof(CStoredDetailedAnimationState));
+ pPedAnims = new CStoredDetailedAnimationState[size];
for (int i = 0; i < size; i++) {
CPed* ped = CPools::GetPedPool()->GetSlot(i);
if (ped)
@@ -1279,7 +1279,7 @@ void CReplay::RestoreStuffFromMem(void)
continue;
RetrieveDetailedPedAnimation(ped, &pPedAnims[i]);
}
- free(pPedAnims);
+ delete[] pPedAnims;
pPedAnims = nil;
DMAudio.ChangeMusicMode(0);
DMAudio.SetRadioInCar(OldRadioStation);
@@ -1525,15 +1525,15 @@ void CReplay::ProcessLookAroundCam(void)
right.Normalise();
CVector up = CrossProduct(forward, right);
up.Normalise();
- TheCamera.GetMatrix().GetForward() = forward;
- TheCamera.GetMatrix().GetUp() = up;
- TheCamera.GetMatrix().GetRight() = right;
- TheCamera.GetMatrix().GetPosition() = camera_pt;
+ TheCamera.GetForward() = forward;
+ TheCamera.GetUp() = up;
+ TheCamera.GetRight() = right;
+ TheCamera.GetPosition() = camera_pt;
RwMatrix* pm = RwFrameGetMatrix(RwCameraGetFrame(TheCamera.m_pRwCamera));
- pm->pos = *(RwV3d*)&TheCamera.GetMatrix().GetPosition();
- pm->at = *(RwV3d*)&TheCamera.GetMatrix().GetForward();
- pm->up = *(RwV3d*)&TheCamera.GetMatrix().GetUp();
- pm->right = *(RwV3d*)&TheCamera.GetMatrix().GetRight();
+ pm->pos = *(RwV3d*)&TheCamera.GetPosition();
+ pm->at = *(RwV3d*)&TheCamera.GetForward();
+ pm->up = *(RwV3d*)&TheCamera.GetUp();
+ pm->right = *(RwV3d*)&TheCamera.GetRight();
TheCamera.CalculateDerivedValues();
RwMatrixUpdate(RwFrameGetMatrix(RwCameraGetFrame(TheCamera.m_pRwCamera)));
RwFrameUpdateObjects(RwCameraGetFrame(TheCamera.m_pRwCamera));
diff --git a/src/control/Replay.h b/src/control/Replay.h
index cd8d9a45..6b11da75 100644
--- a/src/control/Replay.h
+++ b/src/control/Replay.h
@@ -176,7 +176,7 @@ class CReplay
int8 velocityZ;
union{
int8 car_gun;
- uint8 wheel_state;
+ int8 wheel_state;
};
uint8 wheel_susp_dist[4];
uint8 wheel_rotation[4];
diff --git a/src/control/Script.cpp b/src/control/Script.cpp
index b50c101e..bd43d301 100644
--- a/src/control/Script.cpp
+++ b/src/control/Script.cpp
@@ -4,10 +4,17 @@
#include "Script.h"
#include "ScriptCommands.h"
+#include "Boat.h"
#include "Camera.h"
#include "CarCtrl.h"
+#include "CivilianPed.h"
+#include "Clock.h"
+#include "CopPed.h"
#include "DMAudio.h"
+#include "EmergencyPed.h"
#include "FileMgr.h"
+#include "General.h"
+#include "HandlingMgr.h"
#include "Hud.h"
#include "Messages.h"
#include "ModelIndices.h"
@@ -18,9 +25,11 @@
#include "Population.h"
#include "Replay.h"
#include "Streaming.h"
+#include "Text.h"
#include "User.h"
#include "Weather.h"
#include "World.h"
+#include "Zones.h"
uint8 (&CTheScripts::ScriptSpace)[SIZE_SCRIPT_SPACE] = *(uint8(*)[SIZE_SCRIPT_SPACE])*(uintptr*)0x74B248;
CRunningScript(&CTheScripts::ScriptsArray)[MAX_NUM_SCRIPTS] = *(CRunningScript(*)[MAX_NUM_SCRIPTS])*(uintptr*)0x6F5C08;
@@ -70,6 +79,7 @@ CMissionCleanup::CMissionCleanup()
void CMissionCleanup::Init()
{
+ m_nCount = 0;
for (int i = 0; i < MAX_CLEANUP; i++){
m_sEntities[i].type = CLEANUP_UNUSED;
m_sEntities[i].id = 0;
@@ -93,7 +103,7 @@ void CMissionCleanup::AddEntityToList(int32 id, uint8 type)
return;
pNew->id = id;
pNew->type = type;
- m_bCount++;
+ m_nCount++;
}
void CMissionCleanup::RemoveEntityFromList(int32 id, uint8 type)
@@ -102,6 +112,7 @@ void CMissionCleanup::RemoveEntityFromList(int32 id, uint8 type)
if (m_sEntities[i].type == type && m_sEntities[i].id == id){
m_sEntities[i].id = 0;
m_sEntities[i].type = CLEANUP_UNUSED;
+ m_nCount--;
}
}
}
@@ -124,8 +135,8 @@ void CMissionCleanup::Process()
CHud::m_ItemToFlash = -1;
CHud::SetHelpMessage(nil, false);
CUserDisplay::OnscnTimer.m_bDisabled = false;
- CWorld::Players[0].m_pPed->m_pWanted->m_IsIgnoredByCops = false;
- CWorld::Players[0].m_pPed->m_pWanted->m_IsIgnoredByEveryOne = false;
+ CWorld::Players[0].m_pPed->m_pWanted->m_bIgnoredByCops = false;
+ CWorld::Players[0].m_pPed->m_pWanted->m_bIgnoredByEveryone = false;
CWorld::Players[0].MakePlayerSafe(false);
CTheScripts::StoreVehicleIndex = -1;
CTheScripts::StoreVehicleWasRandom = true;
@@ -594,7 +605,7 @@ void CTheScripts::Process()
if (UseTextCommands){
for (int i = 0; i < MAX_NUM_INTRO_TEXT_LINES; i++)
IntroTextLines[i].Reset();
- NumberOfIntroRectanglesThisFrame = 0;
+ NumberOfIntroTextLinesThisFrame = 0;
for (int i = 0; i < MAX_NUM_INTRO_RECTANGLES; i++){
IntroRectangles[i].m_bIsUsed = false;
IntroRectangles[i].m_bBeforeFade = false;
@@ -701,7 +712,7 @@ int8 CRunningScript::ProcessCommandsFrom0To99(int32 command)
return 0;
case COMMAND_SHAKE_CAM:
CollectParameters(&m_nIp, 1);
- TheCamera.CamShake(ScriptParams[0] / 1000.0f);
+ CamShakeNoPos(&TheCamera, ScriptParams[0] / 1000.0f);
return 0;
case COMMAND_SET_VAR_INT:
{
@@ -1342,6 +1353,7 @@ int8 CRunningScript::ProcessCommandsFrom0To99(int32 command)
*(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) -= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
return 0;
default:
+ assert(0);
break;
}
return -1;
@@ -1374,7 +1386,814 @@ void CRunningScript::UpdateCompareFlag(bool flag)
}
-WRAPPER int8 CRunningScript::ProcessCommandsFrom100To199(int32 command) { EAXJMP(0x43AEA0); }
+int8 CRunningScript::ProcessCommandsFrom100To199(int32 command)
+{
+ switch (command) {
+ case COMMAND_SUB_INT_LVAR_FROM_INT_VAR:
+ *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) -= *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ case COMMAND_SUB_INT_VAR_FROM_INT_LVAR:
+ *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) -= *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ case COMMAND_SUB_FLOAT_LVAR_FROM_FLOAT_VAR:
+ *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) -= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ case COMMAND_SUB_FLOAT_VAR_FROM_FLOAT_LVAR:
+ *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) -= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ case COMMAND_MULT_INT_VAR_BY_INT_VAR:
+ *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) *= *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ case COMMAND_MULT_INT_LVAR_BY_INT_VAR:
+ *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) *= *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ case COMMAND_MULT_INT_VAR_BY_INT_LVAR:
+ *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) *= *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ case COMMAND_MULT_INT_LVAR_BY_INT_LVAR:
+ *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) *= *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ case COMMAND_MULT_FLOAT_VAR_BY_FLOAT_VAR:
+ *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) *= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ case COMMAND_MULT_FLOAT_LVAR_BY_FLOAT_VAR:
+ *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) *= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ case COMMAND_MULT_FLOAT_VAR_BY_FLOAT_LVAR:
+ *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) *= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ case COMMAND_MULT_FLOAT_LVAR_BY_FLOAT_LVAR:
+ *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) *= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ case COMMAND_DIV_INT_VAR_BY_INT_VAR:
+ *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) /= *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ case COMMAND_DIV_INT_LVAR_BY_INT_VAR:
+ *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) /= *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ case COMMAND_DIV_INT_VAR_BY_INT_LVAR:
+ *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) /= *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ case COMMAND_DIV_INT_LVAR_BY_INT_LVAR:
+ *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) /= *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ case COMMAND_DIV_FLOAT_VAR_BY_FLOAT_VAR:
+ *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) /= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ case COMMAND_DIV_FLOAT_LVAR_BY_FLOAT_VAR:
+ *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) /= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ case COMMAND_DIV_FLOAT_VAR_BY_FLOAT_LVAR:
+ *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) /= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ case COMMAND_DIV_FLOAT_LVAR_BY_FLOAT_LVAR:
+ *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) /= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ case COMMAND_ADD_TIMED_VAL_TO_FLOAT_VAR:
+ {
+ int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ CollectParameters(&m_nIp, 1);
+ *(float*)ptr += CTimer::GetTimeStep() * *(float*)&ScriptParams[0];
+ return 0;
+ }
+ case COMMAND_ADD_TIMED_VAL_TO_FLOAT_LVAR:
+ {
+ int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ CollectParameters(&m_nIp, 1);
+ *(float*)ptr += CTimer::GetTimeStep() * *(float*)&ScriptParams[0];
+ return 0;
+ }
+ case COMMAND_ADD_TIMED_FLOAT_VAR_TO_FLOAT_VAR:
+ *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) += CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ case COMMAND_ADD_TIMED_FLOAT_LVAR_TO_FLOAT_VAR:
+ *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) += CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ case COMMAND_ADD_TIMED_FLOAT_VAR_TO_FLOAT_LVAR:
+ *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) += CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ case COMMAND_ADD_TIMED_FLOAT_LVAR_TO_FLOAT_LVAR:
+ *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) += CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ case COMMAND_SUB_TIMED_VAL_FROM_FLOAT_VAR:
+ {
+ int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ CollectParameters(&m_nIp, 1);
+ *(float*)ptr -= CTimer::GetTimeStep() * *(float*)&ScriptParams[0];
+ return 0;
+ }
+ case COMMAND_SUB_TIMED_VAL_FROM_FLOAT_LVAR:
+ {
+ int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ CollectParameters(&m_nIp, 1);
+ *(float*)ptr -= CTimer::GetTimeStep() * *(float*)&ScriptParams[0];
+ return 0;
+ }
+ case COMMAND_SUB_TIMED_FLOAT_VAR_FROM_FLOAT_VAR:
+ *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) -= CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ case COMMAND_SUB_TIMED_FLOAT_LVAR_FROM_FLOAT_VAR:
+ *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) -= CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ case COMMAND_SUB_TIMED_FLOAT_VAR_FROM_FLOAT_LVAR:
+ *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) -= CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ case COMMAND_SUB_TIMED_FLOAT_LVAR_FROM_FLOAT_LVAR:
+ *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) -= CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ case COMMAND_SET_VAR_INT_TO_VAR_INT:
+ {
+ int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ *ptr = *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ }
+ case COMMAND_SET_LVAR_INT_TO_VAR_INT:
+ {
+ int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ *ptr = *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ }
+ case COMMAND_SET_VAR_INT_TO_LVAR_INT:
+ {
+ int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ *ptr = *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ }
+ case COMMAND_SET_LVAR_INT_TO_LVAR_INT:
+ {
+ int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ *ptr = *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ }
+ case COMMAND_SET_VAR_FLOAT_TO_VAR_FLOAT:
+ {
+ float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ *ptr = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ }
+ case COMMAND_SET_LVAR_FLOAT_TO_VAR_FLOAT:
+ {
+ float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ *ptr = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ }
+ case COMMAND_SET_VAR_FLOAT_TO_LVAR_FLOAT:
+ {
+ float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ *ptr = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ }
+ case COMMAND_SET_LVAR_FLOAT_TO_LVAR_FLOAT:
+ {
+ float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ *ptr = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ }
+ case COMMAND_CSET_VAR_INT_TO_VAR_FLOAT:
+ {
+ int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ *ptr = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ }
+ case COMMAND_CSET_LVAR_INT_TO_VAR_FLOAT:
+ {
+ int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ *ptr = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ }
+ case COMMAND_CSET_VAR_INT_TO_LVAR_FLOAT:
+ {
+ int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ *ptr = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ }
+ case COMMAND_CSET_LVAR_INT_TO_LVAR_FLOAT:
+ {
+ int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ *ptr = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ }
+ case COMMAND_CSET_VAR_FLOAT_TO_VAR_INT:
+ {
+ float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ *ptr = *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ }
+ case COMMAND_CSET_LVAR_FLOAT_TO_VAR_INT:
+ {
+ float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ *ptr = *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ }
+ case COMMAND_CSET_VAR_FLOAT_TO_LVAR_INT:
+ {
+ float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ *ptr = *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ return 0;
+ }
+ case COMMAND_CSET_LVAR_FLOAT_TO_LVAR_INT:
+ {
+ float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ *ptr = *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ return 0;
+ }
+ case COMMAND_ABS_VAR_INT:
+ {
+ int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ *ptr = ABS(*ptr);
+ return 0;
+ }
+ case COMMAND_ABS_LVAR_INT:
+ {
+ int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ *ptr = ABS(*ptr);
+ return 0;
+ }
+ case COMMAND_ABS_VAR_FLOAT:
+ {
+ float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ *ptr = ABS(*ptr);
+ return 0;
+ }
+ case COMMAND_ABS_LVAR_FLOAT:
+ {
+ float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL);
+ *ptr = ABS(*ptr);
+ return 0;
+ }
+ case COMMAND_GENERATE_RANDOM_FLOAT:
+ {
+ float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
+ CGeneral::GetRandomNumber();
+ CGeneral::GetRandomNumber();
+ CGeneral::GetRandomNumber(); /* To make it EXTRA random! */
+ *ptr = CGeneral::GetRandomNumber() / 65536.0f;
+ /* Between 0 and 0.5 on PC (oh well...), never used in original script. */
+ return 0;
+ }
+ case COMMAND_GENERATE_RANDOM_INT:
+ /* On PC between 0 and 32767, even though script expects values between 0 and 65536 */
+ *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) = CGeneral::GetRandomNumber();
+ return 0;
+ case COMMAND_CREATE_CHAR:
+ {
+ CollectParameters(&m_nIp, 5);
+ switch (ScriptParams[1]) {
+ case MI_COP:
+ if (ScriptParams[0] == PEDTYPE_COP)
+ ScriptParams[1] = COP_STREET;
+ break;
+ case MI_SWAT:
+ if (ScriptParams[0] == PEDTYPE_COP)
+ ScriptParams[1] = COP_SWAT;
+ break;
+ case MI_FBI:
+ if (ScriptParams[0] == PEDTYPE_COP)
+ ScriptParams[1] = COP_FBI;
+ break;
+ case MI_ARMY:
+ if (ScriptParams[0] == PEDTYPE_COP)
+ ScriptParams[1] = COP_ARMY;
+ break;
+ case MI_MEDIC:
+ if (ScriptParams[0] == PEDTYPE_EMERGENCY)
+ ScriptParams[1] = PEDTYPE_EMERGENCY;
+ break;
+ case MI_FIREMAN:
+ if (ScriptParams[0] == PEDTYPE_FIREMAN)
+ ScriptParams[1] = PEDTYPE_FIREMAN;
+ break;
+ default:
+ break;
+ }
+ CPed* ped;
+ if (ScriptParams[0] == PEDTYPE_COP)
+ ped = new CCopPed((eCopType)ScriptParams[1]);
+ else if (ScriptParams[0] == PEDTYPE_EMERGENCY || ScriptParams[0] == PEDTYPE_FIREMAN)
+ ped = new CEmergencyPed(ScriptParams[1]);
+ else
+ ped = new CCivilianPed(ScriptParams[0], ScriptParams[1]);
+ ped->CharCreatedBy = MISSION_CHAR;
+ ped->bRespondsToThreats = false;
+ ped->m_ped_flagG2 = false;
+ CVector pos = *(CVector*)&ScriptParams[2];
+ if (pos.z <= -100.0f)
+ pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y);
+ pos.z += 1.0f;
+ ped->GetPosition() = pos;
+ ped->SetOrientation(0.0f, 0.0f, 0.0f);
+ CTheScripts::ClearSpaceForMissionEntity(pos, ped);
+ CWorld::Add(ped);
+ ped->m_level = CTheZones::GetLevelFromPosition(pos);
+ CPopulation::ms_nTotalMissionPeds++;
+ ScriptParams[0] = CPools::GetPedPool()->GetIndex(ped);
+ StoreParameters(&m_nIp, 1);
+ if (m_bIsMissionScript)
+ CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_CHAR);
+ return 0;
+ }
+ case COMMAND_DELETE_CHAR:
+ {
+ CollectParameters(&m_nIp, 1);
+ CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]);
+ if (ped) {
+ if (ped->bInVehicle && ped->m_pMyVehicle) {
+ if (ped->m_pMyVehicle->pDriver == ped) {
+ ped->m_pMyVehicle->RemoveDriver();
+ ped->m_pMyVehicle->m_status = STATUS_ABANDONED;
+ if (ped->m_pMyVehicle->m_nDoorLock == CARLOCK_LOCKED_INITIALLY)
+ ped->m_pMyVehicle->m_nDoorLock = CARLOCK_UNLOCKED;
+ if (ped->m_nPedType == PEDTYPE_COP && ped->m_pMyVehicle->IsLawEnforcementVehicle())
+ ped->m_pMyVehicle->ChangeLawEnforcerState(0);
+ }
+ else {
+ ped->m_pMyVehicle->RemovePassenger(ped);
+ }
+ }
+ CWorld::RemoveReferencesToDeletedObject(ped);
+ delete ped;
+ --CPopulation::ms_nTotalMissionPeds;
+ }
+ if (m_bIsMissionScript)
+ CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CHAR);
+ return 0;
+ }
+ case COMMAND_CHAR_WANDER_DIR:
+ {
+ CollectParameters(&m_nIp, 2);
+ CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]);
+ assert(ped);
+ ped->ClearAll();
+ int8 path = ScriptParams[1];
+ if (ScriptParams[1] < 0 || ScriptParams[1] > 7)
+ path = CGeneral::GetRandomNumberInRange(0, 7);
+ ped->SetWanderPath(path);
+ return 0;
+ }
+ case COMMAND_CHAR_FOLLOW_PATH:
+ {
+ CollectParameters(&m_nIp, 4);
+ CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]);
+ assert(ped);
+ CVector pos = *(CVector*)&ScriptParams[1];
+ if (pos.z <= -100.0f)
+ pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y);
+ ped->ClearAll();
+ ped->SetFollowPath(pos);
+ return 0;
+ }
+ case COMMAND_CHAR_SET_IDLE:
+ {
+ CollectParameters(&m_nIp, 1);
+ CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]);
+ assert(ped);
+ ped->m_bScriptObjectiveCompleted = false;
+ ped->SetObjective(OBJECTIVE_IDLE);
+ return 0;
+ }
+ case COMMAND_GET_CHAR_COORDINATES:
+ {
+ CollectParameters(&m_nIp, 1);
+ CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]);
+ assert(ped);
+ CVehicle* vehicle;
+ CVector pos;
+ /* Seems a bit clumsy but I'll leave original flow */
+ if (ped->bInVehicle)
+ vehicle = ped->m_pMyVehicle;
+ else
+ vehicle = nil;
+ if (vehicle)
+ pos = vehicle->GetPosition();
+ else
+ pos = ped->GetPosition();
+ *(CVector*)&ScriptParams[0] = pos;
+ StoreParameters(&m_nIp, 3);
+ return 0;
+ }
+ case COMMAND_SET_CHAR_COORDINATES:
+ {
+ CollectParameters(&m_nIp, 4);
+ CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]);
+ assert(ped);
+ CVehicle* vehicle;
+ if (ped->bInVehicle)
+ vehicle = ped->m_pMyVehicle;
+ else
+ vehicle = nil;
+ CVector pos = *(CVector*)&ScriptParams[1];
+ if (pos.z <= -100.0f)
+ pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y);
+ /* The following block was once again written
+ * by someone not familiar with virtual functions.
+ * It doesn't require any ifs at all.
+ * To keep as close to original as possible, I'll keep it.
+ * Maybe there was more commented out/debug
+ * stuff, but I doubt it.
+ */
+ if (!vehicle) {
+ pos.z += ped->GetDistanceFromCentreOfMassToBaseOfModel();
+ ped->Teleport(pos);
+ CTheScripts::ClearSpaceForMissionEntity(pos, ped);
+ }
+ else if (vehicle->IsBoat()) {
+ pos.z += vehicle->GetDistanceFromCentreOfMassToBaseOfModel();
+ vehicle->Teleport(pos);
+ CTheScripts::ClearSpaceForMissionEntity(pos, vehicle);
+ }
+ else {
+ pos.z += vehicle->GetDistanceFromCentreOfMassToBaseOfModel();
+ vehicle->Teleport(pos);
+ CTheScripts::ClearSpaceForMissionEntity(pos, vehicle);
+ }
+ /* Short version of this command.
+ *
+ * CollectParameters(&m_nIp, 4);
+ * CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]);
+ * assert(ped);
+ * CEntity* entityToMove = ped->bInVehicle ? ped->m_pMyVehicle : ped;
+ * CVector pos = *(CVector*)&ScriptParams[1];
+ * if (pos.z <= -100.0f)
+ * pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y);
+ * pos.z += entityToMove->GetDistanceFromCentreOfMassToBaseOfModel();
+ * entityToMove->Teleport(pos);
+ * CTheScripts::ClearSpaceForMissionEntity(pos, entityToMove);
+ *
+ */
+ return 0;
+ }
+ case COMMAND_IS_CHAR_STILL_ALIVE:
+ {
+ CollectParameters(&m_nIp, 1);
+ CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]);
+ UpdateCompareFlag(ped && ped->m_status != PED_DEAD && ped->m_status != PED_DIE);
+ return 0;
+ }
+ case COMMAND_IS_CHAR_IN_AREA_2D:
+ {
+ CollectParameters(&m_nIp, 6);
+ CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]);
+ assert(ped);
+ CVehicle* vehicle;
+ if (ped->bInVehicle)
+ vehicle = ped->m_pMyVehicle;
+ else
+ vehicle = nil;
+ float x1, y1, x2, y2;
+ x1 = *(float*)&ScriptParams[1];
+ y1 = *(float*)&ScriptParams[2];
+ x2 = *(float*)&ScriptParams[3];
+ y2 = *(float*)&ScriptParams[4];
+ if (vehicle)
+ UpdateCompareFlag(ped->m_pMyVehicle->IsWithinArea(x1, y1, x2, y2));
+ else
+ UpdateCompareFlag(ped->IsWithinArea(x1, y1, x2, y2));
+ CTheScripts::HighlightImportantArea((uint32)this + m_nIp, x1, y1, x2, y2, -100.0f);
+ if (CTheScripts::DbgFlag)
+ CTheScripts::DrawDebugSquare(x1, y1, x2, y2);
+ return 0;
+ }
+ case COMMAND_IS_CHAR_IN_AREA_3D:
+ {
+ CollectParameters(&m_nIp, 8);
+ CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]);
+ assert(ped);
+ CVehicle* vehicle;
+ if (ped->bInVehicle)
+ vehicle = ped->m_pMyVehicle;
+ else
+ vehicle = nil;
+ float x1, y1, z1, x2, y2, z2;
+ x1 = *(float*)&ScriptParams[1];
+ y1 = *(float*)&ScriptParams[2];
+ z1 = *(float*)&ScriptParams[3];
+ x2 = *(float*)&ScriptParams[4];
+ y2 = *(float*)&ScriptParams[5];
+ z2 = *(float*)&ScriptParams[6];
+ if (vehicle)
+ UpdateCompareFlag(ped->m_pMyVehicle->IsWithinArea(x1, y1, z1, x2, y2, z2));
+ else
+ UpdateCompareFlag(ped->IsWithinArea(x1, y1, z1, x2, y2, z2));
+ CTheScripts::HighlightImportantArea((uint32)this + m_nIp, x1, y1, x2, y2, -100.0f);
+ if (CTheScripts::DbgFlag)
+ CTheScripts::DrawDebugCube(x1, y1, z1, x2, y2, z2);
+ return 0;
+ }
+ case COMMAND_CREATE_CAR:
+ {
+ CollectParameters(&m_nIp, 4);
+ int32 handle;
+ if (CModelInfo::IsBoatModel(ScriptParams[0])) {
+ CBoat* boat = new CBoat(ScriptParams[0], MISSION_VEHICLE);
+ CVector pos = *(CVector*)&ScriptParams[1];
+ if (pos.z <= -100.0f)
+ pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y);
+ pos.z += boat->GetDistanceFromCentreOfMassToBaseOfModel();
+ boat->GetPosition() = pos;
+ CTheScripts::ClearSpaceForMissionEntity(pos, boat);
+ boat->m_status = STATUS_ABANDONED;
+ boat->bIsLocked = true;
+ boat->AutoPilot.m_nCarMission = MISSION_NONE;
+ boat->AutoPilot.m_nAnimationId = TEMPACT_NONE; /* Animation ID? */
+ boat->AutoPilot.m_nCruiseSpeed = boat->AutoPilot.m_fMaxTrafficSpeed = 20.0f;
+ CWorld::Add(boat);
+ handle = CPools::GetVehiclePool()->GetIndex(boat);
+ }
+ else {
+ CVehicle* car;
+ if (!CModelInfo::IsBikeModel(ScriptParams[0]))
+ car = new CAutomobile(ScriptParams[0], MISSION_VEHICLE);
+ CVector pos = *(CVector*)&ScriptParams[1];
+ if (pos.z <= -100.0f)
+ pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y);
+ pos.z += car->GetDistanceFromCentreOfMassToBaseOfModel();
+ car->GetPosition() = pos;
+ CTheScripts::ClearSpaceForMissionEntity(pos, car);
+ car->m_status = STATUS_ABANDONED;
+ car->bIsLocked = true;
+ CCarCtrl::JoinCarWithRoadSystem(car);
+ car->AutoPilot.m_nCarMission = MISSION_NONE;
+ car->AutoPilot.m_nAnimationId = TEMPACT_NONE; /* Animation ID? */
+ car->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS;
+ car->AutoPilot.m_nCruiseSpeed = car->AutoPilot.m_fMaxTrafficSpeed = 9.0f;
+ car->AutoPilot.m_nPreviousLane = car->AutoPilot.m_nCurrentLane = 0;
+ car->bEngineOn = false;
+ car->m_level = CTheZones::GetLevelFromPosition(pos);
+ car->bHasBeenOwnedByPlayer = true;
+ CWorld::Add(car);
+ handle = CPools::GetVehiclePool()->GetIndex(car);
+ }
+ ScriptParams[0] = handle;
+ StoreParameters(&m_nIp, 1);
+ if (m_bIsMissionScript)
+ CTheScripts::MissionCleanup.AddEntityToList(handle, CLEANUP_CAR);
+ return 0;
+ }
+ case COMMAND_DELETE_CAR:
+ {
+ CollectParameters(&m_nIp, 1);
+ CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
+ if (car) {
+ CWorld::Remove(car);
+ CWorld::RemoveReferencesToDeletedObject(car);
+ delete car;
+ }
+ if (m_bIsMissionScript)
+ CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CAR);
+ return 0;
+ }
+ case COMMAND_CAR_GOTO_COORDINATES:
+ {
+ CollectParameters(&m_nIp, 4);
+ CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
+ assert(car);
+ CVector pos = *(CVector*)&ScriptParams[1];
+ if (pos.z <= -100.0f)
+ pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y);
+ pos.z += car->GetDistanceFromCentreOfMassToBaseOfModel();
+ if (CCarCtrl::JoinCarWithRoadSystemGotoCoors(car, pos, false))
+ car->AutoPilot.m_nCarMission = MISSION_GOTOCOORDS_STRAIGHT;
+ else
+ car->AutoPilot.m_nCarMission = MISSION_GOTOCOORDS;
+ car->m_status = STATUS_PHYSICS;
+ car->bEngineOn = true;
+ car->AutoPilot.m_nCruiseSpeed = max(car->AutoPilot.m_nCruiseSpeed, 6);
+ car->AutoPilot.m_nTimeToStartMission = CTimer::GetTimeInMilliseconds();
+ return 0;
+ }
+ case COMMAND_CAR_WANDER_RANDOMLY:
+ {
+ CollectParameters(&m_nIp, 1);
+ CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
+ assert(car);
+ CCarCtrl::JoinCarWithRoadSystem(car);
+ car->AutoPilot.m_nCarMission = MISSION_CRUISE;
+ car->bEngineOn = true;
+ car->AutoPilot.m_nCruiseSpeed = max(car->AutoPilot.m_nCruiseSpeed, 6);
+ car->AutoPilot.m_nTimeToStartMission = CTimer::GetTimeInMilliseconds();
+ return 0;
+ }
+ case COMMAND_CAR_SET_IDLE:
+ {
+ CollectParameters(&m_nIp, 1);
+ CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
+ assert(car);
+ car->AutoPilot.m_nCarMission = MISSION_NONE;
+ return 0;
+ }
+ case COMMAND_GET_CAR_COORDINATES:
+ {
+ CollectParameters(&m_nIp, 1);
+ CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
+ assert(car);
+ *(CVector*)&ScriptParams[0] = car->GetPosition();
+ StoreParameters(&m_nIp, 3);
+ return 0;
+ }
+ case COMMAND_SET_CAR_COORDINATES:
+ {
+ CollectParameters(&m_nIp, 4);
+ CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
+ assert(car);
+ CVector pos = *(CVector*)&ScriptParams[1];
+ if (pos.z <= -100.0f)
+ pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y);
+ pos.z += car->GetDistanceFromCentreOfMassToBaseOfModel();
+ car->bIsStatic = false;
+ /* Again weird usage of virtual functions. */
+ if (car->IsBoat()) {
+ car->Teleport(pos);
+ CTheScripts::ClearSpaceForMissionEntity(pos, car);
+ }
+ else {
+ car->Teleport(pos);
+ CTheScripts::ClearSpaceForMissionEntity(pos, car);
+ /* May the following be inlined CCarCtrl function? */
+ switch (car->AutoPilot.m_nCarMission) {
+ case MISSION_CRUISE:
+ CCarCtrl::JoinCarWithRoadSystem(car);
+ break;
+ case MISSION_RAMPLAYER_FARAWAY:
+ case MISSION_RAMPLAYER_CLOSE:
+ case MISSION_BLOCKPLAYER_FARAWAY:
+ case MISSION_BLOCKPLAYER_CLOSE:
+ case MISSION_BLOCKPLAYER_HANDBRAKESTOP:
+ CCarCtrl::JoinCarWithRoadSystemGotoCoors(car, FindPlayerCoors(), false);
+ break;
+ case MISSION_GOTOCOORDS:
+ case MISSION_GOTOCOORDS_STRAIGHT:
+ CCarCtrl::JoinCarWithRoadSystemGotoCoors(car, car->AutoPilot.m_vecDestinationCoors, false);
+ break;
+ case MISSION_GOTOCOORDS_ACCURATE:
+ case MISSION_GOTO_COORDS_STRAIGHT_ACCURATE:
+ CCarCtrl::JoinCarWithRoadSystemGotoCoors(car, car->AutoPilot.m_vecDestinationCoors, false);
+ break;
+ case MISSION_RAMCAR_FARAWAY:
+ case MISSION_RAMCAR_CLOSE:
+ case MISSION_BLOCKCAR_FARAWAY:
+ case MISSION_BLOCKCAR_CLOSE:
+ case MISSION_BLOCKCAR_HANDBRAKESTOP:
+ CCarCtrl::JoinCarWithRoadSystemGotoCoors(car, car->AutoPilot.m_pTargetCar->GetPosition(), false);
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+ }
+ case COMMAND_IS_CAR_STILL_ALIVE:
+ {
+ CollectParameters(&m_nIp, 4);
+ CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
+ UpdateCompareFlag(car && car->m_status != STATUS_WRECKED && (car->IsBoat() || !car->bIsInWater));
+ return 0;
+ }
+ case COMMAND_SET_CAR_CRUISE_SPEED:
+ {
+ CollectParameters(&m_nIp, 2);
+ CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
+ assert(car);
+ car->AutoPilot.m_nCruiseSpeed = min(*(float*)&ScriptParams[1], 60.0f * car->pHandling->Transmission.fUnkMaxVelocity);
+ return 0;
+ }
+ case COMMAND_SET_CAR_DRIVING_STYLE:
+ {
+ CollectParameters(&m_nIp, 2);
+ CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
+ assert(car);
+ car->AutoPilot.m_nDrivingStyle = (eCarDrivingStyle)ScriptParams[1];
+ return 0;
+ }
+ case COMMAND_SET_CAR_MISSION:
+ {
+ CollectParameters(&m_nIp, 2);
+ CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
+ assert(car);
+ car->AutoPilot.m_nCarMission = (eCarMission)ScriptParams[1];
+ car->AutoPilot.m_nTimeToStartMission = CTimer::GetTimeInMilliseconds();
+ car->bEngineOn = true;
+ return 0;
+ }
+ case COMMAND_IS_CAR_IN_AREA_2D:
+ {
+ CollectParameters(&m_nIp, 6);
+ CVehicle* vehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
+ assert(vehicle);
+ float x1, y1, x2, y2;
+ x1 = *(float*)&ScriptParams[1];
+ y1 = *(float*)&ScriptParams[2];
+ x2 = *(float*)&ScriptParams[3];
+ y2 = *(float*)&ScriptParams[4];
+ UpdateCompareFlag(vehicle->IsWithinArea(x1, y1, x2, y2));
+ CTheScripts::HighlightImportantArea((uint32)this + m_nIp, x1, y1, x2, y2, -100.0f);
+ if (CTheScripts::DbgFlag)
+ CTheScripts::DrawDebugSquare(x1, y1, x2, y2);
+ return 0;
+ }
+ case COMMAND_IS_CAR_IN_AREA_3D:
+ {
+ CollectParameters(&m_nIp, 8);
+ CVehicle* vehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
+ assert(vehicle);
+ float x1, y1, z1, x2, y2, z2;
+ x1 = *(float*)&ScriptParams[1];
+ y1 = *(float*)&ScriptParams[2];
+ z1 = *(float*)&ScriptParams[3];
+ x2 = *(float*)&ScriptParams[4];
+ y2 = *(float*)&ScriptParams[5];
+ z2 = *(float*)&ScriptParams[6];
+ UpdateCompareFlag(vehicle->IsWithinArea(x1, y1, z1, x2, y2, z2));
+ CTheScripts::HighlightImportantArea((uint32)this + m_nIp, x1, y1, x2, y2, -100.0f);
+ if (CTheScripts::DbgFlag)
+ CTheScripts::DrawDebugCube(x1, y1, z1, x2, y2, z2);
+ return 0;
+ }
+ case COMMAND_SPECIAL_0:
+ case COMMAND_SPECIAL_1:
+ case COMMAND_SPECIAL_2:
+ case COMMAND_SPECIAL_3:
+ case COMMAND_SPECIAL_4:
+ case COMMAND_SPECIAL_5:
+ case COMMAND_SPECIAL_6:
+ case COMMAND_SPECIAL_7:
+ assert(0);
+ return 0;
+ case COMMAND_PRINT_BIG:
+ {
+ wchar* key = TheText.Get((char*)&CTheScripts::ScriptSpace[m_nIp]);
+ m_nIp += 8;
+ CollectParameters(&m_nIp, 2);
+ CMessages::AddBigMessage(key, ScriptParams[0], ScriptParams[1] - 1);
+ return 0;
+ }
+ case COMMAND_PRINT:
+ {
+ wchar* key = TheText.Get((char*)&CTheScripts::ScriptSpace[m_nIp]);
+ m_nIp += 8;
+ CollectParameters(&m_nIp, 2);
+ CMessages::AddMessage(key, ScriptParams[0], ScriptParams[1]);
+ return 0;
+ }
+ case COMMAND_PRINT_NOW:
+ {
+ wchar* key = TheText.Get((char*)&CTheScripts::ScriptSpace[m_nIp]);
+ m_nIp += 8;
+ CollectParameters(&m_nIp, 2);
+ CMessages::AddMessageJumpQ(key, ScriptParams[0], ScriptParams[1]);
+ return 0;
+ }
+ case COMMAND_PRINT_SOON:
+ {
+ wchar* key = TheText.Get((char*)&CTheScripts::ScriptSpace[m_nIp]);
+ m_nIp += 8;
+ CollectParameters(&m_nIp, 2);
+ CMessages::AddMessage(key, ScriptParams[0], ScriptParams[1]);
+ return 0;
+ }
+ case COMMAND_CLEAR_PRINTS:
+ CMessages::ClearMessages();
+ return 0;
+ case COMMAND_GET_TIME_OF_DAY:
+ ScriptParams[0] = CClock::GetHours();
+ ScriptParams[1] = CClock::GetMinutes();
+ StoreParameters(&m_nIp, 2);
+ return 0;
+ case COMMAND_SET_TIME_OF_DAY:
+ CollectParameters(&m_nIp, 2);
+ CClock::SetGameClock(ScriptParams[0], ScriptParams[1]);
+ return 0;
+ case COMMAND_GET_MINUTES_TO_TIME_OF_DAY:
+ CollectParameters(&m_nIp, 2);
+ ScriptParams[0] = CClock::GetGameClockMinutesUntil(ScriptParams[0], ScriptParams[1]);
+ StoreParameters(&m_nIp, 1);
+ return 0;
+ case COMMAND_IS_POINT_ON_SCREEN:
+ {
+ CollectParameters(&m_nIp, 4);
+ CVector pos = *(CVector*)&ScriptParams[0];
+ if (pos.z <= -100)
+ pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y);
+ UpdateCompareFlag(TheCamera.IsSphereVisible(pos, *(float*)&ScriptParams[3]));
+ }
+ case COMMAND_DEBUG_ON:
+ CTheScripts::DbgFlag = true;
+ return 0;
+ case COMMAND_DEBUG_OFF:
+ CTheScripts::DbgFlag = false;
+ return 0;
+ case COMMAND_RETURN_TRUE:
+ UpdateCompareFlag(true);
+ return 0;
+ case COMMAND_RETURN_FALSE:
+ UpdateCompareFlag(false);
+ return 0;
+ default:
+ assert(0);
+ break;
+ }
+ return -1;
+}
+
WRAPPER int8 CRunningScript::ProcessCommandsFrom200To299(int32 command) { EAXJMP(0x43D530); }
WRAPPER int8 CRunningScript::ProcessCommandsFrom300To399(int32 command) { EAXJMP(0x43ED30); }
WRAPPER int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) { EAXJMP(0x440CB0); }
diff --git a/src/control/Script.h b/src/control/Script.h
index 0cbd40c0..9e9d9ab6 100644
--- a/src/control/Script.h
+++ b/src/control/Script.h
@@ -137,7 +137,7 @@ enum {
class CMissionCleanup
{
CMissionCleanupEntity m_sEntities[MAX_CLEANUP];
- uint8 m_bCount;
+ uint8 m_nCount;
public:
CMissionCleanup();
diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp
index 166928c1..a66d6ac9 100644
--- a/src/core/Camera.cpp
+++ b/src/core/Camera.cpp
@@ -23,7 +23,7 @@ WRAPPER void CCamera::DrawBordersForWideScreen(void) { EAXJMP(0x46B430); }
WRAPPER void CCamera::CalculateDerivedValues(void) { EAXJMP(0x46EEA0); }
WRAPPER void CCamera::Restore(void) { EAXJMP(0x46F990); }
WRAPPER void CCamera::SetWidescreenOff(void) { EAXJMP(0x46FF10); }
-WRAPPER void CCamera::CamShake(float) { EAXJMP(0x46B100); }
+WRAPPER void CamShakeNoPos(CCamera*, float) { EAXJMP(0x46B100); }
bool
CCamera::IsSphereVisible(const CVector &center, float radius, const CMatrix *mat)
@@ -95,6 +95,14 @@ CCamera::GetLookDirection(void)
return LOOKING_FORWARD;;
}
+bool
+CCamera::GetLookingForwardFirstPerson()
+{
+ return Cams[ActiveCam].Mode == CCam::MODE_FIRSTPERSON &&
+ Cams[ActiveCam].DirectionWasLooking == LOOKING_FORWARD;
+}
+
+
WRAPPER void CCamera::Fade(float timeout, int16 direction) { EAXJMP(0x46B3A0); }
WRAPPER void CCamera::ProcessFade(void) { EAXJMP(0x46F080); }
WRAPPER void CCamera::ProcessMusicFade(void) { EAXJMP(0x46F1E0); }
diff --git a/src/core/Camera.h b/src/core/Camera.h
index 84af9d55..1a2aae79 100644
--- a/src/core/Camera.h
+++ b/src/core/Camera.h
@@ -441,6 +441,7 @@ int m_iModeObbeCamIsInForCar;
static bool &m_bUseMouse3rdPerson;
+ bool Get_Just_Switched_Status() { return m_bJust_Switched; }
inline const CMatrix GetCameraMatrix(void) { return m_cameraMatrix; }
CVector &GetGameCamPosition(void) { return m_vecGameCamPos; }
bool IsPointVisible(const CVector &center, const CMatrix *mat);
@@ -448,6 +449,7 @@ int m_iModeObbeCamIsInForCar;
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);
@@ -466,7 +468,6 @@ int m_iModeObbeCamIsInForCar;
void DrawBordersForWideScreen(void);
void Restore(void);
void SetWidescreenOff(void);
- void CamShake(float);
void dtor(void) { this->CCamera::~CCamera(); }
};
@@ -479,3 +480,5 @@ static_assert(offsetof(CCamera, m_BlurBlue) == 0x9C, "CCamera: error");
static_assert(offsetof(CCamera, Cams) == 0x1A4, "CCamera: error");
static_assert(sizeof(CCamera) == 0xE9D8, "CCamera: wrong size");
extern CCamera &TheCamera;
+
+void CamShakeNoPos(CCamera*, float);
diff --git a/src/core/Clock.cpp b/src/core/Clock.cpp
index 707b0e57..a97dcb5f 100644
--- a/src/core/Clock.cpp
+++ b/src/core/Clock.cpp
@@ -15,7 +15,7 @@ uint8 &CClock::ms_Stored_nGameClockHours = *(uint8*)0x95CD7B;
uint8 &CClock::ms_Stored_nGameClockMinutes = *(uint8*)0x95CD9B;
uint16 &CClock::ms_Stored_nGameClockSeconds = *(uint16*)0x95CC9C;
uint32 &CClock::ms_nMillisecondsPerGameMinute = *(uint32*)0x8F2C64;
-int32 &CClock::ms_nLastClockTick = *(int32*)0x9430E4;
+uint32 &CClock::ms_nLastClockTick = *(uint32*)0x9430E4;
bool &CClock::ms_bClockHasBeenStored = *(bool*)0x95CD82;
void
@@ -67,10 +67,7 @@ CClock::Update(void)
}
}
}
- ms_nGameClockSeconds +=
- 60
- * (CTimer::GetTimeInMilliseconds() - ms_nLastClockTick)
- / ms_nMillisecondsPerGameMinute;
+ ms_nGameClockSeconds = 60 * (CTimer::GetTimeInMilliseconds() - ms_nLastClockTick) / ms_nMillisecondsPerGameMinute;
}
void
diff --git a/src/core/Clock.h b/src/core/Clock.h
index e11b2293..ea4263bd 100644
--- a/src/core/Clock.h
+++ b/src/core/Clock.h
@@ -9,7 +9,7 @@ class CClock
static uint8 &ms_Stored_nGameClockMinutes;
static uint16 &ms_Stored_nGameClockSeconds;
static uint32 &ms_nMillisecondsPerGameMinute;
- static int32 &ms_nLastClockTick;
+ static uint32 &ms_nLastClockTick;
static bool &ms_bClockHasBeenStored;
public:
diff --git a/src/core/Collision.cpp b/src/core/Collision.cpp
index 1ed08867..7982e77d 100644
--- a/src/core/Collision.cpp
+++ b/src/core/Collision.cpp
@@ -18,6 +18,7 @@
#include "CutsceneMgr.h"
#include "RenderBuffer.h"
#include "SurfaceTable.h"
+#include "Lines.h"
#include "Collision.h"
enum Direction
@@ -1356,6 +1357,7 @@ CCollision::DistToLine(const CVector *l0, const CVector *l1, const CVector *poin
void
CCollision::CalculateTrianglePlanes(CColModel *model)
{
+ assert(model);
if(model->numTriangles == 0)
return;
@@ -1366,7 +1368,6 @@ CCollision::CalculateTrianglePlanes(CColModel *model)
lptr->Remove();
ms_colModelCache.head.Insert(lptr);
}else{
- assert(model);
lptr = ms_colModelCache.Insert(model);
if(lptr == nil){
// make room if we have to, remove last in list
@@ -1387,6 +1388,223 @@ CCollision::CalculateTrianglePlanes(CColModel *model)
void
CCollision::DrawColModel(const CMatrix &mat, const CColModel &colModel)
{
+ int i;
+ CVector min, max;
+ CVector verts[8];
+ CVector c;
+ float r;
+
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
+
+ min = colModel.boundingBox.min;
+ max = colModel.boundingBox.max;
+
+ verts[0] = mat * CVector(min.x, min.y, min.z);
+ verts[1] = mat * CVector(min.x, min.y, max.z);
+ verts[2] = mat * CVector(min.x, max.y, min.z);
+ verts[3] = mat * CVector(min.x, max.y, max.z);
+ verts[4] = mat * CVector(max.x, min.y, min.z);
+ verts[5] = mat * CVector(max.x, min.y, max.z);
+ verts[6] = mat * CVector(max.x, max.y, min.z);
+ verts[7] = mat * CVector(max.x, max.y, max.z);
+
+ CLines::RenderLineWithClipping(
+ verts[0].x, verts[0].y, verts[0].z,
+ verts[1].x, verts[1].y, verts[1].z,
+ 0xFF0000FF, 0xFF0000FF);
+ CLines::RenderLineWithClipping(
+ verts[1].x, verts[1].y, verts[1].z,
+ verts[3].x, verts[3].y, verts[3].z,
+ 0xFF0000FF, 0xFF0000FF);
+ CLines::RenderLineWithClipping(
+ verts[3].x, verts[3].y, verts[3].z,
+ verts[2].x, verts[2].y, verts[2].z,
+ 0xFF0000FF, 0xFF0000FF);
+ CLines::RenderLineWithClipping(
+ verts[2].x, verts[2].y, verts[2].z,
+ verts[0].x, verts[0].y, verts[0].z,
+ 0xFF0000FF, 0xFF0000FF);
+
+ CLines::RenderLineWithClipping(
+ verts[4].x, verts[4].y, verts[4].z,
+ verts[5].x, verts[5].y, verts[5].z,
+ 0xFF0000FF, 0xFF0000FF);
+ CLines::RenderLineWithClipping(
+ verts[5].x, verts[5].y, verts[5].z,
+ verts[7].x, verts[7].y, verts[7].z,
+ 0xFF0000FF, 0xFF0000FF);
+ CLines::RenderLineWithClipping(
+ verts[7].x, verts[7].y, verts[7].z,
+ verts[6].x, verts[6].y, verts[6].z,
+ 0xFF0000FF, 0xFF0000FF);
+ CLines::RenderLineWithClipping(
+ verts[6].x, verts[6].y, verts[6].z,
+ verts[4].x, verts[4].y, verts[4].z,
+ 0xFF0000FF, 0xFF0000FF);
+
+ CLines::RenderLineWithClipping(
+ verts[0].x, verts[0].y, verts[0].z,
+ verts[4].x, verts[4].y, verts[4].z,
+ 0xFF0000FF, 0xFF0000FF);
+ CLines::RenderLineWithClipping(
+ verts[1].x, verts[1].y, verts[1].z,
+ verts[5].x, verts[5].y, verts[5].z,
+ 0xFF0000FF, 0xFF0000FF);
+ CLines::RenderLineWithClipping(
+ verts[2].x, verts[2].y, verts[2].z,
+ verts[6].x, verts[6].y, verts[6].z,
+ 0xFF0000FF, 0xFF0000FF);
+ CLines::RenderLineWithClipping(
+ verts[3].x, verts[3].y, verts[3].z,
+ verts[7].x, verts[7].y, verts[7].z,
+ 0xFF0000FF, 0xFF0000FF);
+
+ for(i = 0; i < colModel.numSpheres; i++){
+ c = mat * colModel.spheres[i].center;
+ r = colModel.spheres[i].radius;
+
+ CLines::RenderLineWithClipping(
+ c.x, c.y, c.z-r,
+ c.x-r, c.y-r, c.z,
+ 0xFF00FFFF, 0xFF00FFFF);
+ CLines::RenderLineWithClipping(
+ c.x, c.y, c.z-r,
+ c.x-r, c.y+r, c.z,
+ 0xFF00FFFF, 0xFF00FFFF);
+ CLines::RenderLineWithClipping(
+ c.x, c.y, c.z-r,
+ c.x+r, c.y-r, c.z,
+ 0xFF00FFFF, 0xFF00FFFF);
+ CLines::RenderLineWithClipping(
+ c.x, c.y, c.z-r,
+ c.x+r, c.y+r, c.z,
+ 0xFF00FFFF, 0xFF00FFFF);
+ CLines::RenderLineWithClipping(
+ c.x-r, c.y-r, c.z,
+ c.x, c.y, c.z+r,
+ 0xFF00FFFF, 0xFF00FFFF);
+ CLines::RenderLineWithClipping(
+ c.x-r, c.y+r, c.z,
+ c.x, c.y, c.z+r,
+ 0xFF00FFFF, 0xFF00FFFF);
+ CLines::RenderLineWithClipping(
+ c.x+r, c.y-r, c.z,
+ c.x, c.y, c.z+r,
+ 0xFF00FFFF, 0xFF00FFFF);
+ CLines::RenderLineWithClipping(
+ c.x+r, c.y+r, c.z,
+ c.x, c.y, c.z+r,
+ 0xFF00FFFF, 0xFF00FFFF);
+ }
+
+ for(i = 0; i < colModel.numLines; i++){
+ verts[0] = colModel.lines[i].p0;
+ verts[1] = colModel.lines[i].p1;
+
+ verts[0] = mat * verts[0];
+ verts[1] = mat * verts[1];
+
+ CLines::RenderLineWithClipping(
+ verts[0].x, verts[0].y, verts[0].z,
+ verts[1].x, verts[1].y, verts[1].z,
+ 0x00FFFFFF, 0x00FFFFFF);
+ }
+
+ for(i = 0; i < colModel.numBoxes; i++){
+ min = colModel.boxes[i].min;
+ max = colModel.boxes[i].max;
+
+ verts[0] = mat * CVector(min.x, min.y, min.z);
+ verts[1] = mat * CVector(min.x, min.y, max.z);
+ verts[2] = mat * CVector(min.x, max.y, min.z);
+ verts[3] = mat * CVector(min.x, max.y, max.z);
+ verts[4] = mat * CVector(max.x, min.y, min.z);
+ verts[5] = mat * CVector(max.x, min.y, max.z);
+ verts[6] = mat * CVector(max.x, max.y, min.z);
+ verts[7] = mat * CVector(max.x, max.y, max.z);
+
+ CLines::RenderLineWithClipping(
+ verts[0].x, verts[0].y, verts[0].z,
+ verts[1].x, verts[1].y, verts[1].z,
+ 0xFFFFFFFF, 0xFFFFFFFF);
+ CLines::RenderLineWithClipping(
+ verts[1].x, verts[1].y, verts[1].z,
+ verts[3].x, verts[3].y, verts[3].z,
+ 0xFFFFFFFF, 0xFFFFFFFF);
+ CLines::RenderLineWithClipping(
+ verts[3].x, verts[3].y, verts[3].z,
+ verts[2].x, verts[2].y, verts[2].z,
+ 0xFFFFFFFF, 0xFFFFFFFF);
+ CLines::RenderLineWithClipping(
+ verts[2].x, verts[2].y, verts[2].z,
+ verts[0].x, verts[0].y, verts[0].z,
+ 0xFFFFFFFF, 0xFFFFFFFF);
+
+ CLines::RenderLineWithClipping(
+ verts[4].x, verts[4].y, verts[4].z,
+ verts[5].x, verts[5].y, verts[5].z,
+ 0xFFFFFFFF, 0xFFFFFFFF);
+ CLines::RenderLineWithClipping(
+ verts[5].x, verts[5].y, verts[5].z,
+ verts[7].x, verts[7].y, verts[7].z,
+ 0xFFFFFFFF, 0xFFFFFFFF);
+ CLines::RenderLineWithClipping(
+ verts[7].x, verts[7].y, verts[7].z,
+ verts[6].x, verts[6].y, verts[6].z,
+ 0xFFFFFFFF, 0xFFFFFFFF);
+ CLines::RenderLineWithClipping(
+ verts[6].x, verts[6].y, verts[6].z,
+ verts[4].x, verts[4].y, verts[4].z,
+ 0xFFFFFFFF, 0xFFFFFFFF);
+
+ CLines::RenderLineWithClipping(
+ verts[0].x, verts[0].y, verts[0].z,
+ verts[4].x, verts[4].y, verts[4].z,
+ 0xFFFFFFFF, 0xFFFFFFFF);
+ CLines::RenderLineWithClipping(
+ verts[1].x, verts[1].y, verts[1].z,
+ verts[5].x, verts[5].y, verts[5].z,
+ 0xFFFFFFFF, 0xFFFFFFFF);
+ CLines::RenderLineWithClipping(
+ verts[2].x, verts[2].y, verts[2].z,
+ verts[6].x, verts[6].y, verts[6].z,
+ 0xFFFFFFFF, 0xFFFFFFFF);
+ CLines::RenderLineWithClipping(
+ verts[3].x, verts[3].y, verts[3].z,
+ verts[7].x, verts[7].y, verts[7].z,
+ 0xFFFFFFFF, 0xFFFFFFFF);
+ }
+
+ for(i = 0; i < colModel.numTriangles; i++){
+ colModel.GetTrianglePoint(verts[0], colModel.triangles[i].a);
+ colModel.GetTrianglePoint(verts[1], colModel.triangles[i].b);
+ colModel.GetTrianglePoint(verts[2], colModel.triangles[i].c);
+ verts[0] = mat * verts[0];
+ verts[1] = mat * verts[1];
+ verts[2] = mat * verts[2];
+ CLines::RenderLineWithClipping(
+ verts[0].x, verts[0].y, verts[0].z,
+ verts[1].x, verts[1].y, verts[1].z,
+ 0x00FF00FF, 0x00FF00FF);
+ CLines::RenderLineWithClipping(
+ verts[0].x, verts[0].y, verts[0].z,
+ verts[2].x, verts[2].y, verts[2].z,
+ 0x00FF00FF, 0x00FF00FF);
+ CLines::RenderLineWithClipping(
+ verts[1].x, verts[1].y, verts[1].z,
+ verts[2].x, verts[2].y, verts[2].z,
+ 0x00FF00FF, 0x00FF00FF);
+ }
+
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
}
void
@@ -1407,7 +1625,6 @@ CCollision::DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel,
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
-extern int gDbgSurf;
for(i = 0; i < colModel.numTriangles; i++){
colModel.GetTrianglePoint(verts[0], colModel.triangles[i].a);
@@ -1417,7 +1634,7 @@ extern int gDbgSurf;
verts[1] = mat * verts[1];
verts[2] = mat * verts[2];
- // TODO: surface
+ // game doesn't do this
r = 255;
g = 128;
b = 0;
@@ -1457,10 +1674,15 @@ extern int gDbgSurf;
b *= f;
}
- // TODO: make some surface types flicker?
-//if(s != gDbgSurf) continue;
+ if(s == SURFACE_SCAFFOLD || s == SURFACE_METAL_FENCE ||
+ s == SURFACE_BOLLARD || s == SURFACE_METAL_POLE)
+ if(CTimer::GetFrameCounter() & 1){
+ r = 0;
+ g = 0;
+ b = 0;
+ }
- if(s > SURFACE_32){
+ if(s > SURFACE_GATE){
r = CGeneral::GetRandomNumber();
g = CGeneral::GetRandomNumber();
b = CGeneral::GetRandomNumber();
@@ -1533,8 +1755,13 @@ extern int gDbgSurf;
b *= f;
}
- // TODO: make some surface types flicker?
-//if(s != gDbgSurf) continue;
+ if(s == SURFACE_SCAFFOLD || s == SURFACE_METAL_FENCE ||
+ s == SURFACE_BOLLARD || s == SURFACE_METAL_POLE)
+ if(CTimer::GetFrameCounter() & 1){
+ r = 0;
+ g = 0;
+ b = 0;
+ }
RenderBuffer::StartStoring(36, 8, &iptr, &vptr);
RwIm3DVertexSetRGBA(&vptr[0], r, g, b, 255);
diff --git a/src/core/EventList.cpp b/src/core/EventList.cpp
new file mode 100644
index 00000000..a833cc8e
--- /dev/null
+++ b/src/core/EventList.cpp
@@ -0,0 +1,238 @@
+#include "common.h"
+#include "patcher.h"
+#include "Pools.h"
+#include "ModelIndices.h"
+#include "World.h"
+#include "Wanted.h"
+#include "Eventlist.h"
+
+int32 CEventList::ms_nFirstFreeSlotIndex;
+//CEvent gaEvent[NUMEVENTS];
+CEvent *gaEvent = (CEvent*)0x6EF830;
+
+enum
+{
+ EVENT_STATE_0,
+ EVENT_STATE_CANDELETE,
+ EVENT_STATE_CLEAR,
+};
+
+void
+CEventList::Initialise(void)
+{
+ int i;
+
+ debug("Initialising CEventList...");
+ for(i = 0; i < NUMEVENTS; i++){
+ gaEvent[i].type = EVENT_NULL;
+ gaEvent[i].entityType = EVENT_ENTITY_NONE;
+ gaEvent[i].entityRef = 0;
+ gaEvent[i].posn.x = 0.0f;
+ gaEvent[i].posn.y = 0.0f;
+ gaEvent[i].posn.z = 0.0f;
+ gaEvent[i].timeout = 0;
+ gaEvent[i].state = EVENT_STATE_0;
+ }
+ ms_nFirstFreeSlotIndex = 0;
+}
+
+void
+CEventList::Update(void)
+{
+ int i;
+
+ ms_nFirstFreeSlotIndex = 0;
+ for(i = 0; i < NUMEVENTS; i++){
+ if(gaEvent[i].type == EVENT_NULL)
+ continue;
+ if(CTimer::GetTimeInMilliseconds() > gaEvent[i].timeout || gaEvent[i].state == EVENT_STATE_CANDELETE){
+ gaEvent[i].type = EVENT_NULL;
+ gaEvent[i].state = EVENT_STATE_0;
+ }
+ if(gaEvent[i].state == EVENT_STATE_CLEAR)
+ gaEvent[i].state = EVENT_STATE_CANDELETE;
+ }
+}
+
+void
+CEventList::RegisterEvent(eEventType type, eEventEntity entityType, CEntity *ent, CPed *criminal, int32 timeout)
+{
+ int i;
+ int ref;
+ bool copsDontCare;
+
+ copsDontCare = false;
+ switch(entityType){
+ case EVENT_ENTITY_PED:
+ ref = CPools::GetPedRef((CPed*)ent);
+ if(ent->GetModelIndex() >= MI_GANG01 && ent->GetModelIndex() <= MI_CRIMINAL02)
+ copsDontCare = true;
+ break;
+ case EVENT_ENTITY_VEHICLE:
+ ref = CPools::GetVehicleRef((CVehicle*)ent);
+ break;
+ case EVENT_ENTITY_OBJECT:
+ ref = CPools::GetObjectRef((CObject*)ent);
+ break;
+ default:
+ Error("Undefined entity type, RegisterEvent, EventList.cpp");
+ ref = 0;
+ break;
+ }
+
+ // only update time if event exists already
+ for(i = 0; i < NUMEVENTS; i++)
+ if(gaEvent[i].type == type &&
+ gaEvent[i].entityType == entityType &&
+ gaEvent[i].entityRef == ref){
+ gaEvent[i].timeout = CTimer::GetTimeInMilliseconds() + timeout;
+ return;
+ }
+
+ for(i = ms_nFirstFreeSlotIndex; i < NUMEVENTS; i++)
+ if(gaEvent[i].type == EVENT_NULL){
+ ms_nFirstFreeSlotIndex = i;
+ break;
+ }
+ if(i < NUMEVENTS){
+ gaEvent[i].type = type;
+ gaEvent[i].entityType = entityType;
+ gaEvent[i].timeout = CTimer::GetTimeInMilliseconds() + timeout;
+ gaEvent[i].entityRef = ref;
+ gaEvent[i].posn = ent->GetPosition();
+ gaEvent[i].criminal = criminal;
+ if(gaEvent[i].criminal)
+ gaEvent[i].criminal->RegisterReference((CEntity**)&gaEvent[i].criminal);
+ if(type == EVENT_GUNSHOT)
+ gaEvent[i].state = EVENT_STATE_CLEAR;
+ else
+ gaEvent[i].state = EVENT_STATE_0;
+ }
+
+ if(criminal == FindPlayerPed())
+ ReportCrimeForEvent(type, (uintptr)ent, copsDontCare);
+}
+
+void
+CEventList::RegisterEvent(eEventType type, CVector posn, int32 timeout)
+{
+ int i;
+
+ // only update time if event exists already
+ for(i = 0; i < NUMEVENTS; i++)
+ if(gaEvent[i].type == type &&
+ gaEvent[i].posn.x == posn.x &&
+ gaEvent[i].posn.y == posn.y &&
+ gaEvent[i].posn.z == posn.z &&
+ gaEvent[i].entityType == EVENT_ENTITY_NONE){
+ gaEvent[i].timeout = CTimer::GetTimeInMilliseconds() + timeout;
+ return;
+ }
+
+ for(i = ms_nFirstFreeSlotIndex; i < NUMEVENTS; i++)
+ if(gaEvent[i].type == EVENT_NULL){
+ ms_nFirstFreeSlotIndex = i;
+ break;
+ }
+ if(i < NUMEVENTS){
+ gaEvent[i].type = type;
+ gaEvent[i].entityType = EVENT_ENTITY_NONE;
+ gaEvent[i].timeout = CTimer::GetTimeInMilliseconds() + timeout;
+ gaEvent[i].posn = posn;
+ gaEvent[i].entityRef = 0;
+ if(type == EVENT_GUNSHOT)
+ gaEvent[i].state = EVENT_STATE_CLEAR;
+ else
+ gaEvent[i].state = EVENT_STATE_0;
+ }
+}
+
+bool
+CEventList::GetEvent(eEventType type, int32 *event)
+{
+ int i;
+ for(i = 0; i < NUMEVENTS; i++)
+ if(gaEvent[i].type == type){
+ *event = i;
+ return true;
+ }
+ return false;
+}
+
+void
+CEventList::ClearEvent(int32 event)
+{
+ if(gaEvent[event].state != EVENT_STATE_CANDELETE)
+ gaEvent[event].state = EVENT_STATE_CLEAR;
+}
+
+bool
+CEventList::FindClosestEvent(eEventType type, CVector posn, int32 *event)
+{
+ int i;
+ float dist;
+ bool found = false;
+ float mindist = 60.0f;
+
+ for(i = 0; i < NUMEVENTS; i++){
+ if(gaEvent[i].type != type)
+ continue;
+ dist = (posn - gaEvent[i].posn).Magnitude();
+ if(dist < mindist){
+ mindist = dist;
+ found = true;
+ *event = i;
+ }
+ }
+ return found;
+}
+
+void
+CEventList::ReportCrimeForEvent(eEventType type, int32 crimeId, bool copsDontCare)
+{
+ eCrimeType crime;
+ switch(type){
+ case EVENT_ASSAULT: crime = CRIME_HIT_PED; break;
+ case EVENT_RUN_REDLIGHT: crime = CRIME_RUN_REDLIGHT; break;
+ case EVENT_ASSAULT_POLICE: crime = CRIME_HIT_COP; break;
+ case EVENT_GUNSHOT: crime = CRIME_POSSESSION_GUN; break;
+ case EVENT_STEAL_CAR: crime = CRIME_STEAL_CAR; break;
+ case EVENT_HIT_AND_RUN: crime = CRIME_RUNOVER_PED; break;
+ case EVENT_HIT_AND_RUN_COP: crime = CRIME_RUNOVER_COP; break;
+ case EVENT_SHOOT_PED: crime = CRIME_SHOOT_PED; break;
+ case EVENT_SHOOT_COP: crime = CRIME_SHOOT_COP; break;
+ case EVENT_PED_SET_ON_FIRE: crime = CRIME_PED_BURNED; break;
+ case EVENT_COP_SET_ON_FIRE: crime = CRIME_COP_BURNED; break;
+ case EVENT_CAR_SET_ON_FIRE: crime = CRIME_VEHICLE_BURNED; break;
+ default: crime = CRIME_NONE; break;
+ }
+
+ if(crime == CRIME_NONE)
+ return;
+
+ CVector playerPedCoors = FindPlayerPed()->GetPosition();
+ CVector playerCoors = FindPlayerCoors();
+
+ if(CWanted::WorkOutPolicePresence(playerCoors, 14.0f) != 0){
+ FindPlayerPed()->m_pWanted->RegisterCrime_Immediately(crime, playerPedCoors, crimeId, copsDontCare);
+ FindPlayerPed()->m_pWanted->SetWantedLevelNoDrop(1);
+ }else
+ FindPlayerPed()->m_pWanted->RegisterCrime(crime, playerPedCoors, crimeId, copsDontCare);
+
+ if(type == EVENT_ASSAULT_POLICE)
+ FindPlayerPed()->SetWantedLevelNoDrop(1);
+ if(type == EVENT_SHOOT_COP)
+ FindPlayerPed()->SetWantedLevelNoDrop(2);
+
+}
+
+STARTPATCHES
+ InjectHook(0x475B60, CEventList::Initialise, PATCH_JUMP);
+ InjectHook(0x475BE0, CEventList::Update, PATCH_JUMP);
+ InjectHook(0x475C50, (void (*)(eEventType,eEventEntity,CEntity *,CPed *,int32))CEventList::RegisterEvent, PATCH_JUMP);
+ InjectHook(0x475E10, (void (*)(eEventType,CVector,int32))CEventList::RegisterEvent, PATCH_JUMP);
+ InjectHook(0x475F40, CEventList::GetEvent, PATCH_JUMP);
+ InjectHook(0x475F70, CEventList::ClearEvent, PATCH_JUMP);
+ InjectHook(0x475F90, CEventList::FindClosestEvent, PATCH_JUMP);
+ InjectHook(0x476070, CEventList::ReportCrimeForEvent, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/core/EventList.h b/src/core/EventList.h
new file mode 100644
index 00000000..9f5756be
--- /dev/null
+++ b/src/core/EventList.h
@@ -0,0 +1,67 @@
+#pragma once
+
+class CEntity;
+class CPed;
+
+enum eEventType
+{
+ EVENT_NULL,
+ EVENT_ASSAULT,
+ EVENT_RUN_REDLIGHT,
+ EVENT_ASSAULT_POLICE,
+ EVENT_GUNSHOT,
+ EVENT_INJURED_PED,
+ EVENT_DEAD_PED,
+ EVENT_FIRE,
+ EVENT_STEAL_CAR,
+ EVENT_HIT_AND_RUN,
+ EVENT_HIT_AND_RUN_COP,
+ EVENT_SHOOT_PED,
+ EVENT_SHOOT_COP,
+ EVENT_EXPLOSION,
+ EVENT_PED_SET_ON_FIRE,
+ EVENT_COP_SET_ON_FIRE,
+ EVENT_CAR_SET_ON_FIRE,
+ EVENT_ASSAULT_NASTYWEAPON,
+ EVENT_ASSAULT_NASTYWEAPON_POLICE,
+ EVENT_ICECREAM,
+ EVENT_ATM,
+ EVENT_SHOPSTALL,
+ EVENT_SHOPWINDOW,
+ EVENT_LAST_EVENT
+};
+
+enum eEventEntity
+{
+ EVENT_ENTITY_NONE,
+ EVENT_ENTITY_PED,
+ EVENT_ENTITY_VEHICLE,
+ EVENT_ENTITY_OBJECT
+};
+
+struct CEvent
+{
+ eEventType type;
+ eEventEntity entityType;
+ int32 entityRef;
+ CPed *criminal;
+ CVector posn;
+ uint32 timeout;
+ int32 state;
+};
+
+class CEventList
+{
+ static int32 ms_nFirstFreeSlotIndex;
+public:
+ static void Initialise(void);
+ static void Update(void);
+ static void RegisterEvent(eEventType type, eEventEntity entityType, CEntity *ent, CPed *criminal, int32 timeout);
+ static void RegisterEvent(eEventType type, CVector posn, int32 timeout);
+ static bool GetEvent(eEventType type, int32 *event);
+ static void ClearEvent(int32 event);
+ static bool FindClosestEvent(eEventType type, CVector posn, int32 *event);
+ static void ReportCrimeForEvent(eEventType type, int32, bool);
+};
+
+extern CEvent *gaEvent; \ No newline at end of file
diff --git a/src/core/FileLoader.cpp b/src/core/FileLoader.cpp
index 0c53ae66..14dc91cd 100644
--- a/src/core/FileLoader.cpp
+++ b/src/core/FileLoader.cpp
@@ -1,7 +1,7 @@
#include "common.h"
#include "main.h"
#include "patcher.h"
-#include "math/Quaternion.h"
+#include "Quaternion.h"
#include "ModelInfo.h"
#include "ModelIndices.h"
#include "TempColModels.h"
@@ -361,10 +361,10 @@ CFileLoader::LoadClumpFile(const char *filename)
nodename = GetFrameNodeName(RpClumpGetFrame(clump));
GetNameAndLOD(nodename, name, &n);
mi = (CClumpModelInfo*)CModelInfo::GetModelInfo(name, nil);
- assert(mi->IsClump());
- if(mi)
+ if(mi){
+ assert(mi->IsClump());
mi->SetClump(clump);
- else
+ }else
RpClumpDestroy(clump);
}
}
diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp
index 77666b12..1de5c94f 100644
--- a/src/core/Frontend.cpp
+++ b/src/core/Frontend.cpp
@@ -26,46 +26,47 @@
#include "PlayerSkin.h"
#include "PlayerInfo.h"
#include "World.h"
+#include "Renderer.h"
#define ALL_ORIGINAL_FRONTEND 1
-int32 &CMenuManager::OS_Language = *(int32*)0x5F2F78;
+int32 &CMenuManager::OS_Language = *(int32*)0x5F2F78; // 9
int8 &CMenuManager::m_PrefsUseVibration = *(int8*)0x95CD92;
int8 &CMenuManager::m_DisplayControllerOnFoot = *(int8*)0x95CD8D;
-int8 &CMenuManager::m_PrefsVsync = *(int8*)0x5F2E58;
-int8 &CMenuManager::m_PrefsVsyncDisp = *(int8*)0x5F2E5C;
-int8 &CMenuManager::m_PrefsFrameLimiter = *(int8*)0x5F2E60;
-int8 &CMenuManager::m_PrefsShowSubtitles = *(int8*)0x5F2E54;
+int8 &CMenuManager::m_PrefsVsync = *(int8*)0x5F2E58; // 1
+int8 &CMenuManager::m_PrefsVsyncDisp = *(int8*)0x5F2E5C; // 1
+int8 &CMenuManager::m_PrefsFrameLimiter = *(int8*)0x5F2E60; // 1
+int8 &CMenuManager::m_PrefsShowSubtitles = *(int8*)0x5F2E54; // 1
int8 &CMenuManager::m_PrefsSpeakers = *(int8*)0x95CD7E;
-int8 &CMenuManager::m_ControlMethod = *(int8*)0x8F5F7C;
-int8 &CMenuManager::m_PrefsDMA = *(int8*)0x5F2F74;
-int8 &CMenuManager::m_PrefsLanguage = *(int8*)0x941238;
+int32 &CMenuManager::m_ControlMethod = *(int32*)0x8F5F7C;
+int8 &CMenuManager::m_PrefsDMA = *(int8*)0x5F2F74; // 1
+int32 &CMenuManager::m_PrefsLanguage = *(int32*)0x941238;
-bool &CMenuManager::m_PrefsAllowNastyGame = *(bool*)0x5F2E64;
+bool &CMenuManager::m_PrefsAllowNastyGame = *(bool*)0x5F2E64; // true
bool &CMenuManager::m_bStartUpFrontEndRequested = *(bool*)0x95CCF4;
bool &CMenuManager::m_bShutDownFrontEndRequested = *(bool*)0x95CD6A;
int8 &CMenuManager::m_PrefsUseWideScreen = *(int8*)0x95CD23;
int8 &CMenuManager::m_PrefsRadioStation = *(int8*)0x95CDA4;
-int8 &CMenuManager::m_bDisableMouseSteering = *(int8*)0x60252C;
-int32 &CMenuManager::m_PrefsBrightness = *(int32*)0x5F2E50;
+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;
-int32 &CMenuManager::m_PrefsMusicVolume = *(int32*)0x5F2E4C;
-int32 &CMenuManager::m_PrefsSfxVolume = *(int32*)0x5F2E48;
+int32 &CMenuManager::m_PrefsMusicVolume = *(int32*)0x5F2E4C; // 102
+int32 &CMenuManager::m_PrefsSfxVolume = *(int32*)0x5F2E48; // 102
-char *CMenuManager::m_PrefsSkinFile = (char*)0x5F2E74;
+char *CMenuManager::m_PrefsSkinFile = (char*)0x5F2E74; //[256] "$$\"\""
-int32 &CMenuManager::m_KeyPressedCode = *(int32*)0x5F2E70;
+int32 &CMenuManager::m_KeyPressedCode = *(int32*)0x5F2E70; // -1
CMenuManager &FrontEndMenuManager = *(CMenuManager*)0x8F59D8;
// Move this somewhere else.
-float lodMultiplier = *(float*)0x5F726C;
+float &CRenderer::ms_lodDistScale = *(float*)0x5F726C; // 1.2
// Stuff not in CMenuManager:
uint32 &VibrationTime = *(uint32*)0x628CF8;
-char* pEditString = (char*)0x628D00;
+char *&pEditString = *(char**)0x628D00;
int32 *&pControlEdit = *(int32**)0x628D08;
bool &DisplayComboButtonErrMsg = *(bool*)0x628D14;
int32 &MouseButtonJustClicked = *(int32*)0x628D0C;
@@ -74,7 +75,6 @@ int32 &nTimeForSomething = *(int32*)0x628D54;
//int32 *pControlTemp = 0;
// Frontend inputs.
-
bool GetPadBack();
bool GetPadExitEnter();
bool GetPadForward();
@@ -149,7 +149,7 @@ char *MenuFilenames[] = {
nil, nil
};
-#if ALL_ORIGINAL_FRONTEND
+#if 0
WRAPPER void CMenuManager::BuildStatLine(char *text, float *stat, bool aFloat, float* stat2) { EAXJMP(0x483870); }
#else
void CMenuManager::BuildStatLine(char *text, float *stat, bool aFloat, float* stat2)
@@ -177,7 +177,7 @@ void CMenuManager::BuildStatLine(char *text, float *stat, bool aFloat, float* st
}
#endif
-#if ALL_ORIGINAL_FRONTEND
+#if 0
WRAPPER void CMenuManager::CentreMousePointer() { EAXJMP(0x48ACE0); }
#else
void CMenuManager::CentreMousePointer()
@@ -205,7 +205,7 @@ void CMenuManager::CheckCodesForControls(int, int)
}
#endif
-#if ALL_ORIGINAL_FRONTEND
+#if 0
WRAPPER bool CMenuManager::CheckHover(int, int, int, int) { EAXJMP(0x48ACA0); }
#else
bool CMenuManager::CheckHover(int x1, int x2, int y1, int y2)
@@ -217,74 +217,35 @@ bool CMenuManager::CheckHover(int x1, int x2, int y1, int y2)
void CMenuManager::CheckSliderMovement(int value)
{
- float fBrightness = 0.0f;
- float fDrawDistance = 0.0f;
- float fRadioVolume = 0.0f;
- float fSfxVolume = 0.0f;
- float fMouseSens = 0.0f;
-
switch (aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_Action) {
case MENUACTION_BRIGHTNESS:
- fBrightness = m_PrefsBrightness + (value * (512.0f) / 16.0f);
-
- if (fBrightness > 511.0f)
- fBrightness = 511.0f;
- else if (fBrightness < 0.0f)
- fBrightness = 0.0f;
-
- m_PrefsBrightness = fBrightness;
- SaveSettings();
+ m_PrefsBrightness += m_PrefsBrightness + value * (512/16);
+ m_PrefsBrightness = clamp(m_PrefsBrightness, 0, 511);
break;
case MENUACTION_DRAWDIST:
- fDrawDistance = m_PrefsLOD + (value * (1.8f - 0.8f) / 16.0f);
-
- if (fDrawDistance > 1.8f)
- fDrawDistance = 1.8f;
- else if (fDrawDistance < 0.8f)
- fDrawDistance = 0.8f;
-
- m_PrefsLOD = fDrawDistance;
- SaveSettings();
+ m_PrefsLOD += value * ((1.8f - 0.8f)/16.0f);
+ m_PrefsLOD = clamp(m_PrefsLOD, 0.8f, 1.8f);
+ CRenderer::ms_lodDistScale = m_PrefsLOD;
break;
case MENUACTION_MUSICVOLUME:
- fRadioVolume = m_PrefsMusicVolume + (value * (128.0f) / 16.0f);
-
- if (fRadioVolume > 127.0f)
- fRadioVolume = 127.0f;
- else if (fRadioVolume < 0.0f)
- fRadioVolume = 0.0f;
-
- m_PrefsMusicVolume = fRadioVolume;
- DMAudio.SetMusicMasterVolume(fRadioVolume);
- SaveSettings();
+ m_PrefsMusicVolume += value * (128/16);
+ m_PrefsMusicVolume = clamp(m_PrefsMusicVolume, 0, 127);
+ DMAudio.SetMusicMasterVolume(m_PrefsMusicVolume);
break;
case MENUACTION_SFXVOLUME:
- fSfxVolume = m_PrefsSfxVolume + (value * (128.0f) / 16.0f);
-
- if (fSfxVolume > 127)
- fSfxVolume = 127;
- else if (fSfxVolume < 0.0f)
- fSfxVolume = 0.0f;
-
- m_PrefsSfxVolume = fSfxVolume;
- DMAudio.SetEffectsMasterVolume(fSfxVolume);
- SaveSettings();
+ m_PrefsSfxVolume += value * (128/16);
+ m_PrefsSfxVolume = clamp(m_PrefsSfxVolume, 0, 127);
+ DMAudio.SetEffectsMasterVolume(m_PrefsSfxVolume);
break;
case MENUACTION_MOUSESENS:
- fMouseSens = TheCamera.m_fMouseAccelHorzntl + (value * (0.005f - 0.0003125f) / 16.0f);
-
- if (fMouseSens > 0.005f)
- fMouseSens = 0.005f;
- else if (fMouseSens < 0.0003125f)
- fMouseSens = 0.0003125f;
-
- TheCamera.m_fMouseAccelHorzntl = fMouseSens;
-
- // BUG: game doesn't set Y Axis.
- TheCamera.m_fMouseAccelVertical = fMouseSens;
- SaveSettings();
+ TheCamera.m_fMouseAccelHorzntl += value * 1.0f/200.0f/15.0f; // ???
+ TheCamera.m_fMouseAccelHorzntl = clamp(TheCamera.m_fMouseAccelHorzntl, 1.0f/3200.0f, 1.0f/200.0f);
+ TheCamera.m_fMouseAccelVertical = TheCamera.m_fMouseAccelHorzntl;
break;
+ default:
+ return;
}
+ SaveSettings();
}
#if 1
@@ -471,7 +432,7 @@ void CMenuManager::Draw()
CFont::PrintString(SCREEN_SCALE_X(MENUACTION_POS_X), SCREEN_SCALE_Y(MENUACTION_POS_Y), str);
}
- for (int i = 0; i < MENUROWS; ++i) {
+ for (int i = 0; i < NUM_MENUROWS; ++i) {
if (aScreens[m_nCurrScreen].m_aEntries[i].m_Action != MENUACTION_LABEL && aScreens[m_nCurrScreen].m_aEntries[i].m_EntryName[0]) {
wchar *textToPrint[MENUCOLUMNS] = { nil, nil };
bool Locked = false;
@@ -543,7 +504,7 @@ void CMenuManager::Draw()
case AR_16_9:
textToPrint[MENUCOLUMN_RIGHT] = (wchar*)L"16:9";
break;
- }
+ }
#endif
break;
case MENUACTION_RADIO:
@@ -611,7 +572,7 @@ void CMenuManager::Draw()
break;
case MENUACTION_MOUSESTEER:
textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_bDisableMouseSteering ? "FEM_ON" : "FEM_OFF");
- break;
+ break;
}
CFont::SetDropShadowPosition(MENUDROP_COLOR_SIZE);
@@ -711,7 +672,7 @@ void CMenuManager::Draw()
CFont::SetColor(CRGBA(255, 217, 106, FadeIn(255)));
CSprite2d::DrawRect(CRect(SCREEN_STRETCH_X(11.0f), vecPositions.y - SCREEN_STRETCH_Y(fBarSize * 0.13f), SCREEN_STRETCH_FROM_RIGHT(11.0f), vecPositions.y + SCREEN_STRETCH_Y(fBarSize)), CRGBA(100, 200, 50, 50));
}
- else
+ else
CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255)));
// Draw
@@ -727,35 +688,27 @@ void CMenuManager::Draw()
}
// Mouse support.
- // TODO: inputs for these pages.
- if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) {
- }
- else if (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) {
-
- }
- else {
- static bool bIsMouseInPosition = false;
- if (m_nMenuFadeAlpha >= 255 && GetMouseInput()) {
- CVector2D vecInputSize = { SCREEN_SCALE_X(20.0f), SCREEN_SCALE_FROM_RIGHT(20.0f) };
- if (m_bShowMouse &&
- ((CheckHover(vecInputSize.x, vecInputSize.y, vecPositions.y, vecPositions.y + SCREEN_STRETCH_Y(20.0f)))))
- bIsMouseInPosition = true;
- else
- bIsMouseInPosition = false;
+ static bool bIsMouseInPosition = false;
+ if (m_nMenuFadeAlpha >= 255 && GetMouseInput()) {
+ CVector2D vecInputSize = { SCREEN_SCALE_X(20.0f), SCREEN_SCALE_FROM_RIGHT(20.0f) };
+ if (m_bShowMouse &&
+ ((CheckHover(vecInputSize.x, vecInputSize.y, vecPositions.y, vecPositions.y + SCREEN_STRETCH_Y(20.0f)))))
+ bIsMouseInPosition = true;
+ else
+ bIsMouseInPosition = false;
- if (bIsMouseInPosition) {
- if (m_nCurrOption != i) {
- m_nCurrOption = i;
- DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
- }
+ if (bIsMouseInPosition) {
+ if (m_nCurrOption != i) {
+ m_nCurrOption = i;
+ DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
+ }
- m_nPrevOption = m_nCurrOption;
+ m_nPrevOption = m_nCurrOption;
- if (GetMouseForward())
- m_nHoverOption = HOVEROPTION_NULL;
- else
- m_nHoverOption = HOVEROPTION_DEFAULT;
- }
+ if (GetMouseForward())
+ m_nHoverOption = HOVEROPTION_42;
+ else
+ m_nHoverOption = HOVEROPTION_DEFAULT;
}
}
@@ -763,16 +716,16 @@ void CMenuManager::Draw()
// TODO: CheckHover
switch (aScreens[m_nCurrScreen].m_aEntries[i].m_Action) {
case MENUACTION_BRIGHTNESS:
- DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), m_PrefsBrightness/512.0f);
+ DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), m_PrefsBrightness / 512.0f);
break;
case MENUACTION_DRAWDIST:
DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), (m_PrefsLOD - 0.8f) * 1.0f);
break;
case MENUACTION_MUSICVOLUME:
- DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), m_PrefsMusicVolume/128.0f);
+ DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), m_PrefsMusicVolume / 128.0f);
break;
case MENUACTION_SFXVOLUME:
- DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), m_PrefsSfxVolume/128.0f);
+ DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), m_PrefsSfxVolume / 128.0f);
break;
case MENUACTION_MOUSESENS:
DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), TheCamera.m_fMouseAccelHorzntl * 200.0f);
@@ -859,7 +812,7 @@ void CMenuManager::DrawControllerSetupScreen()
}
#endif
-#if ALL_ORIGINAL_FRONTEND
+#if 0
WRAPPER void CMenuManager::DrawFrontEnd(void) { EAXJMP(0x47A540); }
#else
void CMenuManager::DrawFrontEnd()
@@ -867,7 +820,7 @@ void CMenuManager::DrawFrontEnd()
CFont::SetAlphaFade(255.0f);
if (m_nCurrScreen == MENUPAGE_NONE) {
- m_nMenuFadeAlpha = 0;
+ // m_nMenuFadeAlpha = 0;
if (m_bGameNotLoaded)
m_nCurrScreen = MENUPAGE_START_MENU;
@@ -875,31 +828,27 @@ void CMenuManager::DrawFrontEnd()
m_nCurrScreen = MENUPAGE_PAUSE_MENU;
}
- if (!m_nCurrOption && aScreens[m_nCurrScreen].m_aEntries[0].m_Action == MENUACTION_LABEL)
- m_nCurrOption = MENUROW_1;
+ if (m_nCurrOption == 0 && aScreens[m_nCurrScreen].m_aEntries[0].m_Action == MENUACTION_LABEL)
+ m_nCurrOption = 1;
CMenuManager::DrawFrontEndNormal();
CMenuManager::PrintErrorMessage();
}
#endif
-#if ALL_ORIGINAL_FRONTEND
+#if 0
WRAPPER void CMenuManager::DrawFrontEndNormal(void) { EAXJMP(0x47A5B0); }
#else
void CMenuManager::DrawFrontEndNormal()
{
- RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE);
RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
- RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void *)FALSE);
- RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE);
- RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA);
- RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA);
- RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void *)rwTEXTUREADDRESSCLAMP);
CSprite2d::InitPerFrame();
CFont::InitPerFrame();
- eMenuSprites previousSprite = MENUSPRITE_MAINMENU;
+ LoadSplash(nil);
+
+ eMenuSprites previousSprite = MENUSPRITE_MAINMENU; // actually uninitialized
if (m_nMenuFadeAlpha < 255) {
switch (m_nPrevScreen) {
case MENUPAGE_STATS:
@@ -939,13 +888,16 @@ void CMenuManager::DrawFrontEndNormal()
break;
}
- if (m_nPrevScreen == MENUPAGE_NONE)
- CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(0, 0, 0, 255));
+ if (m_nPrevScreen == m_nCurrScreen)
+ CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(0, 0, 0, 255-m_nMenuFadeAlpha));
else
- m_aMenuSprites[previousSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255));
+ m_aMenuSprites[previousSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255-m_nMenuFadeAlpha));
}
- eMenuSprites currentSprite = MENUSPRITE_MAINMENU;
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+
+ eMenuSprites currentSprite = MENUSPRITE_MAINMENU; // actually uninitialized
switch (m_nCurrScreen) {
case MENUPAGE_STATS:
case MENUPAGE_START_MENU:
@@ -984,38 +936,45 @@ void CMenuManager::DrawFrontEndNormal()
break;
}
- uint32 savedShade;
- uint32 savedAlpha;
- RwRenderStateGet(rwRENDERSTATESHADEMODE, &savedShade);
- RwRenderStateSet(rwRENDERSTATESHADEMODE, reinterpret_cast<void *>(rwSHADEMODEGOURAUD));
- RwRenderStateGet(rwRENDERSTATEVERTEXALPHAENABLE, &savedAlpha);
- RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, reinterpret_cast<void *>(TRUE));
- if (m_nMenuFadeAlpha >= 255) {
- m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255));
- }
- else {
- if (m_nMenuFadeAlpha < 255) {
- m_nMenuFadeAlpha += 0.1f * 255.0f;
-
- if (m_nMenuFadeAlpha >= 255)
- m_nMenuFadeAlpha = 255;
+ if (m_nMenuFadeAlpha < 255) {
+ static int LastFade = 0;
- m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, m_nMenuFadeAlpha));
+ if(CTimer::GetTimeInMillisecondsPauseMode() - LastFade > 10){
+ m_nMenuFadeAlpha += 20;
+ LastFade = CTimer::GetTimeInMillisecondsPauseMode();
}
- else
+
+ if (m_nMenuFadeAlpha > 255){
m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255));
+ }else{
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, m_nMenuFadeAlpha));
+ }
+ }
+ else {
+ m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255));
+ // TODO: what is this? waiting mouse?
+ if(field_518 == 4){
+ if(m_nHoverOption == 3 || m_nHoverOption == 4 || m_nHoverOption == 5 || m_nHoverOption == 6 || m_nHoverOption == 7)
+ field_518 = 2;
+ else
+ field_518 = 1;
+ }
}
// GTA LOGO
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
if (m_nCurrScreen == MENUPAGE_START_MENU || m_nCurrScreen == MENUPAGE_PAUSE_MENU) {
if (CGame::frenchGame || CGame::germanGame || !CGame::nastyGame)
m_aMenuSprites[MENUSPRITE_GTA3LOGO].Draw(CRect((SCREEN_WIDTH / 2) - SCREEN_SCALE_X(115.0f), SCREEN_SCALE_Y(70.0f), (SCREEN_WIDTH / 2) + SCREEN_SCALE_X(115.0f), SCREEN_SCALE_Y(180.0f)), CRGBA(255, 255, 255, FadeIn(255)));
else
m_aMenuSprites[MENUSPRITE_GTALOGO].Draw(CRect((SCREEN_WIDTH / 2) - SCREEN_SCALE_X(95.0f), SCREEN_SCALE_Y(40.0f), (SCREEN_WIDTH / 2) + SCREEN_SCALE_X(95.0f), SCREEN_SCALE_Y(210.0f)), CRGBA(255, 255, 255, FadeIn(255)));
}
- RwRenderStateSet(rwRENDERSTATESHADEMODE, reinterpret_cast<void *>(savedShade));
- RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, reinterpret_cast<void *>(savedAlpha));
+ RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERNEAREST);
+ RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
switch (m_nCurrScreen) {
case MENUPAGE_SKIN_SELECT:
CMenuManager::DrawPlayerSetupScreen();
@@ -1031,8 +990,25 @@ void CMenuManager::DrawFrontEndNormal()
CFont::DrawFonts();
// Draw mouse
- if (m_bShowMouse)
- m_aMenuSprites[MENUSPRITE_MOUSE].Draw(m_nMousePosX, m_nMousePosY, SCREEN_SCALE_X(60.0f), SCREEN_SCALE_Y(60.0f), CRGBA(255, 255, 255, 255));
+ RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
+ RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP);
+ if (m_bShowMouse) {
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+
+ CRect mouse(0.0f, 0.0f, SCREEN_SCALE_X(75.0f), SCREEN_SCALE_X(75.0f));
+ mouse.Translate(m_nMousePosX, m_nMousePosY);
+ CRect shad = mouse;
+ shad.Translate(SCREEN_SCALE_X(10.0f), SCREEN_SCALE_Y(3.0f));
+ if(field_518 == 4){
+ m_aMenuSprites[MENUSPRITE_MOUSET].Draw(shad, CRGBA(100, 100, 100, 50));
+ m_aMenuSprites[MENUSPRITE_MOUSET].Draw(mouse, CRGBA(255, 255, 255, 255));
+ }else{
+ m_aMenuSprites[MENUSPRITE_MOUSE].Draw(shad, CRGBA(100, 100, 100, 50));
+ m_aMenuSprites[MENUSPRITE_MOUSE].Draw(mouse, CRGBA(255, 255, 255, 255));
+ }
+ }
}
#endif
@@ -1045,7 +1021,7 @@ void CMenuManager::DrawPlayerSetupScreen()
}
#endif
-#if ALL_ORIGINAL_FRONTEND
+#if 0
WRAPPER int CMenuManager::FadeIn(int alpha) { EAXJMP(0x48AC60); }
#else
int CMenuManager::FadeIn(int alpha)
@@ -1054,11 +1030,7 @@ int CMenuManager::FadeIn(int alpha)
m_nCurrScreen == MENUPAGE_SAVING_IN_PROGRESS ||
m_nCurrScreen == MENUPAGE_DELETING)
return alpha;
-
- if (m_nMenuFadeAlpha >= alpha)
- return alpha;
-
- return m_nMenuFadeAlpha;
+ return min(m_nMenuFadeAlpha, alpha);
}
#endif
@@ -1116,7 +1088,7 @@ void CMenuManager::LoadAllTextures()
CMenuManager::CentreMousePointer();
DMAudio.ChangeMusicMode(0);
DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_STARTING, 0);
- m_nCurrOption = MENUROW_0;
+ m_nCurrOption = 0;
m_PrefsRadioStation = DMAudio.GetRadioInCar();
if (DMAudio.IsMP3RadioChannelAvailable()) {
@@ -1165,7 +1137,7 @@ void CMenuManager::LoadAllTextures()
}
#endif
-#if ALL_ORIGINAL_FRONTEND
+#if 0
WRAPPER void CMenuManager::LoadSettings() { EAXJMP(0x488EE0); }
#else
void CMenuManager::LoadSettings()
@@ -1173,46 +1145,47 @@ void CMenuManager::LoadSettings()
CFileMgr::SetDirMyDocuments();
- uint8 prevLang = m_PrefsLanguage;
+ int32 prevLang = m_PrefsLanguage;
+ CMBlur::BlurOn = true;
MousePointerStateHelper.bInvertVertically = true;
static char Ver;
int fileHandle = CFileMgr::OpenFile("gta3.set", "r");
if (fileHandle) {
- CFileMgr::Read(fileHandle, buf(&Ver), sizeof(Ver));
+ CFileMgr::Read(fileHandle, (char*)&Ver, sizeof(Ver));
if (strncmp(&Ver, "THIS FILE IS NOT VALID YET", 26)) {
CFileMgr::Seek(fileHandle, 0, 0);
ControlsManager.LoadSettings(fileHandle);
- CFileMgr::Read(fileHandle, buf(gString), 20);
- CFileMgr::Read(fileHandle, buf(gString), 20);
- CFileMgr::Read(fileHandle, buf(gString), 4);
- CFileMgr::Read(fileHandle, buf(gString), 4);
- CFileMgr::Read(fileHandle, buf(gString), 1);
- CFileMgr::Read(fileHandle, buf(gString), 1);
- CFileMgr::Read(fileHandle, buf(gString), 1);
- CFileMgr::Read(fileHandle, buf(&TheCamera.m_bHeadBob), 1);
- CFileMgr::Read(fileHandle, buf(&TheCamera.m_fMouseAccelHorzntl), 4);
- CFileMgr::Read(fileHandle, buf(&TheCamera.m_fMouseAccelVertical), 4);
- CFileMgr::Read(fileHandle, buf(&MousePointerStateHelper.bInvertVertically), 1);
- CFileMgr::Read(fileHandle, buf(&CVehicle::m_bDisableMouseSteering), 1);
- CFileMgr::Read(fileHandle, buf(&m_PrefsSfxVolume), 1);
- CFileMgr::Read(fileHandle, buf(&m_PrefsMusicVolume), 1);
- CFileMgr::Read(fileHandle, buf(&m_PrefsRadioStation), 1);
- CFileMgr::Read(fileHandle, buf(&m_PrefsSpeakers), 1);
- CFileMgr::Read(fileHandle, buf(&m_nPrefsAudio3DProviderIndex), 1);
- CFileMgr::Read(fileHandle, buf(&m_PrefsDMA), 1);
- CFileMgr::Read(fileHandle, buf(&m_PrefsBrightness), 1);
- CFileMgr::Read(fileHandle, buf(&m_PrefsLOD), 4);
- CFileMgr::Read(fileHandle, buf(&m_PrefsShowSubtitles), 1);
- CFileMgr::Read(fileHandle, buf(&m_PrefsUseWideScreen), 1);
- CFileMgr::Read(fileHandle, buf(&m_PrefsVsyncDisp), 1);
- CFileMgr::Read(fileHandle, buf(&m_PrefsFrameLimiter), 1);
- CFileMgr::Read(fileHandle, buf(&m_nDisplayVideoMode), 1);
- CFileMgr::Read(fileHandle, buf(&CMBlur::BlurOn), 1);
- CFileMgr::Read(fileHandle, buf(m_PrefsSkinFile), 256);
- CFileMgr::Read(fileHandle, buf(&m_ControlMethod), 1);
- CFileMgr::Read(fileHandle, buf(&m_PrefsLanguage), 1);
+ CFileMgr::Read(fileHandle, gString, 20);
+ CFileMgr::Read(fileHandle, gString, 20);
+ CFileMgr::Read(fileHandle, gString, 4);
+ CFileMgr::Read(fileHandle, gString, 4);
+ CFileMgr::Read(fileHandle, gString, 1);
+ CFileMgr::Read(fileHandle, gString, 1);
+ CFileMgr::Read(fileHandle, gString, 1);
+ CFileMgr::Read(fileHandle, (char*)&TheCamera.m_bHeadBob, 1);
+ CFileMgr::Read(fileHandle, (char*)&TheCamera.m_fMouseAccelHorzntl, 4);
+ CFileMgr::Read(fileHandle, (char*)&TheCamera.m_fMouseAccelVertical, 4);
+ CFileMgr::Read(fileHandle, (char*)&MousePointerStateHelper.bInvertVertically, 1);
+ CFileMgr::Read(fileHandle, (char*)&CVehicle::m_bDisableMouseSteering, 1);
+ CFileMgr::Read(fileHandle, (char*)&m_PrefsSfxVolume, 1);
+ CFileMgr::Read(fileHandle, (char*)&m_PrefsMusicVolume, 1);
+ CFileMgr::Read(fileHandle, (char*)&m_PrefsRadioStation, 1);
+ CFileMgr::Read(fileHandle, (char*)&m_PrefsSpeakers, 1);
+ CFileMgr::Read(fileHandle, (char*)&m_nPrefsAudio3DProviderIndex, 1);
+ CFileMgr::Read(fileHandle, (char*)&m_PrefsDMA, 1);
+ CFileMgr::Read(fileHandle, (char*)&m_PrefsBrightness, 1);
+ CFileMgr::Read(fileHandle, (char*)&m_PrefsLOD, 4);
+ CFileMgr::Read(fileHandle, (char*)&m_PrefsShowSubtitles, 1);
+ CFileMgr::Read(fileHandle, (char*)&m_PrefsUseWideScreen, 1);
+ CFileMgr::Read(fileHandle, (char*)&m_PrefsVsyncDisp, 1);
+ CFileMgr::Read(fileHandle, (char*)&m_PrefsFrameLimiter, 1);
+ CFileMgr::Read(fileHandle, (char*)&m_nDisplayVideoMode, 1);
+ CFileMgr::Read(fileHandle, (char*)&CMBlur::BlurOn, 1);
+ CFileMgr::Read(fileHandle, m_PrefsSkinFile, 256);
+ CFileMgr::Read(fileHandle, (char*)&m_ControlMethod, 1);
+ CFileMgr::Read(fileHandle, (char*)&m_PrefsLanguage, 1);
}
}
@@ -1220,7 +1193,7 @@ void CMenuManager::LoadSettings()
CFileMgr::SetDir("");
m_PrefsVsync = m_PrefsVsyncDisp;
- lodMultiplier = m_PrefsLOD;
+ CRenderer::ms_lodDistScale = m_PrefsLOD;
if (m_nPrefsAudio3DProviderIndex == -1)
m_nPrefsAudio3DProviderIndex = -2;
@@ -1237,25 +1210,72 @@ void CMenuManager::LoadSettings()
debug("The previously saved language is now in use");
}
- /*struct _WIN32_FIND_DATAA FindFileData;
- HANDLE H = FindFirstFileA("skins\*.bmp", &FindFileData);
- char Dest;
+ struct _WIN32_FIND_DATAA FindFileData;
+ char skinfile[256+16]; // ?? + 16?
bool SkinFound = false;
-
- for (int i = 1; H != (HANDLE)-1 && i; i = FindNextFileA(H, &FindFileData)) {
- strcpy(&Dest, buf(m_PrefsSkinFile));
- strcat(&Dest, ".bmp");
- if (!strcmp(FindFileData.cFileName, &Dest))
+ HANDLE handle = FindFirstFileA("skins\\*.bmp", &FindFileData);
+ for (int i = 1; handle != (HANDLE)-1 && i; i = FindNextFileA(handle, &FindFileData)) {
+ strcpy(skinfile, m_PrefsSkinFile);
+ strcat(skinfile, ".bmp");
+ if (strcmp(FindFileData.cFileName, skinfile) == 0)
SkinFound = true;
}
-
- FindClose(H);
+ FindClose(handle);
if (!SkinFound) {
debug("Default skin set as no other skins are available OR saved skin not found!");
- strcpy((char *)CMenuManager::m_PrefsSkinFile, "$$\"\"");
+ strcpy(m_PrefsSkinFile, "$$\"\"");
strcpy(m_aSkinName, "$$\"\"");
- }*/
+ }
+}
+#endif
+
+#if 0
+WRAPPER void CMenuManager::SaveSettings() { EAXJMP(0x488CC0); }
+#else
+void CMenuManager::SaveSettings()
+{
+ static char RubbishString[48] = "stuffmorestuffevenmorestuff etc";
+
+ CFileMgr::SetDirMyDocuments();
+
+ int fileHandle = CFileMgr::OpenFile("gta3.set", "w");
+ if (fileHandle) {
+
+ ControlsManager.SaveSettings(fileHandle);
+ CFileMgr::Write(fileHandle, RubbishString, 20);
+ CFileMgr::Write(fileHandle, RubbishString, 20);
+ CFileMgr::Write(fileHandle, RubbishString, 4);
+ CFileMgr::Write(fileHandle, RubbishString, 4);
+ CFileMgr::Write(fileHandle, RubbishString, 1);
+ CFileMgr::Write(fileHandle, RubbishString, 1);
+ CFileMgr::Write(fileHandle, RubbishString, 1);
+ CFileMgr::Write(fileHandle, (char*)&TheCamera.m_bHeadBob, 1);
+ CFileMgr::Write(fileHandle, (char*)&TheCamera.m_fMouseAccelHorzntl, 4);
+ CFileMgr::Write(fileHandle, (char*)&TheCamera.m_fMouseAccelVertical, 4);
+ CFileMgr::Write(fileHandle, (char*)&MousePointerStateHelper.bInvertVertically, 1);
+ CFileMgr::Write(fileHandle, (char*)&CVehicle::m_bDisableMouseSteering, 1);
+ CFileMgr::Write(fileHandle, (char*)&m_PrefsSfxVolume, 1);
+ CFileMgr::Write(fileHandle, (char*)&m_PrefsMusicVolume, 1);
+ CFileMgr::Write(fileHandle, (char*)&m_PrefsRadioStation, 1);
+ CFileMgr::Write(fileHandle, (char*)&m_PrefsSpeakers, 1);
+ CFileMgr::Write(fileHandle, (char*)&m_nPrefsAudio3DProviderIndex, 1);
+ CFileMgr::Write(fileHandle, (char*)&m_PrefsDMA, 1);
+ CFileMgr::Write(fileHandle, (char*)&m_PrefsBrightness, 1);
+ CFileMgr::Write(fileHandle, (char*)&m_PrefsLOD, sizeof(m_PrefsLOD));
+ CFileMgr::Write(fileHandle, (char*)&m_PrefsShowSubtitles, 1);
+ CFileMgr::Write(fileHandle, (char*)&m_PrefsUseWideScreen, 1);
+ CFileMgr::Write(fileHandle, (char*)&m_PrefsVsyncDisp, 1);
+ CFileMgr::Write(fileHandle, (char*)&m_PrefsFrameLimiter, 1);
+ CFileMgr::Write(fileHandle, (char*)&m_nDisplayVideoMode, 1);
+ CFileMgr::Write(fileHandle, (char*)&CMBlur::BlurOn, 1);
+ CFileMgr::Write(fileHandle, m_PrefsSkinFile, 256);
+ CFileMgr::Write(fileHandle, (char*)&m_ControlMethod, 1);
+ CFileMgr::Write(fileHandle, (char*)&m_PrefsLanguage, 1);
+ }
+
+ CFileMgr::CloseFile(fileHandle);
+ CFileMgr::SetDir("");
}
#endif
@@ -1319,7 +1339,7 @@ void CMenuManager::PrintStats()
}
#endif
-#if ALL_ORIGINAL_FRONTEND
+#if 0
WRAPPER void CMenuManager::Process(void) { EAXJMP(0x485100); }
#else
void CMenuManager::Process(void)
@@ -1423,7 +1443,7 @@ void CMenuManager::Process(void)
JoyButtonJustClicked = ControlsManager.GetJoyButtonJustDown();
- int32 TypeOfControl = 0;
+ int32 TypeOfControl = 0;
if (JoyButtonJustClicked)
TypeOfControl = 3;
if (MouseButtonJustClicked)
@@ -1468,11 +1488,10 @@ void CMenuManager::Process(void)
CPad::StopPadsShaking();
VibrationTime = 0;
}
- }
- else {
+
+ } else {
UnloadTextures();
field_452 = 0;
- *(bool*)0x5F33E4 = true;
// byte_5F33E4 = 1; // unused
m_nPrevScreen = 0;
m_nCurrScreen = m_nPrevScreen;
@@ -1493,15 +1512,12 @@ WRAPPER void CMenuManager::ProcessButtonPresses() { EAXJMP(0x4856F0); }
#else
void CMenuManager::ProcessButtonPresses()
{
- if(pEditString)
- return;
- if(pControlEdit)
+ if (pEditString || pControlEdit)
return;
// Update mouse position
m_nMouseOldPosX = m_nMousePosX;
m_nMouseOldPosY = m_nMousePosY;
-
m_nMousePosX = m_nMouseTempPosX;
m_nMousePosY = m_nMouseTempPosY;
@@ -1521,28 +1537,58 @@ void CMenuManager::ProcessButtonPresses()
m_bShowMouse = false;
if (m_nCurrScreen == MENUPAGE_MULTIPLAYER_FIND_GAME || m_nCurrScreen == MENUPAGE_SKIN_SELECT || m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) {
- if (m_nCurrScreen == MENUPAGE_SKIN_SELECT)
- field_440 = m_nSkinsTotal;
+ if (m_nCurrScreen == MENUPAGE_SKIN_SELECT)
+ m_nCurrExSize = m_nSkinsTotal;
- if (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) {
- field_440 = m_ControlMethod ? 30 : 25;
-
- if (field_44C > field_440)
- field_44C = field_440 - 1;
- }
+ if (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS)
+ m_nCurrExSize = m_ControlMethod ? 30 : 25;
if (!GetPadBack() || m_nCurrScreen != MENUPAGE_KEYBOARD_CONTROLS || field_535)
field_535 = 0;
- else if (field_536 == 19) {
- m_nHoverOption = 42;
+ else if (m_nCurrExLayer == 19) {
+ m_nHoverOption = HOVEROPTION_42;
field_113 = 1;
field_456 = 1;
- m_bKeyChangeNotProcessed = 1;
+ m_bKeyChangeNotProcessed = true;
pControlEdit = &m_KeyPressedCode;
}
+ bool Trigger = false;
+ if (!Trigger) {
+ nTimeForSomething = 0;
+ Trigger = true;
+ }
+
+ if ((CTimer::GetTimeInMillisecondsPauseMode() - nTimeForSomething) > 200) {
+ field_520 = 0;
+ field_521 = 0;
+ field_522 = 0;
+ field_523 = 0;
+ field_524 = 0;
+ nTimeForSomething = CTimer::GetTimeInMillisecondsPauseMode();
+ }
+
+ if (CPad::GetPad(0)->NewKeyState.TAB && !CPad::GetPad(0)->OldKeyState.TAB) {
+ switch (m_nCurrExLayer) {
+ case 9:
+ m_nCurrExLayer = 19;
+ break;
+ case 19:
+ m_nCurrExLayer = 21;
+ break;
+ case 21:
+ m_nCurrExLayer = 9;
+ break;
+ }
+ if (m_nCurrScreen == MENUPAGE_SKIN_SELECT && m_nCurrExLayer == 21 && !strcmp(m_aSkinName, m_PrefsSkinFile)) {
+ m_nCurrExLayer = 9;
+ }
+ if (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS && m_nCurrExLayer == 21)
+ m_nCurrExLayer = 9;
+ }
+
if (GetPadForward()) {
- switch (field_536) {
+ switch (m_nCurrExLayer) {
case 19:
if (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) {
field_113 = 1;
@@ -1552,36 +1598,21 @@ void CMenuManager::ProcessButtonPresses()
if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) {
strcpy(m_PrefsSkinFile, m_aSkinName);
CWorld::Players->SetPlayerSkin(m_PrefsSkinFile);
- field_536 = 9;
+ m_nCurrExLayer = 9;
}
- m_nHoverOption = HOVEROPTION_NULL;
+ m_nHoverOption = HOVEROPTION_42;
SaveSettings();
break;
case 21:
strcpy(m_PrefsSkinFile, m_aSkinName);
CWorld::Players->SetPlayerSkin(m_PrefsSkinFile);
- field_536 = 9;
+ m_nCurrExLayer = 9;
break;
default:
break;
}
}
-
- bool once = false;
- if (!once) {
- once = true;
- nTimeForSomething = 0;
- }
-
- if ((CTimer::GetTimeInMillisecondsPauseMode() - nTimeForSomething) > 200) {
- field_520 = 0;
- field_521 = 0;
- field_522 = 0;
- field_523 = 0;
- field_524 = 0;
- nTimeForSomething = CTimer::GetTimeInMillisecondsPauseMode();
- }
}
// Get number of menu options.
@@ -1591,31 +1622,41 @@ void CMenuManager::ProcessButtonPresses()
if (GetPadMoveUp()) {
m_nPrevOption = m_nCurrOption;
m_nCurrOption -= 1;
+ m_nCurrExOption -= 1;
+ //field_438 -= 1;
if (aScreens[m_nCurrScreen].m_aEntries[0].m_Action == MENUACTION_LABEL) {
- if (m_nCurrOption < MENUROW_1)
+ if (m_nCurrOption < 1)
m_nCurrOption = NumberOfMenuOptions;
}
else {
- if (m_nCurrOption < MENUROW_0)
+ if (m_nCurrOption < 0)
m_nCurrOption = NumberOfMenuOptions;
}
+ if (m_nCurrExOption < 0)
+ m_nCurrExOption = 0;
+
DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
}
else if (GetPadMoveDown()) {
m_nPrevOption = m_nCurrOption;
m_nCurrOption += 1;
+ m_nCurrExOption += 1;
+ //field_438 = += 1;
if (aScreens[m_nCurrScreen].m_aEntries[0].m_Action == MENUACTION_LABEL) {
if (m_nCurrOption > NumberOfMenuOptions)
- m_nCurrOption = MENUROW_1;
+ m_nCurrOption = 1;
}
else {
if (m_nCurrOption > NumberOfMenuOptions)
- m_nCurrOption = MENUROW_0;
+ m_nCurrOption = 0;
}
+ if (m_nCurrExOption > m_nCurrExSize - 1)
+ m_nCurrExOption = m_nCurrExSize - 1;
+
DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
}
@@ -1637,6 +1678,8 @@ void CMenuManager::ProcessButtonPresses()
}
else
SwitchToNewScreen(aScreens[m_nCurrScreen].m_PreviousPage[0]);
+
+ PlayEscSound = true;
break;
default:
SwitchToNewScreen(aScreens[m_nCurrScreen].m_PreviousPage[0]);
@@ -1675,7 +1718,7 @@ void CMenuManager::ProcessButtonPresses()
}
break;
default:
- m_nHoverOption = HOVEROPTION_NULL;
+ m_nHoverOption = HOVEROPTION_42;
break;
}
}
@@ -1871,10 +1914,12 @@ void CMenuManager::ProcessOnOffMenuOptions()
break;
case MENUACTION_UPDATESAVE:
PcSaveHelper.PopulateSlotInfo();
- if (aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_SaveSlot >= SAVESLOT_1 && aScreens[m_nCurrOption].m_aEntries[m_nCurrOption].m_SaveSlot <= SAVESLOT_8) {
- m_nCurrSaveSlot = aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_SaveSlot - 2;
+ if (!m_bGameNotLoaded) {
+ if (aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_SaveSlot >= SAVESLOT_1 && aScreens[m_nCurrOption].m_aEntries[m_nCurrOption].m_SaveSlot <= SAVESLOT_8) {
+ m_nCurrSaveSlot = aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_SaveSlot - 2;
- SwitchToNewScreen(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_TargetMenu);
+ SwitchToNewScreen(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_TargetMenu);
+ }
}
break;
case MENUACTION_CHECKSAVE:
@@ -2120,32 +2165,24 @@ void CMenuManager::SaveLoadFileError_SetUpErrorScreen()
case 1:
case 2:
case 3:
- m_nPrevScreen = m_nCurrScreen;
- m_nCurrScreen = MENUPAGE_SAVE_FAILED;
- m_nCurrOption = MENUROW_0;
+ SwitchToNewScreen(MENUPAGE_SAVE_FAILED);
m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode();
break;
break;
case 4:
case 5:
case 6:
- this->m_nPrevScreen = m_nCurrScreen;
- this->m_nCurrScreen = MENUPAGE_LOAD_FAILED;
- m_nCurrOption = MENUROW_0;
+ SwitchToNewScreen(MENUPAGE_LOAD_FAILED);
m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode();
break;
case 7:
- this->m_nPrevScreen = m_nCurrScreen;
- this->m_nCurrScreen = MENUPAGE_LOAD_FAILED_2;
- m_nCurrOption = MENUROW_0;
+ SwitchToNewScreen(MENUPAGE_LOAD_FAILED_2);
m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode();
break;
case 8:
case 9:
case 10:
- m_nPrevScreen = m_nCurrScreen;
- m_nCurrScreen = MENUPAGE_DELETE_FAILED;
- m_nCurrOption = MENUROW_0;
+ SwitchToNewScreen(MENUPAGE_DELETE_FAILED);
m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode();
break;
default:
@@ -2165,53 +2202,6 @@ void CMenuManager::SetHelperText(int text)
#endif
#if ALL_ORIGINAL_FRONTEND
-WRAPPER void CMenuManager::SaveSettings() { EAXJMP(0x488CC0); }
-#else
-void CMenuManager::SaveSettings()
-{
- CFileMgr::SetDirMyDocuments();
-
- int fileHandle = CFileMgr::OpenFile("gta3.set", "w");
- if (fileHandle) {
-
- ControlsManager.SaveSettings(fileHandle);
- CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 20);
- CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 20);
- CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 4);
- CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 4);
- CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 1);
- CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 1);
- CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 1);
- CFileMgr::Write(fileHandle, buf(&TheCamera.m_bHeadBob), 1);
- CFileMgr::Write(fileHandle, buf(&TheCamera.m_fMouseAccelHorzntl), 4);
- CFileMgr::Write(fileHandle, buf(&TheCamera.m_fMouseAccelVertical), 4);
- CFileMgr::Write(fileHandle, buf(&MousePointerStateHelper.bInvertVertically), 1);
- CFileMgr::Write(fileHandle, buf(&CVehicle::m_bDisableMouseSteering), 1);
- CFileMgr::Write(fileHandle, buf(&m_PrefsSfxVolume), 1);
- CFileMgr::Write(fileHandle, buf(&m_PrefsMusicVolume), 1);
- CFileMgr::Write(fileHandle, buf(&m_PrefsRadioStation), 1);
- CFileMgr::Write(fileHandle, buf(&m_PrefsSpeakers), 1);
- CFileMgr::Write(fileHandle, buf(&m_nPrefsAudio3DProviderIndex), 1);
- CFileMgr::Write(fileHandle, buf(&m_PrefsDMA), 1);
- CFileMgr::Write(fileHandle, buf(&m_PrefsBrightness), 1);
- CFileMgr::Write(fileHandle, buf(&m_PrefsLOD), sizeof(m_PrefsLOD));
- CFileMgr::Write(fileHandle, buf(&m_PrefsShowSubtitles), 1);
- CFileMgr::Write(fileHandle, buf(&m_PrefsUseWideScreen), 1);
- CFileMgr::Write(fileHandle, buf(&m_PrefsVsyncDisp), 1);
- CFileMgr::Write(fileHandle, buf(&m_PrefsFrameLimiter), 1);
- CFileMgr::Write(fileHandle, buf(&m_nDisplayVideoMode), 1);
- CFileMgr::Write(fileHandle, buf(&CMBlur::BlurOn), 1);
- CFileMgr::Write(fileHandle, buf(m_PrefsSkinFile), 256);
- CFileMgr::Write(fileHandle, buf(&m_ControlMethod), 1);
- CFileMgr::Write(fileHandle, buf(&m_PrefsLanguage), 1);
- }
-
- CFileMgr::CloseFile(fileHandle);
- CFileMgr::SetDir("");
-}
-#endif
-
-#if ALL_ORIGINAL_FRONTEND
WRAPPER void CMenuManager::ShutdownJustMenu() { EAXJMP(0x488920); }
#else
void CMenuManager::ShutdownJustMenu()
@@ -2221,7 +2211,6 @@ void CMenuManager::ShutdownJustMenu()
}
#endif
-// We won't ever use this again.
#if ALL_ORIGINAL_FRONTEND
WRAPPER float CMenuManager::StretchX(float) { EAXJMP(0x48ABE0); }
#else
@@ -2230,7 +2219,11 @@ float CMenuManager::StretchX(float x)
if (SCREEN_WIDTH == 640)
return x;
else
+#ifndef ASPECT_RATIO_SCALE
return SCREEN_WIDTH * x * 0.0015625f;
+#else
+ return SCREEN_SCALE_X(x);
+#endif
}
#endif
@@ -2337,10 +2330,11 @@ void CMenuManager::WaitForUserCD()
#endif
// New content:
+#if 0
uint8 CMenuManager::GetNumberOfMenuOptions()
{
- uint8 Rows = MENUROW_NONE;
- for (int i = 0; i < MENUROWS; i++) {
+ uint8 Rows = -1;
+ for (int i = 0; i < NUM_MENUROWS; i++) {
if (aScreens[m_nCurrScreen].m_aEntries[i].m_Action == MENUACTION_NOTHING)
break;
@@ -2349,7 +2343,7 @@ uint8 CMenuManager::GetNumberOfMenuOptions()
return Rows;
}
-void CMenuManager::SwitchToNewScreen(int8 screen)
+void CMenuManager::SwitchToNewScreen(int32 screen)
{
ResetHelperText();
@@ -2372,21 +2366,24 @@ void CMenuManager::SwitchToNewScreen(int8 screen)
if (screen) {
m_nPrevScreen = m_nCurrScreen;
m_nCurrScreen = screen;
- m_nCurrOption = MENUROW_0;
+ m_nCurrOption = 0;
+ //
+ m_nCurrExOption = 0;
+ m_nCurrExLayer = 19;
+ //
m_nMenuFadeAlpha = 0;
m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode();
}
else {
m_nPrevScreen = MENUPAGE_NONE;
m_nCurrScreen = MENUPAGE_NONE;
- m_nCurrOption = MENUROW_0;
+ m_nCurrOption = 0;
}
}
// Set player skin.
if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) {
CPlayerSkin::BeginFrontEndSkinEdit();
- field_535 = 19;
m_bSkinsFound = false;
}
@@ -2399,7 +2396,7 @@ void CMenuManager::SwitchToNewScreen(int8 screen)
DMAudio.StopFrontEndTrack();
}
-void CMenuManager::SetDefaultPreferences(int8 screen)
+void CMenuManager::SetDefaultPreferences(int32 screen)
{
switch (screen) {
case MENUPAGE_SOUND_SETTINGS:
@@ -2446,6 +2443,7 @@ void CMenuManager::SetDefaultPreferences(int8 screen)
break;
}
}
+#endif
// Frontend inputs.
bool GetPadBack()
@@ -2480,7 +2478,7 @@ bool GetPadMoveUp()
bool GetPadMoveDown()
{
- return
+ return
(CPad::GetPad(0)->NewState.DPadDown && !CPad::GetPad(0)->OldState.DPadDown) ||
(CPad::GetPad(0)->NewKeyState.DOWN && !CPad::GetPad(0)->OldKeyState.DOWN) ||
(CPad::GetPad(0)->NewState.LeftStickY > 0 && !(CPad::GetPad(0)->OldState.LeftStickY > 0));
@@ -2540,7 +2538,7 @@ bool GetMouseForward()
bool GetMouseBack()
{
- return GetMouseClickRight;
+ return GetMouseClickRight();
}
bool GetMousePos()
@@ -2581,7 +2579,8 @@ bool GetMouseInput()
}
STARTPATCHES
-#ifndef ALL_ORIGINAL_FRONTEND
+#if ALL_ORIGINAL_FRONTEND
+#else
InjectHook(0x47A230, &CMenuManager::LoadAllTextures, PATCH_JUMP);
InjectHook(0x47A440, &CMenuManager::UnloadTextures, PATCH_JUMP);
InjectHook(0x485100, &CMenuManager::Process, PATCH_JUMP);
@@ -2589,8 +2588,13 @@ STARTPATCHES
InjectHook(0x48AE60, &CMenuManager::ProcessOnOffMenuOptions, PATCH_JUMP);
InjectHook(0x488EE0, &CMenuManager::LoadSettings, PATCH_JUMP);
InjectHook(0x488CC0, &CMenuManager::SaveSettings, PATCH_JUMP);
+ InjectHook(0x48ABE0, &CMenuManager::StretchX, PATCH_JUMP);
+ InjectHook(0x48AC20, &CMenuManager::StretchY, PATCH_JUMP);
for (int i = 1; i < ARRAY_SIZE(aScreens); i++)
Patch(0x611930 + sizeof(CMenuScreen) * i, aScreens[i]);
#endif
+
+ InjectHook(0x488EE0, &CMenuManager::LoadSettings, PATCH_JUMP);
+ InjectHook(0x488CC0, &CMenuManager::SaveSettings, PATCH_JUMP);
ENDPATCHES \ No newline at end of file
diff --git a/src/core/Frontend.h b/src/core/Frontend.h
index 9a3cdd50..b588b1af 100644
--- a/src/core/Frontend.h
+++ b/src/core/Frontend.h
@@ -43,8 +43,6 @@
#define MENUSLIDER_X 306.0f
-#define buf(a) (char*)(a)
-
enum eLanguages
{
LANGUAGE_AMERICAN,
@@ -328,7 +326,7 @@ enum eCheckHover
HOVEROPTION_19,
HOVEROPTION_20,
HOVEROPTION_CHANGESKIN,
- HOVEROPTION_NULL = 42,
+ HOVEROPTION_42 = 42,
};
enum eMenuColumns
@@ -339,28 +337,9 @@ enum eMenuColumns
MENUCOLUMNS,
};
-enum eMenuRow
+enum
{
- MENUROW_NONE = -1,
- MENUROW_0,
- MENUROW_1,
- MENUROW_2,
- MENUROW_3,
- MENUROW_4,
- MENUROW_5,
- MENUROW_6,
- MENUROW_7,
- MENUROW_8,
- MENUROW_9,
- MENUROW_10,
- MENUROW_11,
- MENUROW_12,
- MENUROW_13,
- MENUROW_14,
- MENUROW_15,
- MENUROW_16,
- MENUROW_17,
- MENUROWS,
+ NUM_MENUROWS = 18,
};
struct tSkinInfo
@@ -377,7 +356,7 @@ struct CMenuScreen
char m_ScreenName[8];
int32 unk;
int32 m_PreviousPage[2]; // eMenuScreen
- int32 m_ParentEntry[2]; // eMenuRow
+ int32 m_ParentEntry[2]; // row
struct CMenuEntry
{
@@ -385,7 +364,7 @@ struct CMenuScreen
char m_EntryName[8];
int32 m_SaveSlot; // eSaveSlot
int32 m_TargetMenu; // eMenuScreen
- } m_aEntries[MENUROWS];
+ } m_aEntries[NUM_MENUROWS];
};
class CMenuManager
@@ -413,10 +392,10 @@ public:
tSkinInfo *m_pSelectedSkin;
tSkinInfo *field_438;
float field_43C;
- int field_440;
+ int m_nCurrExSize;
int m_nSkinsTotal;
char _unk0[4];
- int field_44C;
+ int m_nCurrExOption;
bool m_bSkinsFound;
bool m_bQuitGameNoCD;
char field_452;
@@ -439,7 +418,7 @@ public:
int field_530;
char field_534;
char field_535;
- int8 field_536;
+ int8 m_nCurrExLayer;
int m_nHelperTextAlpha;
int m_nMouseOldPosX;
int m_nMouseOldPosY;
@@ -452,6 +431,7 @@ public:
int m_nCurrSaveSlot;
int m_nScreenChangeDelayTimer;
+public:
static int32 &OS_Language;
static int8 &m_PrefsUseVibration;
static int8 &m_DisplayControllerOnFoot;
@@ -462,9 +442,9 @@ public:
static int8 &m_PrefsFrameLimiter;
static int8 &m_PrefsShowSubtitles;
static int8 &m_PrefsSpeakers;
- static int8 &m_ControlMethod;
+ static int32 &m_ControlMethod;
static int8 &m_PrefsDMA;
- static int8 &m_PrefsLanguage;
+ static int32 &m_PrefsLanguage;
static int8 &m_bDisableMouseSteering;
static int32 &m_PrefsBrightness;
static float &m_PrefsLOD;
@@ -516,17 +496,16 @@ public:
void SaveSettings();
void SetHelperText(int text);
void ShutdownJustMenu();
- static float StretchX(float);
- static float StretchY(float);
+ float StretchX(float);
+ float StretchY(float);
void SwitchMenuOnAndOff();
void UnloadTextures();
void WaitForUserCD();
// New content:
uint8 GetNumberOfMenuOptions();
- void SwitchToNewScreen(int8 screen);
- void SetDefaultPreferences(int8 screen);
-
+ void SwitchToNewScreen(int32 screen);
+ void SetDefaultPreferences(int32 screen);
};
static_assert(sizeof(CMenuManager) == 0x564, "CMenuManager: error");
diff --git a/src/core/General.h b/src/core/General.h
index 64613478..7c0c9562 100644
--- a/src/core/General.h
+++ b/src/core/General.h
@@ -36,6 +36,22 @@ public:
}
}
+ static float LimitAngle(float angle)
+ {
+ float result = angle;
+
+ while (result >= 180.0f) {
+ result -= 2 * 180.0f;
+ }
+
+ while (result < -180.0f) {
+ result += 2 * 180.0f;
+ }
+
+ return result;
+ }
+
+
static float LimitRadianAngle(float angle)
{
float result;
diff --git a/src/core/MenuScreens.h b/src/core/MenuScreens.h
index 866dfc03..b464d657 100644
--- a/src/core/MenuScreens.h
+++ b/src/core/MenuScreens.h
@@ -2,15 +2,15 @@
const CMenuScreen aScreens[] = {
// MENUPAGE_NONE = 0
- { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, },
+ { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, },
// MENUPAGE_STATS = 1
- { "FET_STA", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_5, MENUROW_2,
+ { "FET_STA", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, 5, 2,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_NEW_GAME = 2
- { "FET_SGA", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_0, MENUROW_1,
+ { "FET_SGA", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, 0, 1,
MENUACTION_CHANGEMENU, "FES_SNG", SAVESLOT_NONE, MENUPAGE_NEW_GAME_RELOAD,
MENUACTION_CHANGEMENU, "GMLOAD", SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT,
MENUACTION_CHANGEMENU, "FES_DGA", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT,
@@ -18,17 +18,17 @@ const CMenuScreen aScreens[] = {
},
// MENUPAGE_BRIEFS = 3
- { "FET_BRE", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_6, MENUROW_3,
+ { "FET_BRE", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, 6, 3,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENU_CONTROLLER_SETTINGS = 4
- { "FET_CON", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_0, MENUROW_0,
+ { "FET_CON", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 0, 0,
},
// MENUPAGE_SOUND_SETTINGS = 5
- { "FET_AUD", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_1, MENUROW_1,
+ { "FET_AUD", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 1, 1,
MENUACTION_MUSICVOLUME, "FEA_MUS", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
MENUACTION_SFXVOLUME, "FEA_SFX", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
MENUACTION_AUDIOHW, "FEA_3DH", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
@@ -40,7 +40,7 @@ const CMenuScreen aScreens[] = {
},
// MENUPAGE_GRAPHICS_SETTINGS = 6
- { "FET_DIS", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_2, MENUROW_2,
+ { "FET_DIS", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 2, 2,
MENUACTION_BRIGHTNESS, "FED_BRI", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
MENUACTION_DRAWDIST, "FEM_LOD", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
MENUACTION_FRAMESYNC, "FEM_VSC", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
@@ -54,7 +54,7 @@ const CMenuScreen aScreens[] = {
},
// MENUPAGE_LANGUAGE_SETTINGS = 7
- { "FET_LAN", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_3, MENUROW_3,
+ { "FET_LAN", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 3, 3,
MENUACTION_LANG_ENG, "FEL_ENG", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_LANG_FRE, "FEL_FRE", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_LANG_GER, "FEL_GER", SAVESLOT_NONE, MENUPAGE_NONE,
@@ -64,7 +64,7 @@ const CMenuScreen aScreens[] = {
},
// MENUPAGE_CHOOSE_LOAD_SLOT = 8
- { "FET_LG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUROW_1, MENUROW_1,
+ { "FET_LG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, 1, 1,
MENUACTION_CHANGEMENU, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NEW_GAME,
MENUACTION_CHECKSAVE, "FEM_SL1", SAVESLOT_1, MENUPAGE_LOAD_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL2", SAVESLOT_2, MENUPAGE_LOAD_SLOT_CONFIRM,
@@ -77,7 +77,7 @@ const CMenuScreen aScreens[] = {
},
// MENUPAGE_CHOOSE_DELETE_SLOT = 9
- { "FET_DG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUROW_2, MENUROW_2,
+ { "FET_DG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, 2, 2,
MENUACTION_CHANGEMENU, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NEW_GAME,
MENUACTION_CHECKSAVE, "FEM_SL1", SAVESLOT_1, MENUPAGE_DELETE_SLOT_CONFIRM,
MENUACTION_CHECKSAVE, "FEM_SL2", SAVESLOT_2, MENUPAGE_DELETE_SLOT_CONFIRM,
@@ -90,96 +90,96 @@ const CMenuScreen aScreens[] = {
},
// MENUPAGE_NEW_GAME_RELOAD = 10
- { "FET_NG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUROW_0, MENUROW_0,
+ { "FET_NG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, 0, 0,
MENUACTION_LABEL, "FESZ_QR", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_NEW_GAME,
MENUACTION_NEWGAME, "FEM_YES", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_LOAD_SLOT_CONFIRM = 11
- { "FET_LG", MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, MENUROW_0, MENUROW_0,
+ { "FET_LG", MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, 0, 0,
MENUACTION_LABEL, "FESZ_QL", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT,
MENUACTION_CHANGEMENU, "FEM_YES", SAVESLOT_NONE, MENUPAGE_LOADING_IN_PROGRESS,
},
// MENUPAGE_DELETE_SLOT_CONFIRM = 12
- { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUROW_0, MENUROW_0,
+ { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, 0, 0,
MENUACTION_LABEL, "FESZ_QD", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT,
MENUACTION_CHANGEMENU, "FEM_YES", SAVESLOT_NONE, MENUPAGE_DELETING,
},
// MENUPAGE_13 = 13
- { "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_LOADING_IN_PROGRESS = 14
- { "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_LABEL, "FED_LDW", SAVESLOT_NONE, MENUPAGE_LOAD_SLOT_CONFIRM,
},
// MENUPAGE_DELETING_IN_PROGRESS = 15
- { "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_LABEL, "FEDL_WR", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_16 = 16
- { "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_LABEL, "FES_LOE", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_DELETE_FAILED = 17
- { "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_LABEL, "FES_DEE", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT,
},
// MENUPAGE_DEBUG_MENU = 18
- { "FED_DBG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FED_DBG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_MEMORY_CARD_1 = 19
- { "FEM_MCM", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FEM_MCM", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_MEMORY_CARD_2 = 20
- { "FEM_MC2", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FEM_MC2", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_MULTIPLAYER_MAIN = 21
- { "FET_MP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FET_MP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_SAVE_FAILED_1 = 22
- { "MCDNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "MCDNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_MEMCARDSAVECONFIRM, "JAILB_U", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_SAVE_FAILED_2 = 23
- { "MCGNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "MCGNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_MEMCARDSAVECONFIRM, "JAILB_U", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_SAVE = 24
- { "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_LABEL, "FES_SCG", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_UPDATESAVE, "GMSAVE", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT,
MENUACTION_UPDATEMEMCARDSAVE, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_NO_MEMORY_CARD = 25
- { "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_CHOOSE_SAVE_SLOT = 26
- { "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_UPDATEMEMCARDSAVE, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_UPDATESAVE, "FEM_SL1", SAVESLOT_1, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
MENUACTION_UPDATESAVE, "FEM_SL2", SAVESLOT_2, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
@@ -192,49 +192,49 @@ const CMenuScreen aScreens[] = {
},
// MENUPAGE_SAVE_OVERWRITE_CONFIRM = 27
- { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0,
+ { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
MENUACTION_LABEL, "FESZ_QO", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEM_YES", SAVESLOT_NONE, MENUPAGE_SAVING_IN_PROGRESS,
MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT,
},
// MENUPAGE_MULTIPLAYER_MAP = 28
- { "FET_MAP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FET_MAP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_MULTIPLAYER_CONNECTION = 29
- { "FET_CON", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FET_CON", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_MULTIPLAYER_FIND_GAME = 30
- { "FET_FG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FET_FG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_MULTIPLAYER_MODE = 31
- { "FET_GT", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FET_GT", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_MULTIPLAYER_CREATE = 32
- { "FET_HG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FET_HG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_MULTIPLAYER_START = 33
- { "FEN_STA", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FEN_STA", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_SKIN_SELECT_OLD = 34
- { "FET_PS", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FET_PS", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_CONTROLLER_PC = 35
- { "FET_CTL", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_0, MENUROW_0,
+ { "FET_CTL", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 0, 0,
MENUACTION_CTRLMETHOD, "FET_CME", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
MENUACTION_CHANGEMENU, "FET_RDK", SAVESLOT_NONE, MENUPAGE_KEYBOARD_CONTROLS,
MENUACTION_CHANGEMENU, "FET_AMS", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS,
@@ -243,32 +243,32 @@ const CMenuScreen aScreens[] = {
},
// MENUPAGE_CONTROLLER_PC_OLD1 = 36
- { "FET_CTL", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUROW_0, MENUROW_0,
+ { "FET_CTL", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 0, 0,
},
// MENUPAGE_CONTROLLER_PC_OLD2 = 37
- { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_CONTROLLER_PC_OLD3 = 38
- { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_CONTROLLER_PC_OLD4 = 39
- { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_CONTROLLER_DEBUG = 40
- { "FEC_DBG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FEC_DBG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_OPTIONS = 41
- { "FET_OPT", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_1, MENUROW_4,
+ { "FET_OPT", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, 1, 4,
MENUACTION_CHANGEMENU, "FET_CTL", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
MENUACTION_CHANGEMENU, "FET_AUD", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
MENUACTION_CHANGEMENU, "FET_DIS", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
@@ -278,65 +278,65 @@ const CMenuScreen aScreens[] = {
},
// MENUPAGE_EXIT = 42
- { "FET_QG", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_2, MENUROW_5,
+ { "FET_QG", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, 2, 5,
MENUACTION_LABEL, "FEQ_SRE", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CANCLEGAME, "FEM_YES", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_SAVING_IN_PROGRESS = 43
- { "", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0,
+ { "", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
MENUACTION_LABEL, "FES_WAR", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_SAVE_SUCCESSFUL = 44
- { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0,
+ { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
MENUACTION_LABEL, "FES_SSC", SAVESLOT_LABEL, MENUPAGE_NONE,
MENUACTION_UPDATEMEMCARDSAVE, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT,
},
// MENUPAGE_DELETING = 45
- { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUROW_0, MENUROW_0,
+ { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, 0, 0,
MENUACTION_LABEL, "FED_DLW", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_DELETE_SUCCESS = 46
- { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUROW_0, MENUROW_0,
+ { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, 0, 0,
MENUACTION_LABEL, "DEL_FNM", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT,
},
// MENUPAGE_SAVE_FAILED = 47
- { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0,
+ { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
MENUACTION_LABEL, "FEC_SVU", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT,
},
// MENUPAGE_LOAD_FAILED = 48
- { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0,
+ { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
MENUACTION_LABEL, "FEC_SVU", SAVESLOT_NONE, MENUPAGE_NONE,
},
// MENUPAGE_LOAD_FAILED_2 = 49
- { "FET_LG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0,
+ { "FET_LG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
MENUACTION_LABEL, "FEC_LUN", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT,
},
// MENUPAGE_FILTER_GAME = 50
- { "FIL_FLT", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FIL_FLT", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_START_MENU = 51
- { "FEM_MM", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FEM_MM", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_CHANGEMENU, "FEN_STA", SAVESLOT_NONE, MENUPAGE_NEW_GAME,
MENUACTION_CHANGEMENU, "FET_OPT", SAVESLOT_NONE, MENUPAGE_OPTIONS,
MENUACTION_CHANGEMENU, "FEM_QT", SAVESLOT_NONE, MENUPAGE_EXIT,
},
// MENUPAGE_PAUSE_MENU = 52
- { "FET_PAU", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FET_PAU", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
MENUACTION_RESUME, "FEM_RES", SAVESLOT_NONE, MENUPAGE_NONE,
MENUACTION_CHANGEMENU, "FEN_STA", SAVESLOT_NONE, MENUPAGE_NEW_GAME,
MENUACTION_CHANGEMENU, "FEP_STA", SAVESLOT_NONE, MENUPAGE_STATS,
@@ -346,22 +346,22 @@ const CMenuScreen aScreens[] = {
},
// MENUPAGE_CHOOSE_MODE = 53
- { "FEN_STA", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "FEN_STA", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_SKIN_SELECT = 54
- { "FET_PSU", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_4, MENUROW_4,
+ { "FET_PSU", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 4, 4,
//MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_MULTIPLAYER_MAIN,
},
// MENUPAGE_KEYBOARD_CONTROLS = 55
- { "FET_STI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUROW_1, MENUROW_1,
+ { "FET_STI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 1, 1,
//MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
},
// MENUPAGE_MOUSE_CONTROLS = 56
- { "FET_MTI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUROW_2, MENUROW_2,
+ { "FET_MTI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 2, 2,
MENUACTION_MOUSESENS, "FEC_MSH", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS,
MENUACTION_INVVERT, "FEC_IVV", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS,
MENUACTION_MOUSESTEER, "FET_MST", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS,
@@ -369,12 +369,12 @@ const CMenuScreen aScreens[] = {
},
// MENUPAGE_57 = 57
- { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
// MENUPAGE_58 = 58
- { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
},
};
diff --git a/src/core/Messages.cpp b/src/core/Messages.cpp
index 7fc23593..c6f3bc1b 100644
--- a/src/core/Messages.cpp
+++ b/src/core/Messages.cpp
@@ -9,6 +9,11 @@ WRAPPER char CMessages::WideStringCompare(wchar* str1, wchar* str2, unsigned sho
WRAPPER void CMessages::InsertNumberInString(wchar* src, int n1, int n2, int n3, int n4, int n5, int n6, wchar* dst) { EAXJMP(0x52A1A0); }
WRAPPER void CMessages::InsertPlayerControlKeysInString(wchar* src) { EAXJMP(0x52A490); }
WRAPPER int CMessages::GetWideStringLength(wchar* src) { EAXJMP(0x529490); }
+WRAPPER void CMessages::AddBigMessage(wchar* key, uint32 time, uint16 pos) { EAXJMP(0x529EB0); }
+WRAPPER void CMessages::AddMessage(wchar* key, uint32 time, uint16 pos) { EAXJMP(0x529900); }
+WRAPPER void CMessages::AddMessageJumpQ(wchar* key, uint32 time, uint16 pos) { EAXJMP(0x529A10); }
+WRAPPER void CMessages::AddMessageSoon(wchar* key, uint32 time, uint16 pos) { EAXJMP(0x529AF0); }
+WRAPPER void CMessages::ClearMessages() { EAXJMP(0x529CE0); }
tPreviousBrief *CMessages::PreviousBriefs = (tPreviousBrief *)0x713C08;
tMessage *CMessages::BriefMessages = (tMessage *)0x8786E0;
diff --git a/src/core/Messages.h b/src/core/Messages.h
index 69cf117c..51c36212 100644
--- a/src/core/Messages.h
+++ b/src/core/Messages.h
@@ -41,4 +41,9 @@ public:
static void InsertNumberInString(wchar* src, int n1, int n2, int n3, int n4, int n5, int n6, wchar* dst);
static void InsertPlayerControlKeysInString(wchar* src);
static int GetWideStringLength(wchar *src);
+ static void AddBigMessage(wchar* key, uint32 time, uint16 pos);
+ static void AddMessage(wchar* key, uint32 time, uint16 pos);
+ static void AddMessageJumpQ(wchar* key, uint32 time, uint16 pos);
+ static void AddMessageSoon(wchar* key, uint32 time, uint16 pos);
+ static void ClearMessages();
};
diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp
index 9c5e1c8a..736e1e9d 100644
--- a/src/core/Pad.cpp
+++ b/src/core/Pad.cpp
@@ -155,7 +155,7 @@ void CPad::Clear(bool bResetPlayerControls)
ShakeDur = 0;
if ( bResetPlayerControls )
- DisablePlayerControls = false;
+ DisablePlayerControls = PLAYERCONTROL_ENABLED;
bApplyBrakes = false;
@@ -659,7 +659,7 @@ CPad *CPad::GetPad(int32 pad)
int16 CPad::GetSteeringLeftRight(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return 0;
switch ( Mode )
@@ -692,7 +692,7 @@ int16 CPad::GetSteeringLeftRight(void)
int16 CPad::GetSteeringUpDown(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return 0;
switch ( Mode )
@@ -725,7 +725,7 @@ int16 CPad::GetSteeringUpDown(void)
int16 CPad::GetCarGunUpDown(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return 0;
switch ( Mode )
@@ -752,7 +752,7 @@ int16 CPad::GetCarGunUpDown(void)
int16 CPad::GetCarGunLeftRight(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return 0;
switch ( Mode )
@@ -779,7 +779,7 @@ int16 CPad::GetCarGunLeftRight(void)
int16 CPad::GetPedWalkLeftRight(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return 0;
switch ( Mode )
@@ -813,7 +813,7 @@ int16 CPad::GetPedWalkLeftRight(void)
int16 CPad::GetPedWalkUpDown(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return 0;
switch ( Mode )
@@ -876,7 +876,7 @@ int16 CPad::GetAnalogueUpDown(void)
bool CPad::GetLookLeft(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
return !!(NewState.LeftShoulder2 && !NewState.RightShoulder2);
@@ -884,7 +884,7 @@ bool CPad::GetLookLeft(void)
bool CPad::GetLookRight(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
return !!(NewState.RightShoulder2 && !NewState.LeftShoulder2);
@@ -893,7 +893,7 @@ bool CPad::GetLookRight(void)
bool CPad::GetLookBehindForCar(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
return !!(NewState.RightShoulder2 && NewState.LeftShoulder2);
@@ -901,7 +901,7 @@ bool CPad::GetLookBehindForCar(void)
bool CPad::GetLookBehindForPed(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
return !!NewState.RightShock;
@@ -909,7 +909,7 @@ bool CPad::GetLookBehindForPed(void)
bool CPad::GetHorn(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
switch ( Mode )
@@ -948,7 +948,7 @@ bool CPad::GetHorn(void)
bool CPad::HornJustDown(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
switch ( Mode )
@@ -988,7 +988,7 @@ bool CPad::HornJustDown(void)
bool CPad::GetCarGunFired(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
switch ( Mode )
@@ -1015,7 +1015,7 @@ bool CPad::GetCarGunFired(void)
bool CPad::CarGunJustDown(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
switch ( Mode )
@@ -1042,7 +1042,7 @@ bool CPad::CarGunJustDown(void)
int16 CPad::GetHandBrake(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return 0;
switch ( Mode )
@@ -1075,7 +1075,7 @@ int16 CPad::GetHandBrake(void)
int16 CPad::GetBrake(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return 0;
switch ( Mode )
@@ -1113,7 +1113,7 @@ int16 CPad::GetBrake(void)
bool CPad::GetExitVehicle(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
switch ( Mode )
@@ -1140,7 +1140,7 @@ bool CPad::GetExitVehicle(void)
bool CPad::ExitVehicleJustDown(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
switch ( Mode )
@@ -1167,7 +1167,7 @@ bool CPad::ExitVehicleJustDown(void)
int32 CPad::GetWeapon(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
switch ( Mode )
@@ -1200,7 +1200,7 @@ int32 CPad::GetWeapon(void)
bool CPad::WeaponJustDown(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
switch ( Mode )
@@ -1233,7 +1233,7 @@ bool CPad::WeaponJustDown(void)
int16 CPad::GetAccelerate(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return 0;
switch ( Mode )
@@ -1319,7 +1319,7 @@ bool CPad::CycleCameraModeDownJustDown(void)
bool CPad::ChangeStationJustDown(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
switch ( Mode )
@@ -1359,7 +1359,7 @@ bool CPad::ChangeStationJustDown(void)
bool CPad::CycleWeaponLeftJustDown(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
return !!(NewState.LeftShoulder2 && !OldState.LeftShoulder2);
@@ -1367,7 +1367,7 @@ bool CPad::CycleWeaponLeftJustDown(void)
bool CPad::CycleWeaponRightJustDown(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
return !!(NewState.RightShoulder2 && !OldState.RightShoulder2);
@@ -1375,7 +1375,7 @@ bool CPad::CycleWeaponRightJustDown(void)
bool CPad::GetTarget(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
switch ( Mode )
@@ -1402,7 +1402,7 @@ bool CPad::GetTarget(void)
bool CPad::TargetJustDown(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
switch ( Mode )
@@ -1429,7 +1429,7 @@ bool CPad::TargetJustDown(void)
bool CPad::JumpJustDown(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
return !!(NewState.Square && !OldState.Square);
@@ -1437,7 +1437,7 @@ bool CPad::JumpJustDown(void)
bool CPad::GetSprint(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
switch ( Mode )
@@ -1464,7 +1464,7 @@ bool CPad::GetSprint(void)
bool CPad::ShiftTargetLeftJustDown(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
return !!(NewState.LeftShoulder2 && !OldState.LeftShoulder2);
@@ -1472,7 +1472,7 @@ bool CPad::ShiftTargetLeftJustDown(void)
bool CPad::ShiftTargetRightJustDown(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
return !!(NewState.RightShoulder2 && !OldState.RightShoulder2);
@@ -1592,7 +1592,7 @@ bool CPad::GetAnaloguePadRightJustUp(void)
bool CPad::ForceCameraBehindPlayer(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
switch ( Mode )
@@ -1625,7 +1625,7 @@ bool CPad::ForceCameraBehindPlayer(void)
bool CPad::SniperZoomIn(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
switch ( Mode )
@@ -1652,7 +1652,7 @@ bool CPad::SniperZoomIn(void)
bool CPad::SniperZoomOut(void)
{
- if ( DisablePlayerControls )
+ if ( ArePlayerControlsDisabled() )
return false;
switch ( Mode )
@@ -1824,7 +1824,7 @@ char *CPad::EditString(char *pStr, int32 nSize)
}
// numbers
- for ( int32 i = 0; i < ('0' - '9' + 1); i++ )
+ for ( int32 i = 0; i < ('9' - '0' + 1); i++ )
{
if ( GetPad(0)->GetCharJustDown(i + '0') && pos < nSize - 1 )
{
diff --git a/src/core/Pad.h b/src/core/Pad.h
index 62585377..4f129e85 100644
--- a/src/core/Pad.h
+++ b/src/core/Pad.h
@@ -51,6 +51,17 @@ enum Key
};
*/
+enum {
+ PLAYERCONTROL_ENABLED = 0,
+ PLAYERCONTROL_DISABLED_1 = 1,
+ PLAYERCONTROL_DISABLED_2 = 2,
+ PLAYERCONTROL_DISABLED_4 = 4,
+ PLAYERCONTROL_DISABLED_8 = 8,
+ PLAYERCONTROL_DISABLED_10 = 16,
+ PLAYERCONTROL_DISABLED_20 = 32,
+ PLAYERCONTROL_DISABLED_40 = 64, // used on phone calls
+ PLAYERCONTROL_DISABLED_80 = 128,
+};
class CControllerState
{
@@ -186,9 +197,9 @@ public:
int16 Mode;
int16 ShakeDur;
uint8 ShakeFreq;
- int8 bHornHistory[5];
+ bool bHornHistory[5];
uint8 iCurrHornHistory;
- bool DisablePlayerControls;
+ uint8 DisablePlayerControls;
int8 bApplyBrakes;
char _unk[12]; //int32 unk[3];
char _pad0[3];
@@ -289,6 +300,10 @@ public:
// mouse
bool GetLeftMouseJustDown() { return !!(NewMouseControllerState.LMB && !OldMouseControllerState.LMB); }
+ bool GetRightMouseJustDown() { return !!(NewMouseControllerState.RMB && !OldMouseControllerState.RMB); }
+ bool GetMiddleMouseJustDown() { return !!(NewMouseControllerState.MMB && !OldMouseControllerState.MMB); }
+ float GetMouseX() { return NewMouseControllerState.x; }
+ float GetMouseY() { return NewMouseControllerState.y; }
// keyboard
@@ -354,6 +369,13 @@ public:
bool GetRightShoulder1JustDown() { return !!(NewState.RightShoulder1 && !OldState.RightShoulder1); }
bool GetRightShoulder2JustDown() { return !!(NewState.RightShoulder2 && !OldState.RightShoulder2); }
+/*
+ int32 GetLeftShoulder1(void) { return NewState.LeftShoulder1; }
+ int32 GetLeftShoulder2(void) { return NewState.LeftShoulder2; }
+ int32 GetRightShoulder1(void) { return NewState.RightShoulder1; }
+ int32 GetRightShoulder2(void) { return NewState.RightShoulder2; }
+*/
+
bool GetTriangle() { return !!NewState.Triangle; }
bool GetCircle() { return !!NewState.Circle; }
bool GetCross() { return !!NewState.Cross; }
@@ -366,10 +388,11 @@ public:
bool GetLeftShoulder2(void) { return !!NewState.LeftShoulder2; }
bool GetRightShoulder1(void) { return !!NewState.RightShoulder1; }
bool GetRightShoulder2(void) { return !!NewState.RightShoulder2; }
+
+ bool ArePlayerControlsDisabled(void) { return DisablePlayerControls != PLAYERCONTROL_ENABLED; }
};
VALIDATE_SIZE(CPad, 0xFC);
+extern CPad *Pads; //[2]
#define IsButtonJustDown(pad, btn) \
(!(pad)->OldState.btn && (pad)->NewState.btn)
-
-void LittleTest(void);
diff --git a/src/core/Pools.cpp b/src/core/Pools.cpp
index f7f93292..404cd558 100644
--- a/src/core/Pools.cpp
+++ b/src/core/Pools.cpp
@@ -9,11 +9,13 @@ CBuildingPool *&CPools::ms_pBuildingPool = *(CBuildingPool**)0x8F2C04;
CTreadablePool *&CPools::ms_pTreadablePool = *(CTreadablePool**)0x8F2568;
CObjectPool *&CPools::ms_pObjectPool = *(CObjectPool**)0x880E28;
CDummyPool *&CPools::ms_pDummyPool = *(CDummyPool**)0x8F2C18;
+CAudioScriptObjectPool *&CPools::ms_pAudioScriptObjectPool = *(CAudioScriptObjectPool**)0x8F1B6C;
void
CPools::Initialise(void)
{
// TODO: unused right now
+ assert(0);
ms_pPtrNodePool = new CCPtrNodePool(NUMPTRNODES);
ms_pEntryInfoNodePool = new CEntryInfoNodePool(NUMENTRYINFOS);
ms_pPedPool = new CPedPool(NUMPEDS);
@@ -22,4 +24,12 @@ CPools::Initialise(void)
ms_pTreadablePool = new CTreadablePool(NUMTREADABLES);
ms_pObjectPool = new CObjectPool(NUMOBJECTS);
ms_pDummyPool = new CDummyPool(NUMDUMMIES);
+ ms_pAudioScriptObjectPool = new CAudioScriptObjectPool(NUMAUDIOSCRIPTOBJECTS);
}
+
+int32 CPools::GetPedRef(CPed *ped) { return ms_pPedPool->GetIndex(ped); }
+CPed *CPools::GetPed(int32 handle) { return ms_pPedPool->GetAt(handle); }
+int32 CPools::GetVehicleRef(CVehicle *vehicle) { return ms_pVehiclePool->GetIndex(vehicle); }
+CVehicle *CPools::GetVehicle(int32 handle) { return ms_pVehiclePool->GetAt(handle); }
+int32 CPools::GetObjectRef(CObject *object) { return ms_pObjectPool->GetIndex(object); }
+CObject *CPools::GetObject(int32 handle) { return ms_pObjectPool->GetAt(handle); }
diff --git a/src/core/Pools.h b/src/core/Pools.h
index 3496064c..bdf668c2 100644
--- a/src/core/Pools.h
+++ b/src/core/Pools.h
@@ -8,6 +8,7 @@
#include "PlayerPed.h"
#include "Automobile.h"
#include "DummyPed.h"
+#include "AudioManager.h"
typedef CPool<CPtrNode> CCPtrNodePool;
typedef CPool<CEntryInfoNode> CEntryInfoNodePool;
@@ -17,6 +18,7 @@ typedef CPool<CBuilding> CBuildingPool;
typedef CPool<CTreadable> CTreadablePool;
typedef CPool<CObject, CCutsceneHead> CObjectPool;
typedef CPool<CDummy, CDummyPed> CDummyPool;
+typedef CPool<cAudioScriptObject, cAudioScriptObject> CAudioScriptObjectPool;
class CPools
{
@@ -28,7 +30,7 @@ class CPools
static CTreadablePool *&ms_pTreadablePool;
static CObjectPool *&ms_pObjectPool;
static CDummyPool *&ms_pDummyPool;
- // ms_pAudioScriptObjectPool
+ static CAudioScriptObjectPool *&ms_pAudioScriptObjectPool;
public:
static CCPtrNodePool *GetPtrNodePool(void) { return ms_pPtrNodePool; }
static CEntryInfoNodePool *GetEntryInfoNodePool(void) { return ms_pEntryInfoNodePool; }
@@ -38,6 +40,13 @@ public:
static CTreadablePool *GetTreadablePool(void) { return ms_pTreadablePool; }
static CObjectPool *GetObjectPool(void) { return ms_pObjectPool; }
static CDummyPool *GetDummyPool(void) { return ms_pDummyPool; }
+ static CAudioScriptObjectPool *GetAudioScriptObjectPool(void) { return ms_pAudioScriptObjectPool; }
static void Initialise(void);
+ static int32 GetPedRef(CPed *ped);
+ static CPed *GetPed(int32 handle);
+ static int32 GetVehicleRef(CVehicle *vehicle);
+ static CVehicle *GetVehicle(int32 handle);
+ static int32 GetObjectRef(CObject *object);
+ static CObject *GetObject(int32 handle);
};
diff --git a/src/core/Stats.cpp b/src/core/Stats.cpp
index 921586bb..01bbf82e 100644
--- a/src/core/Stats.cpp
+++ b/src/core/Stats.cpp
@@ -4,6 +4,7 @@
int32 &CStats::DaysPassed = *(int32*)0x8F2BB8;
int32 &CStats::HeadShots = *(int32*)0x8F647C;
bool& CStats::CommercialPassed = *(bool*)0x8F4334;
+bool& CStats::IndustrialPassed = *(bool*)0x8E2A68;
int32 &CStats::NumberKillFrenziesPassed = *(int32*)0x8E287C;
int32 &CStats::PeopleKilledByOthers = *(int32*)0x8E2C50;
diff --git a/src/core/Stats.h b/src/core/Stats.h
index 30058a59..c536465f 100644
--- a/src/core/Stats.h
+++ b/src/core/Stats.h
@@ -6,6 +6,7 @@ public:
static int32 &DaysPassed;
static int32 &HeadShots;
static bool& CommercialPassed;
+ static bool& IndustrialPassed;
static int32 &NumberKillFrenziesPassed;
static int32 &PeopleKilledByOthers;
diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp
index a23e35be..9d9241e4 100644
--- a/src/core/Streaming.cpp
+++ b/src/core/Streaming.cpp
@@ -1048,8 +1048,6 @@ CStreaming::RemoveReferencedTxds(int32 mem)
return false;
}
-// TODO: RemoveCurrentZonesModels
-
void
CStreaming::RemoveUnusedModelsInLoadedList(void)
{
diff --git a/src/core/SurfaceTable.h b/src/core/SurfaceTable.h
index e1882e69..27f4ecca 100644
--- a/src/core/SurfaceTable.h
+++ b/src/core/SurfaceTable.h
@@ -77,6 +77,8 @@ enum eSurfaceType
SURFACE_LOOSE30,
SURFACE_BOLLARD,
SURFACE_GATE,
+
+ // These are illegal
SURFACE_SAND33,
SURFACE_ROAD34,
};
diff --git a/src/core/Wanted.cpp b/src/core/Wanted.cpp
index 4608bfef..7b865311 100644
--- a/src/core/Wanted.cpp
+++ b/src/core/Wanted.cpp
@@ -1,65 +1,102 @@
#include "common.h"
#include "patcher.h"
+#include "Pools.h"
+#include "ModelIndices.h"
+#include "Timer.h"
+#include "World.h"
+#include "ZoneCull.h"
+#include "Darkel.h"
+#include "DMAudio.h"
#include "Wanted.h"
-int32 &CWanted::MaximumWantedLevel = *(int32*)0x5F7714;
+int32 &CWanted::MaximumWantedLevel = *(int32*)0x5F7714; // 6
+int32 &CWanted::nMaximumWantedLevel = *(int32*)0x5F7718; // 6400
-bool CWanted::AreSwatRequired()
+void
+CWanted::Initialise()
+{
+ int i;
+
+ m_nChaos = 0;
+ m_nLastUpdateTime = 0;
+ m_nLastWantedLevelChange = 0;
+ m_CurrentCops = 0;
+ m_MaxCops = 0;
+ m_MaximumLawEnforcerVehicles = 0;
+ m_RoadblockDensity = 0;
+ m_bIgnoredByCops = false;
+ m_bIgnoredByEveryone = false;
+ m_bSwatRequired = false;
+ m_bFbiRequired = false;
+ m_bArmyRequired = false;
+ m_fCrimeSensitivity = 1.0f;
+ m_nWantedLevel = 0;
+ m_CopsBeatingSuspect = 0;
+ for(i = 0; i < 10; i++)
+ m_pCops[i] = nil;
+ ClearQdCrimes();
+}
+
+bool
+CWanted::AreSwatRequired()
{
return m_nWantedLevel >= 4;
}
-bool CWanted::AreFbiRequired()
+bool
+CWanted::AreFbiRequired()
{
return m_nWantedLevel >= 5;
}
-bool CWanted::AreArmyRequired()
+bool
+CWanted::AreArmyRequired()
{
return m_nWantedLevel >= 6;
}
-int CWanted::NumOfHelisRequired()
+int32
+CWanted::NumOfHelisRequired()
{
- if (m_IsIgnoredByCops)
+ if (m_bIgnoredByCops)
return 0;
- // Return value is number of helicopters, no need to name them.
switch (m_nWantedLevel) {
- case WANTEDLEVEL_3:
- case WANTEDLEVEL_4:
+ case 3:
+ case 4:
return 1;
- case WANTEDLEVEL_5:
- case WANTEDLEVEL_6:
+ case 5:
+ case 6:
return 2;
default:
return 0;
}
}
-void CWanted::SetWantedLevel(int32 level)
+void
+CWanted::SetWantedLevel(int32 level)
{
ClearQdCrimes();
switch (level) {
- case NOTWANTED:
+ case 0:
m_nChaos = 0;
break;
- case WANTEDLEVEL_1:
+ case 1:
m_nChaos = 60;
break;
- case WANTEDLEVEL_2:
+ case 2:
m_nChaos = 220;
break;
- case WANTEDLEVEL_3:
+ case 3:
m_nChaos = 420;
break;
- case WANTEDLEVEL_4:
+ case 4:
m_nChaos = 820;
break;
- case WANTEDLEVEL_5:
+ case 5:
m_nChaos = 1620;
break;
- case WANTEDLEVEL_6:
+ case 6:
m_nChaos = 3220;
break;
default:
@@ -70,61 +107,212 @@ void CWanted::SetWantedLevel(int32 level)
UpdateWantedLevel();
}
-void CWanted::SetWantedLevelNoDrop(int32 level)
+void
+CWanted::SetWantedLevelNoDrop(int32 level)
{
if (level > m_nWantedLevel)
SetWantedLevel(level);
}
-void CWanted::ClearQdCrimes()
+void
+CWanted::SetMaximumWantedLevel(int32 level)
{
- for (int i = 0; i < 16; i++) {
- m_sCrimes[i].m_eCrimeType = CRIME_NONE;
+ switch(level){
+ case 0:
+ nMaximumWantedLevel = 0;
+ MaximumWantedLevel = 0;
+ break;
+ case 1:
+ nMaximumWantedLevel = 120;
+ MaximumWantedLevel = 1;
+ break;
+ case 2:
+ nMaximumWantedLevel = 300;
+ MaximumWantedLevel = 2;
+ break;
+ case 3:
+ nMaximumWantedLevel = 600;
+ MaximumWantedLevel = 3;
+ break;
+ case 4:
+ nMaximumWantedLevel = 1200;
+ MaximumWantedLevel = 4;
+ break;
+ case 5:
+ nMaximumWantedLevel = 2400;
+ MaximumWantedLevel = 5;
+ break;
+ case 6:
+ nMaximumWantedLevel = 4800;
+ MaximumWantedLevel = 6;
+ break;
}
}
-void CWanted::UpdateWantedLevel()
+void
+CWanted::RegisterCrime(eCrimeType type, const CVector &coors, uint32 id, bool policeDoesntCare)
+{
+ AddCrimeToQ(type, id, coors, false, policeDoesntCare);
+}
+
+void
+CWanted::RegisterCrime_Immediately(eCrimeType type, const CVector &coors, uint32 id, bool policeDoesntCare)
+{
+ if(!AddCrimeToQ(type, id, coors, false, policeDoesntCare))
+ ReportCrimeNow(type, coors, policeDoesntCare);
+}
+
+void
+CWanted::ClearQdCrimes()
+{
+ for (int i = 0; i < 16; i++)
+ m_aCrimes[i].m_nType = CRIME_NONE;
+}
+
+// returns whether the crime had been reported already
+bool
+CWanted::AddCrimeToQ(eCrimeType type, int32 id, const CVector &coors, bool reported, bool policeDoesntCare)
+{
+ int i;
+
+ for(i = 0; i < 16; i++)
+ if(m_aCrimes[i].m_nType == type && m_aCrimes[i].m_nId == id){
+ if(m_aCrimes[i].m_bReported)
+ return true;
+ if(reported)
+ m_aCrimes[i].m_bReported = reported;
+ return false;
+ }
+
+ for(i = 0; i < 16; i++)
+ if(m_aCrimes[i].m_nType == CRIME_NONE)
+ break;
+ if(i < 16){
+ m_aCrimes[i].m_nType = type;
+ m_aCrimes[i].m_nId = id;
+ m_aCrimes[i].m_vecPosn = coors;
+ m_aCrimes[i].m_nTime = CTimer::GetTimeInMilliseconds();
+ m_aCrimes[i].m_bReported = reported;
+ m_aCrimes[i].m_bPoliceDoesntCare = policeDoesntCare;
+ }
+ return false;
+}
+
+void
+CWanted::ReportCrimeNow(eCrimeType type, const CVector &coors, bool policeDoesntCare)
+{
+ float sensitivity, chaos;
+ int wantedLevelDrop;
+
+ if(CDarkel::FrenzyOnGoing())
+ sensitivity = m_fCrimeSensitivity*0.3f;
+ else
+ sensitivity = m_fCrimeSensitivity;
+
+ wantedLevelDrop = min(CCullZones::GetWantedLevelDrop(), 100);
+
+ chaos = (1.0f - wantedLevelDrop/100.0f) * sensitivity;
+ if (policeDoesntCare)
+ chaos *= 0.333f;
+ switch(type){
+ case CRIME_POSSESSION_GUN:
+ break;
+ case CRIME_HIT_PED:
+ m_nChaos += 5.0f*chaos;
+ break;
+ case CRIME_HIT_COP:
+ m_nChaos += 45.0f*chaos;
+ break;
+ case CRIME_SHOOT_PED:
+ m_nChaos += 30.0f*chaos;
+ break;
+ case CRIME_SHOOT_COP:
+ m_nChaos += 80.0f*chaos;
+ break;
+ case CRIME_STEAL_CAR:
+ m_nChaos += 15.0f*chaos;
+ break;
+ case CRIME_RUN_REDLIGHT:
+ m_nChaos += 10.0f*chaos;
+ break;
+ case CRIME_RECKLESS_DRIVING:
+ m_nChaos += 5.0f*chaos;
+ break;
+ case CRIME_SPEEDING:
+ m_nChaos += 5.0f*chaos;
+ break;
+ case CRIME_RUNOVER_PED:
+ m_nChaos += 18.0f*chaos;
+ break;
+ case CRIME_RUNOVER_COP:
+ m_nChaos += 80.0f*chaos;
+ break;
+ case CRIME_SHOOT_HELI:
+ m_nChaos += 400.0f*chaos;
+ break;
+ case CRIME_PED_BURNED:
+ m_nChaos += 20.0f*chaos;
+ break;
+ case CRIME_COP_BURNED:
+ m_nChaos += 80.0f*chaos;
+ break;
+ case CRIME_VEHICLE_BURNED:
+ m_nChaos += 20.0f*chaos;
+ break;
+ case CRIME_DESTROYED_CESSNA:
+ m_nChaos += 500.0f*chaos;
+ break;
+ default:
+ // Error("Undefined crime type, RegisterCrime, Crime.cpp"); // different file for some reason
+ Error("Undefined crime type, RegisterCrime, Wanted.cpp");
+ }
+ DMAudio.ReportCrime(type, coors);
+ UpdateWantedLevel();
+}
+
+void
+CWanted::UpdateWantedLevel()
{
int32 CurrWantedLevel = m_nWantedLevel;
if (m_nChaos >= 0 && m_nChaos < 40) {
- m_nWantedLevel = NOTWANTED;
+ m_nWantedLevel = 0;
m_MaximumLawEnforcerVehicles = 0;
m_MaxCops = 0;
m_RoadblockDensity = 0;
}
else if (m_nChaos >= 40 && m_nChaos < 200) {
- m_nWantedLevel = WANTEDLEVEL_1;
+ m_nWantedLevel = 1;
m_MaximumLawEnforcerVehicles = 1;
m_MaxCops = 1;
m_RoadblockDensity = 0;
}
else if (m_nChaos >= 200 && m_nChaos < 400) {
- m_nWantedLevel = WANTEDLEVEL_2;
+ m_nWantedLevel = 2;
m_MaximumLawEnforcerVehicles = 2;
m_MaxCops = 3;
m_RoadblockDensity = 0;
}
else if (m_nChaos >= 400 && m_nChaos < 800) {
- m_nWantedLevel = WANTEDLEVEL_3;
+ m_nWantedLevel = 3;
m_MaximumLawEnforcerVehicles = 2;
m_MaxCops = 4;
m_RoadblockDensity = 4;
}
else if (m_nChaos >= 800 && m_nChaos < 1600) {
- m_nWantedLevel = WANTEDLEVEL_4;
+ m_nWantedLevel = 4;
m_MaximumLawEnforcerVehicles = 2;
m_MaxCops = 6;
m_RoadblockDensity = 8;
}
else if (m_nChaos >= 1600 && m_nChaos < 3200) {
- m_nWantedLevel = WANTEDLEVEL_5;
+ m_nWantedLevel = 5;
m_MaximumLawEnforcerVehicles = 3;
m_MaxCops = 8;
m_RoadblockDensity = 10;
}
else if (m_nChaos >= 3200) {
- m_nWantedLevel = WANTEDLEVEL_6;
+ m_nWantedLevel = 6;
m_MaximumLawEnforcerVehicles = 3;
m_MaxCops = 10;
m_RoadblockDensity = 12;
@@ -132,4 +320,58 @@ void CWanted::UpdateWantedLevel()
if (CurrWantedLevel != m_nWantedLevel)
m_nLastWantedLevelChange = CTimer::GetTimeInMilliseconds();
-} \ No newline at end of file
+}
+
+int32
+CWanted::WorkOutPolicePresence(CVector posn, float radius)
+{
+ int i;
+ CPed *ped;
+ CVehicle *vehicle;
+ int numPolice = 0;
+
+ i = CPools::GetPedPool()->GetSize();
+ while(--i >= 0){
+ ped = CPools::GetPedPool()->GetSlot(i);
+ if(ped &&
+ IsPolicePedModel(ped->GetModelIndex()) &&
+ (posn - ped->GetPosition()).Magnitude() < radius)
+ numPolice++;
+ }
+
+ i = CPools::GetVehiclePool()->GetSize();
+ while(--i >= 0){
+ vehicle = CPools::GetVehiclePool()->GetSlot(i);
+ if(vehicle &&
+ vehicle->bIsLawEnforcer &&
+ IsPoliceVehicleModel(vehicle->GetModelIndex()) &&
+ vehicle != FindPlayerVehicle() &&
+ vehicle->m_status != STATUS_ABANDONED && vehicle->m_status != STATUS_WRECKED &&
+ (posn - vehicle->GetPosition()).Magnitude() < radius)
+ numPolice++;
+ }
+
+ return numPolice;
+}
+
+STARTPATCHES
+ InjectHook(0x4AD6E0, &CWanted::Initialise, 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);
+ InjectHook(0x4ADA50, &CWanted::SetWantedLevel, PATCH_JUMP);
+ InjectHook(0x4ADAC0, &CWanted::SetWantedLevelNoDrop, PATCH_JUMP);
+ InjectHook(0x4ADAE0, &CWanted::SetMaximumWantedLevel, PATCH_JUMP);
+ InjectHook(0x4ADBA0, &CWanted::AreSwatRequired, PATCH_JUMP);
+ 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(0x4ADD00, &CWanted::WorkOutPolicePresence, PATCH_JUMP);
+ InjectHook(0x4ADF20, &CWanted::ClearQdCrimes, PATCH_JUMP);
+ InjectHook(0x4ADFD0, &CWanted::AddCrimeToQ, 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 d3f6638b..1a72f839 100644
--- a/src/core/Wanted.h
+++ b/src/core/Wanted.h
@@ -1,16 +1,38 @@
#pragma once
-#include "Entity.h"
-#include "math/Vector.h"
-#include "CopPed.h"
-
-enum eWantedLevel {
- NOTWANTED,
- WANTEDLEVEL_1,
- WANTEDLEVEL_2,
- WANTEDLEVEL_3,
- WANTEDLEVEL_4,
- WANTEDLEVEL_5,
- WANTEDLEVEL_6,
+
+class CEntity;
+class CCopPed;
+
+enum eCrimeType
+{
+ CRIME_NONE,
+ CRIME_POSSESSION_GUN,
+ CRIME_HIT_PED,
+ CRIME_HIT_COP,
+ CRIME_SHOOT_PED,
+ CRIME_SHOOT_COP,
+ CRIME_STEAL_CAR,
+ CRIME_RUN_REDLIGHT,
+ CRIME_RECKLESS_DRIVING,
+ CRIME_SPEEDING,
+ CRIME_RUNOVER_PED,
+ CRIME_RUNOVER_COP,
+ CRIME_SHOOT_HELI,
+ CRIME_PED_BURNED,
+ CRIME_COP_BURNED,
+ CRIME_VEHICLE_BURNED,
+ CRIME_DESTROYED_CESSNA,
+};
+
+class CCrimeBeingQd
+{
+public:
+ eCrimeType m_nType;
+ uint32 m_nId;
+ int32 m_nTime;
+ CVector m_vecPosn;
+ bool m_bReported;
+ bool m_bPoliceDoesntCare;
};
class CWanted
@@ -23,28 +45,37 @@ public:
uint8 m_CurrentCops;
uint8 m_MaxCops;
uint8 m_MaximumLawEnforcerVehicles;
- int8 field_19;
+ uint8 m_CopsBeatingSuspect;
int16 m_RoadblockDensity;
- uint8 m_IsIgnoredByCops : 1;
- uint8 m_IsIgnoredByEveryOne : 1;
- uint8 m_IsSwatRequired : 1;
- uint8 m_IsFbiRequired : 1;
- uint8 m_IdArmyRequired : 1;
- int8 field_23;
+ uint8 m_bIgnoredByCops : 1;
+ uint8 m_bIgnoredByEveryone : 1;
+ uint8 m_bSwatRequired : 1;
+ uint8 m_bFbiRequired : 1;
+ uint8 m_bArmyRequired : 1;
int32 m_nWantedLevel;
- CCrime m_sCrimes[16];
+ CCrimeBeingQd m_aCrimes[16];
CCopPed *m_pCops[10];
+
static int32 &MaximumWantedLevel;
+ static int32 &nMaximumWantedLevel;
public:
+ void Initialise();
bool AreSwatRequired();
bool AreFbiRequired();
bool AreArmyRequired();
- int NumOfHelisRequired();
+ int32 NumOfHelisRequired();
void SetWantedLevel(int32);
void SetWantedLevelNoDrop(int32 level);
+ void RegisterCrime(eCrimeType type, const CVector &coors, uint32 id, bool policeDoesntCare);
+ void RegisterCrime_Immediately(eCrimeType type, const CVector &coors, uint32 id, bool policeDoesntCare);
void ClearQdCrimes();
+ bool AddCrimeToQ(eCrimeType type, int32 id, const CVector &pos, bool reported, bool policeDoesntCare);
+ void ReportCrimeNow(eCrimeType type, const CVector &coors, bool policeDoesntCare);
void UpdateWantedLevel();
+
+ static int32 WorkOutPolicePresence(CVector posn, float radius);
+ static void SetMaximumWantedLevel(int32 level);
};
static_assert(sizeof(CWanted) == 0x204, "CWanted: error");
diff --git a/src/core/World.cpp b/src/core/World.cpp
index a31f87a7..829a64d4 100644
--- a/src/core/World.cpp
+++ b/src/core/World.cpp
@@ -11,11 +11,13 @@
#include "Garages.h"
#include "TempColModels.h"
#include "World.h"
+#include "ModelIndices.h"
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 = (CPlayerInfo *)0x9412F0;
@@ -26,6 +28,8 @@ bool &CWorld::bSecondShift = *(bool*)0x95CD54;
bool &CWorld::bForceProcessControl = *(bool*)0x95CD6C;
bool &CWorld::bProcessCutsceneOnly = *(bool*)0x95CD8B;
+WRAPPER void CWorld::RemoveReferencesToDeletedObject(CEntity*) { EAXJMP(0x4B3BF0); }
+
void
CWorld::Add(CEntity *ent)
{
@@ -603,12 +607,12 @@ CWorld::FindObjectsInRange(CVector &centre, float distance, bool ignoreZ, short
minY = 0;
int maxX = GetSectorIndexX(centre.x + distance);
- if (maxX >= 100)
- maxX = 100;
+ if (maxX >= NUMSECTORS_X)
+ maxX = NUMSECTORS_X;
int maxY = GetSectorIndexY(centre.y + distance);
- if (maxY >= 100)
- maxY = 100;
+ if (maxY >= NUMSECTORS_Y)
+ maxY = NUMSECTORS_Y;
AdvanceCurrentScanCode();
@@ -617,27 +621,156 @@ CWorld::FindObjectsInRange(CVector &centre, float distance, bool ignoreZ, short
for(int curX = minX; curX <= maxX; curX++) {
CSector *sector = GetSector(curX, curY);
if (checkBuildings) {
- CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, distance, ignoreZ, nextObject, lastObject, objects);
- CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects);
+ 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);
+ }
+ 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);
+ }
+ 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);
+ }
+ 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);
+ }
+ 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);
+ }
+ }
+ }
+}
+
+CEntity*
+CWorld::TestSphereAgainstWorld(CVector centre, float distance, CEntity* entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects)
+{
+ CEntity* foundE = nil;
+
+ int minX = GetSectorIndexX(centre.x - distance);
+ if (minX <= 0)
+ minX = 0;
+
+ int minY = GetSectorIndexY(centre.y - distance);
+ if (minY <= 0)
+ minY = 0;
+
+ int maxX = GetSectorIndexX(centre.x + distance);
+ if (maxX >= NUMSECTORS_X)
+ maxX = NUMSECTORS_X;
+
+ int maxY = GetSectorIndexY(centre.y + distance);
+ if (maxY >= NUMSECTORS_Y)
+ maxY = NUMSECTORS_Y;
+
+ AdvanceCurrentScanCode();
+
+ for (int curY = minY; curY <= maxY; curY++) {
+ 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);
+ if (foundE)
+ return foundE;
+
+ foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, distance, entityToIgnore, false);
+ if (foundE)
+ return foundE;
}
if (checkVehicles) {
- CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, distance, ignoreZ, nextObject, lastObject, objects);
- CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects);
+ foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, distance, entityToIgnore, false);
+ if (foundE)
+ return foundE;
+
+ foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, distance, entityToIgnore, false);
+ if (foundE)
+ return foundE;
}
if (checkPeds) {
- CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, distance, ignoreZ, nextObject, lastObject, objects);
- CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects);
+ foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, distance, entityToIgnore, false);
+ if (foundE)
+ return foundE;
+
+ foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, distance, entityToIgnore, false);
+ if (foundE)
+ return foundE;
}
if (checkObjects) {
- CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, distance, ignoreZ, nextObject, lastObject, objects);
- CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects);
+ foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, distance, entityToIgnore, ignoreSomeObjects);
+ if (foundE)
+ return foundE;
+
+ foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, distance, entityToIgnore, ignoreSomeObjects);
+ if (foundE)
+ return foundE;
}
if (checkDummies) {
- CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, distance, ignoreZ, nextObject, lastObject, objects);
- CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects);
+ foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, distance, entityToIgnore, false);
+ if (foundE)
+ return foundE;
+
+ foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, distance, entityToIgnore, false);
+ if (foundE)
+ return foundE;
}
}
}
+ return foundE;
+}
+
+CEntity*
+CWorld::TestSphereAgainstSectorList(CPtrList &list, CVector spherePos, float radius, CEntity *entityToIgnore, bool ignoreSomeObjects)
+{
+ static CColModel sphereCol;
+
+ sphereCol.boundingSphere.center.x = 0.0f;
+ sphereCol.boundingSphere.center.y = 0.0f;
+ sphereCol.boundingSphere.center.z = 0.0f;
+ sphereCol.boundingSphere.radius = radius;
+ sphereCol.boundingBox.min.x = -radius;
+ sphereCol.boundingBox.min.y = -radius;
+ sphereCol.boundingBox.min.z = -radius;
+ sphereCol.boundingBox.max.x = radius;
+ sphereCol.boundingBox.max.y = radius;
+ sphereCol.boundingBox.max.z = radius;
+ sphereCol.numSpheres = 1;
+ sphereCol.spheres = &sphereCol.boundingSphere;
+ sphereCol.numLines = 0;
+ sphereCol.numBoxes = 0;
+ sphereCol.numTriangles = 0;
+ sphereCol.ownsCollisionVolumes = false;
+
+ CMatrix sphereMat;
+ sphereMat.SetTranslate(spherePos);
+
+ for(CPtrNode *node=list.first; node; node = node->next) {
+ CEntity *e = (CEntity*)node->item;
+
+ if (e->m_scanCode != GetCurrentScanCode()) {
+ e->m_scanCode = GetCurrentScanCode();
+
+ if (e != entityToIgnore && e->bUsesCollision && !(ignoreSomeObjects && CameraToIgnoreThisObject(e))) {
+ CVector diff = spherePos - e->GetPosition();
+ float distance = diff.Magnitude();
+
+ 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);
+
+ if (collidedSpheres != 0 ||
+ (e->IsVehicle() && ((CVehicle*)e)->m_vehType == VEHICLE_TYPE_CAR &&
+ e->m_modelIndex != MI_DODO && radius + eCol->boundingBox.max.x > distance)) {
+ return e;
+ }
+ }
+ }
+ }
+ }
+
+ return nil;
}
float
@@ -790,6 +923,8 @@ STARTPATCHES
InjectHook(0x4B2200, CWorld::FindObjectsInRange, PATCH_JUMP);
InjectHook(0x4B2540, CWorld::FindObjectsInRangeSectorList, PATCH_JUMP);
+ InjectHook(0x4B4AC0, CWorld::TestSphereAgainstSectorList, PATCH_JUMP);
+ InjectHook(0x4B4710, CWorld::TestSphereAgainstWorld, PATCH_JUMP);
InjectHook(0x4B3A80, CWorld::FindGroundZForCoord, PATCH_JUMP);
InjectHook(0x4B3AE0, CWorld::FindGroundZFor3DCoord, PATCH_JUMP);
InjectHook(0x4B3B50, CWorld::FindRoofZFor3DCoord, PATCH_JUMP);
diff --git a/src/core/World.h b/src/core/World.h
index d6063d70..fd9d6fc3 100644
--- a/src/core/World.h
+++ b/src/core/World.h
@@ -56,6 +56,7 @@ class CWorld
static CPtrList &ms_listMovingEntityPtrs;
static CSector (*ms_aSectors)[NUMSECTORS_X]; // [NUMSECTORS_Y][NUMSECTORS_X];
static uint16 &ms_nCurrentScanCode;
+ static CColPoint &ms_testSpherePoint;
public:
static uint8 &PlayerInFocus;
@@ -94,11 +95,14 @@ 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, float, CEntity*, bool, bool, bool, bool, bool, bool);
+ 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);
static float FindGroundZForCoord(float x, float y);
static float FindGroundZFor3DCoord(float x, float y, float z, bool *found);
static float FindRoofZFor3DCoord(float x, float y, float z, bool *found);
+ static void RemoveReferencesToDeletedObject(CEntity*);
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); }
diff --git a/src/core/common.h b/src/core/common.h
index 71c27492..9a5683c6 100644
--- a/src/core/common.h
+++ b/src/core/common.h
@@ -97,11 +97,11 @@ extern void **rwengine;
#define SCREEN_SCALE_AR(a) (a)
#endif
-#include "math/maths.h"
-#include "math/Vector.h"
-#include "math/Vector2D.h"
-#include "math/Matrix.h"
-#include "math/Rect.h"
+#include "maths.h"
+#include "Vector.h"
+#include "Vector2D.h"
+#include "Matrix.h"
+#include "Rect.h"
class CRGBA
{
@@ -139,7 +139,8 @@ inline float sq(float x) { return x*x; }
#define SQR(x) ((x) * (x))
#define PI M_PI
-#define TWOPI PI*2
+#define TWOPI (PI*2)
+#define HALFPI (PI/2)
#define DEGTORAD(x) ((x) * PI / 180.0f)
#define RADTODEG(x) ((x) * 180.0f / PI)
@@ -178,6 +179,7 @@ void re3_assert(const char *expr, const char *filename, unsigned int lineno, con
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
+#define ABS(a) (((a) < 0) ? (-a) : (a))
#define STRINGIFY(x) #x
@@ -294,4 +296,4 @@ _TWEEKCLASS(CTweakInt32, int32);
_TWEEKCLASS(CTweakUInt32, uint32);
_TWEEKCLASS(CTweakFloat, float);
-#undef _TWEEKCLASS \ No newline at end of file
+#undef _TWEEKCLASS
diff --git a/src/core/config.h b/src/core/config.h
index 2dbfc95f..892a06b6 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -63,6 +63,7 @@ enum Config {
NUMONSCREENTIMERENTRIES = 1,
NUMRADARBLIPS = 32,
NUMPICKUPS = 336,
+ NUMEVENTS = 64,
};
// We'll use this once we're ready to become independent of the game
diff --git a/src/core/main.cpp b/src/core/main.cpp
index e301b470..04fee197 100644
--- a/src/core/main.cpp
+++ b/src/core/main.cpp
@@ -295,6 +295,8 @@ void
RenderDebugShit(void)
{
// CTheScripts::RenderTheScriptDebugLines()
+ if(gbShowCollisionLines)
+ CRenderer::RenderCollisionLines();
}
void
diff --git a/src/core/main.h b/src/core/main.h
index 9f27e05e..9b3c27f5 100644
--- a/src/core/main.h
+++ b/src/core/main.h
@@ -27,4 +27,5 @@ void LoadingIslandScreen(const char *levelName);
CSprite2d *LoadSplash(const char *name);
char *GetLevelSplashScreen(int level);
char *GetRandomSplashScreen(void);
-void ValidateVersion(); \ No newline at end of file
+void LittleTest(void);
+void ValidateVersion();
diff --git a/src/core/re3.cpp b/src/core/re3.cpp
index e3aece97..a0032bc6 100644
--- a/src/core/re3.cpp
+++ b/src/core/re3.cpp
@@ -10,6 +10,7 @@
#include "Clock.h"
#include "World.h"
#include "Vehicle.h"
+#include "ModelIndices.h"
#include "Streaming.h"
#include "PathFind.h"
#include "Boat.h"
@@ -58,8 +59,6 @@ mysrand(unsigned int seed)
myrand_seed = seed;
}
-int gDbgSurf;
-
void (*DebugMenuProcess)(void);
void (*DebugMenuRender)(void);
static void stub(void) { }
@@ -102,60 +101,43 @@ void ChittyChittyBangBangCheat();
void StrongGripCheat();
void NastyLimbsCheat();
-// needs too much stuff for now
-#if 0
+DebugMenuEntry *carCol1;
+DebugMenuEntry *carCol2;
+
void
-spawnCar(int id)
+SpawnCar(int id)
{
CVector playerpos;
CStreaming::RequestModel(id, 0);
CStreaming::LoadAllRequestedModels(false);
if(CStreaming::HasModelLoaded(id)){
- FindPlayerCoors(playerpos);
+ playerpos = FindPlayerCoors();
int node = ThePaths.FindNodeClosestToCoors(playerpos, 0, 100.0f, false, false);
if(node < 0)
return;
CVehicle *v;
- if(CModelInfo::IsBoatModel(id)){
-// CBoat* boat = (CBoat*)CVehicle__new(0x484);
-// boat = boat->ctor(id, 1);
-// v = (CVehicle*)(boat);
- }else{
-// CAutomobile *au = (CAutomobile*)CVehicle__new(0x5A8);
-// au = au->ctor(id, 1);
-// v = (CVehicle*)au;
- }
-/*
- // unlock doors
- FIELD(int, v, 0x224) = 1;
- // set player owned
- FIELD(uint8, v, 0x1F7) |= 4;
-
- DebugMenuEntrySetAddress(carCol1, &FIELD(uchar, v, 0x19C));
- DebugMenuEntrySetAddress(carCol2, &FIELD(uchar, v, 0x19D));
- //if(id == MODELID_ESPERANTO)
- // FIELD(uchar, v, 0x19C) = 54;
-
- v->matrix.matrix.pos.x = ThePaths.nodes[node].x;
- v->matrix.matrix.pos.y = ThePaths.nodes[node].y;
- v->matrix.matrix.pos.z = ThePaths.nodes[node].z + 4.0f;
- float x = v->matrix.matrix.pos.x;
- float y = v->matrix.matrix.pos.y;
- float z = v->matrix.matrix.pos.z;
- v->matrix.SetRotate(0.0f, 0.0f, 3.49f);
- v->matrix.matrix.pos.x += x;
- v->matrix.matrix.pos.y += y;
- v->matrix.matrix.pos.z += z;
- v->bfTypeStatus = v->bfTypeStatus & 7 | 0x20;
- FIELD(int, v, 0x224) = 1;
-*/
+ if(CModelInfo::IsBoatModel(id))
+ return;
+ else
+ v = new CAutomobile(id, RANDOM_VEHICLE);
+
+ v->bHasBeenOwnedByPlayer = true;
+ if(carCol1)
+ DebugMenuEntrySetAddress(carCol1, &v->m_currentColour1);
+ if(carCol2)
+ DebugMenuEntrySetAddress(carCol2, &v->m_currentColour2);
+
+ v->GetPosition() = ThePaths.m_pathNodes[node].pos;
+ v->GetPosition().z += 4.0f;
+ v->SetOrientation(0.0f, 0.0f, 3.49f);
+ v->m_status = STATUS_ABANDONED;
+ v->m_nDoorLock = CARLOCK_UNLOCKED;
CWorld::Add(v);
}
}
-#endif
-void
+static void
FixCar(void)
{
CVehicle *veh = FindPlayerVehicle();
@@ -168,6 +150,34 @@ FixCar(void)
((CAutomobile*)veh)->Fix();
}
+static void
+ToggleComedy(void)
+{
+ CVehicle *veh = FindPlayerVehicle();
+ if(veh == nil)
+ return;
+ veh->bComedyControls = !veh->bComedyControls;
+}
+
+static void
+PlaceOnRoad(void)
+{
+ CVehicle *veh = FindPlayerVehicle();
+ if(veh == nil)
+ return;
+
+ if(veh->IsCar())
+ ((CAutomobile*)veh)->PlaceOnRoadProperly();
+}
+
+static const char *carnames[] = {
+ "landstal", "idaho", "stinger", "linerun", "peren", "sentinel", "patriot", "firetruk", "trash", "stretch", "manana", "infernus", "blista", "pony",
+ "mule", "cheetah", "ambulan", "fbicar", "moonbeam", "esperant", "taxi", "kuruma", "bobcat", "mrwhoop", "bfinject", "corpse", "police", "enforcer",
+ "securica", "banshee", "predator", "bus", "rhino", "barracks", "train", "chopper", "dodo", "coach", "cabbie", "stallion", "rumpo", "rcbandit",
+ "bellyup", "mrwongs", "mafia", "yardie", "yakuza", "diablos", "columb", "hoods", "airtrain", "deaddodo", "speeder", "reefer", "panlant", "flatbed",
+ "yankee", "escape", "borgnine", "toyz", "ghost",
+};
+
static std::list<CTweakVar *> TweakVarsList;
static bool bAddTweakVarsNow = false;
static const char *pTweakVarsDefaultPath = NULL;
@@ -259,15 +269,48 @@ DebugMenuPopulate(void)
DebugMenuAddCmd("Cheats", "Strong grip", StrongGripCheat);
DebugMenuAddCmd("Cheats", "Nasty limbs", NastyLimbsCheat);
+ static int spawnCarId = MI_LANDSTAL;
+ e = DebugMenuAddVar("Spawn", "Spawn Car ID", &spawnCarId, nil, 1, MI_LANDSTAL, MI_GHOST, carnames);
+ DebugMenuEntrySetWrap(e, true);
+ DebugMenuAddCmd("Spawn", "Spawn Car", [](){
+ if(spawnCarId == MI_TRAIN ||
+ spawnCarId == MI_CHOPPER ||
+ spawnCarId == MI_AIRTRAIN ||
+ spawnCarId == MI_DEADDODO ||
+ spawnCarId == MI_ESCAPE)
+ return;
+ SpawnCar(spawnCarId);
+ });
+ static uint8 dummy;
+ carCol1 = DebugMenuAddVar("Spawn", "First colour", &dummy, nil, 1, 0, 255, nil);
+ carCol2 = DebugMenuAddVar("Spawn", "Second colour", &dummy, nil, 1, 0, 255, nil);
+ DebugMenuAddCmd("Spawn", "Spawn Stinger", [](){ SpawnCar(MI_STINGER); });
+ DebugMenuAddCmd("Spawn", "Spawn Infernus", [](){ SpawnCar(MI_INFERNUS); });
+ DebugMenuAddCmd("Spawn", "Spawn Cheetah", [](){ SpawnCar(MI_CHEETAH); });
+ DebugMenuAddCmd("Spawn", "Spawn Esperanto", [](){ SpawnCar(MI_ESPERANT); });
+ DebugMenuAddCmd("Spawn", "Spawn Stallion", [](){ SpawnCar(MI_STALLION); });
+ DebugMenuAddCmd("Spawn", "Spawn Kuruma", [](){ SpawnCar(MI_KURUMA); });
+ DebugMenuAddCmd("Spawn", "Spawn Taxi", [](){ SpawnCar(MI_TAXI); });
+ DebugMenuAddCmd("Spawn", "Spawn Police", [](){ SpawnCar(MI_POLICE); });
+ DebugMenuAddCmd("Spawn", "Spawn Enforcer", [](){ SpawnCar(MI_ENFORCER); });
+ DebugMenuAddCmd("Spawn", "Spawn Banshee", [](){ SpawnCar(MI_BANSHEE); });
+ DebugMenuAddCmd("Spawn", "Spawn Yakuza", [](){ SpawnCar(MI_YAKUZA); });
+ DebugMenuAddCmd("Spawn", "Spawn Dodo", [](){ SpawnCar(MI_DODO); });
+
+
DebugMenuAddCmd("Debug", "Fix Car", FixCar);
+ DebugMenuAddCmd("Debug", "Toggle Comedy Controls", ToggleComedy);
+ DebugMenuAddCmd("Debug", "Place Car on Road", PlaceOnRoad);
+
DebugMenuAddVarBool8("Debug", "Show Ped Road Groups", (int8*)&gbShowPedRoadGroups, nil);
DebugMenuAddVarBool8("Debug", "Show Car Road Groups", (int8*)&gbShowCarRoadGroups, nil);
+ DebugMenuAddVarBool8("Debug", "Show Collision Lines", (int8*)&gbShowCollisionLines, nil);
DebugMenuAddVarBool8("Debug", "Show Collision Polys", (int8*)&gbShowCollisionPolys, nil);
DebugMenuAddVarBool8("Debug", "Don't render Buildings", (int8*)&gbDontRenderBuildings, nil);
DebugMenuAddVarBool8("Debug", "Don't render Big Buildings", (int8*)&gbDontRenderBigBuildings, nil);
DebugMenuAddVarBool8("Debug", "Don't render Peds", (int8*)&gbDontRenderPeds, nil);
+ DebugMenuAddVarBool8("Debug", "Don't render Vehicles", (int8*)&gbDontRenderVehicles, nil);
DebugMenuAddVarBool8("Debug", "Don't render Objects", (int8*)&gbDontRenderObjects, nil);
- DebugMenuAddVar("Debug", "Dbg Surface", &gDbgSurf, nil, 1, 0, 34, nil);
DebugMenuAddCmd("Debug", "Start Credits", CCredits::Start);
DebugMenuAddCmd("Debug", "Stop Credits", CCredits::Stop);
diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp
index 0749e8e7..b795931f 100644
--- a/src/entities/Entity.cpp
+++ b/src/entities/Entity.cpp
@@ -13,11 +13,11 @@
#include "Glass.h"
#include "Clock.h"
#include "Weather.h"
-#include "TimeCycle.h"
+#include "Timecycle.h"
#include "Bridge.h"
#include "TrafficLights.h"
#include "Coronas.h"
-#include "Pointlights.h"
+#include "PointLights.h"
#include "Shadows.h"
#include "Pickups.h"
#include "SpecialFX.h"
@@ -42,7 +42,7 @@ CEntity::CEntity(void)
bUseCollisionRecords = false;
bWasPostponed = false;
- m_flagB2 = false;
+ bExplosionProof = false;
bIsVisible = true;
bHasCollided = false;
bRenderScorched = false;
@@ -535,7 +535,7 @@ CEntity::ResolveReferences(void)
for(ref = m_pFirstReference; ref->next; ref = ref->next)
;
ref->next = CReferences::pEmptyList;
- CReferences::pEmptyList = ref;
+ CReferences::pEmptyList = m_pFirstReference;
m_pFirstReference = nil;
}
}
diff --git a/src/entities/Entity.h b/src/entities/Entity.h
index 12a631d2..cdc9a173 100644
--- a/src/entities/Entity.h
+++ b/src/entities/Entity.h
@@ -13,14 +13,11 @@ enum eEntityType
ENTITY_TYPE_PED,
ENTITY_TYPE_OBJECT,
ENTITY_TYPE_DUMMY,
- ENTITY_TYPE_6,
- ENTITY_TYPE_7,
};
enum eEntityStatus
{
- // from SA MTA! let's hope they didn't change from III
- STATUS_PLAYER = 0,
+ STATUS_PLAYER,
STATUS_PLAYER_PLAYBACKFROMBUFFER,
STATUS_SIMPLE,
STATUS_PHYSICS,
@@ -32,8 +29,6 @@ enum eEntityStatus
STATUS_PLANE,
STATUS_PLAYER_REMOTE,
STATUS_PLAYER_DISABLED,
- //STATUS_TRAILER,
- //STATUS_SIMPLE_TRAILER
};
class CEntity : public CPlaceable
@@ -55,7 +50,7 @@ public:
// flagsB
uint32 bWasPostponed : 1;
- uint32 m_flagB2 : 1; // explosion proof?
+ uint32 bExplosionProof : 1;
uint32 bIsVisible : 1;
uint32 bHasCollided : 1; //
uint32 bRenderScorched : 1;
@@ -78,7 +73,7 @@ public:
uint32 bRemoveFromWorld : 1;
uint32 bHasHitWall : 1;
uint32 bImBeingRendered : 1;
- uint32 m_flagD8 : 1;
+ uint32 m_flagD8 : 1; // used by cBuoyancy::ProcessBuoyancy
uint32 bIsSubway : 1; // set when subway, but maybe different meaning?
uint32 bDrawLast : 1;
uint32 m_flagD40 : 1;
@@ -122,6 +117,15 @@ public:
bool IsObject(void) { return m_type == ENTITY_TYPE_OBJECT; }
bool IsDummy(void) { return m_type == ENTITY_TYPE_DUMMY; }
+ RpAtomic *GetAtomic(void) {
+ assert(RwObjectGetType(m_rwObject) == rpATOMIC);
+ return (RpAtomic*)m_rwObject;
+ }
+ RpClump *GetClump(void) {
+ assert(RwObjectGetType(m_rwObject) == rpCLUMP);
+ return (RpClump*)m_rwObject;
+ }
+
void GetBoundCentre(CVector &out);
CVector GetBoundCentre(void) { CVector v; GetBoundCentre(v); return v; }
float GetBoundRadius(void) { return CModelInfo::GetModelInfo(m_modelIndex)->GetColModel()->boundingSphere.radius; }
diff --git a/src/math/Matrix.h b/src/math/Matrix.h
index 2c0108c1..05a6eb03 100644
--- a/src/math/Matrix.h
+++ b/src/math/Matrix.h
@@ -240,7 +240,6 @@ public:
m_matrix.at.y = 0.0f;
m_matrix.at.z = 1.0f;
m_matrix.pos.x = 0.0f;
- m_matrix.pos.x = 0.0f;
m_matrix.pos.y = 0.0f;
m_matrix.pos.z = 0.0f;
}
diff --git a/src/math/Vector.h b/src/math/Vector.h
index de8092eb..f794a57f 100644
--- a/src/math/Vector.h
+++ b/src/math/Vector.h
@@ -22,6 +22,7 @@ public:
return *((RwV3d*)this);
}
#endif
+ // (0,1,0) means no rotation. So get right vector and its atan
float Heading(void) const { return Atan2(-x, y); }
float Magnitude(void) const { return Sqrt(x*x + y*y + z*z); }
float MagnitudeSqr(void) const { return x*x + y*y + z*z; }
diff --git a/src/modelinfo/ModelIndices.h b/src/modelinfo/ModelIndices.h
index 0d9ffb53..a0d3f70c 100644
--- a/src/modelinfo/ModelIndices.h
+++ b/src/modelinfo/ModelIndices.h
@@ -315,6 +315,11 @@ enum
MI_TOYZ,
MI_GHOST,
+ // leftovers on PC
+ MI_MIAMI_RCBARON = 154,
+ MI_MIAMI_RCRAIDER = 155,
+ MI_MIAMI_SPARROW = 159,
+
MI_GRENADE = 170,
MI_AK47,
MI_BASEBALL_BAT,
@@ -465,3 +470,21 @@ IsPickupModel(int16 id)
id == MI_PICKUP_KILLFRENZY ||
id == MI_PICKUP_CAMERA;
}
+
+inline bool
+IsPolicePedModel(int16 id)
+{
+ return id == MI_COP ||
+ id == MI_SWAT ||
+ id == MI_FBI ||
+ id == MI_ARMY;
+}
+
+inline bool
+IsPoliceVehicleModel(int16 id)
+{
+ return id == MI_CHOPPER ||
+ id == MI_PREDATOR ||
+ id == MI_POLICE ||
+ id == MI_ENFORCER;
+}
diff --git a/src/modelinfo/ModelInfo.cpp b/src/modelinfo/ModelInfo.cpp
index 454a73f1..0c3ec76a 100644
--- a/src/modelinfo/ModelInfo.cpp
+++ b/src/modelinfo/ModelInfo.cpp
@@ -175,6 +175,13 @@ CModelInfo::IsBoatModel(int32 id)
((CVehicleModelInfo*)GetModelInfo(id))->m_vehicleType == VEHICLE_TYPE_BOAT;
}
+bool
+CModelInfo::IsBikeModel(int32 id)
+{
+ return GetModelInfo(id)->m_type == MITYPE_VEHICLE &&
+ ((CVehicleModelInfo*)GetModelInfo(id))->m_vehicleType == VEHICLE_TYPE_BIKE;
+}
+
void
CModelInfo::RemoveColModelsFromOtherLevels(eLevelName level)
{
diff --git a/src/modelinfo/ModelInfo.h b/src/modelinfo/ModelInfo.h
index d20367d1..ee82276d 100644
--- a/src/modelinfo/ModelInfo.h
+++ b/src/modelinfo/ModelInfo.h
@@ -36,5 +36,6 @@ public:
}
static bool IsBoatModel(int32 id);
+ static bool IsBikeModel(int32 id);
static void RemoveColModelsFromOtherLevels(eLevelName level);
};
diff --git a/src/modelinfo/PedModelInfo.cpp b/src/modelinfo/PedModelInfo.cpp
index 747cbc99..c5242ef6 100644
--- a/src/modelinfo/PedModelInfo.cpp
+++ b/src/modelinfo/PedModelInfo.cpp
@@ -1,5 +1,6 @@
#include "common.h"
#include "patcher.h"
+#include "Ped.h"
#include "NodeName.h"
#include "VisibilityPlugins.h"
#include "ModelInfo.h"
@@ -14,7 +15,7 @@ CPedModelInfo::DeleteRwObject(void)
}
RwObjectNameIdAssocation CPedModelInfo::m_pPedIds[12] = {
- { "Smid", PED_TORSO, 0, }, // that is strange...
+ { "Smid", PED_MID, 0, }, // that is strange...
{ "Shead", PED_HEAD, 0, },
{ "Supperarml", PED_UPPERARML, 0, },
{ "Supperarmr", PED_UPPERARMR, 0, },
@@ -109,17 +110,16 @@ struct ColNodeInfo
float radius;
};
-// TODO: find out piece types
#define NUMPEDINFONODES 8
ColNodeInfo m_pColNodeInfos[NUMPEDINFONODES] = {
- { nil, PED_HEAD, 6, 0.0f, 0.05f, 0.2f },
- { "Storso", 0, 0, 0.0f, 0.15f, 0.2f },
- { "Storso", 0, 0, 0.0f, -0.05f, 0.3f },
- { nil, PED_TORSO, 1, 0.0f, -0.07f, 0.3f },
- { nil, PED_UPPERARML, 2, 0.07f, -0.1f, 0.2f },
- { nil, PED_UPPERARMR, 3, -0.07f, -0.1f, 0.2f },
- { "Slowerlegl", 0, 4, 0.0f, 0.07f, 0.25f },
- { nil, PED_LOWERLEGR, 5, 0.0f, 0.07f, 0.25f },
+ { nil, PED_HEAD, PEDPIECE_HEAD, 0.0f, 0.05f, 0.2f },
+ { "Storso", 0, PEDPIECE_TORSO, 0.0f, 0.15f, 0.2f },
+ { "Storso", 0, PEDPIECE_TORSO, 0.0f, -0.05f, 0.3f },
+ { nil, PED_MID, PEDPIECE_MID, 0.0f, -0.07f, 0.3f },
+ { nil, PED_UPPERARML, PEDPIECE_LEFTARM, 0.07f, -0.1f, 0.2f },
+ { nil, PED_UPPERARMR, PEDPIECE_RIGHTARM, -0.07f, -0.1f, 0.2f },
+ { "Slowerlegl", 0, PEDPIECE_LEFTLEG, 0.0f, 0.07f, 0.25f },
+ { nil, PED_LOWERLEGR, PEDPIECE_RIGHTLEG, 0.0f, 0.07f, 0.25f },
};
RwObject*
diff --git a/src/modelinfo/PedModelInfo.h b/src/modelinfo/PedModelInfo.h
index bec46b4e..483d13f8 100644
--- a/src/modelinfo/PedModelInfo.h
+++ b/src/modelinfo/PedModelInfo.h
@@ -3,8 +3,8 @@
#include "ClumpModelInfo.h"
enum PedNode {
- PED_WAIST,
- PED_TORSO, // Smid on PS2/PC, Storso on mobile/xbox
+ PED_TORSO,
+ PED_MID, // Smid on PS2/PC, Storso on mobile/xbox
PED_HEAD,
PED_UPPERARML,
PED_UPPERARMR,
diff --git a/src/objects/ObjectData.cpp b/src/objects/ObjectData.cpp
index ef5bcc5e..775a87a1 100644
--- a/src/objects/ObjectData.cpp
+++ b/src/objects/ObjectData.cpp
@@ -93,7 +93,7 @@ CObjectData::SetObjectData(int32 modelId, CObject &object)
if(object.m_fMass >= 99998.0){
object.bInfiniteMass = true;
object.bAffectedByGravity = false;
- object.m_flagB2 = true;
+ object.bExplosionProof = true;
}
}
diff --git a/src/peds/CivilianPed.cpp b/src/peds/CivilianPed.cpp
index cf8a0580..3b1f9e1c 100644
--- a/src/peds/CivilianPed.cpp
+++ b/src/peds/CivilianPed.cpp
@@ -1,18 +1,41 @@
#include "common.h"
#include "patcher.h"
#include "CivilianPed.h"
+#include "Phones.h"
WRAPPER void CCivilianPed::ProcessControl(void) { EAXJMP(0x4BFFE0); }
CCivilianPed::CCivilianPed(int pedtype, int mi) : CPed(pedtype)
{
- CPed::SetModelIndex(mi);
+ SetModelIndex(mi);
for (int i = 0; i < 10; i++)
{
m_nearPeds[i] = nil;
}
}
+bool
+CCivilianPed::ProcessNearestFreePhone(int unused)
+{
+ if (m_nPedState == PED_SEEK_POS)
+ return false;
+
+ int phoneId = gPhoneInfo.FindNearestFreePhone(&GetPosition());
+
+ if (phoneId == -1)
+ return false;
+
+ if (gPhoneInfo.m_aPhones[phoneId].m_nState != PHONE_STATE_FREE)
+ return false;
+
+ field_31C = 1;
+ SetMoveState(PEDMOVE_RUN);
+ SetSeek(gPhoneInfo.m_aPhones[phoneId].m_vecPos, 0.3f);
+ m_phoneId = phoneId;
+ m_lookingForPhone = unused;
+ return true;
+}
+
class CCivilianPed_ : public CCivilianPed
{
public:
@@ -23,4 +46,5 @@ public:
STARTPATCHES
InjectHook(0x4BFF30, &CCivilianPed_::ctor, PATCH_JUMP);
InjectHook(0x4BFFC0, &CCivilianPed_::dtor, PATCH_JUMP);
+ InjectHook(0x4C10C0, &CCivilianPed::ProcessNearestFreePhone, PATCH_JUMP);
ENDPATCHES
diff --git a/src/peds/CivilianPed.h b/src/peds/CivilianPed.h
index 14859a5c..e5e63682 100644
--- a/src/peds/CivilianPed.h
+++ b/src/peds/CivilianPed.h
@@ -9,5 +9,6 @@ public:
~CCivilianPed(void) { }
void ProcessControl(void);
+ bool ProcessNearestFreePhone(int);
};
static_assert(sizeof(CCivilianPed) == 0x53C, "CCivilianPed: error");
diff --git a/src/peds/CopPed.cpp b/src/peds/CopPed.cpp
index 0ac0473f..5bc67e15 100644
--- a/src/peds/CopPed.cpp
+++ b/src/peds/CopPed.cpp
@@ -1,6 +1,64 @@
#include "common.h"
#include "patcher.h"
#include "CopPed.h"
+#include "ModelIndices.h"
+
+WRAPPER void CCopPed::ProcessControl() { EAXJMP(0x4C1400); }
+
+CCopPed::CCopPed(eCopType copType) : CPed(PEDTYPE_COP)
+{
+ m_nCopType = copType;
+ switch (copType) {
+ case COP_STREET:
+ SetModelIndex(MI_COP);
+ GiveWeapon(WEAPONTYPE_COLT45, 1000);
+ m_currentWeapon = WEAPONTYPE_UNARMED;
+ m_fArmour = 0.0f;
+ m_wepSkills = 208; /* TODO: what is this? seems unused */
+ m_wepAccuracy = 60;
+ break;
+ case COP_FBI:
+ SetModelIndex(MI_FBI);
+ GiveWeapon(WEAPONTYPE_COLT45, 1000);
+ GiveWeapon(WEAPONTYPE_AK47, 1000);
+ SetCurrentWeapon(WEAPONTYPE_AK47);
+ m_fArmour = 100.0f;
+ m_wepSkills = 176; /* TODO: what is this? seems unused */
+ m_wepAccuracy = 76;
+ break;
+ case COP_SWAT:
+ SetModelIndex(MI_SWAT);
+ GiveWeapon(WEAPONTYPE_COLT45, 1000);
+ GiveWeapon(WEAPONTYPE_UZI, 1000);
+ SetCurrentWeapon(WEAPONTYPE_UZI);
+ m_fArmour = 50.0f;
+ m_wepSkills = 32; /* TODO: what is this? seems unused */
+ m_wepAccuracy = 64;
+ break;
+ case COP_ARMY:
+ SetModelIndex(MI_ARMY);
+ GiveWeapon(WEAPONTYPE_COLT45, 1000);
+ GiveWeapon(WEAPONTYPE_M16, 1000);
+ GiveWeapon(WEAPONTYPE_GRENADE, 10);
+ SetCurrentWeapon(WEAPONTYPE_M16);
+ m_fArmour = 100.0f;
+ m_wepSkills = 32; /* TODO: what is this? seems unused */
+ m_wepAccuracy = 84;
+ break;
+ default:
+ break;
+ }
+ m_bIsInPursuit = false;
+ field_1350 = 1;
+ m_bIsDisabledCop = false;
+ field_1356 = 0;
+ m_attackTimer = 0;
+ field_1351 = 0;
+ m_bZoneDisabledButClose = false;
+ m_bZoneDisabled = false;
+ field_1364 = -1;
+ m_pPointGunAt = nil;
+}
CCopPed::~CCopPed()
{
@@ -12,9 +70,11 @@ WRAPPER void CCopPed::ClearPursuit(void) { EAXJMP(0x4C28C0); }
class CCopPed_ : public CCopPed
{
public:
+ CCopPed *ctor(eCopType type) { return ::new (this) CCopPed(type); };
void dtor(void) { CCopPed::~CCopPed(); }
};
STARTPATCHES
+ InjectHook(0x4C11B0, &CCopPed_::ctor, PATCH_JUMP);
InjectHook(0x4C13E0, &CCopPed_::dtor, PATCH_JUMP);
ENDPATCHES
diff --git a/src/peds/CopPed.h b/src/peds/CopPed.h
index 5827f9bc..162f14a6 100644
--- a/src/peds/CopPed.h
+++ b/src/peds/CopPed.h
@@ -1,27 +1,6 @@
#pragma once
#include "Ped.h"
-enum eCrimeType
-{
- CRIME_NONE,
- CRIME_POSSESSION_GUN,
- CRIME_HIT_PED,
- CRIME_HIT_COP,
- CRIME_SHOOT_PED,
- CRIME_SHOOT_COP,
- CRIME_STEAL_CAR,
- CRIME_RUN_REDLIGHT,
- CRIME_RECKLESS_DRIVING,
- CRIME_SPEEDING,
- CRIME_RUNOVER_PED,
- CRIME_RUNOVER_COP,
- CRIME_SHOOT_HELI,
- CRIME_PED_BURNED,
- CRIME_COP_BURNED,
- CRIME_VEHICLE_BURNED,
- CRIME_DESTROYED_CESSNA,
-};
-
enum eCopType
{
COP_STREET = 0,
@@ -30,18 +9,6 @@ enum eCopType
COP_ARMY = 3,
};
-class CCrime
-{
-public:
- eCrimeType m_eCrimeType;
- CEntity *m_pVictim;
- int32 m_nCrimeTime;
- CVector m_vecCrimePos;
- int8 m_bReported;
- int8 m_bMultiplier;
- int8 pad_20[2];
-};
-
class CCopPed : public CPed
{
public:
@@ -64,9 +31,11 @@ public:
int8 field_1366;
int8 field_1367;
+ CCopPed(eCopType);
~CCopPed();
void ClearPursuit(void);
+ void ProcessControl(void);
};
static_assert(sizeof(CCopPed) == 0x558, "CCopPed: error");
diff --git a/src/peds/EmergencyPed.cpp b/src/peds/EmergencyPed.cpp
index 664bd6f6..cbcfb403 100644
--- a/src/peds/EmergencyPed.cpp
+++ b/src/peds/EmergencyPed.cpp
@@ -1,13 +1,38 @@
#include "common.h"
#include "patcher.h"
#include "EmergencyPed.h"
+#include "ModelIndices.h"
class CEmergencyPed_ : public CEmergencyPed
{
public:
+ CEmergencyPed *ctor(int pedtype) { return ::new (this) CEmergencyPed(pedtype); };
void dtor(void) { CEmergencyPed::~CEmergencyPed(); }
};
+WRAPPER void CEmergencyPed::ProcessControl(void) { EAXJMP(0x4C2F10); }
+
+CEmergencyPed::CEmergencyPed(uint32 type) : CPed(type)
+{
+ switch (type){
+ case PEDTYPE_EMERGENCY:
+ SetModelIndex(MI_MEDIC);
+ m_pRevivedPed = nil;
+ field_1360 = 0;
+ break;
+ case PEDTYPE_FIREMAN:
+ SetModelIndex(MI_FIREMAN);
+ m_pRevivedPed = nil;
+ break;
+ default:
+ break;
+ }
+ m_nEmergencyPedState = 0;
+ m_pAttendedAccident = nil;
+ field_1356 = 0;
+}
+
STARTPATCHES
+ InjectHook(0x4C2E40, &CEmergencyPed_::ctor, PATCH_JUMP);
InjectHook(0x4C2EF0, &CEmergencyPed_::dtor, PATCH_JUMP);
ENDPATCHES
diff --git a/src/peds/EmergencyPed.h b/src/peds/EmergencyPed.h
index f21996e8..f55fa4e2 100644
--- a/src/peds/EmergencyPed.h
+++ b/src/peds/EmergencyPed.h
@@ -1,11 +1,20 @@
#pragma once
+#include "Fire.h"
#include "Ped.h"
class CEmergencyPed : public CPed
{
public:
// 0x53C
- uint8 stuff[24];
+ CPed* m_pRevivedPed;
+ int32 m_nEmergencyPedState; // looks like flags
+ void* m_pAttendedAccident; //TODO: CAccident*
+ CFire* m_pAttendedFire;
+ int8 field_1356;
+ int32 field_1360;
+
+ CEmergencyPed(uint32);
+ void ProcessControl(void);
};
static_assert(sizeof(CEmergencyPed) == 0x554, "CEmergencyPed: error");
diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp
index 4ad4ac1b..0c4e33d6 100644
--- a/src/peds/Ped.cpp
+++ b/src/peds/Ped.cpp
@@ -25,16 +25,15 @@
#include "PointLights.h"
#include "Pad.h"
#include "Phones.h"
+#include "EventList.h"
+#include "Darkel.h"
+#include "PathFind.h"
+#include "ModelIndices.h"
WRAPPER void CPed::KillPedWithCar(CVehicle *veh, float impulse) { EAXJMP(0x4EC430); }
WRAPPER void CPed::Say(uint16 audio) { EAXJMP(0x4E5A10); }
-WRAPPER void CPed::SetDie(AnimationId anim, float arg1, float arg2) { EAXJMP(0x4D37D0); }
WRAPPER void CPed::SetDead(void) { EAXJMP(0x4D3970); }
WRAPPER void CPed::SpawnFlyingComponent(int, int8) { EAXJMP(0x4EB060); }
-WRAPPER void CPed::RestorePreviousState(void) { EAXJMP(0x4C5E30); }
-WRAPPER void CPed::ClearAttack(void) { EAXJMP(0x4E6790); }
-WRAPPER void CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *dragAssoc, void *arg) { EAXJMP(0x4E2480); }
-WRAPPER void CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation *dragAssoc, void *arg) { EAXJMP(0x4E2920); }
WRAPPER void CPed::SetPedPositionInCar(void) { EAXJMP(0x4D4970); }
WRAPPER void CPed::ProcessControl(void) { EAXJMP(0x4C8910); }
WRAPPER void CPed::PreRender(void) { EAXJMP(0x4CFDD0); }
@@ -45,11 +44,14 @@ WRAPPER void CPed::SetFollowRoute(int16, int16) { EAXJMP(0x4DD690); }
WRAPPER void CPed::SetDuck(uint32) { EAXJMP(0x4E4920); }
WRAPPER void CPed::RegisterThreatWithGangPeds(CEntity*) { EAXJMP(0x4E3870); }
WRAPPER void CPed::MakeChangesForNewWeapon(int8) { EAXJMP(0x4F2560); }
+WRAPPER void CPed::SetSeek(CVector, float) { EAXJMP(0x4D14B0); }
WRAPPER bool CPed::Seek(void) { EAXJMP(0x4D1640); }
+WRAPPER void CPed::SetFollowPath(CVector) { EAXJMP(0x4D2EA0); }
bool &CPed::bNastyLimbsCheat = *(bool*)0x95CD44;
bool &CPed::bPedCheat2 = *(bool*)0x95CD5A;
bool &CPed::bPedCheat3 = *(bool*)0x95CD59;
+CColPoint &CPed::ms_tempColPoint = *(CColPoint*)0x62DB14;
uint16 &CPed::distanceMultToCountPedNear = *(uint16*)0x5F8C98;
@@ -272,8 +274,8 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
bPedPhysics = true;
bUseCollisionRecords = true;
- m_vecAnimMoveDelta.x = 0.0;
- m_vecAnimMoveDelta.y = 0.0;
+ m_vecAnimMoveDelta.x = 0.0f;
+ m_vecAnimMoveDelta.y = 0.0f;
m_fHealth = 100.0f;
m_fArmour = 0.0f;
m_nPedType = pedType;
@@ -290,9 +292,9 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
bInVehicle = 0;
m_pMyVehicle = nil;
m_pVehicleAnim = nil;
- m_vecOffsetSeek.x = 0.0;
- m_vecOffsetSeek.y = 0.0;
- m_vecOffsetSeek.z = 0.0;
+ m_vecOffsetSeek.x = 0.0f;
+ m_vecOffsetSeek.y = 0.0f;
+ m_vecOffsetSeek.z = 0.0f;
m_pedFormation = 0;
m_lastThreatTimer = 0;
m_nPedStateTimer = 0;
@@ -379,10 +381,10 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
m_ped_flagC1 = false;
bRespondsToThreats = true;
- m_ped_flagC4 = true;
- m_ped_flagC8 = false;
+ bRenderPedInCar = true;
+ bChangedSeat = false;
m_ped_flagC10 = false;
- m_ped_flagC20 = false;
+ bBodyPartJustCameOff = false;
m_ped_flagC40 = false;
m_ped_flagC80 = false;
@@ -390,10 +392,10 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
m_ped_flagD2 = false;
m_ped_flagD4 = false;
m_ped_flagD8 = false;
- m_ped_flagD10 = false;
+ bIsPedDieAnimPlaying = false;
m_ped_flagD20 = false;
m_ped_flagD40 = false;
- m_ped_flagD80 = false;
+ m_bScriptObjectiveCompleted = false;
m_ped_flagE1 = false;
m_ped_flagE2 = false;
@@ -668,7 +670,7 @@ CPed::AimGun(void)
if (m_pSeekTarget) {
if (m_pSeekTarget->IsPed()) {
- ((CPed*)m_pSeekTarget)->m_pedIK.GetComponentPosition(&pos, PED_TORSO);
+ ((CPed*)m_pSeekTarget)->m_pedIK.GetComponentPosition(&pos, PED_MID);
vector.x = pos.x;
vector.y = pos.y;
vector.z = pos.z;
@@ -708,7 +710,7 @@ CPed::ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer)
CPed::SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f);
}
- m_ped_flagC20 = true;
+ bBodyPartJustCameOff = true;
m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 150;
CParticle::AddParticle(PARTICLE_TEST, pos2,
@@ -732,7 +734,7 @@ CPed::ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer)
}
void
-CPed::RemoveBodyPart(PedNode nodeId, int8 unk)
+CPed::RemoveBodyPart(PedNode nodeId, int8 direction)
{
RwFrame *frame;
RwV3d pos;
@@ -741,7 +743,7 @@ CPed::RemoveBodyPart(PedNode nodeId, int8 unk)
if (frame) {
if (CGame::nastyGame) {
if (nodeId != PED_HEAD)
- CPed::SpawnFlyingComponent(nodeId, unk);
+ SpawnFlyingComponent(nodeId, direction);
RecurseFrameChildrenVisibilityCB(frame, nil);
pos.x = 0.0f;
@@ -763,7 +765,7 @@ CPed::RemoveBodyPart(PedNode nodeId, int8 unk)
nil, 0.0f, 0, 0, 0, 0);
}
}
- m_ped_flagC20 = true;
+ bBodyPartJustCameOff = true;
m_bodyPartBleeding = nodeId;
}
} else {
@@ -907,8 +909,8 @@ CPed::ClearAimFlag(void)
m_pedIK.m_flags &= ~CPedIK:: FLAG_4;
}
- if (CPed::IsPlayer())
- ((CPlayerPed*)this)->m_fFPSMoveHeading = 0.0;
+ if (IsPlayer())
+ ((CPlayerPed*)this)->m_fFPSMoveHeading = 0.0f;
}
void
@@ -919,14 +921,14 @@ CPed::ClearLookFlag(void) {
m_ped_flagI1 = false;
m_pedIK.m_flags &= ~CPedIK::FLAG_2;
- if (CPed::IsPlayer())
+ if (IsPlayer())
m_lookTimer = CTimer::GetTimeInMilliseconds() + 2000;
else
m_lookTimer = CTimer::GetTimeInMilliseconds() + 4000;
if (m_nPedState == PED_LOOK_HEADING || m_nPedState == PED_LOOK_ENTITY) {
- CPed::RestorePreviousState();
- CPed::ClearLookFlag();
+ RestorePreviousState();
+ ClearLookFlag();
}
}
}
@@ -1042,184 +1044,186 @@ CPed::Attack(void)
weaponAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_WEAPON_THROWU);
delayBetweenAnimAndFire = 0.2f;
}
- }
- if (weaponAnimAssoc) {
- animStart = ourWeapon->m_fAnimLoopStart;
- weaponAnimTime = weaponAnimAssoc->currentTime;
- if (weaponAnimTime > animStart && weaponAnimTime - weaponAnimAssoc->timeStep <= animStart) {
- if (ourWeapon->m_bCanAimWithArm)
- m_pedIK.m_flags |= CPedIK::FLAG_4;
- else
- m_pedIK.m_flags &= ~CPedIK::FLAG_4;
+
+ if (!weaponAnimAssoc) {
+ if (lastReloadWasInFuture) {
+ if (ourWeaponFire != WEAPON_FIRE_PROJECTILE || !IsPlayer() || ((CPlayerPed*)this)->field_1380) {
+ if (!CGame::nastyGame || ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(((CPlayerPed*)this), nil) < PED_ON_THE_FLOOR) {
+ weaponAnimAssoc = CAnimManager::BlendAnimation((RpClump*)m_rwObject, ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f);
+ }
+ else {
+ weaponAnimAssoc = CAnimManager::BlendAnimation((RpClump*)m_rwObject, ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f);
+ }
+
+ weaponAnimAssoc->SetFinishCallback(CPed::FinishedAttackCB, this);
+ weaponAnimAssoc->flags |= ASSOC_RUNNING;
+
+ if (weaponAnimAssoc->currentTime == weaponAnimAssoc->hierarchy->totalLength)
+ weaponAnimAssoc->SetCurrentTime(0.0f);
+
+ if (IsPlayer()) {
+ ((CPlayerPed*)this)->field_1376 = 0.0f;
+ ((CPlayerPed*)this)->field_1380 = false;
+ }
+ }
+ } else
+ FinishedAttackCB(nil, this);
+
+ return;
}
+ }
- if (weaponAnimTime <= delayBetweenAnimAndFire || weaponAnimTime - weaponAnimAssoc->timeStep > delayBetweenAnimAndFire || !weaponAnimAssoc->IsRunning()) {
- if (weaponAnimAssoc->speed < 1.0f)
- weaponAnimAssoc->speed = 1.0f;
+ animStart = ourWeapon->m_fAnimLoopStart;
+ weaponAnimTime = weaponAnimAssoc->currentTime;
+ if (weaponAnimTime > animStart && weaponAnimTime - weaponAnimAssoc->timeStep <= animStart) {
+ if (ourWeapon->m_bCanAimWithArm)
+ m_pedIK.m_flags |= CPedIK::FLAG_4;
+ else
+ m_pedIK.m_flags &= ~CPedIK::FLAG_4;
+ }
- } else {
- firePos = ourWeapon->m_vecFireOffset;
- if (ourWeaponType == WEAPONTYPE_BASEBALLBAT) {
- if (weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay)
- firePos.z = 0.7f * ourWeapon->m_fRadius - 1.0f;
-
- firePos = GetMatrix() * firePos;
- } else if (ourWeaponType != WEAPONTYPE_UNARMED) {
- if (weaponAnimAssoc->animId == ANIM_KICK_FLOOR)
- frame = GetNodeFrame(PED_FOOTR);
- else
- frame = GetNodeFrame(PED_HANDR);
+ if (weaponAnimTime <= delayBetweenAnimAndFire || weaponAnimTime - weaponAnimAssoc->timeStep > delayBetweenAnimAndFire || !weaponAnimAssoc->IsRunning()) {
+ if (weaponAnimAssoc->speed < 1.0f)
+ weaponAnimAssoc->speed = 1.0f;
- for (; frame; frame = RwFrameGetParent(frame))
- RwV3dTransformPoints((RwV3d*)firePos, (RwV3d*)firePos, 1, RwFrameGetMatrix(frame));
- } else {
- firePos = GetMatrix() * firePos;
- }
+ } else {
+ firePos = ourWeapon->m_vecFireOffset;
+ if (ourWeaponType == WEAPONTYPE_BASEBALLBAT) {
+ if (weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay)
+ firePos.z = 0.7f * ourWeapon->m_fRadius - 1.0f;
+
+ firePos = GetMatrix() * firePos;
+ } else if (ourWeaponType != WEAPONTYPE_UNARMED) {
+ if (weaponAnimAssoc->animId == ANIM_KICK_FLOOR)
+ frame = GetNodeFrame(PED_FOOTR);
+ else
+ frame = GetNodeFrame(PED_HANDR);
+
+ for (; frame; frame = RwFrameGetParent(frame))
+ RwV3dTransformPoints((RwV3d*)firePos, (RwV3d*)firePos, 1, RwFrameGetMatrix(frame));
+ } else {
+ firePos = GetMatrix() * firePos;
+ }
- GetWeapon()->Fire(this, &firePos);
+ GetWeapon()->Fire(this, &firePos);
- if (ourWeaponType == WEAPONTYPE_MOLOTOV || ourWeaponType == WEAPONTYPE_GRENADE) {
- RemoveWeaponModel(ourWeapon->m_nModelId);
+ if (ourWeaponType == WEAPONTYPE_MOLOTOV || ourWeaponType == WEAPONTYPE_GRENADE) {
+ RemoveWeaponModel(ourWeapon->m_nModelId);
+ }
+ if (!GetWeapon()->m_nAmmoTotal && ourWeaponFire != WEAPON_FIRE_MELEE && FindPlayerPed() != this) {
+ SelectGunIfArmed();
+ }
+
+ if (GetWeapon()->m_eWeaponState != WEAPONSTATE_MELEE_MADECONTACT) {
+ // If reloading just began, start the animation
+ if (GetWeapon()->m_eWeaponState == WEAPONSTATE_RELOADING && reloadAnim != NUM_ANIMS && !reloadAnimAssoc) {
+ CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, reloadAnim, 8.0f);
+ ClearLookFlag();
+ ClearAimFlag();
+ m_ped_flagA4 = false;
+ bIsPointingGunAt = false;
+ m_lastHitTime = CTimer::GetTimeInMilliseconds();
+ return;
}
- if (!GetWeapon()->m_nAmmoTotal && ourWeaponFire != WEAPON_FIRE_MELEE && FindPlayerPed() != this) {
- SelectGunIfArmed();
+ } else {
+ if (weaponAnimAssoc->animId == ANIM_WEAPON_BAT_V || weaponAnimAssoc->animId == ANIM_WEAPON_BAT_H) {
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_BAT_ATTACK, 1.0f);
+ } else if (weaponAnimAssoc->animId == ANIM_FIGHT_PPUNCH) {
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_PUNCH_ATTACK, 0.0f);
}
- if (GetWeapon()->m_eWeaponState != WEAPONSTATE_MELEE_MADECONTACT) {
- // If reloading just began, start the animation
- if (GetWeapon()->m_eWeaponState == WEAPONSTATE_RELOADING && reloadAnim != NUM_ANIMS && !reloadAnimAssoc) {
- CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, reloadAnim, 8.0f);
- ClearLookFlag();
- ClearAimFlag();
- m_ped_flagA4 = false;
- bIsPointingGunAt = false;
- m_lastHitTime = CTimer::GetTimeInMilliseconds();
- return;
- }
- } else {
- if (weaponAnimAssoc->animId == ANIM_WEAPON_BAT_V || weaponAnimAssoc->animId == ANIM_WEAPON_BAT_H) {
- DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_BAT_ATTACK, 1.0f);
- } else if (weaponAnimAssoc->animId == ANIM_FIGHT_PPUNCH) {
- DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_PUNCH_ATTACK, 0.0f);
- }
-
- weaponAnimAssoc->speed = 0.5f;
+ weaponAnimAssoc->speed = 0.5f;
- // BUG: We currently don't know any situation this cond. could be true.
- if (m_ped_flagA4 || CTimer::GetTimeInMilliseconds() < m_lastHitTime) {
- weaponAnimAssoc->callbackType = 0;
- }
+ // BUG: We currently don't know any situation this cond. could be true.
+ if (m_ped_flagA4 || CTimer::GetTimeInMilliseconds() < m_lastHitTime) {
+ weaponAnimAssoc->callbackType = 0;
}
-
- lastReloadWasInFuture = false;
}
- if (ourWeaponType == WEAPONTYPE_SHOTGUN) {
- weaponAnimTime = weaponAnimAssoc->currentTime;
- firePos = ourWeapon->m_vecFireOffset;
+ lastReloadWasInFuture = false;
+ }
- if (weaponAnimTime > 1.0f && weaponAnimTime - weaponAnimAssoc->timeStep <= 1.0f && weaponAnimAssoc->IsRunning()) {
- for (frame = GetNodeFrame(PED_HANDR); frame; frame = RwFrameGetParent(frame))
- RwV3dTransformPoints((RwV3d*)firePos, (RwV3d*)firePos, 1, RwFrameGetMatrix(frame));
+ if (ourWeaponType == WEAPONTYPE_SHOTGUN) {
+ weaponAnimTime = weaponAnimAssoc->currentTime;
+ firePos = ourWeapon->m_vecFireOffset;
- CVector gunshellPos(
- firePos.x - 0.6f * GetForward().x,
- firePos.y - 0.6f * GetForward().y,
- firePos.z - 0.15f * GetUp().z
- );
+ if (weaponAnimTime > 1.0f && weaponAnimTime - weaponAnimAssoc->timeStep <= 1.0f && weaponAnimAssoc->IsRunning()) {
+ for (frame = GetNodeFrame(PED_HANDR); frame; frame = RwFrameGetParent(frame))
+ RwV3dTransformPoints((RwV3d*)firePos, (RwV3d*)firePos, 1, RwFrameGetMatrix(frame));
- CVector2D gunshellRot(
- GetRight().x,
- GetRight().y
- );
+ CVector gunshellPos(
+ firePos.x - 0.6f * GetForward().x,
+ firePos.y - 0.6f * GetForward().y,
+ firePos.z - 0.15f * GetUp().z
+ );
- gunshellRot.Normalise();
- GetWeapon()->AddGunshell(this, gunshellPos, gunshellRot, 0.025f);
- }
+ CVector2D gunshellRot(
+ GetRight().x,
+ GetRight().y
+ );
+
+ gunshellRot.Normalise();
+ GetWeapon()->AddGunshell(this, gunshellPos, gunshellRot, 0.025f);
}
- animLoopEnd = ourWeapon->m_fAnimLoopEnd;
- if (ourWeaponFire == WEAPON_FIRE_MELEE && weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay)
- animLoopEnd = 3.4f/6.0f;
+ }
+ animLoopEnd = ourWeapon->m_fAnimLoopEnd;
+ if (ourWeaponFire == WEAPON_FIRE_MELEE && weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay)
+ animLoopEnd = 3.4f/6.0f;
- weaponAnimTime = weaponAnimAssoc->currentTime;
+ weaponAnimTime = weaponAnimAssoc->currentTime;
- // Anim loop end, either start the loop again or finish the attack
- if (weaponAnimTime > animLoopEnd || !weaponAnimAssoc->IsRunning() && ourWeaponFire != WEAPON_FIRE_PROJECTILE) {
+ // Anim loop end, either start the loop again or finish the attack
+ if (weaponAnimTime > animLoopEnd || !weaponAnimAssoc->IsRunning() && ourWeaponFire != WEAPON_FIRE_PROJECTILE) {
- if (weaponAnimTime - 2.0f * weaponAnimAssoc->timeStep <= animLoopEnd
- && (m_ped_flagA4 || CTimer::GetTimeInMilliseconds() < m_lastHitTime)
- && GetWeapon()->m_eWeaponState != WEAPONSTATE_RELOADING) {
+ if (weaponAnimTime - 2.0f * weaponAnimAssoc->timeStep <= animLoopEnd
+ && (m_ped_flagA4 || CTimer::GetTimeInMilliseconds() < m_lastHitTime)
+ && GetWeapon()->m_eWeaponState != WEAPONSTATE_RELOADING) {
- weaponAnim = weaponAnimAssoc->animId;
- if (ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(((CPlayerPed*)this), nil) < PED_ON_THE_FLOOR) {
- if (weaponAnim != ourWeapon->m_Anim2ToPlay || weaponAnim == ANIM_RBLOCK_CSHOOT) {
- weaponAnimAssoc->Start(ourWeapon->m_fAnimLoopStart);
- } else {
- CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f);
- }
+ weaponAnim = weaponAnimAssoc->animId;
+ if (ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(((CPlayerPed*)this), nil) < PED_ON_THE_FLOOR) {
+ if (weaponAnim != ourWeapon->m_Anim2ToPlay || weaponAnim == ANIM_RBLOCK_CSHOOT) {
+ weaponAnimAssoc->Start(ourWeapon->m_fAnimLoopStart);
} else {
- if (weaponAnim == ourWeapon->m_Anim2ToPlay)
- weaponAnimAssoc->SetCurrentTime(0.1f);
- else
- CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f);
+ CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f);
}
} else {
- ClearAimFlag();
-
- // Echoes of bullets, at the end of the attack. (Bug: doesn't play while reloading)
- if (weaponAnimAssoc->currentTime - weaponAnimAssoc->timeStep <= ourWeapon->m_fAnimLoopEnd) {
- switch (ourWeaponType) {
- case WEAPONTYPE_UZI:
- DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_UZI_BULLET_ECHO, 0.0f);
- break;
- case WEAPONTYPE_AK47:
- DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_AK47_BULLET_ECHO, 0.0f);
- break;
- case WEAPONTYPE_M16:
- DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_M16_BULLET_ECHO, 0.0f);
- break;
- default:
- break;
- }
- }
-
- // Fun fact: removing this part leds to reloading flamethrower
- if (ourWeaponType == WEAPONTYPE_FLAMETHROWER && weaponAnimAssoc->IsRunning()) {
- weaponAnimAssoc->flags |= ASSOC_DELETEFADEDOUT;
- weaponAnimAssoc->flags &= ~ASSOC_RUNNING;
- weaponAnimAssoc->blendDelta = -4.0f;
- }
+ if (weaponAnim == ourWeapon->m_Anim2ToPlay)
+ weaponAnimAssoc->SetCurrentTime(0.1f);
+ else
+ CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f);
}
- }
- if (weaponAnimAssoc->currentTime > delayBetweenAnimAndFire)
- lastReloadWasInFuture = false;
-
- m_ped_flagA4 = lastReloadWasInFuture;
- return;
- }
-
- if (lastReloadWasInFuture) {
- if (ourWeaponFire != WEAPON_FIRE_PROJECTILE || !CPed::IsPlayer() || ((CPlayerPed*)this)->field_1380) {
- if (!CGame::nastyGame || ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(((CPlayerPed*)this), nil) < PED_ON_THE_FLOOR) {
- weaponAnimAssoc = CAnimManager::BlendAnimation((RpClump*)m_rwObject, ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f);
- } else {
- weaponAnimAssoc = CAnimManager::BlendAnimation((RpClump*)m_rwObject, ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f);
+ } else {
+ ClearAimFlag();
+
+ // Echoes of bullets, at the end of the attack. (Bug: doesn't play while reloading)
+ if (weaponAnimAssoc->currentTime - weaponAnimAssoc->timeStep <= ourWeapon->m_fAnimLoopEnd) {
+ switch (ourWeaponType) {
+ case WEAPONTYPE_UZI:
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_UZI_BULLET_ECHO, 0.0f);
+ break;
+ case WEAPONTYPE_AK47:
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_AK47_BULLET_ECHO, 0.0f);
+ break;
+ case WEAPONTYPE_M16:
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_M16_BULLET_ECHO, 0.0f);
+ break;
+ default:
+ break;
+ }
}
- weaponAnimAssoc->SetFinishCallback(CPed::FinishedAttackCB, this);
- weaponAnimAssoc->flags |= ASSOC_RUNNING;
-
- if (weaponAnimAssoc->currentTime == weaponAnimAssoc->hierarchy->totalLength)
- weaponAnimAssoc->SetCurrentTime(0.0f);
-
- if (CPed::IsPlayer()) {
- ((CPlayerPed*)this)->field_1376 = 0.0f;
- ((CPlayerPed*)this)->field_1380 = false;
+ // Fun fact: removing this part leds to reloading flamethrower
+ if (ourWeaponType == WEAPONTYPE_FLAMETHROWER && weaponAnimAssoc->IsRunning()) {
+ weaponAnimAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ weaponAnimAssoc->flags &= ~ASSOC_RUNNING;
+ weaponAnimAssoc->blendDelta = -4.0f;
}
}
}
- else
- CPed::FinishedAttackCB(nil, this);
+ if (weaponAnimAssoc->currentTime > delayBetweenAnimAndFire)
+ lastReloadWasInFuture = false;
+
+ m_ped_flagA4 = lastReloadWasInFuture;
}
void
@@ -1272,25 +1276,26 @@ CPed::Duck(void)
void
CPed::ClearDuck(void)
{
- CAnimBlendAssociation *animAssoc;
+ CAnimBlendAssociation* animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_DUCK_DOWN);
+ if (!animAssoc) {
+ animAssoc = RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_DUCK_LOW);
- animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_DUCK_DOWN);
- if (!animAssoc)
- animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_DUCK_LOW);
+ if (!animAssoc) {
+ bIsDucking = false;
+ return;
+ }
+ }
- if (animAssoc) {
+ if (!bCrouchWhenShooting)
+ return;
- if (bCrouchWhenShooting) {
+ if (m_nPedState != PED_ATTACK && m_nPedState != PED_AIM_GUN)
+ return;
- if (m_nPedState == PED_ATTACK || m_nPedState == PED_AIM_GUN) {
- animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_RBLOCK_CSHOOT);
- if (!animAssoc || animAssoc->blendDelta < 0.0f) {
- CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ANIM_RBLOCK_CSHOOT, 4.0f);
- }
- }
- }
- } else
- bIsDucking = false;
+ animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_RBLOCK_CSHOOT);
+ if (!animAssoc || animAssoc->blendDelta < 0.0f) {
+ CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ANIM_RBLOCK_CSHOOT, 4.0f);
+ }
}
void
@@ -1404,7 +1409,7 @@ CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg)
if (vehicle->pDriver == ped) {
vehicle->RemoveDriver();
- if (vehicle->m_nDoorLock == CARLOCK_COP_CAR)
+ if (vehicle->m_nDoorLock == CARLOCK_LOCKED_INITIALLY)
vehicle->m_nDoorLock = CARLOCK_UNLOCKED;
if (ped->m_nPedType == PEDTYPE_COP && vehicle->IsLawEnforcementVehicle())
@@ -1456,7 +1461,7 @@ CPed::GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enter
seatOffset = 0.0f;
vehDoorOffset = offsetToOpenVanDoor;
} else {
- seatOffset = veh->m_handling->fSeatOffsetDistance * seatPosMult;
+ seatOffset = veh->pHandling->fSeatOffsetDistance * seatPosMult;
if (veh->bLowVehicle) {
vehDoorOffset = offsetToOpenLowCarDoor;
} else {
@@ -1559,7 +1564,7 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase)
if (CReplay::IsPlayingBack())
return;
- if (!m_ped_flagC8 && phase != LINE_UP_TO_CAR_2) {
+ if (!bChangedSeat && phase != LINE_UP_TO_CAR_2) {
if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_SIT)) {
SetPedPositionInCar();
return;
@@ -1576,7 +1581,7 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase)
SetPedPositionInCar();
return;
}
- m_ped_flagC8 = 1;
+ bChangedSeat = true;
}
if (phase == LINE_UP_TO_CAR_START) {
m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
@@ -1739,10 +1744,10 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase)
float limitedAngle = CGeneral::LimitRadianAngle(m_fRotationDest);
float timeUntilStateChange = (m_nPedStateTimer - CTimer::GetTimeInMilliseconds())/600.0f;
- m_vecOffsetSeek.z = 0.0;
+ m_vecOffsetSeek.z = 0.0f;
if (timeUntilStateChange <= 0.0f) {
- m_vecOffsetSeek.x = 0.0;
- m_vecOffsetSeek.y = 0.0;
+ m_vecOffsetSeek.x = 0.0f;
+ m_vecOffsetSeek.y = 0.0f;
} else {
neededPos -= timeUntilStateChange * m_vecOffsetSeek;
}
@@ -1911,7 +1916,7 @@ CPed::PlayFootSteps(void)
bool
CPed::IsPointerValid(void)
{
- int8 pedIndex = CPools::GetPedPool()->GetIndex(this) >> 8;
+ int pedIndex = CPools::GetPedPool()->GetIndex(this) >> 8;
if (pedIndex < 0 || pedIndex >= NUMPEDS)
return false;
@@ -1966,7 +1971,7 @@ CPed::BuildPedLists(void)
static CPed *unsortedNearPeds[10];
uint16 nextNearPedSlot = 0;
- if ((CTimer::GetFrameCounter() + m_randomSeed) & 15) {
+ if ((CTimer::GetFrameCounter() + m_randomSeed) % 16) {
for(int i = 0; i < 10; ) {
if (m_nearPeds[i]) {
@@ -2261,7 +2266,7 @@ CPed::CanSeeEntity(CEntity *entity, float threshold)
{
float neededAngle = CGeneral::GetRadianAngleBetweenPoints(
entity->GetPosition().x,
- entity->GetPosition().x,
+ entity->GetPosition().y,
GetPosition().x,
GetPosition().y);
@@ -2456,7 +2461,7 @@ CPed::SetObjective(eObjective newObj, void *entity)
// In this special case, entity parameter isn't CEntity, but int.
SetObjectiveTimer((int)entity);
- return;
+ break;
case OBJECTIVE_KILL_CHAR_ON_FOOT:
case OBJECTIVE_KILL_CHAR_ANY_MEANS:
case OBJECTIVE_MUG_CHAR:
@@ -2467,7 +2472,7 @@ CPed::SetObjective(eObjective newObj, void *entity)
m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective);
m_pLookTarget = (CEntity*)entity;
m_pLookTarget->RegisterReference((CEntity**)&m_pLookTarget);
- return;
+ break;
case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE:
case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS:
case OBJECTIVE_GOTO_CHAR_ON_FOOT:
@@ -2475,18 +2480,26 @@ CPed::SetObjective(eObjective newObj, void *entity)
m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f);
m_pedInObjective = (CPed*)entity;
m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective);
- return;
+ break;
case OBJECTIVE_FOLLOW_PED_IN_FORMATION:
m_pedInObjective = (CPed*)entity;
m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective);
m_pedFormation = 1;
- return;
+ break;
case OBJECTIVE_LEAVE_VEHICLE:
case OBJECTIVE_FLEE_CAR:
m_carInObjective = (CVehicle*)entity;
m_carInObjective->RegisterReference((CEntity **)&m_carInObjective);
if (!m_carInObjective->bIsBus || m_leaveCarTimer)
- return;
+ break;
+
+ for (int i = 0; i < m_carInObjective->m_nNumMaxPassengers; i++) {
+ if (m_carInObjective->pPassengers[i] == this) {
+ m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 1200 * i;
+ break;
+ }
+ }
+
break;
case OBJECTIVE_ENTER_CAR_AS_PASSENGER:
case OBJECTIVE_ENTER_CAR_AS_DRIVER:
@@ -2495,7 +2508,7 @@ CPed::SetObjective(eObjective newObj, void *entity)
if (((CVehicle*)entity)->m_vehType == VEHICLE_TYPE_BOAT && !IsPlayer()) {
RestorePreviousObjective();
- return;
+ break;
}
// fall through
case OBJECTIVE_DESTROY_CAR:
@@ -2509,24 +2522,18 @@ CPed::SetObjective(eObjective newObj, void *entity)
if (newObj == OBJECTIVE_SOLICIT) {
m_objectiveTimer = CTimer::GetTimeInMilliseconds() + 10000;
} else if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == MISSION_CHAR &&
- (m_carInObjective->m_status == STATUS_PLAYER_DISABLED || CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls)) {
+ (m_carInObjective->m_status == STATUS_PLAYER_DISABLED || CPad::GetPad(CWorld::PlayerInFocus)->ArePlayerControlsDisabled())) {
SetObjectiveTimer(14000);
} else {
m_objectiveTimer = 0;
}
- return;
+ break;
case OBJECTIVE_SET_LEADER:
SetLeader((CEntity*)entity);
RestorePreviousObjective();
- return;
+ break;
default:
- return;
- }
- for (int i=0; i < m_carInObjective->m_nNumMaxPassengers; i++) {
- if (m_carInObjective->pPassengers[i] == this) {
- m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 1200 * i;
- return;
- }
+ break;
}
}
@@ -2701,7 +2708,7 @@ CPed::QuitEnteringCar(void)
if (veh->m_nNumGettingIn != 0)
veh->m_nNumGettingIn--;
- veh->m_nGettingInFlags = ~GetVehDoorFlag(m_vehEnterType);
+ veh->m_nGettingInFlags &= ~GetVehDoorFlag(m_vehEnterType);
}
bUsesCollision = true;
@@ -2729,8 +2736,8 @@ CPed::QuitEnteringCar(void)
m_pVehicleAnim = nil;
if (veh) {
- if (veh->m_autoPilot.m_nCruiseSpeed == 0)
- veh->m_autoPilot.m_nCruiseSpeed = 17;
+ if (veh->AutoPilot.m_nCruiseSpeed == 0)
+ veh->AutoPilot.m_nCruiseSpeed = 17;
}
}
@@ -2906,6 +2913,1203 @@ CPed::CheckAroundForPossibleCollisions(void)
}
}
+bool
+CPed::MakePhonecall(void)
+{
+ if (CTimer::GetTimeInMilliseconds() <= m_phoneTalkTimer)
+ return false;
+
+ SetIdle();
+ gPhoneInfo.m_aPhones[m_phoneId].m_nState = PHONE_STATE_FREE;
+ m_phoneId = -1;
+ return true;
+}
+
+bool
+CPed::FacePhone(void)
+{
+ // FIX: I don't think this function was working correctly, they confused LimitAngle with LimitRadianAngle etc., so I fixed them
+ float currentRot = m_fRotationCur;
+ float phoneDir = CGeneral::GetRadianAngleBetweenPoints(
+ gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.x,
+ gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.y,
+ GetPosition().x,
+ GetPosition().y);
+
+ SetLookFlag(phoneDir, 0);
+
+ phoneDir = CGeneral::LimitRadianAngle(phoneDir);
+ m_moved = CVector2D(0.0f, 0.0f);
+
+ if (currentRot - PI > phoneDir)
+ phoneDir += 2 * PI;
+ else if (PI + currentRot < phoneDir)
+ phoneDir -= 2 * PI;
+
+ float neededTurn = currentRot - phoneDir;
+
+ if (Abs(neededTurn) <= 0.75f) {
+ SetIdle();
+ ClearLookFlag();
+ m_phoneTalkTimer = CTimer::GetTimeInMilliseconds() + 10000;
+ return true;
+ } else {
+ m_fRotationCur -= neededTurn * 0.2f;
+ return false;
+ }
+}
+
+CPed *
+CPed::CheckForDeadPeds(void)
+{
+ int event;
+ if (CEventList::FindClosestEvent(EVENT_DEAD_PED, GetPosition(), &event)) {
+ int pedHandle = gaEvent[event].entityRef;
+ if (pedHandle && gaEvent[event].entityType == EVENT_ENTITY_PED) {
+ m_ped_flagD2 = true;
+ return CPools::GetPed(pedHandle);
+ }
+ }
+ m_ped_flagD2 = false;
+ return nil;
+}
+
+bool
+CPed::CheckForExplosions(CVector2D &area)
+{
+ int event = 0;
+ if (CEventList::FindClosestEvent(EVENT_EXPLOSION, GetPosition(), &event)) {
+ area.x = gaEvent[event].posn.x;
+ area.y = gaEvent[event].posn.y;
+ CEntity *actualEntity = nil;
+
+ switch (gaEvent[event].entityType) {
+ case EVENT_ENTITY_PED:
+ actualEntity = CPools::GetPed(gaEvent[event].entityRef);
+ break;
+ case EVENT_ENTITY_VEHICLE:
+ actualEntity = CPools::GetVehicle(gaEvent[event].entityRef);
+ break;
+ case EVENT_ENTITY_OBJECT:
+ actualEntity = CPools::GetObject(gaEvent[event].entityRef);
+ break;
+ default:
+ break;
+ }
+
+ if (actualEntity) {
+ m_pEventEntity = actualEntity;
+ m_pEventEntity->RegisterReference((CEntity **) &m_pEventEntity);
+ m_ped_flagD2 = true;
+ } else
+ m_ped_flagD2 = false;
+
+ CEventList::ClearEvent(event);
+ return true;
+ } else if (CEventList::FindClosestEvent(EVENT_FIRE, GetPosition(), &event)) {
+ area.x = gaEvent[event].posn.x;
+ area.y = gaEvent[event].posn.y;
+ CEventList::ClearEvent(event);
+ m_ped_flagD2 = false;
+ return true;
+ }
+
+ m_ped_flagD2 = false;
+ return false;
+}
+
+CPed *
+CPed::CheckForGunShots(void)
+{
+ int event;
+ if (CEventList::FindClosestEvent(EVENT_GUNSHOT, GetPosition(), &event)) {
+ int pedHandle = gaEvent[event].entityRef;
+ if (pedHandle && gaEvent[event].entityType == EVENT_ENTITY_PED) {
+ // Is that a bug?!?
+ m_ped_flagD2 = false;
+ return CPools::GetPed(pedHandle);
+ }
+ }
+ m_ped_flagD2 = false;
+ return nil;
+}
+
+uint8
+CPed::CheckForPointBlankPeds(CPed *pedToVerify)
+{
+ float pbDistance = 1.1f;
+ if (GetWeapon()->IsType2Handed())
+ pbDistance = 1.6f;
+
+ for(int i=0; i<m_numNearPeds; i++) {
+ CPed *nearPed = m_nearPeds[i];
+
+ if (!pedToVerify || pedToVerify == nearPed) {
+
+ CVector diff = nearPed->GetPosition() - GetPosition();
+ if (diff.Magnitude() < pbDistance) {
+
+ float neededAngle = CGeneral::GetRadianAngleBetweenPoints(
+ nearPed->GetPosition().x, nearPed->GetPosition().y,
+ GetPosition().x, GetPosition().y);
+ neededAngle = CGeneral::LimitRadianAngle(neededAngle);
+ m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur);
+
+ float neededTurn = Abs(neededAngle - m_fRotationCur);
+
+ if (neededTurn > PI)
+ neededTurn = 2*PI - neededTurn;
+
+ PedState nearPedState = nearPed->m_nPedState;
+
+ if (nearPedState == PED_FALL || nearPedState == PED_GETUP || nearPedState == PED_DIE || nearPedState == PED_DEAD || nearPedState == PED_DIVE_AWAY)
+ return 0;
+
+ if (neededTurn < DEGTORAD(60.0f)) {
+ if (pedToVerify == nearPed)
+ return 1;
+ else
+ return 2;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+bool
+CPed::CheckIfInTheAir(void)
+{
+ if (bInVehicle)
+ return false;
+
+ CVector pos = GetPosition();
+ CColPoint foundColPoint;
+ CEntity *foundEntity;
+
+ float startZ = pos.z - 1.54f;
+ bool foundGround = CWorld::ProcessVerticalLine(pos, startZ, foundColPoint, foundEntity, true, true, false, true, false, false, false);
+ if (!foundGround && m_nPedState != PED_JUMP)
+ {
+ pos.z -= 1.04f;
+ if (CWorld::TestSphereAgainstWorld(pos, 0.15f, this, true, false, false, false, false, false))
+ foundGround = true;
+ }
+ return !foundGround;
+}
+
+void
+CPed::ClearAll(void)
+{
+ if (!IsPedInControl() && m_nPedState != PED_DEAD)
+ return;
+
+ m_nPedState = PED_NONE;
+ m_nMoveState = PEDMOVE_NONE;
+ m_pSeekTarget = nil;
+ m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f);
+ m_fleeFromPosX = 0.0f;
+ m_fleeFromPosY = 0.0f;
+ m_fleeFrom = nil;
+ m_fleeTimer = 0;
+ bUsesCollision = true;
+ ClearAimFlag();
+ ClearLookFlag();
+ bIsPointingGunAt = false;
+ bRenderPedInCar = true;
+ m_ped_flagH1 = false;
+ m_pCollidingEntity = nil;
+}
+
+void
+CPed::ClearAttack(void)
+{
+ if (m_nPedState != PED_ATTACK || bIsDucking || m_nWaitState == WAITSTATE_PLAYANIM_DUCK)
+ return;
+
+ if (bIsPointingGunAt) {
+ if (m_pLookTarget)
+ SetPointGunAt(m_pLookTarget);
+ else
+ ClearPointGunAt();
+ } else if (m_objective != OBJECTIVE_NONE) {
+ SetIdle();
+ } else {
+ RestorePreviousState();
+ }
+}
+
+void
+CPed::ClearAttackByRemovingAnim(void)
+{
+ if (m_nPedState != PED_ATTACK || bIsDucking)
+ return;
+
+ CWeaponInfo *weapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
+ CAnimBlendAssociation *weaponAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, weapon->m_AnimToPlay);
+ if (!weaponAssoc) {
+ weaponAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, weapon->m_Anim2ToPlay);
+
+ if (!weaponAssoc && weapon->m_bThrow)
+ weaponAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_WEAPON_THROWU);
+
+ if (!weaponAssoc) {
+ ClearAttack();
+ return;
+ }
+ }
+ weaponAssoc->blendDelta = -8.0f;
+ weaponAssoc->flags &= ~ASSOC_RUNNING;
+ weaponAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ weaponAssoc->SetDeleteCallback(FinishedAttackCB, this);
+}
+
+void
+CPed::StopNonPartialAnims(void)
+{
+ CAnimBlendAssociation* assoc;
+
+ for (assoc = RpAnimBlendClumpGetFirstAssociation((RpClump*)m_rwObject); assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) {
+ if (!assoc->IsPartial())
+ assoc->flags &= ~ASSOC_RUNNING;
+ }
+}
+
+void
+CPed::SetStoredState(void)
+{
+ if (m_nLastPedState != PED_NONE || !CanPedReturnToState())
+ return;
+
+ if (m_nPedState == PED_WANDER_PATH) {
+ m_ped_flagC80 = true;
+ if (m_nMoveState == PEDMOVE_NONE || m_nMoveState == PEDMOVE_STILL)
+ m_nMoveState = PEDMOVE_WALK;
+ }
+ m_nLastPedState = m_nPedState;
+ if (m_nMoveState >= m_nPrevActionState)
+ m_nPrevActionState = m_nMoveState;
+}
+
+void
+CPed::SetDie(AnimationId animId, float delta, float speed)
+{
+ CPlayerPed *player = FindPlayerPed();
+ if (player == this) {
+ if (!player->m_bCanBeDamaged)
+ return;
+ }
+
+ m_threatEntity = nil;
+ if (m_nPedState == PED_DIE || m_nPedState == PED_DEAD)
+ return;
+
+ if (m_nPedState == PED_FALL || m_nPedState == PED_GETUP)
+ delta *= 0.5f;
+
+ SetStoredState();
+ ClearAll();
+ m_fHealth = 0.0f;
+ if (m_nPedState == PED_DRIVING) {
+ if (!IsPlayer())
+ FlagToDestroyWhenNextProcessed();
+ } else if (bInVehicle) {
+ if (m_pVehicleAnim)
+ m_pVehicleAnim->blendDelta = -1000.0f;
+ } else if (m_nPedState == PED_ENTER_CAR || m_nPedState == PED_CARJACK) {
+ QuitEnteringCar();
+ }
+
+ m_nPedState = PED_DIE;
+ if (animId == NUM_ANIMS) {
+ bIsPedDieAnimPlaying = false;
+ } else {
+ CAnimBlendAssociation *dieAssoc = CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, animId, delta);
+ if (speed > 0.0f)
+ dieAssoc->speed = speed;
+
+ dieAssoc->flags &= ~ASSOC_FADEOUTWHENDONE;
+ if (dieAssoc->IsRunning()) {
+ dieAssoc->SetFinishCallback(FinishDieAnimCB, this);
+ bIsPedDieAnimPlaying = true;
+ }
+ }
+
+ Say(SOUND_PED_DEATH);
+ if (m_nLastPedState == PED_ENTER_CAR || m_nLastPedState == PED_CARJACK)
+ QuitEnteringCar();
+ if (!bInVehicle)
+ StopNonPartialAnims();
+
+ // ???
+ m_bloodyFootprintCount = CTimer::GetTimeInMilliseconds();
+}
+
+bool
+CPed::InflictDamage(CEntity* damagedBy, eWeaponType method, float damage, ePedPieceTypes pedPiece, uint8 direction)
+{
+ CPlayerPed *player = FindPlayerPed();
+ float dieDelta = 4.0f;
+ float dieSpeed = 0.0f;
+ AnimationId dieAnim = ANIM_KO_SHOT_FRONT1;
+ bool headShot = false;
+ bool willLinger = false;
+ int random;
+
+ if (player == this) {
+ if (!player->m_bCanBeDamaged)
+ return false;
+
+ player->AnnoyPlayerPed(false);
+ }
+
+ if (m_nPedState == PED_DIE || m_nPedState == PED_DEAD)
+ return false;
+
+ if (!bUsesCollision && method != WEAPONTYPE_WATER)
+ return false;
+
+ if (bOnlyDamagedByPlayer && damagedBy != player && damagedBy != FindPlayerVehicle() &&
+ method != WEAPONTYPE_WATER && method != WEAPONTYPE_EXPLOSION)
+ return false;
+
+ float healthImpact;
+ if (IsPlayer())
+ healthImpact = damage * 0.33f;
+ else
+ healthImpact = damage * m_pedStats->m_defendWeakness;
+
+ bool detectDieAnim = true;
+ if (m_nPedState == PED_FALL || m_nPedState == PED_GETUP) {
+ if (!IsPedHeadAbovePos(-0.3f)) {
+ if (RpAnimBlendClumpGetFirstAssociation((RpClump*) m_rwObject, ASSOC_FLAG800))
+ dieAnim = ANIM_FLOOR_HIT_F;
+ else
+ dieAnim = ANIM_FLOOR_HIT;
+ dieDelta *= 2.0f;
+ dieSpeed = 0.5f;
+ detectDieAnim = false;
+ } else if (m_nPedState == PED_FALL) {
+ dieAnim = NUM_ANIMS;
+ detectDieAnim = false;
+ }
+ }
+ if (detectDieAnim) {
+ switch (method) {
+ case WEAPONTYPE_UNARMED:
+ if (bMeleeProof)
+ return false;
+
+ if (m_nPedState == PED_FALL) {
+ if (IsPedHeadAbovePos(-0.3f)) {
+ dieAnim = NUM_ANIMS;
+ } else {
+ if (RpAnimBlendClumpGetFirstAssociation((RpClump*) m_rwObject, ASSOC_FLAG800))
+ dieAnim = ANIM_FLOOR_HIT_F;
+ else
+ dieAnim = ANIM_FLOOR_HIT;
+ dieDelta = dieDelta * 2.0f;
+ dieSpeed = 0.5f;
+ }
+ } else {
+ switch (direction) {
+ case 0:
+ dieAnim = ANIM_KO_SKID_FRONT;
+ break;
+ case 1:
+ dieAnim = ANIM_KO_SPIN_R;
+ break;
+ case 2:
+ dieAnim = ANIM_KO_SKID_BACK;
+ break;
+ case 3:
+ dieAnim = ANIM_KO_SPIN_L;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case WEAPONTYPE_BASEBALLBAT:
+ if (bMeleeProof)
+ return false;
+
+ if (m_nPedState == PED_FALL) {
+ if (IsPedHeadAbovePos(-0.3f)) {
+ dieAnim = NUM_ANIMS;
+ } else {
+ if (RpAnimBlendClumpGetFirstAssociation((RpClump*) m_rwObject, 0x800u))
+ dieAnim = ANIM_FLOOR_HIT_F;
+ else
+ dieAnim = ANIM_FLOOR_HIT;
+ dieDelta = dieDelta * 2.0f;
+ dieSpeed = 0.5f;
+ }
+ } else {
+ switch (direction) {
+ case 0:
+ dieAnim = ANIM_KO_SKID_FRONT;
+ break;
+ case 1:
+ dieAnim = ANIM_KO_SPIN_R;
+ break;
+ case 2:
+ dieAnim = ANIM_KO_SKID_BACK;
+ break;
+ case 3:
+ dieAnim = ANIM_KO_SPIN_L;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case WEAPONTYPE_COLT45:
+ case WEAPONTYPE_UZI:
+ case WEAPONTYPE_SHOTGUN:
+ case WEAPONTYPE_AK47:
+ case WEAPONTYPE_M16:
+ case WEAPONTYPE_SNIPERRIFLE:
+ if (bBulletProof)
+ return false;
+
+ bool dontRemoveLimb;
+ if (IsPlayer() || m_ped_flagI2)
+ dontRemoveLimb = true;
+ else {
+ switch (method)
+ {
+ case WEAPONTYPE_SNIPERRIFLE:
+ dontRemoveLimb = false;
+ break;
+ case WEAPONTYPE_M16:
+ dontRemoveLimb = false;
+ break;
+ case WEAPONTYPE_SHOTGUN:
+ dontRemoveLimb = CGeneral::GetRandomNumberInRange(0,7);
+ break;
+ default:
+ dontRemoveLimb = CGeneral::GetRandomNumberInRange(0,15);
+ break;
+ }
+ }
+
+ if (dontRemoveLimb) {
+ if (method == WEAPONTYPE_SHOTGUN) {
+ switch (direction) {
+ case 0:
+ dieAnim = ANIM_KO_SKID_FRONT;
+ break;
+ case 1:
+ dieAnim = ANIM_KO_SPIN_R;
+ break;
+ case 2:
+ dieAnim = ANIM_KO_SKID_BACK;
+ break;
+ case 3:
+ dieAnim = ANIM_KO_SPIN_L;
+ break;
+ default:
+ break;
+ }
+ } else
+ dieAnim = ANIM_KO_SHOT_FRONT1;
+
+ willLinger = false;
+ } else {
+ switch (pedPiece) {
+ case PEDPIECE_TORSO:
+ willLinger = false;
+ dieAnim = ANIM_KO_SHOT_FRONT1;
+ break;
+ case PEDPIECE_MID:
+ willLinger = false;
+ dieAnim = ANIM_KO_SHOT_STOM;
+ break;
+ case PEDPIECE_LEFTARM:
+ dieAnim = ANIM_KO_SHOT_ARML;
+ RemoveBodyPart(PED_UPPERARML, direction);
+ willLinger = true;
+ break;
+ case PEDPIECE_RIGHTARM:
+ dieAnim = ANIM_KO_SHOT_ARMR;
+ RemoveBodyPart(PED_UPPERARMR, direction);
+ willLinger = true;
+ break;
+ case PEDPIECE_LEFTLEG:
+ dieAnim = ANIM_KO_SHOT_LEGL;
+ RemoveBodyPart(PED_UPPERLEGL, direction);
+ willLinger = true;
+ break;
+ case PEDPIECE_RIGHTLEG:
+ dieAnim = ANIM_KO_SHOT_LEGR;
+ RemoveBodyPart(PED_UPPERLEGR, direction);
+ willLinger = true;
+ break;
+ case PEDPIECE_HEAD:
+ dieAnim = ANIM_KO_SHOT_FACE;
+ RemoveBodyPart(PED_HEAD, direction);
+ headShot = true;
+ willLinger = true;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case WEAPONTYPE_ROCKETLAUNCHER:
+ case WEAPONTYPE_GRENADE:
+ case WEAPONTYPE_EXPLOSION:
+ if (bExplosionProof)
+ return false;
+
+ if (CGame::nastyGame && !IsPlayer() && !bInVehicle &&
+ 1.0f + healthImpact > m_fArmour + m_fHealth) {
+
+ random = CGeneral::GetRandomNumber();
+ if (random & 1)
+ RemoveBodyPart(PED_UPPERARML, direction);
+ if (random & 2)
+ RemoveBodyPart(PED_UPPERLEGR, direction);
+ if (random & 4)
+ RemoveBodyPart(PED_HEAD, direction);
+ if (random & 8)
+ RemoveBodyPart(PED_UPPERARMR, direction);
+ if (random & 0x10)
+ RemoveBodyPart(PED_UPPERLEGL, direction);
+ if (bBodyPartJustCameOff)
+ willLinger = true;
+ }
+ // fall through
+ case WEAPONTYPE_MOLOTOV:
+ if (bExplosionProof)
+ return false;
+
+ switch (direction) {
+ case 0:
+ dieAnim = ANIM_KO_SKID_FRONT;
+ break;
+ case 1:
+ dieAnim = ANIM_KO_SPIN_R;
+ break;
+ case 2:
+ dieAnim = ANIM_KO_SKID_BACK;
+ break;
+ case 3:
+ dieAnim = ANIM_KO_SPIN_L;
+ break;
+ default:
+ break;
+ }
+ break;
+ case WEAPONTYPE_FLAMETHROWER:
+ if (bFireProof)
+ return false;
+
+ dieAnim = ANIM_KO_SHOT_FRONT1;
+ break;
+ case WEAPONTYPE_RAMMEDBYCAR:
+ case WEAPONTYPE_RUNOVERBYCAR:
+ if (bCollisionProof)
+ return false;
+
+ random = CGeneral::GetRandomNumberInRange(0, 3);
+ switch (random) {
+ case 0:
+ if ((pedPiece != PEDPIECE_LEFTARM || random <= 1)
+ && (pedPiece != PEDPIECE_MID || random != 1)) {
+ if (pedPiece == PEDPIECE_RIGHTARM && random > 1
+ || pedPiece == PEDPIECE_MID && random == 2)
+
+ dieAnim = ANIM_KO_SPIN_L;
+ else
+ dieAnim = ANIM_KO_SKID_FRONT;
+ } else
+ dieAnim = ANIM_KO_SPIN_R;
+
+ break;
+ case 1:
+ if (m_nPedState == PED_DIVE_AWAY)
+ dieAnim = ANIM_KD_LEFT;
+ else
+ dieAnim = ANIM_KO_SPIN_R;
+ break;
+ case 2:
+ if ((pedPiece != PEDPIECE_LEFTARM || random <= 1)
+ && (pedPiece != PEDPIECE_MID || random != 1)) {
+ if ((pedPiece != PEDPIECE_RIGHTARM || random <= 1)
+ && (pedPiece != PEDPIECE_MID || random != 2)) {
+ dieAnim = ANIM_KO_SKID_BACK;
+ } else {
+ dieAnim = ANIM_KD_RIGHT;
+ }
+ } else
+ dieAnim = ANIM_KD_LEFT;
+ break;
+ case 3:
+ if (m_nPedState == PED_DIVE_AWAY)
+ dieAnim = ANIM_KD_RIGHT;
+ else
+ dieAnim = ANIM_KO_SPIN_L;
+ break;
+ default:
+ break;
+ }
+ if (damagedBy) {
+ CVehicle *vehicle = (CVehicle*)damagedBy;
+ if (method == WEAPONTYPE_RAMMEDBYCAR) {
+ float vehSpeed = vehicle->m_vecMoveSpeed.Magnitude();
+ dieDelta = 8.0f * vehSpeed + 4.0f;
+ } else {
+ float vehSpeed = vehicle->m_vecMoveSpeed.Magnitude();
+ dieDelta = 12.0f * vehSpeed + 4.0f;
+ dieSpeed = 16.0f * vehSpeed + 1.0f;
+ }
+ }
+ break;
+ case WEAPONTYPE_WATER:
+ dieAnim = ANIM_DROWN;
+ break;
+ case WEAPONTYPE_FALL_DAMAGE:
+ if (bCollisionProof)
+ return false;
+
+ switch (direction) {
+ case 0:
+ dieAnim = ANIM_KO_SKID_FRONT;
+ break;
+ case 1:
+ dieAnim = ANIM_KO_SPIN_R;
+ break;
+ case 2:
+ dieAnim = ANIM_KO_SKID_BACK;
+ break;
+ case 3:
+ dieAnim = ANIM_KO_SPIN_L;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (m_fArmour != 0.0f && method != WEAPONTYPE_WATER) {
+ if (player == this)
+ CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastArmourLoss = CTimer::GetTimeInMilliseconds();
+
+ if (healthImpact < m_fArmour) {
+ m_fArmour = m_fArmour - healthImpact;
+ healthImpact = 0.0f;
+ } else {
+ healthImpact = healthImpact - m_fArmour;
+ m_fArmour = 0.0f;
+ }
+ }
+
+ if (healthImpact != 0.0f) {
+ if (player == this)
+ CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss = CTimer::GetTimeInMilliseconds();
+
+ m_lastWepDam = method;
+ }
+
+ if (m_fHealth - healthImpact >= 1.0f && !willLinger) {
+ m_fHealth -= healthImpact;
+ return false;
+ }
+
+ if (bInVehicle) {
+ if (method != WEAPONTYPE_WATER) {
+ m_fHealth = 1.0f;
+ return false;
+ }
+ m_fHealth = 0.0f;
+ if (player == this)
+ m_pMyVehicle->m_status = STATUS_PLAYER_DISABLED;
+
+ SetDie(NUM_ANIMS, 4.0f, 0.0f);
+ return true;
+ } else {
+ m_fHealth = 0.0f;
+ SetDie(dieAnim, dieDelta, dieSpeed);
+
+ if (damagedBy == player || damagedBy && damagedBy == FindPlayerVehicle()) {
+ CDarkel::RegisterKillByPlayer(this, method, headShot);
+ m_threatEntity = player;
+ } else {
+ CDarkel::RegisterKillNotByPlayer(this, method);
+ }
+ // WAT?
+ if (method == WEAPONTYPE_WATER)
+ bIsInTheAir = false;
+
+ return true;
+ }
+}
+
+void
+CPed::ClearFlee(void)
+{
+ RestorePreviousState();
+ m_ped_flagD20 = false;
+ m_standardTimer = 0;
+ m_fleeTimer = 0;
+}
+
+void
+CPed::ClearFall(void)
+{
+ SetGetUp();
+}
+
+void
+CPed::SetGetUp(void)
+{
+ if (m_nPedState == PED_GETUP && m_ped_flagE20)
+ return;
+
+ if (!CanSetPedState())
+ return;
+
+ if (m_fHealth >= 1.0f || IsPedHeadAbovePos(-0.3f)) {
+ if (m_ped_flagC10) {
+ m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur);
+ m_fRotationCur -= 0.5*PI;
+ m_ped_flagC10 = false;
+ }
+ if (m_nPedState != PED_GETUP) {
+ SetStoredState();
+ m_nPedState = PED_GETUP;
+ }
+
+ CVehicle* collidingVeh = (CVehicle*)m_pCollidingEntity;
+ CVehicle *veh = (CVehicle*)CPedPlacement::IsPositionClearOfCars(&GetPosition());
+ if (veh && veh->m_vehType != VEHICLE_TYPE_BIKE ||
+ collidingVeh && collidingVeh->IsVehicle() && collidingVeh->m_vehType != VEHICLE_TYPE_BIKE
+ && ((CTimer::GetFrameCounter() + m_randomSeed % 256 + 5) % 8
+ || CCollision::ProcessColModels(GetMatrix(), *CModelInfo::GetModelInfo(m_modelIndex)->GetColModel(),
+ collidingVeh->GetMatrix(), *CModelInfo::GetModelInfo(collidingVeh->m_modelIndex)->GetColModel(),
+ &ms_tempColPoint, nil, nil) > 0)) {
+
+ m_ped_flagE20 = false;
+ if (IsPlayer())
+ InflictDamage(nil, WEAPONTYPE_RUNOVERBYCAR, CTimer::GetTimeStep(), PEDPIECE_TORSO, 0);
+ else {
+ if (!CPad::GetPad(0)->ArePlayerControlsDisabled())
+ return;
+
+ InflictDamage(nil, WEAPONTYPE_RUNOVERBYCAR, 1000.0f, PEDPIECE_TORSO, 0);
+ }
+ return;
+ }
+ m_ped_flagE20 = true;
+ m_pCollidingEntity = nil;
+ m_ped_flagH1 = false;
+ CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_SPRINT);
+ if (animAssoc) {
+ if (RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_RUN)) {
+ CAnimManager::BlendAnimation((RpClump*) m_rwObject, m_animGroup, ANIM_RUN, 8.0f);
+ } else {
+ CAnimManager::BlendAnimation((RpClump*) m_rwObject, m_animGroup, ANIM_IDLE_STANCE, 8.0f);
+ }
+ animAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ }
+
+ if (RpAnimBlendClumpGetFirstAssociation((RpClump*) m_rwObject, ASSOC_FLAG800))
+ animAssoc = CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ANIM_GETUP_FRONT, 1000.0f);
+ else
+ animAssoc = CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ANIM_GETUP1, 1000.0f);
+
+ animAssoc->SetFinishCallback(PedGetupCB,this);
+ } else {
+ m_fHealth = 0.0f;
+ SetDie(NUM_ANIMS, 4.0f, 0.0f);
+ }
+}
+
+void
+CPed::ClearInvestigateEvent(void)
+{
+ CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_ROAD_CROSS);
+ if (!animAssoc)
+ animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_XPRESS_SCRATCH);
+ if (!animAssoc)
+ animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_HBHB);
+ if (!animAssoc)
+ animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_CHAT);
+ if (animAssoc) {
+ animAssoc->blendDelta = -8.0f;
+ animAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ }
+ if (m_eventType > EVENT_EXPLOSION)
+ m_standardTimer = CTimer::GetTimeInMilliseconds() + 15000;
+
+ m_ped_flagD2 = false;
+ m_pEventEntity = nil;
+ ClearLookFlag();
+ RestorePreviousState();
+ if(m_nMoveState == PEDMOVE_NONE || m_nMoveState == PEDMOVE_STILL)
+ SetMoveState(PEDMOVE_WALK);
+}
+
+void
+CPed::ClearLeader(void)
+{
+ if (!m_leader)
+ return;
+
+ m_leader = nil;
+ if (IsPedInControl()) {
+ SetObjective(OBJECTIVE_NONE);
+ if (CharCreatedBy == MISSION_CHAR) {
+ SetIdle();
+ } else {
+ SetWanderPath(CGeneral::GetRandomNumberInRange(0,8));
+ }
+ } else if (m_objective != OBJECTIVE_NONE) {
+ m_ped_flagH8 = true;
+ }
+}
+
+void
+CPed::ClearLook(void)
+{
+ RestorePreviousState();
+ ClearLookFlag();
+}
+
+void
+CPed::ClearObjective(void)
+{
+ if (IsPedInControl() || m_nPedState == PED_DRIVING) {
+
+ m_objective = OBJECTIVE_NONE;
+ if (m_nPedState == PED_DRIVING && m_pMyVehicle) {
+
+ if (m_pMyVehicle->pDriver != this) {
+
+ m_ped_flagF1 = true;
+ SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle);
+ }
+ } else {
+ SetIdle();
+ SetMoveState(PEDMOVE_STILL);
+ }
+ } else {
+ m_ped_flagH8 = true;
+ }
+}
+
+void
+CPed::ClearPause(void)
+{
+ RestorePreviousState();
+}
+
+void
+CPed::ClearSeek(void)
+{
+ SetIdle();
+ field_31C = 0;
+}
+
+bool
+CPed::SetWanderPath(int8 pathStateDest)
+{
+ uint8 nextPathState;
+
+ if (IsPedInControl()) {
+ if (m_ped_flagE1) {
+ SetIdle();
+ return false;
+ } else {
+
+ // m_nPathState is pure direction for values 1,2,3 and 5,6,7
+
+ m_nPathState = pathStateDest;
+ if (pathStateDest == 0)
+ pathStateDest = CGeneral::GetRandomNumberInRange(1, 7);
+
+ ThePaths.FindNextNodeWandering(1, GetPosition(), &m_pNextPathNode, &m_pLastPathNode,
+ m_nPathState, &nextPathState);
+
+ // Circular loop until we find a node for current m_nPathState
+ while (!m_pLastPathNode) {
+ m_nPathState = (m_nPathState+1) % 8;
+
+ // We're at where we started and couldn't find any node
+ if (m_nPathState == pathStateDest) {
+ ClearAll();
+ SetIdle();
+ return false;
+ }
+ ThePaths.FindNextNodeWandering(1, GetPosition(), &m_pNextPathNode, &m_pLastPathNode,
+ m_nPathState, &nextPathState);
+ }
+
+ // We did it, save next path state and return true
+ m_nPathState = nextPathState;
+ m_nPedState = PED_WANDER_PATH;
+ SetMoveState(PEDMOVE_WALK);
+ m_ped_flagB20 = false;
+ return true;
+ }
+ } else {
+ m_nPathState = pathStateDest;
+ m_ped_flagG8 = true;
+ return false;
+ }
+}
+
+void
+CPed::ClearWeapons(void)
+{
+ CWeaponInfo *currentWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
+ RemoveWeaponModel(currentWeapon->m_nModelId);
+
+ m_maxWeaponTypeAllowed = WEAPONTYPE_BASEBALLBAT;
+ m_currentWeapon = WEAPONTYPE_UNARMED;
+
+ currentWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
+ AddWeaponModel(currentWeapon->m_nModelId);
+ for(int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++)
+ {
+ CWeapon &weapon = GetWeapon(i);
+ weapon.m_eWeaponType = WEAPONTYPE_UNARMED;
+ weapon.m_eWeaponState = WEAPONSTATE_READY;
+ weapon.m_nAmmoInClip = 0;
+ weapon.m_nAmmoTotal = 0;
+ weapon.m_nTimer = 0;
+ }
+}
+
+void
+CPed::RestoreGunPosition(void)
+{
+ if (bIsLooking) {
+ m_pedIK.m_flags &= ~CPedIK::FLAG_2;
+ bIsRestoringGun = false;
+ } else if (m_pedIK.RestoreGunPosn()) {
+ bIsRestoringGun = false;
+ } else {
+ if (IsPlayer())
+ ((CPlayerPed*)this)->m_fFPSMoveHeading = 0.0f;
+ }
+}
+
+void
+CPed::RestoreHeadingRate(void)
+{
+ m_headingRate = m_pedStats->m_headingChangeRate;
+}
+
+void
+CPed::RestoreHeadingRateCB(CAnimBlendAssociation* assoc, void* arg)
+{
+ ((CPed*)arg)->m_headingRate = ((CPed*)arg)->m_pedStats->m_headingChangeRate;
+}
+
+void
+CPed::RestorePreviousState(void)
+{
+ if(!CanSetPedState() || m_nPedState == PED_FALL)
+ return;
+
+ if (m_nPedState == PED_GETUP && !m_ped_flagE20)
+ return;
+
+ if (bInVehicle && m_pMyVehicle) {
+ m_nPedState = PED_DRIVING;
+ m_nLastPedState = PED_NONE;
+ } else {
+ if (m_nLastPedState == PED_NONE) {
+ if (!IsPlayer() && CharCreatedBy != MISSION_CHAR && m_objective == OBJECTIVE_NONE) {
+ if (SetWanderPath(CGeneral::GetRandomNumberInRange(0, 7)) != 0)
+ return;
+ }
+ SetIdle();
+ return;
+ }
+
+ switch (m_nLastPedState) {
+ case PED_IDLE:
+ SetIdle();
+ break;
+ case PED_WANDER_PATH:
+ m_nPedState = PED_WANDER_PATH;
+ m_ped_flagB20 = false;
+ if (!m_ped_flagC80) {
+ if (m_pLastPathNode) {
+ CVector diff = m_pLastPathNode->pos - GetPosition();
+ if (diff.MagnitudeSqr() < 49.0f) {
+ SetMoveState(PEDMOVE_WALK);
+ break;
+ }
+ }
+ }
+ SetWanderPath(CGeneral::GetRandomNumberInRange(0, 7));
+ break;
+ default:
+ m_nPedState = m_nLastPedState;
+ SetMoveState((eMoveState) m_nPrevActionState);
+ break;
+ }
+ m_nLastPedState = PED_NONE;
+ }
+}
+
+void
+CPed::SetAimFlag(CEntity *to)
+{
+ bIsAimingGun = true;
+ bIsRestoringGun = false;
+ m_pLookTarget = to;
+ m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget);
+ m_pSeekTarget = to;
+ m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget);
+ m_lookTimer = 0;
+}
+
+void
+CPed::SetAimFlag(float angle)
+{
+ bIsAimingGun = true;
+ bIsRestoringGun = false;
+ m_fLookDirection = angle;
+ m_lookTimer = 0;
+ m_pLookTarget = nil;
+ m_pSeekTarget = nil;
+ if (CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bCanAimWithArm)
+ m_pedIK.m_flags |= CPedIK::FLAG_4;
+ else
+ m_pedIK.m_flags &= ~CPedIK::FLAG_4;
+}
+
+void
+CPed::SetPointGunAt(CEntity *to)
+{
+ if (to) {
+ SetLookFlag(to,1);
+ SetAimFlag(to);
+ }
+
+ if (m_nPedState == PED_AIM_GUN || bIsDucking || m_nWaitState == WAITSTATE_PLAYANIM_DUCK)
+ return;
+
+ if (m_nPedState != PED_ATTACK)
+ SetStoredState();
+
+ m_nPedState = PED_AIM_GUN;
+ bIsPointingGunAt = true;
+ CWeaponInfo *curWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
+ SetMoveState(PEDMOVE_NONE);
+
+ CAnimBlendAssociation *aimAssoc;
+
+ if (bCrouchWhenShooting)
+ aimAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, curWeapon->m_Anim2ToPlay);
+ else
+ aimAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, curWeapon->m_AnimToPlay);
+
+ if (!aimAssoc || aimAssoc->blendDelta < 0.0f) {
+ if (bCrouchWhenShooting)
+ aimAssoc = CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, curWeapon->m_Anim2ToPlay, 4.0f);
+ else
+ aimAssoc = CAnimManager::AddAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, curWeapon->m_AnimToPlay);
+
+ aimAssoc->blendAmount = 0.0f;
+ aimAssoc->blendDelta = 8.0f;
+ }
+ if (to)
+ Say(SOUND_PED_ATTACK);
+}
+
+void
+CPed::SetAmmo(eWeaponType weaponType, uint32 ammo)
+{
+ if (HasWeapon(weaponType)) {
+ GetWeapon(weaponType).m_nAmmoTotal = ammo;
+ } else {
+ GetWeapon(weaponType).Initialise(weaponType, ammo);
+ m_maxWeaponTypeAllowed++;
+ }
+}
+
+void
+CPed::SetEvasiveStep(CEntity *reason, uint8 animType)
+{
+ AnimationId stepAnim;
+
+ if (m_nPedState == PED_STEP_AWAY || !IsPedInControl() || ((IsPlayer() || !bRespondsToThreats) && animType == 0))
+ return;
+
+ float angleToFace = CGeneral::GetRadianAngleBetweenPoints(
+ reason->GetPosition().x, reason->GetPosition().y,
+ GetPosition().x, GetPosition().y);
+ angleToFace = CGeneral::LimitRadianAngle(angleToFace);
+ m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur);
+ float neededTurn = Abs(angleToFace - m_fRotationCur);
+ bool vehPressedHorn = false;
+
+ if (neededTurn > PI)
+ neededTurn = 2 * PI - neededTurn;
+
+ CVehicle *veh = (CVehicle*)reason;
+ if (reason->IsVehicle() && veh->m_vehType == VEHICLE_TYPE_CAR) {
+ if (veh->m_nCarHornTimer) {
+ vehPressedHorn = true;
+ if (!IsPlayer())
+ animType = 1;
+ }
+ }
+ if (neededTurn <= DEGTORAD(90.0f) || veh->m_modelIndex == MI_RCBANDIT || vehPressedHorn || animType != 0) {
+ SetLookFlag(veh, 1);
+ if (CGeneral::GetRandomNumberInRange(0,1) && veh->m_modelIndex != MI_RCBANDIT && animType == 0) {
+ stepAnim = ANIM_IDLE_TAXI;
+ } else {
+
+ // I didn't get these things too much.
+ float vehDirection = CGeneral::GetRadianAngleBetweenPoints(
+ veh->m_vecMoveSpeed.x, veh->m_vecMoveSpeed.y,
+ 0.0f, 0.0f);
+
+ float inversedAngleToFace = angleToFace + PI;
+ if (inversedAngleToFace > PI)
+ inversedAngleToFace -= 2*PI;
+
+ neededTurn = inversedAngleToFace - vehDirection;
+ neededTurn = CGeneral::LimitRadianAngle(neededTurn);
+ if (neededTurn <= 0.0)
+ angleToFace = 0.5*PI + vehDirection;
+ else
+ angleToFace = vehDirection - 0.5*PI;
+
+ if (animType == 2)
+ stepAnim = ANIM_HANDSCOWER;
+ else if (animType < 2)
+ stepAnim = ANIM_EV_STEP;
+ else
+ stepAnim = NUM_ANIMS;
+ }
+ if (!RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, stepAnim)) {
+ CAnimBlendAssociation *stepAssoc = CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, stepAnim, 8.0f);
+ stepAssoc->flags &= ~ASSOC_DELETEFADEDOUT;
+ stepAssoc->SetFinishCallback(PedEvadeCB, this);
+
+ if (animType == 0)
+ Say(SOUND_PED_EVADE);
+
+ m_fRotationCur = CGeneral::LimitRadianAngle(angleToFace);
+ ClearAimFlag();
+ SetStoredState();
+ m_nPedState = PED_STEP_AWAY;
+ }
+ }
+}
+
WRAPPER void CPed::PedGetupCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE810); }
WRAPPER void CPed::PedStaggerCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8D0); }
WRAPPER void CPed::PedEvadeCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D36E0); }
@@ -2921,6 +4125,8 @@ WRAPPER void CPed::SetInCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(
WRAPPER void CPed::PedSetOutCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8F0); }
WRAPPER void CPed::PedAnimAlignCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DE130); }
WRAPPER void CPed::PedAnimStepOutCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DF5C0); }
+WRAPPER void CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation* dragAssoc, void* arg) { EAXJMP(0x4E2480); }
+WRAPPER void CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation* dragAssoc, void* arg) { EAXJMP(0x4E2920); }
WRAPPER void CPed::PedSetInTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E3290); }
WRAPPER void CPed::PedSetOutTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E36E0); }
WRAPPER void CPed::FinishFightMoveCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E9830); }
@@ -2928,7 +4134,6 @@ WRAPPER void CPed::PedAnimDoorCloseRollingCB(CAnimBlendAssociation *assoc, void
WRAPPER void CPed::FinishJumpCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D7A50); }
WRAPPER void CPed::PedLandCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8A0); }
WRAPPER void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4C6580); }
-WRAPPER void CPed::RestoreHeadingRateCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D6550); }
class CPed_ : public CPed
{
@@ -2999,4 +4204,38 @@ STARTPATCHES
InjectHook(0x4D1390, &CPed::TurnBody, PATCH_JUMP);
InjectHook(0x4D3AC0, &CPed::Chat, PATCH_JUMP);
InjectHook(0x4D0490, &CPed::CheckAroundForPossibleCollisions, PATCH_JUMP);
+ InjectHook(0x4D3E20, &CPed::MakePhonecall, PATCH_JUMP);
+ InjectHook(0x4D3CC0, &CPed::FacePhone, PATCH_JUMP);
+ InjectHook(0x4D4860, &CPed::CheckForDeadPeds, PATCH_JUMP);
+ InjectHook(0x4D4650, &CPed::CheckForExplosions, PATCH_JUMP);
+ InjectHook(0x4D47D0, &CPed::CheckForGunShots, PATCH_JUMP);
+ InjectHook(0x4E6990, &CPed::CheckForPointBlankPeds, PATCH_JUMP);
+ InjectHook(0x4D0BE0, &CPed::CheckIfInTheAir, PATCH_JUMP);
+ InjectHook(0x4C7F20, &CPed::ClearAll, PATCH_JUMP);
+ InjectHook(0x4E6790, &CPed::ClearAttack, PATCH_JUMP);
+ InjectHook(0x4E67F0, &CPed::ClearAttackByRemovingAnim, PATCH_JUMP);
+ InjectHook(0x4D37D0, &CPed::SetDie, PATCH_JUMP);
+ InjectHook(0x4C5D50, &CPed::StopNonPartialAnims, PATCH_JUMP);
+ InjectHook(0x4C5DB0, &CPed::SetStoredState, PATCH_JUMP);
+ InjectHook(0x4EA420, &CPed::InflictDamage, PATCH_JUMP);
+ InjectHook(0x4D1EA0, &CPed::ClearFlee, PATCH_JUMP);
+ InjectHook(0x4D0BB0, &CPed::ClearFall, PATCH_JUMP);
+ InjectHook(0x4D0F20, &CPed::SetGetUp, PATCH_JUMP);
+ InjectHook(0x4D6550, &CPed::RestoreHeadingRateCB, PATCH_JUMP);
+ InjectHook(0x4C5E30, &CPed::RestorePreviousState, PATCH_JUMP);
+ InjectHook(0x4E5F70, &CPed::SetPointGunAt, PATCH_JUMP);
+ InjectHook(0x4D2750, &CPed::SetWanderPath, PATCH_JUMP);
+ InjectHook(0x4D30C0, &CPed::SetEvasiveStep, PATCH_JUMP);
+ InjectHook(0x4EA360, &CPed::ClearInvestigateEvent, PATCH_JUMP);
+ InjectHook(0x4D8E80, &CPed::ClearLeader, PATCH_JUMP);
+ InjectHook(0x4D1360, &CPed::ClearLook, PATCH_JUMP);
+ InjectHook(0x4D8DF0, &CPed::ClearObjective, PATCH_JUMP);
+ InjectHook(0x4D0970, &CPed::ClearPause, PATCH_JUMP);
+ InjectHook(0x4D1620, &CPed::ClearSeek, PATCH_JUMP);
+ InjectHook(0x4CFB70, &CPed::ClearWeapons, PATCH_JUMP);
+ InjectHook(0x4C6BB0, &CPed::RestoreGunPosition, PATCH_JUMP);
+ InjectHook(0x4D6540, &CPed::RestoreHeadingRate, PATCH_JUMP);
+ InjectHook(0x4C69E0, (void (CPed::*)(CEntity*)) &CPed::SetAimFlag, PATCH_JUMP);
+ InjectHook(0x4C6960, (void (CPed::*)(float)) &CPed::SetAimFlag, PATCH_JUMP);
+ InjectHook(0x4CFB20, &CPed::SetAmmo, PATCH_JUMP);
ENDPATCHES
diff --git a/src/peds/Ped.h b/src/peds/Ped.h
index cd7d88af..7b8bc2ce 100644
--- a/src/peds/Ped.h
+++ b/src/peds/Ped.h
@@ -13,6 +13,17 @@
struct CPathNode;
+enum ePedPieceTypes
+{
+ PEDPIECE_TORSO,
+ PEDPIECE_MID,
+ PEDPIECE_LEFTARM,
+ PEDPIECE_RIGHTARM,
+ PEDPIECE_LEFTLEG,
+ PEDPIECE_RIGHTLEG,
+ PEDPIECE_HEAD,
+};
+
enum eWaitState {
WAITSTATE_FALSE,
WAITSTATE_TRAFFIC_LIGHTS,
@@ -196,28 +207,28 @@ public:
uint8 m_ped_flagC1 : 1;
uint8 bRespondsToThreats : 1;
- uint8 m_ped_flagC4 : 1; // false when in bus, bRenderPedInCar?
- uint8 m_ped_flagC8 : 1;
- uint8 m_ped_flagC10 : 1;
- uint8 m_ped_flagC20 : 1; // just left some body part?
+ uint8 bRenderPedInCar : 1;
+ uint8 bChangedSeat : 1;
+ uint8 m_ped_flagC10 : 1; // related with phone
+ uint8 bBodyPartJustCameOff : 1;
uint8 m_ped_flagC40 : 1;
uint8 m_ped_flagC80 : 1;
uint8 m_ped_flagD1 : 1;
- uint8 m_ped_flagD2 : 1;
+ uint8 m_ped_flagD2 : 1; // seen an event
uint8 m_ped_flagD4 : 1;
uint8 m_ped_flagD8 : 1;
- uint8 m_ped_flagD10 : 1;
+ uint8 bIsPedDieAnimPlaying : 1;
uint8 m_ped_flagD20 : 1;
uint8 m_ped_flagD40 : 1; // reset when objective changes
- uint8 m_ped_flagD80 : 1;
+ uint8 m_bScriptObjectiveCompleted : 1;
uint8 m_ped_flagE1 : 1;
uint8 m_ped_flagE2 : 1;
uint8 bNotAllowedToDuck : 1;
uint8 bCrouchWhenShooting : 1;
uint8 bIsDucking : 1; // set if you don't want ped to attack
- uint8 m_ped_flagE20 : 1;
+ uint8 m_ped_flagE20 : 1; // getup complete?
uint8 bDoBloodyFootprints : 1;
uint8 m_ped_flagE80 : 1;
@@ -225,7 +236,7 @@ public:
uint8 m_ped_flagF2 : 1;
uint8 m_ped_flagF4 : 1;
uint8 m_ped_flagF8 : 1;
- uint8 m_ped_flagF10 : 1;
+ uint8 m_ped_flagF10 : 1; // set before "quickjack"
uint8 m_ped_flagF20 : 1;
uint8 m_ped_flagF40 : 1;
uint8 m_ped_flagF80 : 1;
@@ -249,7 +260,7 @@ public:
uint8 m_ped_flagH80 : 1;
uint8 m_ped_flagI1 : 1;
- uint8 m_ped_flagI2 : 1;
+ uint8 m_ped_flagI2 : 1; // if set, limbs won't came off
uint8 m_ped_flagI4 : 1;
uint8 bHasAlreadyBeenRecorded : 1;
uint8 m_ped_flagI10 : 1;
@@ -325,10 +336,10 @@ public:
bool bInVehicle;
uint8 pad_315[3];
float field_318;
- uint8 field_31C;
+ uint8 field_31C; // may be cutscene or phone cutscene status
uint8 field_31D;
int16 m_phoneId;
- uint32 m_lookingForPhone;
+ uint32 m_lookingForPhone; // unused
uint32 m_phoneTalkTimer;
void *m_lastAccident;
int32 m_nPedType;
@@ -416,8 +427,8 @@ public:
void SetDie(AnimationId anim, float arg1, float arg2);
void SetDead(void);
void ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer);
- void RemoveBodyPart(PedNode nodeId, int8 unknown);
- void SpawnFlyingComponent(int, int8 unknown);
+ void RemoveBodyPart(PedNode nodeId, int8 direction);
+ void SpawnFlyingComponent(int, int8);
bool OurPedCanSeeThisOne(CEntity *target);
void Avoid(void);
void Attack(void);
@@ -459,7 +470,39 @@ public:
void Chat(void);
void MakeChangesForNewWeapon(int8);
void CheckAroundForPossibleCollisions(void);
+ void SetSeek(CVector, float);
+ bool MakePhonecall(void);
+ bool FacePhone(void);
+ CPed *CheckForDeadPeds(void);
+ bool CheckForExplosions(CVector2D &area);
+ CPed *CheckForGunShots(void);
+ uint8 CheckForPointBlankPeds(CPed*);
+ bool CheckIfInTheAir(void);
+ void ClearAll(void);
+ void SetPointGunAt(CEntity*);
bool Seek(void);
+ bool SetWanderPath(int8);
+ void SetFollowPath(CVector);
+ void ClearAttackByRemovingAnim(void);
+ void SetStoredState(void);
+ void StopNonPartialAnims(void);
+ bool InflictDamage(CEntity*, eWeaponType, float, ePedPieceTypes, uint8);
+ void ClearFlee(void);
+ void ClearFall(void);
+ void SetGetUp(void);
+ void ClearInvestigateEvent(void);
+ void ClearLeader(void);
+ void ClearLook(void);
+ void ClearObjective(void);
+ void ClearPause(void);
+ void ClearSeek(void);
+ void ClearWeapons(void);
+ void RestoreGunPosition(void);
+ void RestoreHeadingRate(void);
+ void SetAimFlag(CEntity* to);
+ void SetAimFlag(float angle);
+ void SetAmmo(eWeaponType weaponType, uint32 ammo);
+ void SetEvasiveStep(CEntity*, uint8);
// Static methods
static void GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float offset);
@@ -533,6 +576,7 @@ public:
static bool &bNastyLimbsCheat;
static bool &bPedCheat2;
static bool &bPedCheat3;
+ static CColPoint &ms_tempColPoint;
};
void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg);
diff --git a/src/peds/PedIK.cpp b/src/peds/PedIK.cpp
index 9b3f401f..3d5bcfb5 100644
--- a/src/peds/PedIK.cpp
+++ b/src/peds/PedIK.cpp
@@ -8,6 +8,8 @@ WRAPPER bool CPedIK::PointGunAtPosition(CVector *position) { EAXJMP(0x4ED920); }
WRAPPER void CPedIK::ExtractYawAndPitchLocal(RwMatrixTag*, float*, float*) { EAXJMP(0x4ED2C0); }
WRAPPER void CPedIK::ExtractYawAndPitchWorld(RwMatrixTag*, float*, float*) { EAXJMP(0x4ED140); }
+LimbMovementInfo &CPedIK::ms_torsoInfo = *(LimbMovementInfo*)0x5F9F8C;
+
CPedIK::CPedIK(CPed *ped)
{
m_ped = ped;
@@ -102,8 +104,61 @@ CPedIK::GetWorldMatrix(RwFrame *source, RwMatrix *destination)
return destination;
}
+// A helper function that adjusts "limb" parameter according to limitations. Doesn't move the limb.
+int8
+CPedIK::MoveLimb(LimbOrientation &limb, float approxPhi, float approxTheta, LimbMovementInfo &moveInfo)
+{
+ int result = 1;
+
+ // phi
+
+ if (limb.phi > approxPhi) {
+ limb.phi -= moveInfo.yawD;
+ } else if (limb.phi < approxPhi) {
+ limb.phi += moveInfo.yawD;
+ }
+
+ if (Abs(limb.phi - approxPhi) < moveInfo.yawD) {
+ limb.phi = approxPhi;
+ result = 2;
+ }
+ if (limb.phi > moveInfo.maxYaw || limb.phi < moveInfo.minYaw) {
+ limb.phi = clamp(limb.phi, moveInfo.minYaw, moveInfo.maxYaw);
+ result = 0;
+ }
+
+ // theta
+
+ if (limb.theta > approxTheta) {
+ limb.theta -= moveInfo.pitchD;
+ } else if (limb.theta < approxTheta) {
+ limb.theta += moveInfo.pitchD;
+ }
+
+ if (Abs(limb.theta - approxTheta) < moveInfo.pitchD)
+ limb.theta = approxTheta;
+ else
+ result = 1;
+
+ if (limb.theta > moveInfo.maxPitch || limb.theta < moveInfo.minPitch) {
+ limb.theta = clamp(limb.theta, moveInfo.minPitch, moveInfo.maxPitch);
+ result = 0;
+ }
+ return result;
+}
+
+bool
+CPedIK::RestoreGunPosn(void)
+{
+ int limbStatus = MoveLimb(m_torsoOrient, 0.0f, 0.0f, ms_torsoInfo);
+ RotateTorso(m_ped->m_pFrames[PED_MID], &m_torsoOrient, false);
+ return limbStatus == 2;
+}
+
STARTPATCHES
InjectHook(0x4ED0F0, &CPedIK::GetComponentPosition, PATCH_JUMP);
InjectHook(0x4ED060, &CPedIK::GetWorldMatrix, PATCH_JUMP);
InjectHook(0x4EDDB0, &CPedIK::RotateTorso, PATCH_JUMP);
+ InjectHook(0x4ED440, &CPedIK::MoveLimb, PATCH_JUMP);
+ InjectHook(0x4EDD70, &CPedIK::RestoreGunPosn, PATCH_JUMP);
ENDPATCHES \ No newline at end of file
diff --git a/src/peds/PedIK.h b/src/peds/PedIK.h
index e17d52eb..5f321280 100644
--- a/src/peds/PedIK.h
+++ b/src/peds/PedIK.h
@@ -9,6 +9,15 @@ struct LimbOrientation
float theta;
};
+struct LimbMovementInfo {
+ float maxYaw;
+ float minYaw;
+ float yawD;
+ float maxPitch;
+ float minPitch;
+ float pitchD;
+};
+
class CPed;
class CPedIK
@@ -28,6 +37,8 @@ public:
LimbOrientation m_lowerArmOrient;
int32 m_flags;
+ static LimbMovementInfo &ms_torsoInfo;
+
CPedIK(CPed *ped);
bool PointGunInDirection(float phi, float theta);
bool PointGunAtPosition(CVector *position);
@@ -36,5 +47,7 @@ public:
void RotateTorso(AnimBlendFrameData* animBlend, LimbOrientation* limb, bool changeRoll);
void ExtractYawAndPitchLocal(RwMatrixTag*, float*, float*);
void ExtractYawAndPitchWorld(RwMatrixTag*, float*, float*);
+ int8 MoveLimb(LimbOrientation &a1, float a2, float a3, LimbMovementInfo &a4);
+ bool RestoreGunPosn(void);
};
static_assert(sizeof(CPedIK) == 0x28, "CPedIK: error");
diff --git a/src/peds/PedPlacement.cpp b/src/peds/PedPlacement.cpp
index e9a3f7d9..f292f4fa 100644
--- a/src/peds/PedPlacement.cpp
+++ b/src/peds/PedPlacement.cpp
@@ -35,6 +35,13 @@ CPedPlacement::FindZCoorForPed(CVector* pos)
pos->z = 1.04f + zForPed;
}
+CEntity*
+CPedPlacement::IsPositionClearOfCars(CVector* pos)
+{
+ return CWorld::TestSphereAgainstWorld(*pos, 0.25f, false, true, true, false, false, false, false);
+}
+
STARTPATCHES
InjectHook(0x4EE340, &CPedPlacement::FindZCoorForPed, PATCH_JUMP);
+ InjectHook(0x4EE310, &CPedPlacement::IsPositionClearOfCars, PATCH_JUMP);
ENDPATCHES
diff --git a/src/peds/PedPlacement.h b/src/peds/PedPlacement.h
index 4bd48b62..1edb50b4 100644
--- a/src/peds/PedPlacement.h
+++ b/src/peds/PedPlacement.h
@@ -1,8 +1,10 @@
#pragma once
class CVector;
+class CEntity;
class CPedPlacement {
public:
static void FindZCoorForPed(CVector* pos);
+ static CEntity* IsPositionClearOfCars(CVector*);
}; \ No newline at end of file
diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp
index 4b484a7f..24eb4a35 100644
--- a/src/peds/PlayerPed.cpp
+++ b/src/peds/PlayerPed.cpp
@@ -13,6 +13,8 @@ WRAPPER void CPlayerPed::ReApplyMoveAnims(void) { EAXJMP(0x4F07C0); }
WRAPPER void CPlayerPed::SetupPlayerPed(int32) { EAXJMP(0x4EFB60); }
WRAPPER void CPlayerPed::DeactivatePlayerPed(int32) { EAXJMP(0x4EFC00); }
WRAPPER void CPlayerPed::ReactivatePlayerPed(int32) { EAXJMP(0x4EFC20); }
+WRAPPER void CPlayerPed::KeepAreaAroundPlayerClear(void) { EAXJMP(0x4F3460); }
+
void CPlayerPed::ClearWeaponTarget()
{
@@ -36,6 +38,22 @@ CPlayerPed::SetWantedLevelNoDrop(int32 level)
m_pWanted->SetWantedLevelNoDrop(level);
}
+// I don't know the actual purpose of parameter
+void
+CPlayerPed::AnnoyPlayerPed(bool itsPolice)
+{
+ if (m_pedStats->m_temper < 52) {
+ m_pedStats->m_temper++;
+ } else {
+ if (itsPolice) {
+ if (m_pedStats->m_temper < 55) {
+ m_pedStats->m_temper++;
+ } else {
+ m_pedStats->m_temper = 46;
+ }
+ }
+ }
+}
class CPlayerPed_ : public CPlayerPed
{
@@ -46,4 +64,5 @@ public:
STARTPATCHES
InjectHook(0x4EFB30, &CPlayerPed_::dtor, PATCH_JUMP);
InjectHook(0x4F28A0, &CPlayerPed::ClearWeaponTarget, PATCH_JUMP);
+ InjectHook(0x4F3700, &CPlayerPed::AnnoyPlayerPed, PATCH_JUMP);
ENDPATCHES
diff --git a/src/peds/PlayerPed.h b/src/peds/PlayerPed.h
index 51a45203..fa6d9d43 100644
--- a/src/peds/PlayerPed.h
+++ b/src/peds/PlayerPed.h
@@ -29,7 +29,7 @@ public:
bool m_bHasLockOnTarget;
int8 field_1406;
int8 field_1407;
- bool m_bAdrenalineTime;
+ uint32 m_bAdrenalineTime;
bool m_bCanBeDamaged;
int8 field_1413;
int8 field_1414;
@@ -45,6 +45,8 @@ public:
void ClearWeaponTarget();
void SetWantedLevel(int32 level);
void SetWantedLevelNoDrop(int32 level);
+ void KeepAreaAroundPlayerClear(void);
+ void AnnoyPlayerPed(bool);
static void SetupPlayerPed(int32);
static void DeactivatePlayerPed(int32);
diff --git a/src/render/Draw.h b/src/render/Draw.h
index ad14e5a9..75b2b75f 100644
--- a/src/render/Draw.h
+++ b/src/render/Draw.h
@@ -2,9 +2,12 @@
enum eAspectRatio
{
- AR_AUTO,
+ // Make sure these work the same as FrontEndMenuManager.m_PrefsUseWideScreen
+ // without widescreen support
AR_4_3,
AR_16_9,
+
+ AR_AUTO,
};
class CDraw
diff --git a/src/render/Fluff.cpp b/src/render/Fluff.cpp
index b1b8aa92..7c35319f 100644
--- a/src/render/Fluff.cpp
+++ b/src/render/Fluff.cpp
@@ -1,5 +1,830 @@
#include "common.h"
+#include "main.h"
#include "patcher.h"
#include "Fluff.h"
+#include "Camera.h"
+#include "Sprite.h"
+#include "Coronas.h"
+#include "General.h"
+#include "Timer.h"
+#include "Clock.h"
+#include "Weather.h"
+#include "Stats.h"
+#include "math/maths.h"
+#include "Frontend.h"
-WRAPPER void CMovingThings::Render(void) { EAXJMP(0x4FF210); }
+uint8 ScrollCharSet[59][5] = {
+ { 0x00, 0x00, 0x00, 0x00, 0x00 }, // ' '
+ { 0x00, 0x00, 0x1D, 0x00, 0x00 }, // '!'
+ { 0x00, 0x00, 0x00, 0x00, 0x00 }, // '"'
+ { 0x0A, 0x1F, 0x0A, 0x1F, 0x0A }, // '#'
+ { 0x00, 0x09, 0x1F, 0x12, 0x00 }, // '$'
+ { 0x18, 0x18, 0x00, 0x03, 0x03 }, // '%'
+ { 0x00, 0x00, 0x00, 0x00, 0x00 }, // '&'
+ { 0x00, 0x00, 0x00, 0x00, 0x00 }, // '''
+ { 0x01, 0x02, 0x04, 0x08, 0x10 }, // '('
+ { 0x00, 0x00, 0x18, 0x00, 0x00 }, // ')'
+ { 0x15, 0x04, 0x1F, 0x04, 0x15 }, // '*'
+ { 0x00, 0x04, 0x0E, 0x04, 0x00 }, // '+'
+ { 0x00, 0x00, 0x03, 0x00, 0x00 }, // ','
+ { 0x00, 0x04, 0x04, 0x04, 0x00 }, // '-'
+ { 0x00, 0x00, 0x01, 0x00, 0x00 }, // '.'
+ { 0x00, 0x00, 0x00, 0x00, 0x00 }, // '/'
+ { 0x0E, 0x11, 0x11, 0x11, 0x0E }, // '0'
+ { 0x01, 0x09, 0x1F, 0x01, 0x01 }, // '1'
+ { 0x03, 0x15, 0x15, 0x15, 0x09 }, // '2'
+ { 0x11, 0x11, 0x15, 0x15, 0x0A }, // '3'
+ { 0x02, 0x06, 0x0A, 0x1F, 0x02 }, // '4'
+ { 0x1D, 0x15, 0x15, 0x15, 0x12 }, // '5'
+ { 0x0E, 0x15, 0x15, 0x15, 0x12 }, // '6'
+ { 0x18, 0x10, 0x13, 0x14, 0x18 }, // '7'
+ { 0x0A, 0x15, 0x15, 0x15, 0x0A }, // '8'
+ { 0x08, 0x15, 0x15, 0x15, 0x0E }, // '9'
+ { 0x00, 0x00, 0x0A, 0x00, 0x00 }, // ':'
+ { 0x18, 0x18, 0x00, 0x03, 0x03 }, // ';'
+ { 0x04, 0x08, 0x1F, 0x08, 0x04 }, // '<'
+ { 0x00, 0x0A, 0x0A, 0x0A, 0x00 }, // '='
+ { 0x04, 0x02, 0x1F, 0x02, 0x04 }, // '>'
+ { 0x10, 0x10, 0x15, 0x14, 0x1D }, // '?'
+ { 0x00, 0x1C, 0x14, 0x1C, 0x00 }, // '@'
+ { 0x0F, 0x12, 0x12, 0x12, 0x0F }, // 'A'
+ { 0x1F, 0x15, 0x15, 0x15, 0x0A }, // 'B'
+ { 0x0E, 0x11, 0x11, 0x11, 0x0A }, // 'C'
+ { 0x1F, 0x11, 0x11, 0x11, 0x0E }, // 'D'
+ { 0x1F, 0x15, 0x15, 0x11, 0x11 }, // 'E'
+ { 0x1F, 0x14, 0x14, 0x10, 0x10 }, // 'F'
+ { 0x0E, 0x11, 0x15, 0x15, 0x06 }, // 'G'
+ { 0x1F, 0x04, 0x04, 0x04, 0x1F }, // 'H'
+ { 0x11, 0x11, 0x1F, 0x11, 0x11 }, // 'I'
+ { 0x02, 0x01, 0x01, 0x01, 0x1E }, // 'J'
+ { 0x1F, 0x04, 0x0C, 0x12, 0x01 }, // 'K'
+ { 0x1F, 0x01, 0x01, 0x01, 0x01 }, // 'L'
+ { 0x1F, 0x08, 0x06, 0x08, 0x1F }, // 'M'
+ { 0x1F, 0x08, 0x04, 0x02, 0x1F }, // 'N'
+ { 0x0E, 0x11, 0x11, 0x11, 0x0E }, // 'O'
+ { 0x1F, 0x12, 0x12, 0x12, 0x0C }, // 'P'
+ { 0x0C, 0x12, 0x12, 0x13, 0x0D }, // 'Q'
+ { 0x1F, 0x14, 0x14, 0x16, 0x09 }, // 'R'
+ { 0x09, 0x15, 0x15, 0x15, 0x02 }, // 'S'
+ { 0x10, 0x10, 0x1F, 0x10, 0x10 }, // 'T'
+ { 0x1E, 0x01, 0x01, 0x01, 0x1E }, // 'U'
+ { 0x1C, 0x02, 0x01, 0x02, 0x1C }, // 'V'
+ { 0x1E, 0x01, 0x06, 0x01, 0x1E }, // 'W'
+ { 0x11, 0x0A, 0x04, 0x0A, 0x11 }, // 'X'
+ { 0x18, 0x04, 0x03, 0x04, 0x18 }, // 'Y'
+ { 0x11, 0x13, 0x15, 0x19, 0x11 } // 'Z'
+};
+
+// ---------- CMovingThings ----------
+enum eScrollBarTypes
+{
+ SCROLL_BUSINESS,
+ SCROLL_TRAFFIC,
+ SCROLL_ENTERTAINMENT,
+ SCROLL_AIRPORT_DOORS,
+ SCROLL_AIRPORT_FRONT,
+ SCROLL_STORE,
+ SCROLL_USED_CARS
+};
+
+CScrollBar aScrollBars[11];
+CTowerClock aTowerClocks[2];
+CDigitalClock aDigitalClocks[3];
+
+void CMovingThings::Init()
+{
+ /*
+ * Some unused code about CMovingThing was here...
+ */
+
+ // Initialize scroll bars
+ aScrollBars[0].Init(CVector( 228.3f, -669.0f, 39.0f ), SCROLL_BUSINESS, 0.0, 0.5, 0.5, 255, 128, 0, 0.3);
+ aScrollBars[1].Init(CVector( 772.0f, 164.0f, -9.5f ), SCROLL_TRAFFIC, 0.0, 0.5, 0.25, 128, 255, 0, 0.3);
+ aScrollBars[2].Init(CVector(-1089.61f, -584.224f, 13.246f), SCROLL_AIRPORT_DOORS, 0.0, -0.1706, 0.107, 255, 0, 0, 0.11);
+ aScrollBars[3].Init(CVector(-1089.61f, -602.04602f, 13.246f), SCROLL_AIRPORT_DOORS, 0.0, -0.1706, 0.107, 0, 255, 0, 0.11);
+ aScrollBars[4].Init(CVector(-1089.61f, -619.81702f, 13.246f), SCROLL_AIRPORT_DOORS, 0.0, -0.1706, 0.107, 255, 128, 0, 0.11);
+ aScrollBars[5].Init(CVector(-754.578f, -633.50897f, 18.411f), SCROLL_AIRPORT_FRONT, 0.0, 0.591, 0.52, 100, 100, 255, 0.3);
+ aScrollBars[6].Init(CVector( -754.578f, -586.672f, 18.411f), SCROLL_AIRPORT_FRONT, 0.0, 0.591, 0.52, 100, 100, 255, 0.3);
+ aScrollBars[7].Init(CVector( 85.473f, -1069.512f, 30.5f ), SCROLL_STORE, 0.625, -0.3125, 0.727, 100, 100, 255, 0.5);
+ aScrollBars[8].Init(CVector( 74.823f, -1086.879f, 31.495f), SCROLL_ENTERTAINMENT, -0.2083, 0.1041, 0.5, 255, 255, 128, 0.3);
+ aScrollBars[9].Init(CVector( -36.459f, -1031.2371f, 32.534f), SCROLL_ENTERTAINMENT, -0.1442, 0.0721, 0.229, 150, 255, 50, 0.3);
+ aScrollBars[10].Init(CVector( 1208.0f, -62.208f, 19.157f), SCROLL_USED_CARS, 0.0642, -0.20365, 0.229, 255, 128, 0, 0.3);
+
+ // Initialize tower clocks
+ aTowerClocks[0].Init(CVector(59.4f, -1081.3f, 54.15f), -1.0f, 0.0f, 0, 0, 0, 80.0f, 2.0f);
+ aTowerClocks[1].Init(CVector(55.4f, -1083.6f, 54.15f), 0.0f, -1.0f, 0, 0, 0, 80.0f, 2.0f);
+
+ // Initialize digital clocks
+ CVector2D sz(3.7f, 2.144f);
+ sz.Normalise();
+ aDigitalClocks[0].Init(
+ CVector(54.485f - sz.x * 0.05f + sz.y * 0.3f, -1081.679f - sz.y * 0.05f - sz.x * 0.3f, 32.803f),
+ sz.y, -sz.x, 255, 0, 0, 100.0f, 0.8f
+ );
+ aDigitalClocks[1].Init(
+ CVector(60.564f + sz.x * 0.05f - sz.y * 0.3f, -1083.089f + sz.y * 0.05f + sz.x * 0.3f, 32.803f),
+ -sz.y, sz.x, 0, 0, 255, 100.0f, 0.8f
+ );
+ aDigitalClocks[2].Init(
+ CVector(58.145f - sz.y * 0.05f - sz.x * 0.3f, -1079.268f + sz.x * 0.05f - sz.y * 0.3f, 32.803f),
+ -sz.x, -sz.y, 0, 255, 0, 100.0f, 0.8f
+ );
+}
+
+void CMovingThings::Shutdown()
+{
+ int i;
+ for (i = 0; i < 11; ++i)
+ aScrollBars[i].SetVisibility(false);
+ for (i = 0; i < 2; ++i)
+ aTowerClocks[i].SetVisibility(false);
+ for (i = 0; i < 3; ++i)
+ aDigitalClocks[i].SetVisibility(false);
+}
+
+void CMovingThings::Update()
+{
+ /*
+ * Some unused code about CMovingThing was here...
+ */
+
+ int i;
+ for (i = 0; i < 11; ++i)
+ {
+ if (aScrollBars[i].IsVisible() || (CTimer::GetFrameCounter() + i) % 8 == 0)
+ aScrollBars[i].Update();
+ }
+ for (i = 0; i < 2; ++i)
+ {
+ if (aTowerClocks[i].IsVisible() || (CTimer::GetFrameCounter() + i) % 8 == 0)
+ aTowerClocks[i].Update();
+ }
+ for (i = 0; i < 3; ++i)
+ {
+ if (aDigitalClocks[i].IsVisible() || (CTimer::GetFrameCounter() + i) % 8 == 0)
+ aDigitalClocks[i].Update();
+ }
+}
+
+void CMovingThings::Render()
+{
+ int i;
+ for (i = 0; i < 11; ++i)
+ {
+ if (aScrollBars[i].IsVisible())
+ aScrollBars[i].Render();
+ }
+ for (i = 0; i < 2; ++i)
+ {
+ if (aTowerClocks[i].IsVisible())
+ aTowerClocks[i].Render();
+ }
+ for (i = 0; i < 3; ++i)
+ {
+ if (aDigitalClocks[i].IsVisible())
+ aDigitalClocks[i].Render();
+ }
+}
+
+// ---------- CMovingThing ----------
+WRAPPER void CMovingThing::Update() { EAXJMP(0x4FF290); }
+WRAPPER void CMovingThing::AddToList() { EAXJMP(0x4FF320); }
+WRAPPER void CMovingThing::RemoveFromList() { EAXJMP(0x4FF340); }
+
+// ---------- Find message functions ----------
+const char* FindTunnelMessage()
+{
+ if (CStats::CommercialPassed)
+ return "LIBERTY TUNNEL HAS BEEN OPENED TO ALL TRAFFIC . . . ";
+
+ if (CStats::IndustrialPassed)
+ return "FIRST PHASE LIBERTY TUNNEL HAS BEEN COMPLETED . . . ";
+
+ return "FIRST PHASE LIBERTY TUNNEL ABOUT TO BE COMPLETED . . . ";
+}
+
+const char* FindBridgeMessage()
+{
+ if (CStats::CommercialPassed)
+ return "STAUNTON LIFT BRIDGE IS OPERATIONAL AGAIN ";
+
+ if (CStats::IndustrialPassed)
+ return "LONG DELAYS BEHIND US AS CALLAHAN BRIDGE IS FIXED . . . STAUNTON LIFT BRIDGE STUCK OPEN ";
+
+ return "CHAOS AS CALLAHAN BRIDGE IS UNDER REPAIR. . . ";
+}
+
+char String_Time[] = "THE TIME IS 12:34 ";
+const char* FindTimeMessage()
+{
+ String_Time[12] = '0' + CClock::GetHours() / 10;
+ String_Time[13] = '0' + CClock::GetHours() % 10;
+ String_Time[15] = '0' + CClock::GetMinutes() / 10;
+ String_Time[16] = '0' + CClock::GetMinutes() % 10;
+ return String_Time;
+}
+
+char String_DigitalClock[] = "12:34";
+const char* FindDigitalClockMessage()
+{
+ if (((CTimer::GetTimeInMilliseconds() >> 10) & 7) < 6)
+ {
+ String_DigitalClock[0] = '0' + CClock::GetHours() / 10;
+ String_DigitalClock[1] = '0' + CClock::GetHours() % 10;
+ String_DigitalClock[2] = CTimer::GetTimeInMilliseconds() & 0x200 ? ':' : ' ';
+ String_DigitalClock[3] = '0' + CClock::GetMinutes() / 10;
+ String_DigitalClock[4] = '0' + CClock::GetMinutes() % 10;
+ }
+ else
+ {
+ int temperature = 13.0f - 6.0f * Cos((CClock::GetMinutes() + 60.0f * CClock::GetHours()) * 0.0043611112f - 1.0f);
+ String_DigitalClock[0] = '0' + temperature / 10;
+ if (String_DigitalClock[0] == '0')
+ String_DigitalClock[0] = ' ';
+ String_DigitalClock[1] = '0' + temperature % 10;
+ String_DigitalClock[2] = ' ';
+ String_DigitalClock[3] = '@';
+ String_DigitalClock[4] = 'C';
+ }
+ return String_DigitalClock;
+}
+
+// ---------- CScrollBar ----------
+void CScrollBar::Init(CVector position, uint8 type, float sizeX, float sizeY, float sizeZ, uint8 red, uint8 green, uint8 blue, float scale)
+{
+ for (int i = 0; i < 40; ++i)
+ m_MessageBar[i] = 0;
+
+ m_pMessage = ". ";
+ m_MessageCurrentChar = 0;
+ m_MessageLength = 2;
+
+ m_Counter = 0;
+ m_bVisible = false;
+ m_Position = position;
+ m_Type = type;
+ m_Size.x = sizeX;
+ m_Size.y = sizeY;
+ m_Size.z = sizeZ;
+ m_uRed = red;
+ m_uGreen = green;
+ m_uBlue = blue;
+ m_fScale = scale;
+}
+
+void CScrollBar::Update()
+{
+ float distanceFromCamera = (TheCamera.GetPosition() - m_Position).Magnitude();
+ if (distanceFromCamera > 100.0f)
+ {
+ m_bVisible = false;
+ return;
+ }
+
+ m_bVisible = true;
+
+ if (distanceFromCamera < 75.0f)
+ m_fIntensity = 1.0f;
+ else
+ m_fIntensity = 1.0f - 4.0f * (distanceFromCamera - 75.0f) / 100.0f;
+
+ m_Counter = (m_Counter + 1) % 8;
+
+ // if message is fully printed, load up the next one
+ if (m_Counter == 0 && ++m_MessageCurrentChar >= m_MessageLength)
+ {
+ const char* previousMessage = m_pMessage;
+ switch (m_Type)
+ {
+ case SCROLL_BUSINESS:
+ while (previousMessage == m_pMessage)
+ {
+ switch (CGeneral::GetRandomNumber() % 7)
+ {
+ case 0:
+ m_pMessage = "SHARES UYE<10% DWD<20% NDWE>22% . . . ";
+ break;
+ case 1:
+ m_pMessage = "CRIME WAVE HITS LIBERTY CITY . . . ";
+ break;
+ case 2:
+ m_pMessage = "SHARES OBR>29% MADD<76% LEZ<11% ADAMSKI>53% AAG>110%. . . ";
+ break;
+ case 3:
+ m_pMessage = FindTunnelMessage();
+ break;
+ case 4:
+ m_pMessage = FindBridgeMessage();
+ break;
+ case 5:
+ m_pMessage = FindTimeMessage();
+ break;
+ case 6:
+ if (CMenuManager::m_PrefsLanguage == LANGUAGE_FRENCH || CMenuManager::m_PrefsLanguage == LANGUAGE_GERMAN)
+ m_pMessage = FindTimeMessage();
+ else
+ m_pMessage = "WWW.GRANDTHEFTAUTO3.COM ";
+ break;
+ }
+ }
+ break;
+ case SCROLL_TRAFFIC:
+ while (previousMessage == m_pMessage)
+ {
+ switch (CGeneral::GetRandomNumber() % 8)
+ {
+ case 0:
+ m_pMessage = "DRIVE CAREFULLY . . . ";
+ break;
+ case 1:
+ m_pMessage = "RECENT WAVE OF CARJACKINGS. KEEP YOUR DOORS LOCKED !!! ";
+ break;
+ case 2:
+ m_pMessage = "CHECK YOUR SPEED . . . ";
+ break;
+ case 3:
+ m_pMessage = "KEEP YOUR EYES ON THE ROAD AND NOT ON THIS SIGN ";
+ break;
+ case 4:
+ if (CWeather::Foggyness > 0.5)
+ m_pMessage = "POOR VISIBILITY ! ";
+ else if (CWeather::WetRoads > 0.5)
+ m_pMessage = "ROADS ARE SLIPPERY ! ";
+ else
+ m_pMessage = "ENJOY YOUR TRIP ";
+ break;
+ case 5:
+ m_pMessage = FindTunnelMessage();
+ break;
+ case 6:
+ m_pMessage = FindBridgeMessage();
+ break;
+ case 7:
+ m_pMessage = FindTimeMessage();
+ break;
+ }
+ }
+ break;
+ case SCROLL_ENTERTAINMENT:
+ while (previousMessage == m_pMessage)
+ {
+ switch (CGeneral::GetRandomNumber() % 12)
+ {
+ case 0:
+ m_pMessage = " )69TH STREET) STILL HOLDS TOP POSITION THIS MONTH AT THE BOX-OFFICE WITH )MY FAIR LADYBOY) JUST CREEPING UP BEHIND. ";
+ break;
+ case 1:
+ m_pMessage = " TALKING OF )FANNIE). THERE IS STILL TIME TO CATCH THIS LOVELY FAMILY MUSICAL, ABOUT THE ORPHAN WHO IS SO EASILY TAKEN IN BY ANY MAN WITH LOADS OF MONEY. ";
+ break;
+ case 2:
+ m_pMessage = " DO NOT MISS )GTA3, THE MUSICAL) . . . ";
+ break;
+ case 3:
+ m_pMessage =
+ " STILL RUNNING ARE )RATS) AND )GUYS AND DOGS), BETWEEN THEN THEY SHOULD HAVE THE LEGS TO LAST TILL THE AND OF THE YEAR. . . "
+ " ALSO FOR FOUR LEGGED FANS, THE STAGE VERSION OF THE GRITTY REALISTIC )SATERDAY NIGHT BEAVER) OPENED LAST WEEKEND,"
+ " AND I FOR ONE CERTAINLY ENJOYED THAT. ";
+ break;
+ case 4:
+ m_pMessage =
+ " NOW SHOWING STATE-WIDE, ARNOLD STEELONE, HOLLYWOODS BEST LIVING SPECIAL EFFECT, APPEARS AGAIN AS A HALF_MAN,"
+ " HALF ANDROID IN THE HALF-BAKED ROMP, )TOP DOWN CITY). AN HOMAGE TO HIS EARLIER TWO MULTI_MILLION MAKING MOVIES,"
+ " IN WHICH HE PLAYED TWO-DEE, AN OUT OF CONTROL MONSTER, INTENT ON CORRUPTING CIVILISATION! ";
+ break;
+ case 5:
+ m_pMessage =
+ " ALSO APPEARING THIS WEEK )HALF-COCKED) SEES CHUCK SCHWARTZ UP TO HIS USUAL NONSENSE AS HE TAKES ON HALF OF LIBERTY CITY"
+ " IN AN ATTEMPT TO SAVE HIS CROSS-DRESSING LADY-BOY SIDEKICK, )MISS PING-PONG), FROM A GANG OF RUTHLESS COSMETIC SURGEONS. ";
+ break;
+ case 6:
+ m_pMessage =
+ " STILL SHOWING: )SOLDIERS OF MISFORTUNE), ATTROCIOUS ACTING WHICH SEES BOYZ 2 GIRLZ) TRANSITION FROM THE CHARTS TO THE BIG SCREEN,"
+ " AT LEAST THEY ALL DIE AT THE END. . . ";
+ break;
+ case 7:
+ m_pMessage =
+ " )BADFELLAS) IS STILL GOING STRONG WITH CROWDS ALMOST BEING PUSHED INTO CINEMAS TO SEE THIS ONE."
+ " ANOTHER ONE WORTH LOOKING INTO IS )THE TUNNEL). ";
+ break;
+ case 8:
+ m_pMessage = FindTunnelMessage();
+ break;
+ case 9:
+ m_pMessage = FindBridgeMessage();
+ break;
+ case 10:
+ m_pMessage = FindTimeMessage();
+ break;
+ case 11:
+ m_pMessage = "WWW.ROCKSTARGAMES.COM ";
+ break;
+ }
+ }
+ break;
+ case SCROLL_AIRPORT_DOORS:
+ while (previousMessage == m_pMessage)
+ {
+ switch (CGeneral::GetRandomNumber() % 4)
+ {
+ case 0:
+ m_pMessage = "WELCOME TO LIBERTY CITY . . . ";
+ break;
+ case 1:
+ m_pMessage = "PLEASE HAVE YOUR PASSPORT READY . . . ";
+ break;
+ case 2:
+ m_pMessage = "PLACE KEYS, FIREARMS, CHANGE AND OTHER METAL OBJECTS ON THE TRAY PLEASE . . . ";
+ break;
+ case 3:
+ m_pMessage = FindTimeMessage();
+ break;
+ }
+ }
+ break;
+ case SCROLL_AIRPORT_FRONT:
+ while (previousMessage == m_pMessage)
+ {
+ switch (CGeneral::GetRandomNumber() % 4)
+ {
+ case 0:
+ m_pMessage = "WELCOME TO FRANCIS INTERNATIONAL AIRPORT . . . ";
+ break;
+ case 1:
+ m_pMessage = "PLEASE DO NOT LEAVE LUGGAGE UNATTENDED . . . ";
+ break;
+ case 2:
+ m_pMessage = "FOLLOW 1 FOR LONG AND SHORT TERM PARKING ";
+ break;
+ case 3:
+ m_pMessage = FindTimeMessage();
+ break;
+ }
+ }
+ break;
+ case SCROLL_STORE:
+ while (previousMessage == m_pMessage)
+ {
+ switch (CGeneral::GetRandomNumber() % 10)
+ {
+ case 0:
+ m_pMessage = "WWW.ROCKSTARGAMES.COM ";
+ break;
+ case 1:
+ m_pMessage = "GTA3 OUT NOW . . . ";
+ break;
+ case 2:
+ m_pMessage = "OUR STUFF IS CHEAP CHEAP CHEAP ";
+ break;
+ case 3:
+ m_pMessage = "BUY 12 CDS GET ONE FREE . . . ";
+ break;
+ case 4:
+ m_pMessage = "APPEARING IN SHOP SOON, )THE BLOODY CHOPPERS), WITH THEIR NEW ALBUM, )IS THAT MY DAUGHTER?) ";
+ break;
+ case 5:
+ m_pMessage = "THIS MONTH IS OUR CRAZY CLEAROUT MONTH, EVERYTHING MUST GO, CDS, DVDS, STAFF, EVEN OUR CARPETS! ";
+ break;
+ case 6:
+ m_pMessage =
+ "OUT THIS WEEK: THE THEME TUNE TO )BOYS TO GIRLS) FIRST MOVIE )SOLDIERS OF MISFORTUNE), "
+ "THE SINGLE )LET ME IN YOU)RE BODY-BAG) IS TAKEN FROM THE SOUNDTRACK ALBUM, )BOOT CAMP BOYS). "
+ "ALSO INCLUDES THE SMASH SINGLE, )PRAY IT GOES OK). ";
+ break;
+ case 7:
+ m_pMessage =
+ "ALBUMS OUT THIS WEEK: MARYDANCING, )MUTHA O) CHRIST), FEATURING THE SINGLE )WASH HIM OFF), "
+ "ALSO CRAIG GRAYS) DEBUT, )FADE AWAY), INCLUDES THE SINGLE OF THE SAME NAME. . . ";
+ break;
+ case 8:
+ m_pMessage =
+ "ON THE FILM FRONT, A NELY COMPILED COMPILATION OF ARNOLD STEELONES GREATEST MOVIES ON DVD. "
+ "THE PACK INCLUDES THE EARLY )BY-CEP), THE CULT CLASSIC )FUTURE ANNHILATOR), AND THE HILARIOUS CROSS-DRESSING COMEDY )SISTERS). "
+ "ONE FOR ALL THE FAMILY. . . ";
+ break;
+ case 9:
+ m_pMessage = (char*)FindTimeMessage();
+ break;
+ }
+ }
+ break;
+ case SCROLL_USED_CARS:
+ while (previousMessage == m_pMessage)
+ {
+ switch (CGeneral::GetRandomNumber() % 11)
+ {
+ case 0:
+ m_pMessage = "QUICK, TAKE A LOOK AT OUR CURRENT STOCK )CAUSE THESE AUTOS ARE MOVIN) FAST . . . ";
+ break;
+ case 1:
+ m_pMessage = "THAT)S RIGHT, HERE AT )CAPITAL AUTO SALES) OUR VEHICLES ARE SO GOOD THAT THEY PRACTICALLY DRIVE THEMSELVES OFF OUR LOT . . . ";
+ break;
+ case 2:
+ m_pMessage = "EASY CREDIT ON ALL CARS . . . ";
+ break;
+ case 3:
+ m_pMessage = "FEEL LIKE A STUD IN ONE OF OUR STALLIONS OR TEST-DRIVE OUR BANSHEE, IT)S A REAL STEAL!!! ";
+ break;
+ case 4:
+ m_pMessage = "TRY OUR HARDY PERENNIAL, IT)LL LAST YOU THE WHOLE YEAR. OUR BOBCATS AIN)T NO PUSSIES EITHER!!! ";
+ break;
+ case 5:
+ m_pMessage = "IF IT)S A GUARANTEE YOU'RE AFTER, GO SOMEWHERE ELSE, )CAPITAL) CARS ARE THAT GOOD THEY DON)T NEED GUARANTEES!!! ";
+ break;
+ case 6:
+ m_pMessage = "TOP DOLLAR OFFERED FOR YOUR OLD WHEELS, NOT YOUR CAR, JUST IT)S WHEELS. . . ";
+ break;
+ case 7:
+ m_pMessage = "THAT)S RIGHT WE)RE CAR SILLY. TEST DRIVE ANY CAR, YOU WON)T WANT TO BRING IT BACK!!! ";
+ break;
+ case 8:
+ m_pMessage = "FREE FLUFFY DICE WITH ALL PURCHASES. . .";
+ break;
+ case 9:
+ if (CMenuManager::m_PrefsLanguage == LANGUAGE_FRENCH || CMenuManager::m_PrefsLanguage == LANGUAGE_GERMAN)
+ m_pMessage = "QUICK, TAKE A LOOK AT OUR CURRENT STOCK )CAUSE THESE AUTOS ARE MOVIN) FAST . . . ";
+ else
+ m_pMessage = "HTTP:((ROCKSTARGAMES.COM(GRANDTHEFTAUTO3(CAPITALAUTOS ";
+ break;
+ case 10:
+ m_pMessage = FindTimeMessage();
+ break;
+ }
+ }
+ break;
+ }
+
+ m_MessageLength = strlen(m_pMessage);
+ m_MessageCurrentChar = 0;
+ }
+
+ // Scroll
+ for (int i = 0; i < 39; i++)
+ m_MessageBar[i] = m_MessageBar[i + 1];
+ m_MessageBar[39] = m_Counter < 5 ? ScrollCharSet[m_pMessage[m_MessageCurrentChar] - ' '][m_Counter] : 0;
+
+ // Introduce some random displaying glitches; signs aren't supposed to be perfect :P
+ switch (CGeneral::GetRandomNumber() & 0xFF)
+ {
+ case 0x0D: m_MessageBar[39] = 0; break;
+ case 0xE3: m_MessageBar[39] = 0xE3; break;
+ case 0x64: m_MessageBar[39] = ~m_MessageBar[39]; break;
+ }
+}
+
+void CScrollBar::Render()
+{
+ if (!TheCamera.IsSphereVisible(m_Position, 2.0f * 20.0f * (ABS(m_Size.x) + ABS(m_Size.y))))
+ return;
+
+ CSprite::InitSpriteBuffer();
+
+ // Calculate intensity of colours
+ uint8 r = m_fIntensity * m_uRed;
+ uint8 g = m_fIntensity * m_uGreen;
+ uint8 b = m_fIntensity * m_uBlue;
+
+ // Set render states
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[0]));
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
+
+ CVector coronaCoord, screenCoord;
+ float screenW, screenH;
+ for (int i = 1; i < 40; ++i)
+ {
+ for (int j = 0; j < 5; ++j)
+ {
+ coronaCoord.x = m_Position.x + m_Size.x * i;
+ coronaCoord.y = m_Position.y + m_Size.y * i;
+ coronaCoord.z = m_Position.z + m_Size.z * j;
+
+ // Render main coronas
+ if (m_MessageBar[i] & (1 << j))
+ {
+ if (CSprite::CalcScreenCoors(coronaCoord, screenCoord, &screenW, &screenH, true))
+ {
+ CSprite::RenderBufferedOneXLUSprite(
+ screenCoord.x, screenCoord.y, screenCoord.z,
+ screenW * m_fScale, screenH * m_fScale,
+ r, g, b,
+ 255, 1.0f / screenCoord.z, 255);
+ }
+ }
+ // Render smaller and faded coronas for a trailing effect
+ else if (m_MessageBar[i - 1] & (1 << j))
+ {
+ if (CSprite::CalcScreenCoors(coronaCoord, screenCoord, &screenW, &screenH, true))
+ {
+ CSprite::RenderBufferedOneXLUSprite(
+ screenCoord.x, screenCoord.y, screenCoord.z,
+ screenW * m_fScale * 0.8f,
+ screenH * m_fScale * 0.8f,
+ r / 2,
+ g / 2,
+ b / 2,
+ 255, 1.0 / screenCoord.z, 255);
+ }
+ }
+ }
+ }
+
+ CSprite::FlushSpriteBuffer();
+}
+
+// ---------- CTowerClock ----------
+void CTowerClock::Init(CVector position, float sizeX, float sizeY, uint8 red, uint8 green, uint8 blue, float drawDistance, float scale)
+{
+ m_bVisible = false;
+ m_Position = position;
+ m_Size.x = sizeX;
+ m_Size.y = sizeY;
+ m_Size.z = 0.0f;
+ m_uRed = red;
+ m_uGreen = green;
+ m_uBlue = blue;
+ m_fDrawDistance = drawDistance;
+ m_fScale = scale;
+}
+
+void CTowerClock::Update()
+{
+ float distanceFromCamera = (TheCamera.GetPosition() - m_Position).Magnitude();
+ if (distanceFromCamera < m_fDrawDistance)
+ {
+ m_bVisible = true;
+ if (distanceFromCamera < 0.75f * m_fDrawDistance)
+ m_fIntensity = 1.0f;
+ else
+ m_fIntensity = 1.0f - (distanceFromCamera - 0.75f * m_fDrawDistance) * 4.0f / m_fDrawDistance;
+ }
+ else
+ m_bVisible = false;
+}
+
+RwIm3DVertex TempV[4];
+void CTowerClock::Render()
+{
+ if (TheCamera.IsSphereVisible(m_Position, m_fScale))
+ {
+ // Calculate angle for each clock index
+ float angleHour = 2.0f * (float)PI * (CClock::GetMinutes() + 60.0f * CClock::GetHours()) / 720.0f;
+ float angleMinute = 2.0f * (float)PI * (CClock::GetSeconds() + 60.0f * CClock::GetMinutes()) / 3600.0f;
+
+ // Prepare render states
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
+
+ // Set vertices colors
+ RwIm3DVertexSetRGBA(&TempV[0], m_uRed, m_uGreen, m_uBlue, (uint8)(m_fIntensity * 255.0f));
+ RwIm3DVertexSetRGBA(&TempV[1], m_uRed, m_uGreen, m_uBlue, (uint8)(m_fIntensity * 255.0f));
+ RwIm3DVertexSetRGBA(&TempV[2], m_uRed, m_uGreen, m_uBlue, (uint8)(m_fIntensity * 255.0f));
+ RwIm3DVertexSetRGBA(&TempV[3], m_uRed, m_uGreen, m_uBlue, (uint8)(m_fIntensity * 255.0f));
+
+ // Set vertices position
+ RwIm3DVertexSetPos(&TempV[0], m_Position.x, m_Position.y, m_Position.z);
+ RwIm3DVertexSetPos(
+ &TempV[1],
+ m_Position.x + Sin(angleMinute) * m_fScale * m_Size.x,
+ m_Position.y + Sin(angleMinute) * m_fScale * m_Size.y,
+ m_Position.z + Cos(angleMinute) * m_fScale;
+ );
+ RwIm3DVertexSetPos(&TempV[2], m_Position.x, m_Position.y, m_Position.z);
+ RwIm3DVertexSetPos(
+ &TempV[3],
+ m_Position.x + Sin(angleHour) * 0.75f * m_fScale * m_Size.x,
+ m_Position.y + Sin(angleHour) * 0.75f * m_fScale * m_Size.y,
+ m_Position.z + Cos(angleHour) * 0.75f * m_fScale;
+ );
+
+ LittleTest();
+
+ // Draw lines
+ if (RwIm3DTransform(TempV, 4, nil, 0))
+ {
+ RwIm3DRenderLine(0, 1);
+ RwIm3DRenderLine(2, 3);
+ RwIm3DEnd();
+ }
+ }
+}
+
+// ---------- CDigitalClock ----------
+void CDigitalClock::Init(CVector position, float sizeX, float sizeY, uint8 red, uint8 green, uint8 blue, float drawDistance, float scale)
+{
+ m_bVisible = false;
+ m_Position = position;
+ m_Size.x = sizeX;
+ m_Size.y = sizeY;
+ m_Size.z = 0.0f;
+ m_uRed = red;
+ m_uGreen = green;
+ m_uBlue = blue;
+ m_fDrawDistance = drawDistance;
+ m_fScale = scale;
+}
+
+void CDigitalClock::Update()
+{
+ float distanceFromCamera = (TheCamera.GetPosition() - m_Position).Magnitude();
+ if (distanceFromCamera < m_fDrawDistance)
+ {
+ m_bVisible = true;
+ if (distanceFromCamera < 0.75f * m_fDrawDistance)
+ m_fIntensity = 1.0f;
+ else
+ m_fIntensity = 1.0f - (distanceFromCamera - 0.75f * m_fDrawDistance) * 4.0f / m_fDrawDistance;
+ }
+ else
+ m_bVisible = false;
+}
+
+void CDigitalClock::Render()
+{
+ if (TheCamera.IsSphereVisible(m_Position, 5.0f * m_fScale))
+ {
+ CSprite::InitSpriteBuffer();
+
+ // Simulate flicker
+ float currentIntensity = m_fIntensity * CGeneral::GetRandomNumberInRange(0x300, 0x400) / 1024.0f;
+
+ uint8 r = currentIntensity * m_uRed;
+ uint8 g = currentIntensity * m_uGreen;
+ uint8 b = currentIntensity * m_uBlue;
+
+ // Set render states
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[0]));
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
+
+ const char* clockMessage = FindDigitalClockMessage();
+
+ CVector coronaCoord, screenCoord;
+ float screenW, screenH;
+ for (int c = 0; c < 5; ++c) // for each char to be displayed
+ {
+ for (int i = 0; i < 5; ++i) // for each column of coronas
+ {
+ for (int j = 0; j < 5; ++j) // for each row of coronas
+ {
+ if (ScrollCharSet[clockMessage[c] - ' '][i] & (1 << j))
+ {
+ coronaCoord.x = m_Position.x + (8 * c + i) * m_Size.x * m_fScale / 8.0f;
+ coronaCoord.y = m_Position.y + (8 * c + i) * m_Size.y * m_fScale / 8.0f;
+ coronaCoord.z = m_Position.z + j * m_fScale / 8.0f;
+
+ if (CSprite::CalcScreenCoors(coronaCoord, screenCoord, &screenW, &screenH, true))
+ {
+ CSprite::RenderBufferedOneXLUSprite(
+ screenCoord.x, screenCoord.y, screenCoord.z,
+ screenW * m_fScale * 0.12,
+ screenW * m_fScale * 0.12,
+ r, g, b,
+ 255,
+ 1.0 / screenCoord.z,
+ 255);
+ }
+ }
+ }
+ }
+ }
+
+ CSprite::FlushSpriteBuffer();
+ }
+}
+
+STARTPATCHES
+InjectHook(0x4FE7C0, &CMovingThings::Init, PATCH_JUMP);
+InjectHook(0x4FF020, &CMovingThings::Shutdown, PATCH_JUMP);
+InjectHook(0x4FF0D0, &CMovingThings::Update, PATCH_JUMP);
+InjectHook(0x4FF210, &CMovingThings::Render, PATCH_JUMP);
+
+InjectHook(0x4FF360, &FindTunnelMessage, PATCH_JUMP);
+InjectHook(0x4FF390, &FindBridgeMessage, PATCH_JUMP);
+InjectHook(0x4FF3C0, &FindTimeMessage, PATCH_JUMP);
+InjectHook(0x4FF450, &FindDigitalClockMessage, PATCH_JUMP);
+
+InjectHook(0x4FF610, &CScrollBar::Init, PATCH_JUMP);
+InjectHook(0x4FF6E0, &CScrollBar::Update, PATCH_JUMP);
+InjectHook(0x4FFCE0, &CScrollBar::Render, PATCH_JUMP);
+
+InjectHook(0x5000D0, &CTowerClock::Init, PATCH_JUMP);
+InjectHook(0x500130, &CTowerClock::Update, PATCH_JUMP);
+InjectHook(0x5001D0, &CTowerClock::Render, PATCH_JUMP);
+
+InjectHook(0x5004F0, &CDigitalClock::Init, PATCH_JUMP);
+InjectHook(0x500550, &CDigitalClock::Update, PATCH_JUMP);
+InjectHook(0x5005F0, &CDigitalClock::Render, PATCH_JUMP);
+ENDPATCHES \ No newline at end of file
diff --git a/src/render/Fluff.h b/src/render/Fluff.h
index 33532efa..f33b016e 100644
--- a/src/render/Fluff.h
+++ b/src/render/Fluff.h
@@ -1,7 +1,91 @@
#pragma once
+#include "common.h"
+#include "math/Vector.h"
class CMovingThings
{
public:
- static void Render(void);
+ static void Init();
+ static void Shutdown();
+ static void Update();
+ static void Render();
};
+
+class CMovingThing
+{
+public:
+ void Update();
+ void AddToList();
+ void RemoveFromList();
+};
+
+class CScrollBar
+{
+private:
+ uint8 m_Counter;
+ const char* m_pMessage;
+ CVector m_Position;
+ uint32 m_MessageCurrentChar;
+ uint32 m_MessageLength;
+ CVector m_Size;
+ float m_fIntensity;
+ uint8 m_MessageBar[40];
+ uint8 m_Type;
+ bool m_bVisible;
+ uint8 m_uRed;
+ uint8 m_uGreen;
+ uint8 m_uBlue;
+ float m_fScale;
+
+public:
+ void SetVisibility(bool visible) { m_bVisible = visible; }
+ bool IsVisible() { return m_bVisible; }
+
+ void Init(CVector, uint8, float, float, float, uint8, uint8, uint8, float);
+ void Update();
+ void Render();
+};
+
+class CTowerClock
+{
+private:
+ CVector m_Position;
+ CVector m_Size;
+ float m_fDrawDistance;
+ float m_fScale;
+ uint8 m_uRed;
+ uint8 m_uGreen;
+ uint8 m_uBlue;
+ bool m_bVisible;
+ float m_fIntensity;
+
+public:
+ void SetVisibility(bool visible) { m_bVisible = visible; }
+ bool IsVisible() { return m_bVisible; }
+
+ void Init(CVector, float, float, uint8, uint8, uint8, float, float);
+ void Update();
+ void Render();
+};
+
+class CDigitalClock
+{
+private:
+ CVector m_Position;
+ CVector m_Size;
+ float m_fDrawDistance;
+ float m_fScale;
+ uint8 m_uRed;
+ uint8 m_uGreen;
+ uint8 m_uBlue;
+ bool m_bVisible;
+ float m_fIntensity;
+
+public:
+ void SetVisibility(bool visible) { m_bVisible = visible; }
+ bool IsVisible() { return m_bVisible; }
+
+ void Init(CVector, float, float, uint8, uint8, uint8, float, float);
+ void Update();
+ void Render();
+}; \ No newline at end of file
diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp
index 81f27153..1db7b07c 100644
--- a/src/render/Hud.cpp
+++ b/src/render/Hud.cpp
@@ -325,7 +325,7 @@ void CHud::Draw()
else {
Clip = AmmoInClip;
- if (TotalAmmo - AmmoInClip > 9999)
+ if ((TotalAmmo - AmmoInClip) > 9999)
Ammo = 9999;
else
Ammo = TotalAmmo - AmmoInClip;
diff --git a/src/render/Lines.cpp b/src/render/Lines.cpp
new file mode 100644
index 00000000..ea433048
--- /dev/null
+++ b/src/render/Lines.cpp
@@ -0,0 +1,74 @@
+#include "common.h"
+#include "patcher.h"
+#include "main.h"
+#include "Lines.h"
+
+// This is super inefficient, why split the line into segments at all?
+void
+CLines::RenderLineWithClipping(float x1, float y1, float z1, float x2, float y2, float z2, uint32 c1, uint32 c2)
+{
+ static RwIm3DVertex v[2];
+#ifdef THIS_IS_STUPID
+ int i;
+ float f1, f2;
+ float len = sqrt(sq(x1-x2) + sq(y1-y2) + sq(z1-z2));
+ int numsegs = len/1.5f + 1.0f;
+
+ RwRGBA col1;
+ col1.red = c1>>24;
+ col1.green = c1>>16;
+ col1.blue = c1>>8;
+ col1.alpha = c1;
+ RwRGBA col2;
+ col2.red = c2>>24;
+ col2.green = c2>>16;
+ col2.blue = c2>>8;
+ col2.alpha = c2;
+
+ float dx = x2 - x1;
+ float dy = y2 - y1;
+ float dz = z2 - z1;
+ for(i = 0; i < numsegs; i++){
+ f1 = (float)i/numsegs;
+ f2 = (float)(i+1)/numsegs;
+
+ RwIm3DVertexSetRGBA(&v[0], (int)(col1.red + (col2.red-col1.red)*f1),
+ (int)(col1.green + (col2.green-col1.green)*f1),
+ (int)(col1.blue + (col2.blue-col1.blue)*f1),
+ (int)(col1.alpha + (col2.alpha-col1.alpha)*f1));
+ RwIm3DVertexSetRGBA(&v[1], (int)(col1.red + (col2.red-col1.red)*f2),
+ (int)(col1.green + (col2.green-col1.green)*f2),
+ (int)(col1.blue + (col2.blue-col1.blue)*f2),
+ (int)(col1.alpha + (col2.alpha-col1.alpha)*f2));
+ RwIm3DVertexSetPos(&v[0], x1 + dx*f1, y1 + dy*f1, z1 + dz*f1);
+ RwIm3DVertexSetPos(&v[1], x1 + dx*f2, y1 + dy*f2, z1 + dz*f2);
+
+ LittleTest();
+ if(RwIm3DTransform(v, 2, nil, 0)){
+ RwIm3DRenderLine(0, 1);
+ RwIm3DEnd();
+ }
+ }
+#else
+ RwRGBA col1;
+ col1.red = c1>>24;
+ col1.green = c1>>16;
+ col1.blue = c1>>8;
+ col1.alpha = c1;
+ RwRGBA col2;
+ col2.red = c2>>24;
+ col2.green = c2>>16;
+ col2.blue = c2>>8;
+ col2.alpha = c2;
+
+ RwIm3DVertexSetRGBA(&v[0], col1.red, col1.green, col1.blue, col1.alpha);
+ RwIm3DVertexSetRGBA(&v[1], col2.red, col2.green, col2.blue, col2.alpha);
+ RwIm3DVertexSetPos(&v[0], x1, y1, z1);
+ RwIm3DVertexSetPos(&v[1], x2, y2, z2);
+ LittleTest();
+ if(RwIm3DTransform(v, 2, nil, 0)){
+ RwIm3DRenderLine(0, 1);
+ RwIm3DEnd();
+ }
+#endif
+}
diff --git a/src/render/Lines.h b/src/render/Lines.h
new file mode 100644
index 00000000..f2694fc0
--- /dev/null
+++ b/src/render/Lines.h
@@ -0,0 +1,7 @@
+#pragma once
+
+class CLines
+{
+public:
+ static void RenderLineWithClipping(float x1, float y1, float z1, float x2, float y2, float z2, uint32 c1, uint32 c2);
+};
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index 69df63ba..7bf4593f 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -23,11 +23,13 @@
bool gbShowPedRoadGroups;
bool gbShowCarRoadGroups;
bool gbShowCollisionPolys;
+bool gbShowCollisionLines;
bool gbDontRenderBuildings;
bool gbDontRenderBigBuildings;
bool gbDontRenderPeds;
bool gbDontRenderObjects;
+bool gbDontRenderVehicles;
struct EntityInfo
{
@@ -132,6 +134,10 @@ CRenderer::RenderOneNonRoad(CEntity *e)
else if(e->IsObject() || e->IsDummy()){
if(gbDontRenderObjects)
return;
+ }else if(e->IsVehicle()){
+ // re3 addition
+ if(gbDontRenderVehicles)
+ return;
}
#endif
@@ -285,6 +291,21 @@ CRenderer::RenderFadingInEntities(void)
CVisibilityPlugins::RenderFadingEntities();
}
+void
+CRenderer::RenderCollisionLines(void)
+{
+ int i;
+
+ // game doesn't draw fading in entities
+ // this should probably be fixed
+ for(i = 0; i < ms_nNoOfVisibleEntities; i++){
+ CEntity *e = ms_aVisibleEntityPtrs[i];
+ if(Abs(e->GetPosition().x - ms_vecCameraPosition.x) < 100.0f &&
+ Abs(e->GetPosition().y - ms_vecCameraPosition.y) < 100.0f)
+ CCollision::DrawColModel(e->GetMatrix(), *e->GetColModel());
+ }
+}
+
enum Visbility
{
VIS_INVISIBLE,
diff --git a/src/render/Renderer.h b/src/render/Renderer.h
index 4b96c775..817cdaae 100644
--- a/src/render/Renderer.h
+++ b/src/render/Renderer.h
@@ -5,11 +5,13 @@ class CEntity;
extern bool gbShowPedRoadGroups;
extern bool gbShowCarRoadGroups;
extern bool gbShowCollisionPolys;
+extern bool gbShowCollisionLines;
extern bool gbDontRenderBuildings;
extern bool gbDontRenderBigBuildings;
extern bool gbDontRenderPeds;
extern bool gbDontRenderObjects;
+extern bool gbDontRenderVehicles;
class CVehicle;
class CPtrList;
@@ -23,7 +25,9 @@ class CRenderer
static CVector &ms_vecCameraPosition;
static CVehicle *&m_pFirstPersonVehicle;
+
public:
+ static float &ms_lodDistScale; // defined in Frontend.cpp
static bool &m_loadingPriority;
static void Init(void);
@@ -39,6 +43,8 @@ public:
static void RenderOneNonRoad(CEntity *);
static void RenderFirstPersonVehicle(void);
+ static void RenderCollisionLines(void);
+
static int32 SetupEntityVisibility(CEntity *ent);
static int32 SetupBigBuildingVisibility(CEntity *ent);
diff --git a/src/render/Rubbish.cpp b/src/render/Rubbish.cpp
index 975f2554..c925df1c 100644
--- a/src/render/Rubbish.cpp
+++ b/src/render/Rubbish.cpp
@@ -3,3 +3,4 @@
#include "Rubbish.h"
WRAPPER void CRubbish::Render(void) { EAXJMP(0x512190); }
+WRAPPER void CRubbish::StirUp(CVehicle *veh) { EAXJMP(0x512690); }
diff --git a/src/render/Rubbish.h b/src/render/Rubbish.h
index f4f976e9..9f946dc2 100644
--- a/src/render/Rubbish.h
+++ b/src/render/Rubbish.h
@@ -1,7 +1,10 @@
#pragma once
+class CVehicle;
+
class CRubbish
{
public:
static void Render(void);
+ static void StirUp(CVehicle *veh); // CAutomobile on PS2
};
diff --git a/src/render/WaterLevel.cpp b/src/render/WaterLevel.cpp
index 07c88d3e..247b9f3d 100644
--- a/src/render/WaterLevel.cpp
+++ b/src/render/WaterLevel.cpp
@@ -1,4 +1,5 @@
#include "common.h"
+#include "main.h"
#include "FileMgr.h"
#include "TxdStore.h"
#include "Timer.h"
@@ -172,9 +173,8 @@ CWaterLevel::CreateWavyAtomic()
{
wavyMorphTarget = RpGeometryGetMorphTarget(wavyGeometry, 0);
- wavyVert = RpMorphTargetGetVertices(wavyMorphTarget);
-
ASSERT(wavyMorphTarget != NULL);
+ wavyVert = RpMorphTargetGetVertices(wavyMorphTarget);
ASSERT(wavyVert != NULL);
for ( int32 i = 0; i < 9; i++ )
@@ -1148,10 +1148,10 @@ CWaterLevel::AllocateBoatWakeArray()
ASSERT(ms_pWavyAtomic != NULL );
RpGeometry *wavyGeometry = RpAtomicGetGeometry(ms_pWavyAtomic);
+ ASSERT(wavyGeometry != NULL );
RpMorphTarget *wavyMorphTarget = RpGeometryGetMorphTarget(wavyGeometry, 0);
RpMaterial *wavyMaterial = RpGeometryGetMaterial(wavyGeometry, 0);
- ASSERT(wavyGeometry != NULL );
ASSERT(wavyMorphTarget != NULL );
ASSERT(wavyMaterial != NULL );
@@ -1240,7 +1240,7 @@ STARTPATCHES
InjectHook(0x554FE0, &CWaterLevel::Shutdown, PATCH_JUMP);
InjectHook(0x555010, &CWaterLevel::CreateWavyAtomic, PATCH_JUMP);
InjectHook(0x5552A0, &CWaterLevel::DestroyWavyAtomic, PATCH_JUMP);
- InjectHook(0x5552C0, &CWaterLevel::GetWaterLevel, PATCH_JUMP);
+ InjectHook(0x5552C0, (bool (*)(float,float,float,float*,bool))&CWaterLevel::GetWaterLevel, PATCH_JUMP);
InjectHook(0x555440, &CWaterLevel::GetWaterLevelNoWaves, PATCH_JUMP);
InjectHook(0x5554E0, &CWaterLevel::RenderWater, PATCH_JUMP);
InjectHook(0x556C30, &CWaterLevel::RenderOneFlatSmallWaterPoly, PATCH_JUMP);
diff --git a/src/render/WaterLevel.h b/src/render/WaterLevel.h
index b8ec7a4d..afc6eac3 100644
--- a/src/render/WaterLevel.h
+++ b/src/render/WaterLevel.h
@@ -82,6 +82,7 @@ public:
static void CreateWavyAtomic();
static void DestroyWavyAtomic();
static bool GetWaterLevel(float fX, float fY, float fZ, float *pfOutLevel, bool bDontCheckZ);
+ static bool GetWaterLevel(CVector coors, float *pfOutLevel, bool bDontCheckZ) { return GetWaterLevel(coors.x, coors.y, coors.z, pfOutLevel, bDontCheckZ); }
static bool GetWaterLevelNoWaves(float fX, float fY, float fZ, float *pfOutLevel);
static void RenderWater();
static void RenderOneFlatSmallWaterPoly (float fX, float fY, float fZ, RwRGBA const &color);
diff --git a/src/skel/events.cpp b/src/skel/events.cpp
index 877b969e..60e1482e 100644
--- a/src/skel/events.cpp
+++ b/src/skel/events.cpp
@@ -775,7 +775,7 @@ HandlePadButtonUp(RsPadButtonStatus *padButtonStatus)
bool bCam = false;
int16 mode = TheCamera.Cams[TheCamera.ActiveCam].Mode;
if ( mode == CCam::MODE_FLYBY || mode == CCam::MODE_FIXED )
- bool bCam = true;
+ bCam = true;
ControlsManager.UpdateJoyButtonState(padNumber);
diff --git a/src/skel/win/win.rc b/src/skel/win/win.rc
index 051f31ed..676b8ef7 100644
--- a/src/skel/win/win.rc
+++ b/src/skel/win/win.rc
@@ -4,11 +4,11 @@
//
// Generated from the TEXTINCLUDE 2 resource.
//
-#if !defined(__GNU_C__)
-#include "afxres.h"
-#else
+//#if !defined(__GNU_C__)
+//#include "afxres.h"
+//#else
#include "winresrc.h"
-#endif /* !defined(__GNU_C__) */
+//#endif /* !defined(__GNU_C__) */
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp
index 7d3f8ee3..fb42e6e6 100644
--- a/src/vehicles/Automobile.cpp
+++ b/src/vehicles/Automobile.cpp
@@ -1,32 +1,187 @@
#include "common.h"
+#include "main.h"
#include "patcher.h"
#include "General.h"
+#include "RwHelper.h"
+#include "Pad.h"
#include "ModelIndices.h"
#include "VisibilityPlugins.h"
#include "DMAudio.h"
#include "Camera.h"
#include "Darkel.h"
+#include "Rubbish.h"
#include "Fire.h"
#include "Explosion.h"
+#include "Particle.h"
#include "World.h"
#include "SurfaceTable.h"
#include "HandlingMgr.h"
+#include "Record.h"
+#include "Remote.h"
+#include "Population.h"
#include "CarCtrl.h"
+#include "CarAI.h"
+#include "Garages.h"
#include "PathFind.h"
+#include "AnimManager.h"
+#include "RpAnimBlend.h"
#include "Ped.h"
#include "PlayerPed.h"
#include "Object.h"
#include "Automobile.h"
+bool bAllCarCheat; // unused
+
RwObject *GetCurrentAtomicObjectCB(RwObject *object, void *data);
bool &CAutomobile::m_sAllTaxiLights = *(bool*)0x95CD21;
-WRAPPER CAutomobile* CAutomobile::ctor(int, uint8) { EAXJMP(0x52C6B0); }
-
-CAutomobile::CAutomobile(int mi, uint8 CreatedBy)
+CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
+ : CVehicle(CreatedBy)
{
- ctor(mi, CreatedBy);
+ int i;
+
+ m_vehType = VEHICLE_TYPE_CAR;
+
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(id);
+ m_fFireBlowUpTimer = 0.0f;
+ field_4E0 = 0;
+ bTaxiLight = m_sAllTaxiLights;
+ m_auto_flagA20 = false;
+ m_auto_flagA40 = false;
+ m_auto_flagA80 = false;
+
+ SetModelIndex(id);
+
+ pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)mi->m_handlingId);
+
+ field_49C = 20.0f;
+ field_4D8 = 0;
+
+ mi->ChooseVehicleColour(m_currentColour1, m_currentColour2);
+
+ bIsVan = !!(pHandling->Flags & HANDLING_IS_VAN);
+ bIsBig = !!(pHandling->Flags & HANDLING_IS_BIG);
+ bIsBus = !!(pHandling->Flags & HANDLING_IS_BUS);
+ bLowVehicle = !!(pHandling->Flags & HANDLING_IS_LOW);
+
+ // Doors
+ if(bIsBus){
+ Doors[DOOR_FRONT_LEFT].Init(-HALFPI, 0.0f, 0, 2);
+ Doors[DOOR_FRONT_RIGHT].Init(0.0f, HALFPI, 1, 2);
+ }else{
+ Doors[DOOR_FRONT_LEFT].Init(-PI*0.4f, 0.0f, 0, 2);
+ Doors[DOOR_FRONT_RIGHT].Init(0.0f, PI*0.4f, 1, 2);
+ }
+ if(bIsVan){
+ Doors[DOOR_REAR_LEFT].Init(-HALFPI, 0.0f, 1, 2);
+ Doors[DOOR_REAR_RIGHT].Init(0.0f, HALFPI, 0, 2);
+ }else{
+ Doors[DOOR_REAR_LEFT].Init(-PI*0.4f, 0.0f, 0, 2);
+ Doors[DOOR_REAR_RIGHT].Init(0.0f, PI*0.4f, 1, 2);
+ }
+ if(pHandling->Flags & HANDLING_REV_BONNET)
+ Doors[DOOR_BONNET].Init(-PI*0.3f, 0.0f, 1, 0);
+ else
+ Doors[DOOR_BONNET].Init(0.0f, PI*0.3f, 1, 0);
+ if(pHandling->Flags & HANDLING_HANGING_BOOT)
+ Doors[DOOR_BOOT].Init(PI*0.4f, 0.0f, 0, 0);
+ else if(pHandling->Flags & HANDLING_TAILGATE_BOOT)
+ Doors[DOOR_BOOT].Init(0.0, HALFPI, 1, 0);
+ else
+ Doors[DOOR_BOOT].Init(-PI*0.3f, 0.0f, 1, 0);
+ if(pHandling->Flags & HANDLING_NO_DOORS){
+ Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_MISSING);
+ Damage.SetDoorStatus(DOOR_FRONT_RIGHT, DOOR_STATUS_MISSING);
+ Damage.SetDoorStatus(DOOR_REAR_LEFT, DOOR_STATUS_MISSING);
+ Damage.SetDoorStatus(DOOR_REAR_RIGHT, DOOR_STATUS_MISSING);
+ }
+
+ for(i = 0; i < 6; i++)
+ m_randomValues[i] = CGeneral::GetRandomNumberInRange(-0.15f, 0.15f);
+
+ m_fMass = pHandling->fMass;
+ m_fTurnMass = pHandling->fTurnMass;
+ m_vecCentreOfMass = pHandling->CentreOfMass;
+ m_fAirResistance = pHandling->Dimension.x*pHandling->Dimension.z/m_fMass;
+ m_fElasticity = 0.05f;
+ m_fBuoyancy = pHandling->fBuoyancy;
+
+ m_nBusDoorTimerEnd = 0;
+ m_nBusDoorTimerStart = 0;
+
+ m_fSteerAngle = 0.0f;
+ m_fGasPedal = 0.0f;
+ m_fBrakePedal = 0.0f;
+ m_pSetOnFireEntity = nil;
+ field_594 = 0;
+ bNotDamagedUpsideDown = false;
+ bMoreResistantToDamage = false;
+ m_fVelocityChangeForAudio = 0.f;
+ field_4E2 = 0;
+
+ for(i = 0; i < 4; i++){
+ m_aGroundPhysical[i] = nil;
+ m_aGroundOffset[i] = CVector(0.0f, 0.0f, 0.0f);
+ m_aSuspensionSpringRatio[i] = 1.0f;
+ m_aSuspensionSpringRatioPrev[i] = m_aSuspensionSpringRatio[i];
+ m_aWheelTimer[i] = 0.0f;
+ m_aWheelRotation[i] = 0.0f;
+ m_aWheelSpeed[i] = 0.0f;
+ m_aWheelState[i] = WHEEL_STATE_0;
+ m_aWheelSkidmarkMuddy[i] = false;
+ m_aWheelSkidmarkBloody[i] = false;
+ }
+
+ m_nWheelsOnGround = 0;
+ m_nDriveWheelsOnGround = 0;
+ m_nDriveWheelsOnGroundPrev = 0;
+ m_fHeightAboveRoad = 0.0f;
+ m_fTraction = 1.0f;
+
+ CColModel *colModel = mi->GetColModel();
+ if(colModel->lines == nil){
+ colModel->lines = (CColLine*)RwMalloc(4*sizeof(CColLine));
+ colModel->numLines = 4;
+ }
+
+ SetupSuspensionLines();
+
+ m_status = STATUS_SIMPLE;
+ bUseCollisionRecords = true;
+
+ m_nNumPassengers = 0;
+
+ m_bombType = CARBOMB_NONE;
+ bHadDriver = false;
+ m_pBombRigger = nil;
+
+ if(m_nDoorLock == CARLOCK_UNLOCKED &&
+ (id == MI_POLICE || id == MI_ENFORCER || id == MI_RHINO))
+ m_nDoorLock = CARLOCK_LOCKED_INITIALLY;
+
+ m_fCarGunLR = 0.0f;
+ m_fCarGunUD = 0.05f;
+ m_fWindScreenRotation = 0.0f;
+ m_weaponDoorTimerLeft = 0.0f;
+ m_weaponDoorTimerRight = m_weaponDoorTimerLeft;
+
+ if(GetModelIndex() == MI_DODO){
+ RpAtomicSetFlags(GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]), 0);
+ CMatrix mat1;
+ mat1.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF]));
+ CMatrix mat2(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LF]));
+ mat1.GetPosition() += CVector(mat2.GetPosition().x + 0.1f, 0.0f, mat2.GetPosition().z);
+ mat1.UpdateRW();
+ }else if(GetModelIndex() == MI_MIAMI_SPARROW || GetModelIndex() == MI_MIAMI_RCRAIDER){
+ RpAtomicSetFlags(GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]), 0);
+ RpAtomicSetFlags(GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]), 0);
+ RpAtomicSetFlags(GetFirstObject(m_aCarNodes[CAR_WHEEL_LB]), 0);
+ RpAtomicSetFlags(GetFirstObject(m_aCarNodes[CAR_WHEEL_RB]), 0);
+ }else if(GetModelIndex() == MI_RHINO){
+ bExplosionProof = true;
+ bBulletProof = true;
+ }
}
@@ -37,7 +192,998 @@ CAutomobile::SetModelIndex(uint32 id)
SetupModelNodes();
}
-WRAPPER void CAutomobile::ProcessControl(void) { EAXJMP(0x531470); }
+CVector vecDAMAGE_ENGINE_POS_SMALL(-0.1f, -0.1f, 0.0f);
+CVector vecDAMAGE_ENGINE_POS_BIG(-0.5f, -0.3f, 0.0f);
+
+void
+CAutomobile::ProcessControl(void)
+{
+ int i;
+ CColModel *colModel;
+
+ if(m_veh_flagC80)
+ colModel = &CWorld::Players[CWorld::PlayerInFocus].m_ColModel;
+ else
+ colModel = GetColModel();
+ bWarnedPeds = false;
+
+ // skip if the collision isn't for the current level
+ if(colModel->level > LEVEL_NONE && colModel->level != CCollision::ms_collisionInMemory)
+ return;
+
+ // Improve grip of vehicles in certain cases
+ bool strongGrip1 = false;
+ bool strongGrip2 = false;
+ if(FindPlayerVehicle() && this != FindPlayerVehicle()){
+ switch(AutoPilot.m_nCarMission){
+ case MISSION_RAMPLAYER_FARAWAY:
+ case MISSION_RAMPLAYER_CLOSE:
+ case MISSION_BLOCKPLAYER_FARAWAY:
+ case MISSION_BLOCKPLAYER_CLOSE:
+ if(FindPlayerSpeed().Magnitude() > 0.3f){
+ strongGrip1 = true;
+ if(FindPlayerSpeed().Magnitude() > 0.4f){
+ if(m_vecMoveSpeed.Magnitude() < 0.3f)
+ strongGrip2 = true;
+ }else{
+ if((GetPosition() - FindPlayerCoors()).Magnitude() > 50.0f)
+ strongGrip2 = true;
+ }
+ }
+ }
+ }
+
+ if(bIsBus)
+ ProcessAutoBusDoors();
+
+ ProcessCarAlarm();
+
+ // Scan if this car is committing a crime that the police can see
+ if(m_status != STATUS_ABANDONED && m_status != STATUS_WRECKED &&
+ m_status != STATUS_PLAYER && m_status != STATUS_PLAYER_REMOTE && m_status != STATUS_PLAYER_DISABLED){
+ switch(GetModelIndex())
+ case MI_FBICAR:
+ case MI_POLICE:
+ case MI_ENFORCER:
+ case MI_SECURICA:
+ case MI_RHINO:
+ case MI_BARRACKS:
+ ScanForCrimes();
+ }
+
+ // Process driver
+ if(pDriver){
+ if(!bHadDriver && m_bombType == CARBOMB_ONIGNITIONACTIVE){
+ // If someone enters the car and there is a bomb, detonate
+ m_nBombTimer = 1000;
+ m_pBlowUpEntity = m_pBombRigger;
+ if(m_pBlowUpEntity)
+ m_pBlowUpEntity->RegisterReference((CEntity**)&m_pBlowUpEntity);
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_BOMB_TICK, 1.0f);
+ }
+ bHadDriver = true;
+
+ if(IsUpsideDown() && CanPedEnterCar()){
+ if(!pDriver->IsPlayer() &&
+ !(pDriver->m_leader && pDriver->m_leader->bInVehicle) &&
+ pDriver->CharCreatedBy != MISSION_CHAR)
+ pDriver->SetObjective(OBJECTIVE_LEAVE_VEHICLE, this);
+ }
+ }else
+ bHadDriver = false;
+
+ // Process passengers
+ if(m_nNumPassengers != 0 && IsUpsideDown() && CanPedEnterCar()){
+ for(i = 0; i < m_nNumMaxPassengers; i++)
+ if(pPassengers[i])
+ if(!pPassengers[i]->IsPlayer() &&
+ !(pPassengers[i]->m_leader && pPassengers[i]->m_leader->bInVehicle) &&
+ pPassengers[i]->CharCreatedBy != MISSION_CHAR)
+ pPassengers[i]->SetObjective(OBJECTIVE_LEAVE_VEHICLE, this);
+ }
+
+ CRubbish::StirUp(this);
+
+ // blend in clump
+ int clumpAlpha = CVisibilityPlugins::GetClumpAlpha((RpClump*)m_rwObject);
+ if(bFadeOut){
+ clumpAlpha -= 8;
+ if(clumpAlpha < 0)
+ clumpAlpha = 0;
+ }else if(clumpAlpha < 255){
+ clumpAlpha += 16;
+ if(clumpAlpha > 255)
+ clumpAlpha = 255;
+ }
+ CVisibilityPlugins::SetClumpAlpha((RpClump*)m_rwObject, clumpAlpha);
+
+ AutoPilot.m_flag1 = false;
+ AutoPilot.m_flag2 = false;
+
+ // Set Center of Mass to make car more stable
+ if(strongGrip1 || bCheat3)
+ m_vecCentreOfMass.z = 0.3f*m_aSuspensionSpringLength[0] + -1.0*m_fHeightAboveRoad;
+ else if(pHandling->Flags & HANDLING_NONPLAYER_STABILISER && m_status == STATUS_PHYSICS)
+ m_vecCentreOfMass.z = pHandling->CentreOfMass.z - 0.2f*pHandling->Dimension.z;
+ else
+ m_vecCentreOfMass.z = pHandling->CentreOfMass.z;
+
+ // Process depending on status
+
+ bool playerRemote = false;
+ switch(m_status){
+ case STATUS_PLAYER_REMOTE:
+ if(CPad::GetPad(0)->WeaponJustDown()){
+ BlowUpCar(FindPlayerPed());
+ CRemote::TakeRemoteControlledCarFromPlayer();
+ }
+
+ if(GetModelIndex() == MI_RCBANDIT){
+ CVector pos = GetPosition();
+ // FindPlayerCoors unused
+ if(RcbanditCheckHitWheels() || bIsInWater || CPopulation::IsPointInSafeZone(&pos)){
+ if(CPopulation::IsPointInSafeZone(&pos))
+ CGarages::TriggerMessage("HM2_5", -1, 5000, -1);
+ CRemote::TakeRemoteControlledCarFromPlayer();
+ BlowUpCar(FindPlayerPed());
+ }
+ }
+
+ if(CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle == this)
+ playerRemote = true;
+ // fall through
+ case STATUS_PLAYER:
+ if(playerRemote ||
+ pDriver && pDriver->GetPedState() != PED_EXIT_CAR && pDriver->GetPedState() != PED_DRAG_FROM_CAR){
+ // process control input if controlled by player
+ if(playerRemote || pDriver->m_nPedType == PEDTYPE_PLAYER1)
+ ProcessControlInputs(0);
+
+ PruneReferences();
+
+ if(m_status == STATUS_PLAYER && CRecordDataForChase::Status != RECORDSTATE_1)
+ DoDriveByShootings();
+ }
+ break;
+
+ case STATUS_SIMPLE:
+ CCarAI::UpdateCarAI(this);
+ CPhysical::ProcessControl();
+ CCarCtrl::UpdateCarOnRails(this);
+
+ m_nWheelsOnGround = 4;
+ m_nDriveWheelsOnGroundPrev = m_nDriveWheelsOnGround;
+ m_nDriveWheelsOnGround = 4;
+
+ pHandling->Transmission.CalculateGearForSimpleCar(AutoPilot.m_fMaxTrafficSpeed/50.0f, m_nCurrentGear);
+
+ {
+ float wheelRot = ProcessWheelRotation(WHEEL_STATE_0, GetForward(), m_vecMoveSpeed, 0.35f);
+ for(i = 0; i < 4; i++)
+ m_aWheelRotation[i] += wheelRot;
+ }
+
+ PlayHornIfNecessary();
+ ReduceHornCounter();
+ bVehicleColProcessed = false;
+ // that's all we do for simple vehicles
+ return;
+
+ case STATUS_PHYSICS:
+ CCarAI::UpdateCarAI(this);
+ CCarCtrl::SteerAICarWithPhysics(this);
+ PlayHornIfNecessary();
+ break;
+
+ case STATUS_ABANDONED:
+ m_fBrakePedal = 0.2f;
+ bIsHandbrakeOn = false;
+
+ m_fSteerAngle = 0.0f;
+ m_fGasPedal = 0.0f;
+ m_nCarHornTimer = 0;
+ break;
+
+ case STATUS_WRECKED:
+ m_fBrakePedal = 0.05f;
+ bIsHandbrakeOn = true;
+
+ m_fSteerAngle = 0.0f;
+ m_fGasPedal = 0.0f;
+ m_nCarHornTimer = 0;
+ break;
+
+ case STATUS_PLAYER_DISABLED:
+ m_fBrakePedal = 1.0f;
+ bIsHandbrakeOn = true;
+
+ m_fSteerAngle = 0.0f;
+ m_fGasPedal = 0.0f;
+ m_nCarHornTimer = 0;
+ break;
+ }
+
+ // what's going on here?
+ if(GetPosition().z < -0.6f &&
+ Abs(m_vecMoveSpeed.x) < 0.05f &&
+ Abs(m_vecMoveSpeed.y) < 0.05f)
+ m_vecTurnSpeed *= Pow(0.95f, CTimer::GetTimeStep());
+
+ // Skip physics if object is found to have been static recently
+ bool skipPhysics = false;
+ if(!bIsStuck && (m_status == STATUS_ABANDONED || m_status == STATUS_WRECKED)){
+ bool makeStatic = false;
+ float moveSpeedLimit, turnSpeedLimit, distanceLimit;
+
+ if(!bVehicleColProcessed &&
+ m_vecMoveSpeed.IsZero() &&
+ // BUG? m_aSuspensionSpringRatioPrev[3] is checked twice in the game. also, why 3?
+ m_aSuspensionSpringRatioPrev[3] != 1.0f)
+ makeStatic = true;
+
+ if(m_status == STATUS_WRECKED){
+ moveSpeedLimit = 0.006f;
+ turnSpeedLimit = 0.0015f;
+ distanceLimit = 0.015f;
+ }else{
+ moveSpeedLimit = 0.003f;
+ turnSpeedLimit = 0.0009f;
+ distanceLimit = 0.005f;
+ }
+
+ m_vecMoveSpeedAvg = (m_vecMoveSpeedAvg + m_vecMoveSpeed)/2.0f;
+ m_vecTurnSpeedAvg = (m_vecTurnSpeedAvg + m_vecTurnSpeed)/2.0f;
+
+ if(m_vecMoveSpeedAvg.MagnitudeSqr() <= sq(moveSpeedLimit*CTimer::GetTimeStep()) &&
+ m_vecTurnSpeedAvg.MagnitudeSqr() <= sq(turnSpeedLimit*CTimer::GetTimeStep()) &&
+ m_fDistanceTravelled < distanceLimit ||
+ makeStatic){
+ m_nStaticFrames++;
+
+ if(m_nStaticFrames > 10 || makeStatic)
+ if(!CCarCtrl::MapCouldMoveInThisArea(GetPosition().x, GetPosition().y)){
+ if(!makeStatic || m_nStaticFrames > 10)
+ m_nStaticFrames = 10;
+
+ skipPhysics = true;
+
+ m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
+ m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
+ }
+ }else
+ m_nStaticFrames = 0;
+ }
+
+ // Postpone
+ for(i = 0; i < 4; i++)
+ if(m_aGroundPhysical[i] && !CWorld::bForceProcessControl && m_aGroundPhysical[i]->bIsInSafePosition){
+ bWasPostponed = true;
+ return;
+ }
+
+ VehicleDamage(0.0f, 0);
+
+ // special control
+ switch(GetModelIndex()){
+ case MI_FIRETRUCK:
+ FireTruckControl();
+ break;
+ case MI_RHINO:
+ TankControl();
+ BlowUpCarsInPath();
+ break;
+ case MI_YARDIE:
+ // beta also had esperanto here it seems
+ HydraulicControl();
+ break;
+ default:
+ if(CVehicle::bCheat3){
+ // Make vehicle jump when horn is sounded
+ if(m_status == STATUS_PLAYER && m_vecMoveSpeed.MagnitudeSqr() > sq(0.2f) &&
+ // BUG: game checks [0] four times, instead of all wheels
+ m_aSuspensionSpringRatio[0] < 1.0f &&
+ CPad::GetPad(0)->HornJustDown()){
+
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRALIC_1, 0.0f);
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_JUMP, 1.0f);
+
+ CParticle::AddParticle(PARTICLE_ENGINE_STEAM,
+ m_aWheelColPoints[0].point + 0.5f*GetUp(),
+ 1.3f*m_vecMoveSpeed, nil, 2.5f);
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE,
+ m_aWheelColPoints[0].point + 0.5f*GetUp(),
+ 1.2f*m_vecMoveSpeed, nil, 2.0f);
+
+ CParticle::AddParticle(PARTICLE_ENGINE_STEAM,
+ m_aWheelColPoints[2].point + 0.5f*GetUp(),
+ 1.3f*m_vecMoveSpeed, nil, 2.5f);
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE,
+ m_aWheelColPoints[2].point + 0.5f*GetUp(),
+ 1.2f*m_vecMoveSpeed, nil, 2.0f);
+
+ CParticle::AddParticle(PARTICLE_ENGINE_STEAM,
+ m_aWheelColPoints[0].point + 0.5f*GetUp() - GetForward(),
+ 1.3f*m_vecMoveSpeed, nil, 2.5f);
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE,
+ m_aWheelColPoints[0].point + 0.5f*GetUp() - GetForward(),
+ 1.2f*m_vecMoveSpeed, nil, 2.0f);
+
+ CParticle::AddParticle(PARTICLE_ENGINE_STEAM,
+ m_aWheelColPoints[2].point + 0.5f*GetUp() - GetForward(),
+ 1.3f*m_vecMoveSpeed, nil, 2.5f);
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE,
+ m_aWheelColPoints[2].point + 0.5f*GetUp() - GetForward(),
+ 1.2f*m_vecMoveSpeed, nil, 2.0f);
+
+ ApplyMoveForce(CVector(0.0f, 0.0f, 1.0f)*m_fMass*0.4f);
+ ApplyTurnForce(GetUp()*m_fMass*0.035f, GetForward()*1.0f);
+ }
+ }
+ break;
+ }
+
+ float brake;
+ if(skipPhysics){
+ bHasContacted = false;
+ bIsInSafePosition = false;
+ bWasPostponed = false;
+ bHasHitWall = false;
+ m_nCollisionRecords = 0;
+ bHasCollided = false;
+ bVehicleColProcessed = false;
+ m_nDamagePieceType = 0;
+ m_fDamageImpulse = 0.0f;
+ m_pDamageEntity = nil;
+ m_vecTurnFriction = CVector(0.0f, 0.0f, 0.0f);
+ m_vecMoveFriction = CVector(0.0f, 0.0f, 0.0f);
+ }else{
+
+ // This has to be done if ProcessEntityCollision wasn't called
+ if(!bVehicleColProcessed){
+ CMatrix mat(GetMatrix());
+ bIsStuck = false;
+ bHasContacted = false;
+ bIsInSafePosition = false;
+ bWasPostponed = false;
+ bHasHitWall = false;
+ m_fDistanceTravelled = 0.0f;
+ field_EF = false;
+ m_phy_flagA80 = false;
+ ApplyMoveSpeed();
+ ApplyTurnSpeed();
+ for(i = 0; CheckCollision() && i < 5; i++){
+ GetMatrix() = mat;
+ ApplyMoveSpeed();
+ ApplyTurnSpeed();
+ }
+ bIsInSafePosition = true;
+ bIsStuck = false;
+ }
+
+ CPhysical::ProcessControl();
+
+ ProcessBuoyancy();
+
+ // Rescale spring ratios, i.e. subtract wheel radius
+ for(i = 0; i < 4; i++){
+ // wheel radius in relation to suspension line
+ float wheelRadius = 1.0f - m_aSuspensionSpringLength[i]/m_aSuspensionLineLength[i];
+ // rescale such that 0.0 is fully compressed and 1.0 is fully extended
+ m_aSuspensionSpringRatio[i] = (m_aSuspensionSpringRatio[i]-wheelRadius)/(1.0f-wheelRadius);
+ }
+
+ float fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward());
+ CVector contactPoints[4]; // relative to model
+ CVector contactSpeeds[4]; // speed at contact points
+ CVector springDirections[4]; // normalized, in model space
+
+ for(i = 0; i < 4; i++){
+ // Set spring under certain circumstances
+ if(Damage.GetWheelStatus(i) == WHEEL_STATUS_MISSING)
+ m_aSuspensionSpringRatio[i] = 1.0f;
+ else if(Damage.GetWheelStatus(i) == WHEEL_STATUS_BURST){
+ // wheel more bumpy the faster we are
+ if(CGeneral::GetRandomNumberInRange(0, (uint16)(40*fwdSpeed) + 98) < 100){
+ m_aSuspensionSpringRatio[i] += 0.3f*(m_aSuspensionLineLength[i]-m_aSuspensionSpringLength[i])/m_aSuspensionSpringLength[i];
+ if(m_aSuspensionSpringRatio[i] > 1.0f)
+ m_aSuspensionSpringRatio[i] = 1.0f;
+ }
+ }
+
+ // get points and directions if spring is compressed
+ if(m_aSuspensionSpringRatio[i] < 1.0f){
+ contactPoints[i] = m_aWheelColPoints[i].point - GetPosition();
+ springDirections[i] = Multiply3x3(GetMatrix(), colModel->lines[i].p1 - colModel->lines[i].p0);
+ springDirections[i].Normalise();
+ }
+ }
+
+ // Make springs push up vehicle
+ for(i = 0; i < 4; i++){
+ if(m_aSuspensionSpringRatio[i] < 1.0f){
+ float bias = pHandling->fSuspensionBias;
+ if(i == 1 || i == 3) // rear
+ bias = 1.0f - bias;
+
+ ApplySpringCollision(pHandling->fSuspensionForceLevel,
+ springDirections[i], contactPoints[i],
+ m_aSuspensionSpringRatio[i], bias);
+ m_aWheelSkidmarkMuddy[i] =
+ m_aWheelColPoints[i].surfaceB == SURFACE_GRASS ||
+ m_aWheelColPoints[i].surfaceB == SURFACE_DIRTTRACK ||
+ m_aWheelColPoints[i].surfaceB == SURFACE_SAND;
+ }else{
+ contactPoints[i] = Multiply3x3(GetMatrix(), colModel->lines[i].p1);
+ }
+ }
+
+ // Get speed at contact points
+ for(i = 0; i < 4; i++){
+ contactSpeeds[i] = GetSpeed(contactPoints[i]);
+ if(m_aGroundPhysical[i]){
+ // subtract movement of physical we're standing on
+ contactSpeeds[i] -= m_aGroundPhysical[i]->GetSpeed(m_aGroundOffset[i]);
+#ifndef FIX_BUGS
+ // this shouldn't be reset because we still need it below
+ m_aGroundPhysical[i] = nil;
+#endif
+ }
+ }
+
+ // dampen springs
+ for(i = 0; i < 4; i++)
+ if(m_aSuspensionSpringRatio[i] < 1.0f)
+ ApplySpringDampening(pHandling->fSuspensionDampingLevel,
+ springDirections[i], contactPoints[i], contactSpeeds[i]);
+
+ // Get speed at contact points again
+ for(i = 0; i < 4; i++){
+ contactSpeeds[i] = GetSpeed(contactPoints[i]);
+ if(m_aGroundPhysical[i]){
+ // subtract movement of physical we're standing on
+ contactSpeeds[i] -= m_aGroundPhysical[i]->GetSpeed(m_aGroundOffset[i]);
+ m_aGroundPhysical[i] = nil;
+ }
+ }
+
+
+ bool gripCheat = true;
+ fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward());
+ if(!strongGrip1 && !CVehicle::bCheat3)
+ gripCheat = false;
+ float acceleration = pHandling->Transmission.CalculateDriveAcceleration(m_fGasPedal, m_nCurrentGear, m_fChangeGearTime, fwdSpeed, gripCheat);
+ acceleration /= fForceMultiplier;
+
+ // unused
+ if(GetModelIndex() == MI_MIAMI_RCBARON ||
+ GetModelIndex() == MI_MIAMI_RCRAIDER ||
+ GetModelIndex() == MI_MIAMI_SPARROW)
+ acceleration = 0.0f;
+
+ brake = m_fBrakePedal * pHandling->fBrakeDeceleration * CTimer::GetTimeStep();
+ bool neutralHandling = !!(pHandling->Flags & HANDLING_NEUTRALHANDLING);
+ float brakeBiasFront = neutralHandling ? 1.0f : 2.0f*pHandling->fBrakeBias;
+ float brakeBiasRear = neutralHandling ? 1.0f : 2.0f*(1.0f-pHandling->fBrakeBias);
+ float tractionBiasFront = neutralHandling ? 1.0f : 2.0f*pHandling->fTractionBias;
+ float tractionBiasRear = neutralHandling ? 1.0f : 2.0f*(1.0f-pHandling->fTractionBias);
+
+ // Count how many wheels are touching the ground
+
+ m_nWheelsOnGround = 0;
+ m_nDriveWheelsOnGroundPrev = m_nDriveWheelsOnGround;
+ m_nDriveWheelsOnGround = 0;
+
+ for(i = 0; i < 4; i++){
+ if(m_aSuspensionSpringRatio[i] < 1.0f)
+ m_aWheelTimer[i] = 4.0f;
+ else
+ m_aWheelTimer[i] = max(m_aWheelTimer[i]-CTimer::GetTimeStep(), 0.0f);
+
+ if(m_aWheelTimer[i] > 0.0f){
+ m_nWheelsOnGround++;
+ switch(pHandling->Transmission.nDriveType){
+ case '4':
+ m_nDriveWheelsOnGround++;
+ break;
+ case 'F':
+ if(i == CARWHEEL_FRONT_LEFT || i == CARWHEEL_FRONT_RIGHT)
+ m_nDriveWheelsOnGround++;
+ break;
+ case 'R':
+ if(i == CARWHEEL_REAR_LEFT || i == CARWHEEL_REAR_RIGHT)
+ m_nDriveWheelsOnGround++;
+ break;
+ }
+ }
+ }
+
+ float traction;
+ if(m_status == STATUS_PHYSICS)
+ traction = 0.004f * m_fTraction;
+ else
+ traction = 0.004f;
+ traction *= pHandling->fTractionMultiplier / 4.0f;
+ traction /= fForceMultiplier;
+ if(CVehicle::bCheat3)
+ traction *= 4.0f;
+
+ if(FindPlayerVehicle() && FindPlayerVehicle() == this){
+ if(CPad::GetPad(0)->WeaponJustDown()){
+ if(m_bombType == CARBOMB_TIMED){
+ m_bombType = CARBOMB_TIMEDACTIVE;
+ m_nBombTimer = 7000;
+ m_pBlowUpEntity = FindPlayerPed();
+ CGarages::TriggerMessage("GA_12", -1, 3000, -1);
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_BOMB_TIMED_ACTIVATED, 1.0f);
+ }else if(m_bombType == CARBOMB_ONIGNITION){
+ m_bombType = CARBOMB_ONIGNITIONACTIVE;
+ CGarages::TriggerMessage("GA_12", -1, 3000, -1);
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_BOMB_ONIGNITION_ACTIVATED, 1.0f);
+ }
+ }
+ }else if(strongGrip1 || CVehicle::bCheat3){
+ traction *= 1.2f;
+ acceleration *= 1.4f;
+ if(strongGrip2 || CVehicle::bCheat3){
+ traction *= 1.3f;
+ acceleration *= 1.4f;
+ }
+ }
+
+ static float fThrust;
+ static tWheelState WheelState[4];
+
+ // Process front wheels on ground
+
+ if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] > 0.0f || m_aWheelTimer[CARWHEEL_FRONT_RIGHT] > 0.0f){
+ float s = Sin(m_fSteerAngle);
+ float c = Cos(m_fSteerAngle);
+ CVector wheelFwd = Multiply3x3(GetMatrix(), CVector(-s, c, 0.0f));
+ CVector wheelRight = Multiply3x3(GetMatrix(), CVector(c, s, 0.0f));
+
+ if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] > 0.0f){
+ if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier))
+ fThrust = 0.0f;
+ else
+ fThrust = acceleration;
+
+ m_aWheelColPoints[CARWHEEL_FRONT_LEFT].surfaceA = SURFACE_RUBBER29;
+ float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_FRONT_LEFT])*traction;
+ if(m_status == STATUS_PLAYER)
+ adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[CARWHEEL_FRONT_LEFT].surfaceB);
+ WheelState[CARWHEEL_FRONT_LEFT] = m_aWheelState[CARWHEEL_FRONT_LEFT];
+
+ if(Damage.GetWheelStatus(VEHWHEEL_FRONT_LEFT) == WHEEL_STATUS_BURST)
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[CARWHEEL_FRONT_LEFT], contactPoints[CARWHEEL_FRONT_LEFT],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBiasFront,
+ adhesion*tractionBiasFront*Damage.m_fWheelDamageEffect,
+ CARWHEEL_FRONT_LEFT,
+ &m_aWheelSpeed[CARWHEEL_FRONT_LEFT],
+ &WheelState[CARWHEEL_FRONT_LEFT],
+ WHEEL_STATUS_BURST);
+ else
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[CARWHEEL_FRONT_LEFT], contactPoints[CARWHEEL_FRONT_LEFT],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBiasFront,
+ adhesion*tractionBiasFront,
+ CARWHEEL_FRONT_LEFT,
+ &m_aWheelSpeed[CARWHEEL_FRONT_LEFT],
+ &WheelState[CARWHEEL_FRONT_LEFT],
+ WHEEL_STATUS_OK);
+ }
+
+ if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] > 0.0f){
+ if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier))
+ fThrust = 0.0f;
+ else
+ fThrust = acceleration;
+
+ m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].surfaceA = SURFACE_RUBBER29;
+ float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_FRONT_RIGHT])*traction;
+ if(m_status == STATUS_PLAYER)
+ adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].surfaceB);
+ WheelState[CARWHEEL_FRONT_RIGHT] = m_aWheelState[CARWHEEL_FRONT_RIGHT];
+
+ if(Damage.GetWheelStatus(VEHWHEEL_FRONT_RIGHT) == WHEEL_STATUS_BURST)
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[CARWHEEL_FRONT_RIGHT], contactPoints[CARWHEEL_FRONT_RIGHT],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBiasFront,
+ adhesion*tractionBiasFront*Damage.m_fWheelDamageEffect,
+ CARWHEEL_FRONT_RIGHT,
+ &m_aWheelSpeed[CARWHEEL_FRONT_RIGHT],
+ &WheelState[CARWHEEL_FRONT_RIGHT],
+ WHEEL_STATUS_BURST);
+ else
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[CARWHEEL_FRONT_RIGHT], contactPoints[CARWHEEL_FRONT_RIGHT],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBiasFront,
+ adhesion*tractionBiasFront,
+ CARWHEEL_FRONT_RIGHT,
+ &m_aWheelSpeed[CARWHEEL_FRONT_RIGHT],
+ &WheelState[CARWHEEL_FRONT_RIGHT],
+ WHEEL_STATUS_OK);
+ }
+ }
+
+ // Process front wheels off ground
+
+ if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] <= 0.0f){
+ if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_LEFT] *= 0.95f;
+ else{
+ if(acceleration > 0.0f){
+ if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] < 2.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_LEFT] -= 0.2f;
+ }else{
+ if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] > -2.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_LEFT] += 0.1f;
+ }
+ }
+ m_aWheelRotation[CARWHEEL_FRONT_LEFT] += m_aWheelSpeed[CARWHEEL_FRONT_LEFT];
+ }
+ if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] <= 0.0f){
+ if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] *= 0.95f;
+ else{
+ if(acceleration > 0.0f){
+ if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] < 2.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] -= 0.2f;
+ }else{
+ if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] > -2.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] += 0.1f;
+ }
+ }
+ m_aWheelRotation[CARWHEEL_FRONT_RIGHT] += m_aWheelSpeed[CARWHEEL_FRONT_RIGHT];
+ }
+
+ // Process rear wheels
+
+ if(m_aWheelTimer[CARWHEEL_REAR_LEFT] > 0.0f || m_aWheelTimer[CARWHEEL_REAR_RIGHT] > 0.0f){
+ CVector wheelFwd = GetForward();
+ CVector wheelRight = GetRight();
+
+ if(bIsHandbrakeOn)
+ brake = 20000.0f;
+
+ if(m_aWheelTimer[CARWHEEL_REAR_LEFT] > 0.0f){
+ if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier))
+ fThrust = 0.0f;
+ else
+ fThrust = acceleration;
+
+ m_aWheelColPoints[CARWHEEL_REAR_LEFT].surfaceA = SURFACE_RUBBER29;
+ float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_REAR_LEFT])*traction;
+ if(m_status == STATUS_PLAYER)
+ adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[CARWHEEL_REAR_LEFT].surfaceB);
+ WheelState[CARWHEEL_REAR_LEFT] = m_aWheelState[CARWHEEL_REAR_LEFT];
+
+ if(Damage.GetWheelStatus(VEHWHEEL_REAR_LEFT) == WHEEL_STATUS_BURST)
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[CARWHEEL_REAR_LEFT], contactPoints[CARWHEEL_REAR_LEFT],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBiasRear,
+ adhesion*tractionBiasRear*Damage.m_fWheelDamageEffect,
+ CARWHEEL_REAR_LEFT,
+ &m_aWheelSpeed[CARWHEEL_REAR_LEFT],
+ &WheelState[CARWHEEL_REAR_LEFT],
+ WHEEL_STATUS_BURST);
+ else
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[CARWHEEL_REAR_LEFT], contactPoints[CARWHEEL_REAR_LEFT],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBiasRear,
+ adhesion*tractionBiasRear,
+ CARWHEEL_REAR_LEFT,
+ &m_aWheelSpeed[CARWHEEL_REAR_LEFT],
+ &WheelState[CARWHEEL_REAR_LEFT],
+ WHEEL_STATUS_OK);
+ }
+
+ if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] > 0.0f){
+ if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier))
+ fThrust = 0.0f;
+ else
+ fThrust = acceleration;
+
+ m_aWheelColPoints[CARWHEEL_REAR_RIGHT].surfaceA = SURFACE_RUBBER29;
+ float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_REAR_RIGHT])*traction;
+ if(m_status == STATUS_PLAYER)
+ adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[CARWHEEL_REAR_RIGHT].surfaceB);
+ WheelState[CARWHEEL_REAR_RIGHT] = m_aWheelState[CARWHEEL_REAR_RIGHT];
+
+ if(Damage.GetWheelStatus(VEHWHEEL_REAR_RIGHT) == WHEEL_STATUS_BURST)
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[CARWHEEL_REAR_RIGHT], contactPoints[CARWHEEL_REAR_RIGHT],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBiasRear,
+ adhesion*tractionBiasRear*Damage.m_fWheelDamageEffect,
+ CARWHEEL_REAR_RIGHT,
+ &m_aWheelSpeed[CARWHEEL_REAR_RIGHT],
+ &WheelState[CARWHEEL_REAR_RIGHT],
+ WHEEL_STATUS_BURST);
+ else
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[CARWHEEL_REAR_RIGHT], contactPoints[CARWHEEL_REAR_RIGHT],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBiasRear,
+ adhesion*tractionBiasRear,
+ CARWHEEL_REAR_RIGHT,
+ &m_aWheelSpeed[CARWHEEL_REAR_RIGHT],
+ &WheelState[CARWHEEL_REAR_RIGHT],
+ WHEEL_STATUS_OK);
+ }
+ }
+
+ // Process rear wheels off ground
+
+ if(m_aWheelTimer[CARWHEEL_REAR_LEFT] <= 0.0f){
+ if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
+ m_aWheelSpeed[CARWHEEL_REAR_LEFT] *= 0.95f;
+ else{
+ if(acceleration > 0.0f){
+ if(m_aWheelSpeed[CARWHEEL_REAR_LEFT] < 2.0f)
+ m_aWheelSpeed[CARWHEEL_REAR_LEFT] -= 0.2f;
+ }else{
+ if(m_aWheelSpeed[CARWHEEL_REAR_LEFT] > -2.0f)
+ m_aWheelSpeed[CARWHEEL_REAR_LEFT] += 0.1f;
+ }
+ }
+ m_aWheelRotation[CARWHEEL_REAR_LEFT] += m_aWheelSpeed[CARWHEEL_REAR_LEFT];
+ }
+ if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] <= 0.0f){
+ if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
+ m_aWheelSpeed[CARWHEEL_REAR_RIGHT] *= 0.95f;
+ else{
+ if(acceleration > 0.0f){
+ if(m_aWheelSpeed[CARWHEEL_REAR_RIGHT] < 2.0f)
+ m_aWheelSpeed[CARWHEEL_REAR_RIGHT] -= 0.2f;
+ }else{
+ if(m_aWheelSpeed[CARWHEEL_REAR_RIGHT] > -2.0f)
+ m_aWheelSpeed[CARWHEEL_REAR_RIGHT] += 0.1f;
+ }
+ }
+ m_aWheelRotation[CARWHEEL_REAR_RIGHT] += m_aWheelSpeed[CARWHEEL_REAR_RIGHT];
+ }
+
+ for(i = 0; i < 4; i++){
+ float wheelPos = colModel->lines[i].p0.z;
+ if(m_aSuspensionSpringRatio[i] > 0.0f)
+ wheelPos -= m_aSuspensionSpringRatio[i]*m_aSuspensionSpringLength[i];
+ m_aWheelPosition[i] += (wheelPos - m_aWheelPosition[i])*0.75f;
+ }
+ for(i = 0; i < 4; i++)
+ m_aWheelState[i] = WheelState[i];
+
+ // Process horn
+
+ if(m_status != STATUS_PLAYER){
+ ReduceHornCounter();
+ }else{
+ if(GetModelIndex() == MI_MRWHOOP){
+ if(Pads[0].bHornHistory[Pads[0].iCurrHornHistory] &&
+ !Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % 5]){
+ m_bSirenOrAlarm = !m_bSirenOrAlarm;
+ printf("m_bSirenOrAlarm toggled to %d\n", m_bSirenOrAlarm);
+ }
+ }else if(UsesSiren(GetModelIndex())){
+ if(Pads[0].bHornHistory[Pads[0].iCurrHornHistory]){
+ if(Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % 5] &&
+ Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+3) % 5])
+ m_nCarHornTimer = 1;
+ else
+ m_nCarHornTimer = 0;
+ }else if(Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % 5] &&
+ !Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+1) % 5]){
+ m_nCarHornTimer = 0;
+ m_bSirenOrAlarm = !m_bSirenOrAlarm;
+ }else
+ m_nCarHornTimer = 0;
+ }else if(GetModelIndex() != MI_YARDIE && !CVehicle::bCheat3){
+ if(Pads[0].GetHorn())
+ m_nCarHornTimer = 1;
+ else
+ m_nCarHornTimer = 0;
+ }
+ }
+
+ // Flying
+
+ if(m_status != STATUS_PLAYER && m_status != STATUS_PLAYER_REMOTE && m_status != STATUS_PHYSICS){
+ if(GetModelIndex() == MI_MIAMI_RCRAIDER || GetModelIndex() == MI_MIAMI_SPARROW)
+ m_aWheelSpeed[0] = max(m_aWheelSpeed[0]-0.0005f, 0.0f);
+ }else if((GetModelIndex() == MI_DODO || CVehicle::bAllDodosCheat) &&
+ m_vecMoveSpeed.Magnitude() > 0.0f && CTimer::GetTimeStep() > 0.0f){
+ FlyingControl(FLIGHT_MODEL_DODO);
+ }else if(GetModelIndex() == MI_MIAMI_RCBARON){
+ FlyingControl(FLIGHT_MODEL_HELI);
+ }else if(GetModelIndex() == MI_MIAMI_RCRAIDER || GetModelIndex() == MI_MIAMI_SPARROW || bAllCarCheat){
+ if(CPad::GetPad(0)->GetCircleJustDown())
+ m_aWheelSpeed[0] = max(m_aWheelSpeed[0]-0.03f, 0.0f);
+ if(m_aWheelSpeed[0] < 0.22f)
+ m_aWheelSpeed[0] += 0.0001f;
+ if(m_aWheelSpeed[0] > 0.15f)
+ FlyingControl(FLIGHT_MODEL_HELI);
+ }
+ }
+
+
+
+ // Process car on fire
+ // A similar calculation of damagePos is done elsewhere for smoke
+
+ uint8 engineStatus = Damage.GetEngineStatus();
+ CVector damagePos = ((CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()))->m_positions[CAR_POS_HEADLIGHTS];
+
+ switch(Damage.GetDoorStatus(DOOR_BONNET)){
+ case DOOR_STATUS_OK:
+ case DOOR_STATUS_SMASHED:
+ // Bonnet is still there, smoke comes out at the edge
+ damagePos += vecDAMAGE_ENGINE_POS_SMALL;
+ break;
+ case DOOR_STATUS_SWINGING:
+ case DOOR_STATUS_MISSING:
+ // Bonnet is gone, smoke comes out at the engine
+ damagePos += vecDAMAGE_ENGINE_POS_BIG;
+ break;
+ }
+
+ // move fire forward if in first person
+ if(this == FindPlayerVehicle() && TheCamera.GetLookingForwardFirstPerson())
+ if(m_fHealth < 250.0f && m_status != STATUS_WRECKED){
+ if(GetModelIndex() == MI_FIRETRUCK)
+ damagePos += CVector(0.0f, 3.0f, -0.2f);
+ else
+ damagePos += CVector(0.0f, 1.2f, -0.8f);
+ }
+
+ damagePos = GetMatrix()*damagePos;
+ damagePos.z += 0.15f;
+
+ if(m_fHealth < 250.0f && m_status != STATUS_WRECKED){
+ // Car is on fire
+
+ CParticle::AddParticle(PARTICLE_CARFLAME, damagePos,
+ CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(0.01125f, 0.09f)),
+ nil, 0.9f);
+
+ CVector coors = damagePos;
+ coors.x += CGeneral::GetRandomNumberInRange(-0.5625f, 0.5625f),
+ coors.y += CGeneral::GetRandomNumberInRange(-0.5625f, 0.5625f),
+ coors.z += CGeneral::GetRandomNumberInRange(0.5625f, 2.25f);
+ CParticle::AddParticle(PARTICLE_CARFLAME_SMOKE, coors, CVector(0.0f, 0.0f, 0.0f));
+
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE2, damagePos, CVector(0.0f, 0.0f, 0.0f), nil, 0.5f);
+
+ // Blow up car after 5 seconds
+ m_fFireBlowUpTimer += CTimer::GetTimeStepInMilliseconds();
+ if(m_fFireBlowUpTimer > 5000.0f){
+ CWorld::Players[CWorld::PlayerInFocus].AwardMoneyForExplosion(this);
+ BlowUpCar(m_pSetOnFireEntity);
+ }
+ }else
+ m_fFireBlowUpTimer = 0.0f;
+
+ // Decrease car health if engine is damaged badly
+ if(engineStatus > ENGINE_STATUS_ON_FIRE && m_fHealth > 250.0f)
+ m_fHealth -= 2.0f;
+
+ ProcessDelayedExplosion();
+
+
+ if(m_bSirenOrAlarm && (CTimer::GetFrameCounter()&7) == 5 &&
+ UsesSiren(GetModelIndex()) && GetModelIndex() != MI_RCBANDIT)
+ CCarAI::MakeWayForCarWithSiren(this);
+
+
+ // Find out how much to shake the pad depending on suspension and ground surface
+
+ float suspShake = 0.0f;
+ float surfShake = 0.0f;
+ for(i = 0; i < 4; i++){
+ float suspChange = m_aSuspensionSpringRatioPrev[i] - m_aSuspensionSpringRatio[i];
+ if(suspChange > 0.3f){
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_JUMP, suspChange);
+ if(suspChange > suspShake)
+ suspShake = suspChange;
+ }
+
+ uint8 surf = m_aWheelColPoints[i].surfaceB;
+ if(surf == SURFACE_DIRT || surf == SURFACE_PUDDLE || surf == SURFACE_HEDGE){
+ if(surfShake < 0.2f)
+ surfShake = 0.3f;
+ }else if(surf == SURFACE_DIRTTRACK || surf == SURFACE_SAND){
+ if(surfShake < 0.1f)
+ surfShake = 0.2f;
+ }else if(surf == SURFACE_GRASS){
+ if(surfShake < 0.05f)
+ surfShake = 0.1f;
+ }
+
+ m_aSuspensionSpringRatioPrev[i] = m_aSuspensionSpringRatio[i];
+ m_aSuspensionSpringRatio[i] = 1.0f;
+ }
+
+ // Shake pad
+
+ if((suspShake > 0.0f || surfShake > 0.0f) && m_status == STATUS_PLAYER){
+ float speed = m_vecMoveSpeed.MagnitudeSqr();
+ if(speed > sq(0.1f)){
+ speed = Sqrt(speed);
+ if(suspShake > 0.0f){
+ uint8 freq = min(200.0f*suspShake*speed*2000.0f/m_fMass + 100.0f, 250.0f);
+ CPad::GetPad(0)->StartShake(20000.0f*CTimer::GetTimeStep()/freq, freq);
+ }else{
+ uint8 freq = min(200.0f*surfShake*speed*2000.0f/m_fMass + 40.0f, 145.0f);
+ CPad::GetPad(0)->StartShake(5000.0f*CTimer::GetTimeStep()/freq, freq);
+ }
+ }
+ }
+
+ bVehicleColProcessed = false;
+
+ if(!bWarnedPeds)
+ CCarCtrl::ScanForPedDanger(this);
+
+
+ // Turn around at the edge of the world
+ // TODO: make the numbers defines
+
+ float heading;
+ if(GetPosition().x > 1900.0f){
+ if(m_vecMoveSpeed.x > 0.0f)
+ m_vecMoveSpeed.x *= -1.0f;
+ heading = GetForward().Heading();
+ if(heading > 0.0f) // going west
+ SetHeading(-heading);
+ }else if(GetPosition().x < -1900.0f){
+ if(m_vecMoveSpeed.x < 0.0f)
+ m_vecMoveSpeed.x *= -1.0f;
+ heading = GetForward().Heading();
+ if(heading < 0.0f) // going east
+ SetHeading(-heading);
+ }
+ if(GetPosition().y > 1900.0f){
+ if(m_vecMoveSpeed.y > 0.0f)
+ m_vecMoveSpeed.y *= -1.0f;
+ heading = GetForward().Heading();
+ if(heading < HALFPI && heading > 0.0f)
+ SetHeading(PI-heading);
+ else if(heading > -HALFPI && heading < 0.0f)
+ SetHeading(-PI-heading);
+ }else if(GetPosition().y < -1900.0f){
+ if(m_vecMoveSpeed.y < 0.0f)
+ m_vecMoveSpeed.y *= -1.0f;
+ heading = GetForward().Heading();
+ if(heading > HALFPI)
+ SetHeading(PI-heading);
+ else if(heading < -HALFPI)
+ SetHeading(-PI-heading);
+ }
+
+ if(bInfiniteMass){
+ m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
+ m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
+ m_vecMoveFriction = CVector(0.0f, 0.0f, 0.0f);
+ m_vecTurnFriction = CVector(0.0f, 0.0f, 0.0f);
+ }else if(!skipPhysics &&
+ (m_fGasPedal == 0.0f && brake == 0.0f || m_status == STATUS_WRECKED)){
+ if(Abs(m_vecMoveSpeed.x) < 0.005f &&
+ Abs(m_vecMoveSpeed.y) < 0.005f &&
+ Abs(m_vecMoveSpeed.z) < 0.005f){
+ m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
+ m_vecTurnSpeed.z = 0.0f;
+ }
+ }
+
+// TEMP
+if(pDriver)
+ pDriver->m_fHealth = 100.0f;
+}
void
CAutomobile::Teleport(CVector pos)
@@ -86,7 +1232,7 @@ CAutomobile::ProcessEntityCollision(CEntity *ent, CColPoint *colpoints)
// In ProcessControl these will be re-normalized to ignore the tyre radius.
if(field_EF || m_phy_flagA80 ||
- GetModelIndex() == MI_DODO && (ent->m_status == STATUS_PHYSICS || ent->m_status == STATUS_SIMPLE)){
+ GetModelIndex() == MI_DODO && (ent->IsPed() || ent->IsVehicle())){
// don't do line collision
for(i = 0; i < 4; i++)
m_aSuspensionSpringRatio[i] = prevRatios[i];
@@ -141,8 +1287,613 @@ CAutomobile::ProcessEntityCollision(CEntity *ent, CColPoint *colpoints)
return numCollisions;
}
+static int16 nLastControlInput;
+static float fMouseCentreRange = 0.35f;
+static float fMouseSteerSens = -0.0035f;
+static float fMouseCentreMult = 0.975f;
+
+void
+CAutomobile::ProcessControlInputs(uint8 pad)
+{
+ float speed = DotProduct(m_vecMoveSpeed, GetForward());
+
+ if(CPad::GetPad(pad)->GetExitVehicle())
+ bIsHandbrakeOn = true;
+ else
+ bIsHandbrakeOn = !!CPad::GetPad(pad)->GetHandBrake();
+
+ // Steer left/right
+ if(CCamera::m_bUseMouse3rdPerson && !CVehicle::m_bDisableMouseSteering){
+ if(CPad::GetPad(pad)->GetMouseX() != 0.0f){
+ m_fSteerRatio += fMouseSteerSens*CPad::GetPad(pad)->GetMouseX();
+ nLastControlInput = 2;
+ if(Abs(m_fSteerRatio) < fMouseCentreRange)
+ m_fSteerRatio *= Pow(fMouseCentreMult, CTimer::GetTimeStep());
+ }else if(CPad::GetPad(pad)->GetSteeringLeftRight() || nLastControlInput != 2){
+ // mouse hasn't move, steer with pad like below
+ m_fSteerRatio += (-CPad::GetPad(pad)->GetSteeringLeftRight()/128.0f - m_fSteerRatio)*
+ 0.2f*CTimer::GetTimeStep();
+ nLastControlInput = 0;
+ }
+ }else{
+ m_fSteerRatio += (-CPad::GetPad(pad)->GetSteeringLeftRight()/128.0f - m_fSteerRatio)*
+ 0.2f*CTimer::GetTimeStep();
+ nLastControlInput = 0;
+ }
+ m_fSteerRatio = clamp(m_fSteerRatio, -1.0f, 1.0f);
+
+ // Accelerate/Brake
+ float acceleration = (CPad::GetPad(pad)->GetAccelerate() - CPad::GetPad(pad)->GetBrake())/255.0f;
+ if(GetModelIndex() == MI_DODO && acceleration < 0.0f)
+ acceleration *= 0.3f;
+ if(Abs(speed) < 0.01f){
+ // standing still, go into direction we want
+ m_fGasPedal = acceleration;
+ m_fBrakePedal = 0.0f;
+ }else{
+#if 1
+ // simpler than the code below
+ if(speed * acceleration < 0.0f){
+ // if opposite directions, have to brake first
+ m_fGasPedal = 0.0f;
+ m_fBrakePedal = Abs(acceleration);
+ }else{
+ // accelerating in same direction we were already going
+ m_fGasPedal = acceleration;
+ m_fBrakePedal = 0.0f;
+ }
+#else
+ if(speed < 0.0f){
+ // moving backwards currently
+ if(acceleration < 0.0f){
+ // still go backwards
+ m_fGasPedal = acceleration;
+ m_fBrakePedal = 0.0f;
+ }else{
+ // want to go forwards, so brake
+ m_fGasPedal = 0.0f;
+ m_fBrakePedal = acceleration;
+ }
+ }else{
+ // moving forwards currently
+ if(acceleration < 0.0f){
+ // want to go backwards, so brake
+ m_fGasPedal = 0.0f;
+ m_fBrakePedal = -acceleration;
+ }else{
+ // still go forwards
+ m_fGasPedal = acceleration;
+ m_fBrakePedal = 0.0f;
+ }
+ }
+#endif
+ }
+
+ // Actually turn wheels
+ static float fValue; // why static?
+ if(m_fSteerRatio < 0.0f)
+ fValue = -sq(m_fSteerRatio);
+ else
+ fValue = sq(m_fSteerRatio);
+ m_fSteerAngle = DEGTORAD(pHandling->fSteeringLock) * fValue;
+
+ if(bComedyControls){
+ int rnd = CGeneral::GetRandomNumber() % 10;
+ switch(m_comedyControlState){
+ case 0:
+ if(rnd < 2)
+ m_comedyControlState = 1;
+ else if(rnd < 4)
+ m_comedyControlState = 2;
+ break;
+ case 1:
+ m_fSteerAngle += 0.05f;
+ if(rnd < 2)
+ m_comedyControlState = 0;
+ break;
+ case 2:
+ m_fSteerAngle -= 0.05f;
+ if(rnd < 2)
+ m_comedyControlState = 0;
+ break;
+ }
+ }else
+ m_comedyControlState = 0;
+
+ // Brake if player isn't in control
+ // BUG: game always uses pad 0 here
+ if(CPad::GetPad(pad)->DisablePlayerControls){
+ m_fBrakePedal = 1.0f;
+ bIsHandbrakeOn = true;
+ m_fGasPedal = 0.0f;
+
+ FindPlayerPed()->KeepAreaAroundPlayerClear();
+
+ // slow down car immediately
+ speed = m_vecMoveSpeed.Magnitude();
+ if(speed > 0.28f)
+ m_vecMoveSpeed *= 0.28f/speed;
+ }
+}
+
+WRAPPER void
+CAutomobile::FireTruckControl(void)
+{ EAXJMP(0x522590);
+}
-WRAPPER void CAutomobile::ProcessControlInputs(uint8) { EAXJMP(0x53B660); }
+WRAPPER void
+CAutomobile::TankControl(void)
+{ EAXJMP(0x53D530);
+}
+
+WRAPPER void
+CAutomobile::HydraulicControl(void)
+{ EAXJMP(0x52D4E0);
+}
+
+WRAPPER void
+CAutomobile::ProcessBuoyancy(void)
+{ EAXJMP(0x5308D0);
+}
+
+void
+CAutomobile::DoDriveByShootings(void)
+{
+ CAnimBlendAssociation *anim;
+ CWeapon *weapon = pDriver->GetWeapon();
+ if(weapon->m_eWeaponType != WEAPONTYPE_UZI)
+ return;
+
+ weapon->Update(pDriver->m_audioEntityId);
+
+ bool lookingLeft = false;
+ bool lookingRight = false;
+ if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN1){
+ if(CPad::GetPad(0)->GetLookLeft())
+ lookingLeft = true;
+ if(CPad::GetPad(0)->GetLookRight())
+ lookingRight = true;
+ }else{
+ if(TheCamera.Cams[TheCamera.ActiveCam].LookingLeft)
+ lookingLeft = true;
+ if(TheCamera.Cams[TheCamera.ActiveCam].LookingRight)
+ lookingRight = true;
+ }
+
+ if(lookingLeft || lookingRight){
+ if(lookingLeft){
+ anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_R);
+ if(anim)
+ anim->blendDelta = -1000.0f;
+ anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_L);
+ if(anim == nil || anim->blendDelta < 0.0f)
+ CAnimManager::AddAnimation(pDriver->GetClump(), ASSOCGRP_STD, ANIM_DRIVEBY_L);
+ else
+ anim->SetRun();
+ }else if(pDriver->m_pMyVehicle->pPassengers[0] == nil || TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FIRSTPERSON){
+ anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_L);
+ if(anim)
+ anim->blendDelta = -1000.0f;
+ anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_R);
+ if(anim == nil || anim->blendDelta < 0.0f)
+ CAnimManager::AddAnimation(pDriver->GetClump(), ASSOCGRP_STD, ANIM_DRIVEBY_R);
+ else
+ anim->SetRun();
+ }
+
+ if(CPad::GetPad(0)->GetCarGunFired() && CTimer::GetTimeInMilliseconds() > weapon->m_nTimer){
+ weapon->FireFromCar(this, lookingLeft);
+ weapon->m_nTimer = CTimer::GetTimeInMilliseconds() + 70;
+ }
+ }else{
+ weapon->Reload();
+ anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_L);
+ if(anim)
+ anim->blendDelta = -1000.0f;
+ anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_R);
+ if(anim)
+ anim->blendDelta = -1000.0f;
+ }
+
+ // TODO: what is this?
+ if(!lookingLeft && m_weaponDoorTimerLeft > 0.0f){
+ m_weaponDoorTimerLeft = max(m_weaponDoorTimerLeft - CTimer::GetTimeStep()*0.1f, 0.0f);
+ ProcessOpenDoor(CAR_DOOR_LF, NUM_ANIMS, m_weaponDoorTimerLeft);
+ }
+ if(!lookingRight && m_weaponDoorTimerRight > 0.0f){
+ m_weaponDoorTimerRight = max(m_weaponDoorTimerRight - CTimer::GetTimeStep()*0.1f, 0.0f);
+ ProcessOpenDoor(CAR_DOOR_RF, NUM_ANIMS, m_weaponDoorTimerRight);
+ }
+}
+
+int32
+CAutomobile::RcbanditCheckHitWheels(void)
+{
+ int x, xmin, xmax;
+ int y, ymin, ymax;
+
+ xmin = CWorld::GetSectorIndexX(GetPosition().x - 2.0f);
+ if(xmin < 0) xmin = 0;
+ xmax = CWorld::GetSectorIndexX(GetPosition().x + 2.0f);
+ if(xmax > NUMSECTORS_X-1) xmax = NUMSECTORS_X-1;
+ ymin = CWorld::GetSectorIndexX(GetPosition().y - 2.0f);
+ if(ymin < 0) ymin = 0;
+ ymax = CWorld::GetSectorIndexX(GetPosition().y + 2.0f);
+ if(ymax > NUMSECTORS_Y-1) ymax = NUMSECTORS_X-1;
+
+ CWorld::AdvanceCurrentScanCode();
+
+ for(y = ymin; y <= ymax; y++)
+ for(x = xmin; x <= xmax; x++){
+ CSector *s = CWorld::GetSector(x, y);
+ if(RcbanditCheck1CarWheels(s->m_lists[ENTITYLIST_VEHICLES]) ||
+ RcbanditCheck1CarWheels(s->m_lists[ENTITYLIST_VEHICLES_OVERLAP]))
+ return 1;
+ }
+ return 0;
+}
+
+int32
+CAutomobile::RcbanditCheck1CarWheels(CPtrList &list)
+{
+ static CMatrix matW2B;
+ int i;
+ CPtrNode *node;
+ CAutomobile *car;
+ CColModel *colModel = GetColModel();
+ CVehicleModelInfo *mi;
+
+ for(node = list.first; node; node = node->next){
+ car = (CAutomobile*)node->item;
+ if(this != car && car->IsCar() && car->m_scanCode != CWorld::GetCurrentScanCode()){
+ car->m_scanCode = CWorld::GetCurrentScanCode();
+
+ if(Abs(this->GetPosition().x - car->GetPosition().x) < 10.0f &&
+ Abs(this->GetPosition().y - car->GetPosition().y) < 10.0f){
+ mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(car->GetModelIndex());
+
+ for(i = 0; i < 4; i++){
+ if(car->m_aSuspensionSpringRatioPrev[i] < 1.0f || car->m_status == STATUS_SIMPLE){
+ CVector wheelPos;
+ CColSphere sph;
+ mi->GetWheelPosn(i, wheelPos);
+ matW2B = Invert(GetMatrix());
+ sph.center = matW2B * (car->GetMatrix() * wheelPos);
+ sph.radius = mi->m_wheelScale*0.25f;
+ if(CCollision::TestSphereBox(sph, colModel->boundingBox))
+ return 1;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+void
+CAutomobile::PlaceOnRoadProperly(void)
+{
+ CColPoint point;
+ CEntity *entity;
+ CColModel *colModel = GetColModel();
+ float lenFwd, lenBack;
+ float frontZ, rearZ;
+
+ lenFwd = colModel->boundingBox.max.y;
+ lenBack = -colModel->boundingBox.min.y;
+
+ CVector front(GetPosition().x + GetForward().x*lenFwd,
+ GetPosition().y + GetForward().y*lenFwd,
+ GetPosition().z + 5.0f);
+ if(CWorld::ProcessVerticalLine(front, GetPosition().z - 5.0f, point, entity,
+ true, false, false, false, false, false, nil)){
+ frontZ = point.point.z;
+ m_pCurGroundEntity = entity;
+ }else{
+ frontZ = field_21C;
+ }
+
+ CVector rear(GetPosition().x - GetForward().x*lenBack,
+ GetPosition().y - GetForward().y*lenBack,
+ GetPosition().z + 5.0f);
+ if(CWorld::ProcessVerticalLine(rear, GetPosition().z - 5.0f, point, entity,
+ true, false, false, false, false, false, nil)){
+ rearZ = point.point.z;
+ m_pCurGroundEntity = entity;
+ }else{
+ rearZ = field_220;
+ }
+
+ float len = lenFwd + lenBack;
+ float angle = Atan((frontZ - rearZ)/len);
+ float c = Cos(angle);
+ float s = Sin(angle);
+
+ GetRight() = CVector((front.y - rear.y)/len, -(front.x - rear.x)/len, 0.0f);
+ GetForward() = CVector(-c*GetRight().y, c*GetRight().x, s);
+ GetUp() = CrossProduct(GetRight(), GetForward());
+ GetPosition() = CVector((front.x + rear.x)/2.0f, (front.y + rear.y)/2.0f, (frontZ + rearZ)/2.0f + GetHeightAboveRoad());
+}
+
+void
+CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece)
+{
+ int i;
+ float damageMultiplier = 0.2f;
+ bool doubleMoney = false;
+
+ if(impulse == 0.0f){
+ impulse = m_fDamageImpulse;
+ damagedPiece = m_nDamagePieceType;
+ damageMultiplier = 1.0f;
+ }
+
+ CVector pos(0.0f, 0.0f, 0.0f);
+
+ if(!bCanBeDamaged)
+ return;
+
+ // damage flipped over car
+ if(GetUp().z < 0.0f && this != FindPlayerVehicle()){
+ if(bNotDamagedUpsideDown || m_status == STATUS_PLAYER_REMOTE || bIsInWater)
+ return;
+ m_fHealth -= 4.0f*CTimer::GetTimeStep();
+ }
+
+ if(impulse > 25.0f && m_status != STATUS_WRECKED){
+ if(bIsLawEnforcer &&
+ FindPlayerVehicle() && FindPlayerVehicle() == m_pDamageEntity &&
+ m_status != STATUS_ABANDONED &&
+ FindPlayerVehicle()->m_vecMoveSpeed.Magnitude() >= m_vecMoveSpeed.Magnitude() &&
+ FindPlayerVehicle()->m_vecMoveSpeed.Magnitude() > 0.1f)
+ FindPlayerPed()->SetWantedLevelNoDrop(1);
+
+ if(m_status == STATUS_PLAYER && impulse > 50.0f){
+ uint8 freq = min(0.4f*impulse*2000.0f/m_fMass + 100.0f, 250.0f);
+ CPad::GetPad(0)->StartShake(40000/freq, freq);
+ }
+
+ if(bOnlyDamagedByPlayer){
+ if(m_pDamageEntity != FindPlayerPed() &&
+ m_pDamageEntity != FindPlayerVehicle())
+ return;
+ }
+
+ if(bCollisionProof)
+ return;
+
+ if(m_pDamageEntity){
+ if(m_pDamageEntity->IsBuilding() &&
+ DotProduct(m_vecDamageNormal, GetUp()) > 0.6f)
+ return;
+ }
+
+ int oldLightStatus[4];
+ for(i = 0; i < 4; i++)
+ oldLightStatus[i] = Damage.GetLightStatus((eLights)i);
+
+ if(GetUp().z > 0.0f || m_vecMoveSpeed.MagnitudeSqr() > 0.1f){
+ float impulseMult = bMoreResistantToDamage ? 0.5f : 4.0f;
+
+ switch(damagedPiece){
+ case CAR_PIECE_BUMP_FRONT:
+ GetComponentWorldPosition(CAR_BUMP_FRONT, pos);
+ dmgDrawCarCollidingParticles(pos, impulse);
+ if(Damage.ApplyDamage(COMPONENT_BUMPER_FRONT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ SetBumperDamage(CAR_BUMP_FRONT, VEHBUMPER_FRONT);
+ doubleMoney = true;
+ }
+ if(m_aCarNodes[CAR_BONNET] && Damage.GetPanelStatus(VEHBUMPER_FRONT) == PANEL_STATUS_MISSING){
+ case CAR_PIECE_BONNET:
+ GetComponentWorldPosition(CAR_BONNET, pos);
+ dmgDrawCarCollidingParticles(pos, impulse);
+ if(Damage.ApplyDamage(COMPONENT_DOOR_BONNET, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ SetDoorDamage(CAR_BONNET, DOOR_BONNET);
+ doubleMoney = true;
+ }
+ }
+ break;
+
+ case CAR_PIECE_BUMP_REAR:
+ GetComponentWorldPosition(CAR_BUMP_REAR, pos);
+ dmgDrawCarCollidingParticles(pos, impulse);
+ if(Damage.ApplyDamage(COMPONENT_BUMPER_FRONT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ SetBumperDamage(CAR_BUMP_REAR, VEHBUMPER_REAR);
+ doubleMoney = true;
+ }
+ if(m_aCarNodes[CAR_BOOT] && Damage.GetPanelStatus(VEHBUMPER_REAR) == PANEL_STATUS_MISSING){
+ case CAR_PIECE_BOOT:
+ GetComponentWorldPosition(CAR_BOOT, pos);
+ dmgDrawCarCollidingParticles(pos, impulse);
+ if(Damage.ApplyDamage(COMPONENT_DOOR_BOOT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ SetDoorDamage(CAR_BOOT, DOOR_BOOT);
+ doubleMoney = true;
+ }
+ }
+ break;
+
+ case CAR_PIECE_DOOR_LF:
+ GetComponentWorldPosition(CAR_DOOR_LF, pos);
+ dmgDrawCarCollidingParticles(pos, impulse);
+ if((m_nDoorLock == CARLOCK_NOT_USED || m_nDoorLock == CARLOCK_UNLOCKED) &&
+ Damage.ApplyDamage(COMPONENT_DOOR_FRONT_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ SetDoorDamage(CAR_DOOR_LF, DOOR_FRONT_LEFT);
+ doubleMoney = true;
+ }
+ break;
+ case CAR_PIECE_DOOR_RF:
+ GetComponentWorldPosition(CAR_DOOR_RF, pos);
+ dmgDrawCarCollidingParticles(pos, impulse);
+ if((m_nDoorLock == CARLOCK_NOT_USED || m_nDoorLock == CARLOCK_UNLOCKED) &&
+ Damage.ApplyDamage(COMPONENT_DOOR_FRONT_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ SetDoorDamage(CAR_DOOR_RF, DOOR_FRONT_RIGHT);
+ doubleMoney = true;
+ }
+ break;
+ case CAR_PIECE_DOOR_LR:
+ GetComponentWorldPosition(CAR_DOOR_LR, pos);
+ dmgDrawCarCollidingParticles(pos, impulse);
+ if((m_nDoorLock == CARLOCK_NOT_USED || m_nDoorLock == CARLOCK_UNLOCKED) &&
+ Damage.ApplyDamage(COMPONENT_DOOR_REAR_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ SetDoorDamage(CAR_DOOR_LR, DOOR_REAR_LEFT);
+ doubleMoney = true;
+ }
+ break;
+ case CAR_PIECE_DOOR_RR:
+ GetComponentWorldPosition(CAR_DOOR_RR, pos);
+ dmgDrawCarCollidingParticles(pos, impulse);
+ if((m_nDoorLock == CARLOCK_NOT_USED || m_nDoorLock == CARLOCK_UNLOCKED) &&
+ Damage.ApplyDamage(COMPONENT_DOOR_REAR_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ SetDoorDamage(CAR_DOOR_RR, DOOR_REAR_RIGHT);
+ doubleMoney = true;
+ }
+ break;
+
+ case CAR_PIECE_WING_LF:
+ GetComponentWorldPosition(CAR_WING_LF, pos);
+ dmgDrawCarCollidingParticles(pos, impulse);
+ if(Damage.ApplyDamage(COMPONENT_PANEL_FRONT_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ SetPanelDamage(CAR_WING_LF, VEHPANEL_FRONT_LEFT);
+ doubleMoney = true;
+ }
+ break;
+ case CAR_PIECE_WING_RF:
+ GetComponentWorldPosition(CAR_WING_RF, pos);
+ dmgDrawCarCollidingParticles(pos, impulse);
+ if(Damage.ApplyDamage(COMPONENT_PANEL_FRONT_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ SetPanelDamage(CAR_WING_RF, VEHPANEL_FRONT_RIGHT);
+ doubleMoney = true;
+ }
+ break;
+ case CAR_PIECE_WING_LR:
+ GetComponentWorldPosition(CAR_WING_LR, pos);
+ dmgDrawCarCollidingParticles(pos, impulse);
+ if(Damage.ApplyDamage(COMPONENT_PANEL_REAR_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ SetPanelDamage(CAR_WING_LR, VEHPANEL_REAR_LEFT);
+ doubleMoney = true;
+ }
+ break;
+ case CAR_PIECE_WING_RR:
+ GetComponentWorldPosition(CAR_WING_RR, pos);
+ dmgDrawCarCollidingParticles(pos, impulse);
+ if(Damage.ApplyDamage(COMPONENT_PANEL_REAR_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ SetPanelDamage(CAR_WING_RR, VEHPANEL_REAR_RIGHT);
+ doubleMoney = true;
+ }
+ break;
+
+ case CAR_PIECE_WHEEL_LF:
+ case CAR_PIECE_WHEEL_LR:
+ case CAR_PIECE_WHEEL_RF:
+ case CAR_PIECE_WHEEL_RR:
+ break;
+
+ case CAR_PIECE_WINDSCREEN:
+ if(Damage.ApplyDamage(COMPONENT_PANEL_WINDSCREEN, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ uint8 oldStatus = Damage.GetPanelStatus(VEHPANEL_WINDSCREEN);
+ SetPanelDamage(CAR_WINDSCREEN, VEHPANEL_WINDSCREEN);
+ if(oldStatus != Damage.GetPanelStatus(VEHPANEL_WINDSCREEN)){
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_WINDSHIELD_CRACK, 0.0f);
+ doubleMoney = true;
+ }
+ }
+ break;
+ }
+
+ if(m_pDamageEntity && m_pDamageEntity == FindPlayerVehicle() && impulse > 10.0f){
+ int money = (doubleMoney ? 2 : 1) * impulse*pHandling->nMonetaryValue/1000000.0f;
+ money = min(money, 40);
+ if(money > 2){
+ sprintf(gString, "$%d", money);
+ CWorld::Players[CWorld::PlayerInFocus].m_nMoney += money;
+ }
+ }
+ }
+
+ float damage = (impulse-25.0f)*pHandling->fCollisionDamageMultiplier*0.6f*damageMultiplier;
+
+ if(GetModelIndex() == MI_SECURICA && m_pDamageEntity && m_pDamageEntity->m_status == STATUS_PLAYER)
+ damage *= 7.0f;
+
+ if(damage > 0.0f){
+ int oldHealth = m_fHealth;
+ if(this == FindPlayerVehicle()){
+ m_fHealth -= bTakeLessDamage ? damage/6.0f : damage/2.0f;
+ }else{
+ if(damage > 35.0f && pDriver)
+ pDriver->Say(SOUND_PED_CAR_COLLISION);
+ m_fHealth -= bTakeLessDamage ? damage/12.0f : damage/4.0f;
+ }
+ if(m_fHealth <= 0.0f && oldHealth > 0)
+ m_fHealth = 1.0f;
+ }
+
+ // play sound if a light broke
+ for(i = 0; i < 4; i++)
+ if(oldLightStatus[i] != 1 && Damage.GetLightStatus((eLights)i) == 1){
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_LIGHT_BREAK, i); // BUG? i?
+ break;
+ }
+ }
+
+ if(m_fHealth < 250.0f){
+ // Car is on fire
+ if(Damage.GetEngineStatus() < ENGINE_STATUS_ON_FIRE){
+ // Set engine on fire and remember who did this
+ Damage.SetEngineStatus(ENGINE_STATUS_ON_FIRE);
+ m_fFireBlowUpTimer = 0.0f;
+ m_pSetOnFireEntity = m_pDamageEntity;
+ if(m_pSetOnFireEntity)
+ m_pSetOnFireEntity->RegisterReference(&m_pSetOnFireEntity);
+ }
+ }else{
+ if(GetModelIndex() == MI_BFINJECT){
+ if(m_fHealth < 400.0f)
+ Damage.SetEngineStatus(200);
+ else if(m_fHealth < 600.0f)
+ Damage.SetEngineStatus(100);
+ }
+ }
+}
+
+void
+CAutomobile::dmgDrawCarCollidingParticles(const CVector &pos, float amount)
+{
+ int i, n;
+
+ if(!GetIsOnScreen())
+ return;
+
+ // FindPlayerSpeed() unused
+
+ n = (int)amount/20;
+
+ for(i = 0; i < ((n+4)&0x1F); i++)
+ CParticle::AddParticle(PARTICLE_SPARK_SMALL, pos,
+ CVector(CGeneral::GetRandomNumberInRange(-0.1f, 0.1f),
+ CGeneral::GetRandomNumberInRange(-0.1f, 0.1f),
+ 0.006f));
+
+ for(i = 0; i < n+2; i++)
+ CParticle::AddParticle(PARTICLE_CARCOLLISION_DUST,
+ CVector(CGeneral::GetRandomNumberInRange(-1.2f, 1.2f) + pos.x,
+ CGeneral::GetRandomNumberInRange(-1.2f, 1.2f) + pos.y,
+ pos.z),
+ CVector(0.0f, 0.0f, 0.0f), nil, 0.5f);
+
+ n = (int)amount/50 + 1;
+ for(i = 0; i < n; i++)
+ CParticle::AddParticle(PARTICLE_CAR_DEBRIS, pos,
+ CVector(CGeneral::GetRandomNumberInRange(-0.25f, 0.25f),
+ CGeneral::GetRandomNumberInRange(-0.25f, 0.25f),
+ CGeneral::GetRandomNumberInRange(0.1f, 0.25f)),
+ nil,
+ CGeneral::GetRandomNumberInRange(0.02f, 0.08f),
+ CVehicleModelInfo::ms_vehicleColourTable[m_currentColour1],
+ CGeneral::GetRandomNumberInRange(-40.0f, 40.0f),
+ 0,
+ CGeneral::GetRandomNumberInRange(0.0f, 4.0f));
+}
void
CAutomobile::GetComponentWorldPosition(int32 component, CVector &pos)
@@ -390,6 +2141,7 @@ CAutomobile::BlowUpCar(CEntity *culprit)
SetDoorDamage(CAR_DOOR_LR, DOOR_REAR_LEFT);
SetDoorDamage(CAR_DOOR_RR, DOOR_REAR_RIGHT);
SpawnFlyingComponent(CAR_WHEEL_LF, COMPGROUP_WHEEL);
+ atomic = nil;
RwFrameForAllObjects(m_aCarNodes[CAR_WHEEL_LF], GetCurrentAtomicObjectCB, &atomic);
if(atomic)
RpAtomicSetFlags(atomic, 0);
@@ -397,7 +2149,7 @@ CAutomobile::BlowUpCar(CEntity *culprit)
m_fHealth = 0.0f;
m_nBombTimer = 0;
- m_auto_flagA7 = 0;
+ m_bombType = CARBOMB_NONE;
TheCamera.CamShake(0.7f, GetPosition().x, GetPosition().y, GetPosition().z);
@@ -533,8 +2285,8 @@ CAutomobile::PlayCarHorn(void)
void
CAutomobile::PlayHornIfNecessary(void)
{
- if(m_autoPilot.m_flag2 ||
- m_autoPilot.m_flag1)
+ if(AutoPilot.m_flag2 ||
+ AutoPilot.m_flag1)
if(!HasCarStoppedBecauseOfLight())
PlayCarHorn();
}
@@ -546,9 +2298,9 @@ CAutomobile::ResetSuspension(void)
int i;
for(i = 0; i < 4; i++){
m_aSuspensionSpringRatio[i] = 1.0f;
- m_aWheelSkidThing[i] = 0.0f;
+ m_aWheelTimer[i] = 0.0f;
m_aWheelRotation[i] = 0.0f;
- m_aWheelState[i] = 0; // TODO: enum?
+ m_aWheelState[i] = WHEEL_STATE_0;
}
}
@@ -567,23 +2319,23 @@ CAutomobile::SetupSuspensionLines(void)
m_aWheelPosition[i] = posn.z;
// uppermost wheel position
- posn.z += m_handling->fSuspensionUpperLimit;
+ posn.z += pHandling->fSuspensionUpperLimit;
colModel->lines[i].p0 = posn;
// lowermost wheel position
- posn.z += m_handling->fSuspensionLowerLimit - m_handling->fSuspensionUpperLimit;
+ posn.z += pHandling->fSuspensionLowerLimit - pHandling->fSuspensionUpperLimit;
// lowest point on tyre
posn.z -= mi->m_wheelScale*0.5f;
colModel->lines[i].p1 = posn;
// this is length of the spring at rest
- m_aSuspensionSpringLength[i] = m_handling->fSuspensionUpperLimit - m_handling->fSuspensionLowerLimit;
+ m_aSuspensionSpringLength[i] = pHandling->fSuspensionUpperLimit - pHandling->fSuspensionLowerLimit;
m_aSuspensionLineLength[i] = colModel->lines[i].p0.z - colModel->lines[i].p1.z;
}
// Compress spring somewhat to get normal height on road
m_fHeightAboveRoad = -(colModel->lines[0].p0.z + (colModel->lines[0].p1.z - colModel->lines[0].p0.z)*
- (1.0f - 1.0f/(8.0f*m_handling->fSuspensionForceLevel)));
+ (1.0f - 1.0f/(8.0f*pHandling->fSuspensionForceLevel)));
for(i = 0; i < 4; i++)
m_aWheelPosition[i] = mi->m_wheelScale*0.5f - m_fHeightAboveRoad;
@@ -606,7 +2358,7 @@ void
CAutomobile::ScanForCrimes(void)
{
if(FindPlayerVehicle() && FindPlayerVehicle()->IsCar())
- if(FindPlayerVehicle()->m_nAlarmState != -1)
+ if(FindPlayerVehicle()->IsAlarmOn())
// if player's alarm is on, increase wanted level
if((FindPlayerVehicle()->GetPosition() - GetPosition()).MagnitudeSqr() < sq(20.0f))
CWorld::Players[CWorld::PlayerInFocus].m_pPed->SetWantedLevelNoDrop(1);
@@ -634,20 +2386,20 @@ CAutomobile::HasCarStoppedBecauseOfLight(void)
if(m_status != STATUS_SIMPLE && m_status != STATUS_PHYSICS)
return false;
- if(m_autoPilot.m_nCurrentRouteNode && m_autoPilot.m_nNextRouteNode){
- CPathNode *curnode = &ThePaths.m_pathNodes[m_autoPilot.m_nCurrentRouteNode];
+ if(AutoPilot.m_nCurrentRouteNode && AutoPilot.m_nNextRouteNode){
+ CPathNode *curnode = &ThePaths.m_pathNodes[AutoPilot.m_nCurrentRouteNode];
for(i = 0; i < curnode->numLinks; i++)
- if(ThePaths.m_connections[curnode->firstLink + i] == m_autoPilot.m_nNextRouteNode)
+ if(ThePaths.m_connections[curnode->firstLink + i] == AutoPilot.m_nNextRouteNode)
break;
if(i < curnode->numLinks &&
ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[curnode->firstLink + i]].trafficLightType & 3) // TODO
return true;
}
- if(m_autoPilot.m_nCurrentRouteNode && m_autoPilot.m_nPrevRouteNode){
- CPathNode *curnode = &ThePaths.m_pathNodes[m_autoPilot.m_nCurrentRouteNode];
+ if(AutoPilot.m_nCurrentRouteNode && AutoPilot.m_nPrevRouteNode){
+ CPathNode *curnode = &ThePaths.m_pathNodes[AutoPilot.m_nCurrentRouteNode];
for(i = 0; i < curnode->numLinks; i++)
- if(ThePaths.m_connections[curnode->firstLink + i] == m_autoPilot.m_nPrevRouteNode)
+ if(ThePaths.m_connections[curnode->firstLink + i] == AutoPilot.m_nPrevRouteNode)
break;
if(i < curnode->numLinks &&
ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[curnode->firstLink + i]].trafficLightType & 3) // TODO
@@ -734,7 +2486,7 @@ CAutomobile::Fix(void)
Damage.ResetDamageStatus();
- if(m_handling->Flags & HANDLING_NO_DOORS){
+ if(pHandling->Flags & HANDLING_NO_DOORS){
Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_MISSING);
Damage.SetDoorStatus(DOOR_FRONT_RIGHT, DOOR_STATUS_MISSING);
Damage.SetDoorStatus(DOOR_REAR_LEFT, DOOR_STATUS_MISSING);
@@ -860,7 +2612,7 @@ CAutomobile::SpawnFlyingComponent(int32 component, uint32 type)
obj->m_fElasticity = 0.1f;
obj->m_fBuoyancy = obj->m_fMass*GRAVITY/0.75f;
obj->ObjectCreatedBy = TEMP_OBJECT;
- obj->bIsStatic = true;
+ obj->bIsStatic = false;
obj->bIsPickup = false;
obj->bUseVehicleColours = true;
obj->m_colour1 = m_currentColour1;
@@ -987,7 +2739,7 @@ CAutomobile::SetDoorDamage(int32 component, eDoors door, bool noFlyingComponents
return;
}
- if(door == DOOR_BOOT && status == DOOR_STATUS_SWINGING && m_handling->Flags & HANDLING_NOSWING_BOOT){
+ if(door == DOOR_BOOT && status == DOOR_STATUS_SWINGING && pHandling->Flags & HANDLING_NOSWING_BOOT){
Damage.SetDoorStatus(DOOR_BOOT, DOOR_STATUS_MISSING);
status = DOOR_STATUS_MISSING;
}
@@ -1051,7 +2803,7 @@ CAutomobile::SetTaxiLight(bool light)
bool
CAutomobile::GetAllWheelsOffGround(void)
{
- return m_nWheelsOnGround == 0;
+ return m_nDriveWheelsOnGround == 0;
}
void
@@ -1091,7 +2843,7 @@ public:
int32 ProcessEntityCollision_(CEntity *ent, CColPoint *colpoints){ return CAutomobile::ProcessEntityCollision(ent, colpoints); }
- void ProcessControlInputs_(uint8 x) { CAutomobile::ProcessControlInputs(x); }
+ void ProcessControlInputs_(uint8 pad) { CAutomobile::ProcessControlInputs(pad); }
void GetComponentWorldPosition_(int32 component, CVector &pos) { CAutomobile::GetComponentWorldPosition(component, pos); }
bool IsComponentPresent_(int32 component) { return CAutomobile::IsComponentPresent(component); }
void SetComponentRotation_(int32 component, CVector rotation) { CAutomobile::SetComponentRotation(component, rotation); }
@@ -1113,8 +2865,10 @@ public:
STARTPATCHES
InjectHook(0x52D170, &CAutomobile_::dtor, PATCH_JUMP);
InjectHook(0x52D190, &CAutomobile_::SetModelIndex_, PATCH_JUMP);
+ InjectHook(0x531470, &CAutomobile_::ProcessControl_, PATCH_JUMP);
InjectHook(0x535180, &CAutomobile_::Teleport_, PATCH_JUMP);
InjectHook(0x53B270, &CAutomobile_::ProcessEntityCollision_, PATCH_JUMP);
+ InjectHook(0x53B660, &CAutomobile_::ProcessControlInputs_, PATCH_JUMP);
InjectHook(0x52E5F0, &CAutomobile_::GetComponentWorldPosition_, PATCH_JUMP);
InjectHook(0x52E660, &CAutomobile_::IsComponentPresent_, PATCH_JUMP);
InjectHook(0x52E680, &CAutomobile_::SetComponentRotation_, PATCH_JUMP);
@@ -1129,6 +2883,8 @@ STARTPATCHES
InjectHook(0x53C0E0, &CAutomobile_::BurstTyre_, PATCH_JUMP);
InjectHook(0x437690, &CAutomobile_::GetHeightAboveRoad_, PATCH_JUMP);
InjectHook(0x53C450, &CAutomobile_::PlayCarHorn_, PATCH_JUMP);
+ InjectHook(0x53E090, &CAutomobile::PlaceOnRoadProperly, PATCH_JUMP);
+ InjectHook(0x52F030, &CAutomobile::dmgDrawCarCollidingParticles, PATCH_JUMP);
InjectHook(0x5353A0, &CAutomobile::ResetSuspension, PATCH_JUMP);
InjectHook(0x52D210, &CAutomobile::SetupSuspensionLines, PATCH_JUMP);
InjectHook(0x53E000, &CAutomobile::BlowUpCarsInPath, PATCH_JUMP);
diff --git a/src/vehicles/Automobile.h b/src/vehicles/Automobile.h
index 60e08d0a..1a103777 100644
--- a/src/vehicles/Automobile.h
+++ b/src/vehicles/Automobile.h
@@ -6,6 +6,25 @@
class CObject;
+// These are used for all the wheel arrays
+// DON'T confuse with VEHWHEEL, which are vehicle components
+enum {
+ CARWHEEL_FRONT_LEFT,
+ CARWHEEL_REAR_LEFT,
+ CARWHEEL_FRONT_RIGHT,
+ CARWHEEL_REAR_RIGHT
+};
+
+enum eBombType
+{
+ CARBOMB_NONE,
+ CARBOMB_TIMED,
+ CARBOMB_ONIGNITION,
+ CARBOMB_REMOTE,
+ CARBOMB_TIMEDACTIVE,
+ CARBOMB_ONIGNITIONACTIVE,
+};
+
class CAutomobile : public CVehicle
{
public:
@@ -16,7 +35,7 @@ public:
CColPoint m_aWheelColPoints[4];
float m_aSuspensionSpringRatio[4];
float m_aSuspensionSpringRatioPrev[4];
- float m_aWheelSkidThing[4];
+ float m_aWheelTimer[4]; // set to 4.0 when wheel is touching ground, then decremented
float field_49C;
bool m_aWheelSkidmarkMuddy[4];
bool m_aWheelSkidmarkBloody[4];
@@ -24,39 +43,45 @@ public:
float m_aWheelPosition[4];
float m_aWheelSpeed[4];
uint8 field_4D8;
- uint8 m_auto_flagA7 : 1;
+ uint8 m_bombType : 3;
uint8 bTaxiLight : 1;
- uint8 m_auto_flagA10 : 1;
+ uint8 bHadDriver : 1; // for bombs
uint8 m_auto_flagA20 : 1;
uint8 m_auto_flagA40 : 1;
uint8 m_auto_flagA80 : 1;
- uint8 field_4DA[10];
+ uint8 bNotDamagedUpsideDown : 1;
+ uint8 bMoreResistantToDamage : 1;
+ uint8 field_4DB;
+ CEntity *m_pBombRigger;
+ int16 field_4E0;
+ int16 field_4E2;
uint32 m_nBusDoorTimerEnd;
uint32 m_nBusDoorTimerStart;
float m_aSuspensionSpringLength[4];
float m_aSuspensionLineLength[4];
float m_fHeightAboveRoad;
- float m_fImprovedHandling;
- uint8 stuff6[28];
- float field_530;
+ float m_fTraction;
+ float m_fVelocityChangeForAudio;
+ float m_randomValues[6]; // used for what?
+ float m_fFireBlowUpTimer;
CPhysical *m_aGroundPhysical[4]; // physicals touching wheels
CVector m_aGroundOffset[4]; // from ground object to colpoint
- CEntity *m_pBlowUpEntity;
- float m_weaponThingA; // TODO
- float m_weaponThingB; // TODO
+ CEntity *m_pSetOnFireEntity;
+ float m_weaponDoorTimerLeft; // still don't know what exactly this is
+ float m_weaponDoorTimerRight;
float m_fCarGunLR;
float m_fCarGunUD;
float m_fWindScreenRotation;
uint8 stuff4[4];
- uint8 m_nWheelsOnGround_2;
uint8 m_nWheelsOnGround;
- uint8 m_nWheelsOnGroundPrev;
- uint8 stuff5[5];
- int32 m_aWheelState[4];
+ uint8 m_nDriveWheelsOnGround;
+ uint8 m_nDriveWheelsOnGroundPrev;
+ int32 field_594;
+ tWheelState m_aWheelState[4];
static bool &m_sAllTaxiLights;
- CAutomobile(int, uint8);
+ CAutomobile(int32, uint8);
// from CEntity
void SetModelIndex(uint32 id);
@@ -87,6 +112,16 @@ public:
float GetHeightAboveRoad(void);
void PlayCarHorn(void);
+ void FireTruckControl(void);
+ void TankControl(void);
+ void HydraulicControl(void);
+ void VehicleDamage(float impulse, uint16 damagedPiece);
+ void ProcessBuoyancy(void);
+ void DoDriveByShootings(void);
+ int32 RcbanditCheckHitWheels(void);
+ int32 RcbanditCheck1CarWheels(CPtrList &list);
+ void PlaceOnRoadProperly(void);
+ void dmgDrawCarCollidingParticles(const CVector &pos, float amount);
void PlayHornIfNecessary(void);
void ResetSuspension(void);
void SetupSuspensionLines(void);
@@ -113,7 +148,5 @@ public:
void ReduceHornCounter(void);
static void SetAllTaxiLights(bool set);
-
- CAutomobile* ctor(int, uint8);
};
static_assert(sizeof(CAutomobile) == 0x5A8, "CAutomobile: error");
diff --git a/src/vehicles/DamageManager.cpp b/src/vehicles/DamageManager.cpp
index 380537f2..3a7bd9e9 100644
--- a/src/vehicles/DamageManager.cpp
+++ b/src/vehicles/DamageManager.cpp
@@ -7,6 +7,13 @@
float G_aComponentDamage[] = { 2.5f, 1.25f, 3.2f, 1.4f, 2.5f, 2.8f, 0.5f };
+CDamageManager::CDamageManager(void)
+{
+ ResetDamageStatus();
+ m_fWheelDamageEffect = 0.75f;
+ field_24 = 1;
+}
+
void
CDamageManager::ResetDamageStatus(void)
{
@@ -18,15 +25,15 @@ CDamageManager::FuckCarCompletely(void)
{
int i;
- m_wheelStatus[0] = 2;
+ m_wheelStatus[0] = WHEEL_STATUS_MISSING;
// wheels 1-3 not reset?
- m_doorStatus[0] = 3;
- m_doorStatus[1] = 3;
- m_doorStatus[2] = 3;
- m_doorStatus[3] = 3;
- m_doorStatus[4] = 3;
- m_doorStatus[5] = 3;
+ m_doorStatus[0] = DOOR_STATUS_MISSING;
+ m_doorStatus[1] = DOOR_STATUS_MISSING;
+ m_doorStatus[2] = DOOR_STATUS_MISSING;
+ m_doorStatus[3] = DOOR_STATUS_MISSING;
+ m_doorStatus[4] = DOOR_STATUS_MISSING;
+ m_doorStatus[5] = DOOR_STATUS_MISSING;
for(i = 0; i < 3; i++){
#ifdef FIX_BUGS
@@ -216,8 +223,8 @@ CDamageManager::ProgressEngineDamage(void)
{
int status = GetEngineStatus();
int newstatus = status + 32 + (CGeneral::GetRandomNumber() & 0x1F);
- if(status < 225 && newstatus > 224)
- newstatus = 224;
+ if(status < ENGINE_STATUS_ON_FIRE && newstatus > ENGINE_STATUS_ON_FIRE-1)
+ newstatus = ENGINE_STATUS_ON_FIRE-1;
SetEngineStatus(newstatus);
return true;
}
diff --git a/src/vehicles/DamageManager.h b/src/vehicles/DamageManager.h
index b815f724..adcd7430 100644
--- a/src/vehicles/DamageManager.h
+++ b/src/vehicles/DamageManager.h
@@ -4,6 +4,11 @@
// TODO: move some of this into Vehicle.h
+enum eEngineStatus
+{
+ ENGINE_STATUS_ON_FIRE = 225
+};
+
enum eDoorStatus
{
DOOR_STATUS_OK,
@@ -23,7 +28,8 @@ enum ePanelStatus
enum eWheelStatus
{
WHEEL_STATUS_OK,
- WHEEL_STATUS_BURST
+ WHEEL_STATUS_BURST,
+ WHEEL_STATUS_MISSING
};
enum tComponent
@@ -65,7 +71,7 @@ class CDamageManager
{
public:
- float field_0;
+ float m_fWheelDamageEffect;
uint8 m_engineStatus;
uint8 m_wheelStatus[4];
uint8 m_doorStatus[6];
@@ -73,6 +79,8 @@ public:
uint32 m_panelStatus;
uint32 field_24;
+ CDamageManager(void);
+
void ResetDamageStatus(void);
void FuckCarCompletely(void);
bool ApplyDamage(tComponent component, float damage, float unused);
diff --git a/src/vehicles/Door.h b/src/vehicles/Door.h
index fc771a40..7bb7bba3 100644
--- a/src/vehicles/Door.h
+++ b/src/vehicles/Door.h
@@ -26,6 +26,12 @@ struct CDoor
CVector m_vecSpeed;
CDoor(void);
+ void Init(float minAngle, float maxAngle, int8 dir, int8 axis) {
+ m_fMinAngle = minAngle;
+ m_fMaxAngle = maxAngle;
+ m_nDirn = dir;
+ m_nAxis = axis;
+ }
void Open(float ratio);
void Process(CVehicle *veh);
float RetAngleWhenClosed(void);
diff --git a/src/vehicles/Floater.cpp b/src/vehicles/Floater.cpp
new file mode 100644
index 00000000..cabe00c3
--- /dev/null
+++ b/src/vehicles/Floater.cpp
@@ -0,0 +1,195 @@
+#include "common.h"
+#include "patcher.h"
+#include "Timer.h"
+#include "WaterLevel.h"
+#include "ModelIndices.h"
+#include "Physical.h"
+#include "Vehicle.h"
+#include "Floater.h"
+
+cBuoyancy &mod_Buoyancy = *(cBuoyancy*)0x8F2674;
+
+//static float fVolMultiplier = 1.0f;
+static float &fVolMultiplier = *(float*)0x601394;
+// amount of boat volume in bounding box
+// 1.0-volume is the empty space in the bbox
+static float fBoatVolumeDistribution[9] = {
+ // rear
+ 0.75f, 0.9f, 0.75f,
+ 0.95f, 1.0f, 0.95f,
+ 0.3f, 0.7f, 0.3f
+ // bow
+};
+
+bool
+cBuoyancy::ProcessBuoyancy(CPhysical *phys, float buoyancy, CVector *impulse, CVector *point)
+{
+ m_numSteps = 2.0f;
+
+ if(!CWaterLevel::GetWaterLevel(phys->GetPosition(), &m_waterlevel, phys->m_flagD8))
+ return false;
+ m_matrix = phys->GetMatrix();
+
+ PreCalcSetup(phys, buoyancy);
+ SimpleCalcBuoyancy();
+ float f = CalcBuoyancyForce(phys, impulse, point);
+ if(m_isBoat)
+ return true;
+ return f != 0.0f;
+}
+
+void
+cBuoyancy::PreCalcSetup(CPhysical *phys, float buoyancy)
+{
+ CColModel *colModel;
+
+ m_isBoat = phys->IsVehicle() && ((CVehicle*)phys)->IsBoat();
+ colModel = phys->GetColModel();
+ m_dimMin = colModel->boundingBox.min;
+ m_dimMax = colModel->boundingBox.max;
+
+ if(m_isBoat){
+ if(phys->GetModelIndex() == MI_PREDATOR){
+ m_dimMax.y *= 0.9f;
+ m_dimMin.y *= 0.9f;
+ }else if(phys->GetModelIndex() == MI_SPEEDER){
+ m_dimMax.y *= 1.1f;
+ m_dimMin.y *= 0.9f;
+ }else if(phys->GetModelIndex() == MI_REEFER){
+ m_dimMin.y *= 0.9f;
+ }else{
+ m_dimMax.y *= 0.9f;
+ m_dimMin.y *= 0.9f;
+ }
+ }
+
+ m_step = (m_dimMax - m_dimMin)/m_numSteps;
+
+ if(m_step.z > m_step.x && m_step.z > m_step.y){
+ m_stepRatio.x = m_step.x/m_step.z;
+ m_stepRatio.y = m_step.y/m_step.z;
+ m_stepRatio.z = 1.0f;
+ }else if(m_step.y > m_step.x && m_step.y > m_step.z){
+ m_stepRatio.x = m_step.x/m_step.y;
+ m_stepRatio.y = 1.0f;
+ m_stepRatio.z = m_step.z/m_step.y;
+ }else{
+ m_stepRatio.x = 1.0f;
+ m_stepRatio.y = m_step.y/m_step.x;
+ m_stepRatio.z = m_step.z/m_step.x;
+ }
+
+ m_haveVolume = false;
+ m_numPartialVolumes = 1.0f;
+ m_volumeUnderWater = 0.0f;
+ m_impulse = CVector(0.0f, 0.0f, 0.0f);
+ m_position = phys->GetPosition();
+ m_positionZ = CVector(0.0f, 0.0f, m_position.z);
+ m_buoyancy = buoyancy;
+ m_waterlevel += m_waterLevelInc;
+}
+
+void
+cBuoyancy::SimpleCalcBuoyancy(void)
+{
+ float x, y;
+ int ix, i;
+ tWaterLevel waterPosition;
+
+ // Floater is divided into 3x3 parts. Process and sum each of them
+ ix = 0;
+ for(x = m_dimMin.x; x <= m_dimMax.x; x += m_step.x){
+ i = ix;
+ for(y = m_dimMin.y; y <= m_dimMax.y; y += m_step.y){
+ CVector waterLevel(x, y, 0.0f);
+ FindWaterLevel(m_positionZ, &waterLevel, &waterPosition);
+ fVolMultiplier = m_isBoat ? fBoatVolumeDistribution[i] : 1.0f;
+ if(waterPosition != FLOATER_ABOVE_WATER)
+ SimpleSumBuoyancyData(waterLevel, waterPosition);
+ i += 3;
+ }
+ ix++;
+ }
+
+ m_volumeUnderWater /= (m_dimMax.z - m_dimMin.z)*sq(m_numSteps+1.0f);
+}
+
+float
+cBuoyancy::SimpleSumBuoyancyData(CVector &waterLevel, tWaterLevel waterPosition)
+{
+ static float fThisVolume;
+ static CVector AverageOfWaterLevel;
+ static float fFraction;
+ static float fRemainingSlice;
+
+ float submerged = Abs(waterLevel.z - m_dimMin.z);
+ // subtract empty space from submerged volume
+ fThisVolume = submerged - (1.0f - fVolMultiplier);
+ if(fThisVolume < 0.0f)
+ return 0.0f;
+
+ if(m_isBoat){
+ fThisVolume *= fVolMultiplier;
+ if(fThisVolume < 0.5f)
+ fThisVolume = 2.0f*sq(fThisVolume);
+ if(fThisVolume < 1.0f)
+ fThisVolume = sq(fThisVolume);
+ fThisVolume = sq(fThisVolume);
+ }
+
+ m_volumeUnderWater += fThisVolume;
+
+ AverageOfWaterLevel.x = waterLevel.x * m_stepRatio.x;
+ AverageOfWaterLevel.y = waterLevel.y * m_stepRatio.y;
+ AverageOfWaterLevel.z = (waterLevel.z+m_dimMin.z)/2.0f * m_stepRatio.z;
+
+ if(m_flipAverage)
+ AverageOfWaterLevel = -AverageOfWaterLevel;
+
+ fFraction = 1.0f/m_numPartialVolumes;
+ fRemainingSlice = 1.0f - fFraction;
+ m_impulse = m_impulse*fRemainingSlice + AverageOfWaterLevel*fThisVolume*fFraction;
+ m_numPartialVolumes += 1.0f;
+ m_haveVolume = true;
+ return fThisVolume;
+}
+
+void
+cBuoyancy::FindWaterLevel(const CVector &zpos, CVector *waterLevel, tWaterLevel *waterPosition)
+{
+ *waterPosition = FLOATER_IN_WATER;
+ // waterLevel is a local x,y point
+ // m_position is the global position of our floater
+ // zpos is the global z coordinate of our floater
+ CVector xWaterLevel = Multiply3x3(m_matrix, *waterLevel);
+ CWaterLevel::GetWaterLevel(xWaterLevel.x + m_position.x, xWaterLevel.y + m_position.y, m_position.z,
+ &waterLevel->z, true);
+ waterLevel->z -= xWaterLevel.z + zpos.z; // make local
+ if(waterLevel->z > m_dimMax.z){
+ waterLevel->z = m_dimMax.z;
+ *waterPosition = FLOATER_UNDER_WATER;
+ }else if(waterLevel->z < m_dimMin.z){
+ waterLevel->z = m_dimMin.z;
+ *waterPosition = FLOATER_ABOVE_WATER;
+ }
+}
+
+bool
+cBuoyancy::CalcBuoyancyForce(CPhysical *phys, CVector *impulse, CVector *point)
+{
+ if(!m_haveVolume)
+ return false;
+
+ *impulse = Multiply3x3(m_matrix, m_impulse);
+ *point = CVector(0.0f, 0.0f, m_volumeUnderWater*m_buoyancy*CTimer::GetTimeStep());
+ return true;
+}
+
+STARTPATCHES
+ InjectHook(0x546270, &cBuoyancy::ProcessBuoyancy, PATCH_JUMP);
+ InjectHook(0x546360, &cBuoyancy::PreCalcSetup, PATCH_JUMP);
+ InjectHook(0x5466F0, &cBuoyancy::SimpleCalcBuoyancy, PATCH_JUMP);
+ InjectHook(0x546820, &cBuoyancy::SimpleSumBuoyancyData, PATCH_JUMP);
+ InjectHook(0x546620, &cBuoyancy::FindWaterLevel, PATCH_JUMP);
+ InjectHook(0x5465A0, &cBuoyancy::CalcBuoyancyForce, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/vehicles/Floater.h b/src/vehicles/Floater.h
new file mode 100644
index 00000000..ede2b9d0
--- /dev/null
+++ b/src/vehicles/Floater.h
@@ -0,0 +1,45 @@
+#pragma once
+
+class Physical;
+
+enum tWaterLevel
+{
+ FLOATER_ABOVE_WATER,
+ FLOATER_IN_WATER,
+ FLOATER_UNDER_WATER,
+};
+
+class cBuoyancy
+{
+public:
+ CVector m_position;
+ CMatrix m_matrix;
+ int m_field_54;
+ CVector m_positionZ;
+ float m_waterlevel;
+ float m_waterLevelInc;
+ float m_buoyancy;
+ CVector m_dimMax;
+ CVector m_dimMin;
+ float m_numPartialVolumes;
+ int m_field_8C;
+ int m_field_90;
+ int m_field_94;
+ bool m_haveVolume;
+ CVector m_step;
+ CVector m_stepRatio;
+ float m_numSteps;
+ bool m_flipAverage;
+ char m_field_B9;
+ bool m_isBoat;
+ float m_volumeUnderWater;
+ CVector m_impulse;
+
+ bool ProcessBuoyancy(CPhysical *phys, float buoyancy, CVector *impulse, CVector *point);
+ void PreCalcSetup(CPhysical *phys, float buoyancy);
+ void SimpleCalcBuoyancy(void);
+ float SimpleSumBuoyancyData(CVector &waterLevel, tWaterLevel waterPosition);
+ void FindWaterLevel(const CVector &zpos, CVector *waterLevel, tWaterLevel *waterPosition);
+ bool CalcBuoyancyForce(CPhysical *phys, CVector *impulse, CVector *point);
+};
+extern cBuoyancy &mod_Buoyancy;
diff --git a/src/vehicles/HandlingMgr.cpp b/src/vehicles/HandlingMgr.cpp
index 47d0564c..be96ab08 100644
--- a/src/vehicles/HandlingMgr.cpp
+++ b/src/vehicles/HandlingMgr.cpp
@@ -70,7 +70,7 @@ char VehicleNames[NUMHANDLINGS][14] = {
cHandlingDataMgr::cHandlingDataMgr(void)
{
- memset(this, 0, sizeof(this));
+ memset(this, 0, sizeof(*this));
}
void
@@ -127,7 +127,7 @@ cHandlingDataMgr::LoadHandlingData(void)
handlingId = FindExactWord(word, (const char*)VehicleNames, 14, NUMHANDLINGS);
assert(handlingId >= 0 && handlingId < NUMHANDLINGS);
handling = &HandlingData[handlingId];
- handling->nIdentifier = handlingId;
+ handling->nIdentifier = (eHandlingId)handlingId;
break;
case 1: handling->fMass = strtod(word, nil); break;
case 2: handling->Dimension.x = strtod(word, nil); break;
@@ -140,11 +140,11 @@ cHandlingDataMgr::LoadHandlingData(void)
case 9: handling->fTractionMultiplier = strtod(word, nil); break;
case 10: handling->fTractionLoss = strtod(word, nil); break;
case 11: handling->fTractionBias = strtod(word, nil); break;
- case 12: handling->TransmissionData.nNumberOfGears = atoi(word); break;
- case 13: handling->TransmissionData.fMaxVelocity = strtod(word, nil); break;
- case 14: handling->TransmissionData.fEngineAcceleration = strtod(word, nil) * 0.4f; break;
- case 15: handling->TransmissionData.nDriveType = word[0]; break;
- case 16: handling->TransmissionData.nEngineType = word[0]; break;
+ case 12: handling->Transmission.nNumberOfGears = atoi(word); break;
+ case 13: handling->Transmission.fMaxVelocity = strtod(word, nil); break;
+ case 14: handling->Transmission.fEngineAcceleration = strtod(word, nil) * 0.4f; break;
+ case 15: handling->Transmission.nDriveType = word[0]; break;
+ case 16: handling->Transmission.nEngineType = word[0]; break;
case 17: handling->fBrakeDeceleration = strtod(word, nil); break;
case 18: handling->fBrakeBias = strtod(word, nil); break;
case 19: handling->bABS = !!atoi(word); break;
@@ -159,7 +159,7 @@ cHandlingDataMgr::LoadHandlingData(void)
case 28: handling->fSuspensionBias = strtod(word, nil); break;
case 29:
sscanf(word, "%x", &handling->Flags);
- handling->TransmissionData.Flags = handling->Flags;
+ handling->Transmission.Flags = handling->Flags;
break;
case 30: handling->FrontLights = atoi(word); break;
case 31: handling->RearLights = atoi(word); break;
@@ -192,8 +192,8 @@ cHandlingDataMgr::ConvertDataToGameUnits(tHandlingData *handling)
// TODO: figure out what exactly is being converted here
float velocity, a, b, specificVolume;
- handling->TransmissionData.fEngineAcceleration /= 2500.0f;
- handling->TransmissionData.fMaxVelocity /= 180.0f;
+ handling->Transmission.fEngineAcceleration /= 2500.0f;
+ handling->Transmission.fMaxVelocity /= 180.0f;
handling->fBrakeDeceleration /= 2500.0f;
handling->fTurnMass = (sq(handling->Dimension.x) + sq(handling->Dimension.y)) * handling->fMass / 12.0f;
if(handling->fTurnMass < 10.0f)
@@ -205,27 +205,27 @@ cHandlingDataMgr::ConvertDataToGameUnits(tHandlingData *handling)
specificVolume = handling->Dimension.x*handling->Dimension.z*0.5f / handling->fMass; // ?
a = 0.0f;
b = 100.0f;
- velocity = handling->TransmissionData.fMaxVelocity;
+ velocity = handling->Transmission.fMaxVelocity;
while(a < b && velocity > 0.0f){
velocity -= 0.01;
- a = handling->TransmissionData.fEngineAcceleration/6.0f;
+ a = handling->Transmission.fEngineAcceleration/6.0f;
b = -velocity * (1.0f/(specificVolume * sq(velocity) + 1.0f) - 1.0f);
}
if(handling->nIdentifier == HANDLING_RCBANDIT){
- handling->TransmissionData.fUnkMaxVelocity = handling->TransmissionData.fMaxVelocity;
+ handling->Transmission.fUnkMaxVelocity = handling->Transmission.fMaxVelocity;
}else{
- handling->TransmissionData.fUnkMaxVelocity = velocity;
- handling->TransmissionData.fMaxVelocity = velocity * 1.2f;
+ handling->Transmission.fUnkMaxVelocity = velocity;
+ handling->Transmission.fMaxVelocity = velocity * 1.2f;
}
- handling->TransmissionData.fMaxReverseVelocity = -0.2f;
+ handling->Transmission.fMaxReverseVelocity = -0.2f;
- if(handling->TransmissionData.nDriveType == '4')
- handling->TransmissionData.fEngineAcceleration /= 4.0f;
+ if(handling->Transmission.nDriveType == '4')
+ handling->Transmission.fEngineAcceleration /= 4.0f;
else
- handling->TransmissionData.fEngineAcceleration /= 2.0f;
+ handling->Transmission.fEngineAcceleration /= 2.0f;
- handling->TransmissionData.InitGearRatios();
+ handling->Transmission.InitGearRatios();
}
int32
diff --git a/src/vehicles/HandlingMgr.h b/src/vehicles/HandlingMgr.h
index 2627fbae..70f1c005 100644
--- a/src/vehicles/HandlingMgr.h
+++ b/src/vehicles/HandlingMgr.h
@@ -85,7 +85,7 @@ enum
struct tHandlingData
{
- int32 nIdentifier;
+ eHandlingId nIdentifier;
float fMass;
float fInvMass;
float fTurnMass;
@@ -94,7 +94,7 @@ struct tHandlingData
int8 nPercentSubmerged;
float fBuoyancy;
float fTractionMultiplier;
- cTransmission TransmissionData;
+ cTransmission Transmission;
float fBrakeDeceleration;
float fBrakeBias;
int8 bABS;
@@ -136,6 +136,8 @@ public:
void ConvertDataToGameUnits(tHandlingData *handling);
int32 GetHandlingId(const char *name);
tHandlingData *GetHandlingData(eHandlingId id) { return &HandlingData[id]; }
+ bool HasRearWheelDrive(eHandlingId id) { return HandlingData[id].Transmission.nDriveType == 'R'; }
+ bool HasFrontWheelDrive(eHandlingId id) { return HandlingData[id].Transmission.nDriveType == 'F'; }
};
VALIDATE_SIZE(cHandlingDataMgr, 0x3030);
extern cHandlingDataMgr &mod_HandlingManager;
diff --git a/src/vehicles/Plane.h b/src/vehicles/Plane.h
index 1f54e529..e263766e 100644
--- a/src/vehicles/Plane.h
+++ b/src/vehicles/Plane.h
@@ -7,7 +7,17 @@ class CPlane : public CVehicle
{
public:
// 0x288
- uint8 stuff[20];
+ int16 m_wIndex;
+ int16 field_650;
+ int16 m_wNextPathNode;
+ char field_654;
+ char field_655;
+ float field_656;
+ int m_nFrameWhenHit;
+ char m_bHasBeenHit;
+ char m_bIsIncomingCesna;
+ char m_bIsDropoffCesna;
+ char field_667;
CPlane(int, uint8);
~CPlane(void);
diff --git a/src/vehicles/Transmission.cpp b/src/vehicles/Transmission.cpp
index 2be25cbb..d500d004 100644
--- a/src/vehicles/Transmission.cpp
+++ b/src/vehicles/Transmission.cpp
@@ -1,5 +1,7 @@
#include "common.h"
#include "patcher.h"
+#include "Timer.h"
+#include "HandlingMgr.h"
#include "Transmission.h"
void
@@ -35,3 +37,107 @@ cTransmission::InitGearRatios(void)
Gears[1].fShiftDownVelocity = -0.01f;
}
+
+void
+cTransmission::CalculateGearForSimpleCar(float speed, uint8 &gear)
+{
+ static tGear *pGearRatio;
+
+ pGearRatio = &Gears[gear];
+ fCurVelocity = speed;
+ if(speed > pGearRatio->fShiftUpVelocity)
+ gear++;
+ else if(speed < pGearRatio->fShiftDownVelocity){
+ if(gear - 1 < 0)
+ gear = 0;
+ else
+ gear--;
+ }
+}
+
+float
+cTransmission::CalculateDriveAcceleration(const float &gasPedal, uint8 &gear, float &time, const float &velocity, bool cheat)
+{
+ static float fAcceleration = 0.0f;
+ static float fVelocity;
+ static float fCheat;
+ static tGear *pGearRatio;
+
+ fVelocity = velocity;
+ if(fVelocity < fMaxReverseVelocity){
+ fVelocity = fMaxReverseVelocity;
+ return 0.0f;
+ }
+ if(fVelocity > fMaxVelocity){
+ fVelocity = fMaxVelocity;
+ return 0.0f;
+ }
+ fCurVelocity = fVelocity;
+
+ assert(gear <= nNumberOfGears);
+
+ pGearRatio = &Gears[gear];
+ if(fVelocity > pGearRatio->fShiftUpVelocity){
+ if(gear != 0 || gasPedal > 0.0f){
+ gear++;
+ time = 0.0f;
+ return CalculateDriveAcceleration(gasPedal, gear, time, fVelocity, false);
+ }
+ }else if(fVelocity < pGearRatio->fShiftDownVelocity && gear != 0){
+ if(gear != 1 || gasPedal < 0.0f){
+ gear--;
+ time = 0.0f;
+ return CalculateDriveAcceleration(gasPedal, gear, time, fVelocity, false);
+ }
+ }
+
+ if(time > 0.0f){
+ // changing gears currently, can't accelerate
+ fAcceleration = 0.0f;
+ time -= CTimer::GetTimeStepInSeconds();
+ }else{
+ float speedMul, accelMul;
+
+ if(gear < 1){
+ // going reverse
+ accelMul = (Flags & HANDLING_2G_BOOST) ? 2.0f : 1.0f;
+ speedMul = -1.0f;
+ }else if(nNumberOfGears == 1){
+ accelMul = 1.0f;
+ speedMul = 1.0f;
+ }else{
+ // BUG or not? this is 1.0 normally but 0.0 in the highest gear
+ float f = 1.0f - (gear-1)/(nNumberOfGears-1);
+ speedMul = 3.0f*sq(f) + 1.0f;
+ // This is pretty ugly, could be written more clearly
+ if(Flags & HANDLING_2G_BOOST){
+ if(gear == 1)
+ accelMul = (Flags & HANDLING_1G_BOOST) ? 3.0f : 2.0f;
+ else if(gear == 2)
+ accelMul = 1.3f;
+ else
+ accelMul = 1.0f;
+ }else if(Flags & HANDLING_1G_BOOST && gear == 1){
+ accelMul = 3.0f;
+ }else
+ accelMul = 1.0f;
+ }
+
+ if(cheat)
+ fCheat = 1.2f;
+ else
+ fCheat = 1.0f;
+ float targetVelocity = Gears[gear].fMaxVelocity*speedMul*fCheat;
+ float accel = fEngineAcceleration*accelMul * (targetVelocity - fVelocity)/Abs(targetVelocity);
+ if(Abs(fVelocity) < Abs(Gears[gear].fMaxVelocity*fCheat))
+ fAcceleration = gasPedal * accel * CTimer::GetTimeStep();
+ else
+ fAcceleration = 0.0f;
+ }
+ return fAcceleration;
+}
+
+STARTPATCHES
+ InjectHook(0x550A00, &cTransmission::CalculateGearForSimpleCar, PATCH_JUMP);
+ InjectHook(0x5506B0, &cTransmission::CalculateDriveAcceleration, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/vehicles/Transmission.h b/src/vehicles/Transmission.h
index 686e0aca..8eeef1e8 100644
--- a/src/vehicles/Transmission.h
+++ b/src/vehicles/Transmission.h
@@ -20,7 +20,9 @@ public:
float fMaxVelocity;
float fUnkMaxVelocity;
float fMaxReverseVelocity;
- float field_5C;
+ float fCurVelocity;
void InitGearRatios(void);
+ void CalculateGearForSimpleCar(float speed, uint8 &gear);
+ float CalculateDriveAcceleration(const float &gasPedal, uint8 &gear, float &time, const float &velocity, bool cheat);
};
diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp
index d8ed1a15..cc98bbe9 100644
--- a/src/vehicles/Vehicle.cpp
+++ b/src/vehicles/Vehicle.cpp
@@ -35,7 +35,7 @@ CVehicle::CVehicle(uint8 CreatedBy)
int i;
m_nCurrentGear = 0;
- field_208 = 0;
+ m_fChangeGearTime = 0;
m_fSteerRatio = 0.0f;
m_type = ENTITY_TYPE_VEHICLE;
VehicleCreatedBy = CreatedBy;
@@ -56,16 +56,18 @@ CVehicle::CVehicle(uint8 CreatedBy)
for(i = 0; i < m_nNumMaxPassengers; i++)
pPassengers[i] = nil;
m_nBombTimer = 0;
- m_pWhoSetMeOnFire = nil;
+ m_pBlowUpEntity = nil;
field_1FB = 0;
- m_veh_flagB10 = false;
+ bComedyControls = false;
m_veh_flagB40 = false;
m_veh_flagB80 = false;
- m_veh_flagC1 = false;
+ bTakeLessDamage = false;
bIsDamaged = false;
- m_veh_flagC8 = false;
+ bFadeOut = false;
m_veh_flagC10 = false;
- m_veh_flagC4 = false;
+ m_nTimeOfDeath = 0;
+ m_pCarFire = nil;
+ bHasBeenOwnedByPlayer = false;
m_veh_flagC20 = false;
bCanBeDamaged = true;
m_veh_flagC80 = false;
@@ -93,14 +95,14 @@ CVehicle::CVehicle(uint8 CreatedBy)
m_pCurGroundEntity = nil;
field_22A = 0;
field_22B = 0;
- field_22F = 0;
+ m_comedyControlState = 0;
m_aCollPolys[0].valid = false;
m_aCollPolys[1].valid = false;
- m_autoPilot.m_nCarMission = MISSION_NONE;
- m_autoPilot.m_nAnimationId = TEMPACT_NONE;
- m_autoPilot.m_nTimeToStartMission = CTimer::GetTimeInMilliseconds();
- m_autoPilot.m_flag4 = false;
- m_autoPilot.m_flag10 = false;
+ AutoPilot.m_nCarMission = MISSION_NONE;
+ AutoPilot.m_nAnimationId = TEMPACT_NONE;
+ AutoPilot.m_nTimeToStartMission = CTimer::GetTimeInMilliseconds();
+ AutoPilot.m_flag4 = false;
+ AutoPilot.m_flag10 = false;
}
CVehicle::~CVehicle()
@@ -259,7 +261,7 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
adhesion *= CTimer::GetTimeStep();
if(bAlreadySkidding)
- adhesion *= m_handling->fTractionLoss;
+ adhesion *= pHandling->fTractionLoss;
// moving sideways
if(contactSpeedRight != 0.0f){
@@ -318,7 +320,7 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
}
float l = Sqrt(sq(right) + sq(fwd));
- float tractionLoss = bAlreadySkidding ? 1.0f : m_handling->fTractionLoss;
+ float tractionLoss = bAlreadySkidding ? 1.0f : pHandling->fTractionLoss;
right *= adhesion * tractionLoss / l;
fwd *= adhesion * tractionLoss / l;
}
@@ -362,9 +364,9 @@ CVehicle::ExtinguishCarFire(void)
m_pCarFire->Extinguish();
if(IsCar()){
CAutomobile *car = (CAutomobile*)this;
- if(car->Damage.GetEngineStatus() >= 225)
- car->Damage.SetEngineStatus(215);
- car->field_530 = 0.0f;
+ if(car->Damage.GetEngineStatus() >= ENGINE_STATUS_ON_FIRE)
+ car->Damage.SetEngineStatus(ENGINE_STATUS_ON_FIRE-10);
+ car->m_fFireBlowUpTimer = 0.0f;
}
}
@@ -374,20 +376,21 @@ CVehicle::ProcessDelayedExplosion(void)
if(m_nBombTimer == 0)
return;
- if(m_nBombTimer == 0){
- int tick = CTimer::GetTimeStep()/60.0f*1000.0f;
- if(tick > m_nBombTimer)
- m_nBombTimer = 0;
- else
- m_nBombTimer -= tick;
+ int tick = CTimer::GetTimeStep()/60.0f*1000.0f;
+ if(tick > m_nBombTimer)
+ m_nBombTimer = 0;
+ else
+ m_nBombTimer -= tick;
- if(IsCar() && ((CAutomobile*)this)->m_auto_flagA7 == 4 && (m_nBombTimer & 0xFE00) != 0xFE00)
- DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_BOMB_TICK, 0.0f);
+ if(IsCar() && ((CAutomobile*)this)->m_bombType == CARBOMB_TIMEDACTIVE && (m_nBombTimer & 0xFE00) != 0xFE00)
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_BOMB_TICK, 0.0f);
- if(FindPlayerVehicle() != this && m_pWhoSetMeOnFire == FindPlayerPed())
- CWorld::Players[CWorld::PlayerInFocus].AwardMoneyForExplosion(this);
- BlowUpCar(m_pWhoSetMeOnFire);
- }
+ if (m_nBombTimer != 0)
+ return;
+
+ if(FindPlayerVehicle() != this && m_pBlowUpEntity == FindPlayerPed())
+ CWorld::Players[CWorld::PlayerInFocus].AwardMoneyForExplosion(this);
+ BlowUpCar(m_pBlowUpEntity);
}
bool
@@ -449,7 +452,7 @@ CVehicle::IsVehicleNormal(void)
bool
CVehicle::CarHasRoof(void)
{
- if((m_handling->Flags & HANDLING_HAS_NO_ROOF) == 0)
+ if((pHandling->Flags & HANDLING_HAS_NO_ROOF) == 0)
return true;
if(m_aExtras[0] && m_aExtras[1])
return false;
@@ -519,7 +522,7 @@ bool
CVehicle::CanPedOpenLocks(CPed *ped)
{
if(m_nDoorLock == CARLOCK_LOCKED ||
- m_nDoorLock == CARLOCK_COP_CAR ||
+ m_nDoorLock == CARLOCK_LOCKED_INITIALLY ||
m_nDoorLock == CARLOCK_LOCKED_PLAYER_INSIDE)
return false;
if(ped->IsPlayer() && m_nDoorLock == CARLOCK_LOCKOUT_PLAYER_ONLY)
@@ -602,7 +605,7 @@ CVehicle::SetUpDriver(void)
pDriver->bInVehicle = true;
pDriver->SetPedState(PED_DRIVING);
if(bIsBus)
- pDriver->m_ped_flagC4 = false;
+ pDriver->bRenderPedInCar = false;
return pDriver;
}
@@ -618,7 +621,7 @@ CVehicle::SetupPassenger(int n)
pPassengers[n]->bInVehicle = true;
pPassengers[n]->SetPedState(PED_DRIVING);
if(bIsBus)
- pPassengers[n]->m_ped_flagC4 = false;
+ pPassengers[n]->bRenderPedInCar = false;
return pPassengers[n];
}
diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h
index c293b8a6..38d411cd 100644
--- a/src/vehicles/Vehicle.h
+++ b/src/vehicles/Vehicle.h
@@ -20,7 +20,7 @@ enum eCarLock {
CARLOCK_LOCKED,
CARLOCK_LOCKOUT_PLAYER_ONLY,
CARLOCK_LOCKED_PLAYER_INSIDE,
- CARLOCK_COP_CAR,
+ CARLOCK_LOCKED_INITIALLY,
CARLOCK_FORCE_SHUT_DOORS,
CARLOCK_SKIP_SHUT_DOORS
};
@@ -98,10 +98,23 @@ enum eWheels
enum
{
- CAR_PIECE_WHEEL_LF = 13,
+ CAR_PIECE_BONNET = 1,
+ CAR_PIECE_BOOT,
+ CAR_PIECE_BUMP_FRONT,
+ CAR_PIECE_BUMP_REAR,
+ CAR_PIECE_DOOR_LF,
+ CAR_PIECE_DOOR_RF,
+ CAR_PIECE_DOOR_LR,
+ CAR_PIECE_DOOR_RR,
+ CAR_PIECE_WING_LF,
+ CAR_PIECE_WING_RF,
+ CAR_PIECE_WING_LR,
+ CAR_PIECE_WING_RR,
+ CAR_PIECE_WHEEL_LF,
CAR_PIECE_WHEEL_LR,
CAR_PIECE_WHEEL_RF,
CAR_PIECE_WHEEL_RR,
+ CAR_PIECE_WINDSCREEN,
};
enum tWheelState
@@ -125,12 +138,12 @@ class CVehicle : public CPhysical
{
public:
// 0x128
- tHandlingData *m_handling;
- CAutoPilot m_autoPilot;
+ tHandlingData *pHandling;
+ CAutoPilot AutoPilot;
uint8 m_currentColour1;
uint8 m_currentColour2;
uint8 m_aExtras[2];
- int16 m_nAlarmState; // m_nWantedStarsOnEnter on DK22
+ int16 m_nAlarmState;
int16 m_nMissionValue;
CPed *pDriver;
CPed *pPassengers[8];
@@ -144,7 +157,7 @@ public:
CFire *m_pCarFire;
float m_fSteerAngle;
float m_fGasPedal;
- float m_fBreakPedal;
+ float m_fBrakePedal;
uint8 VehicleCreatedBy;
// cf. https://github.com/DK22Pac/plugin-sdk/blob/master/plugin_sa/game_sa/CVehicle.h from R*
@@ -161,15 +174,15 @@ public:
uint8 bIsBus: 1; // Is this vehicle a bus
uint8 bIsBig: 1; // Is this vehicle a bus
uint8 bLowVehicle: 1; // Need this for sporty type cars to use low getting-in/out anims
- uint8 m_veh_flagB10 : 1;
- uint8 m_veh_flagB20 : 1;
+ uint8 bComedyControls : 1; // Will make the car hard to control (hopefully in a funny way)
+ uint8 bWarnedPeds : 1; // Has scan and warn peds of danger been processed?
uint8 m_veh_flagB40 : 1;
uint8 m_veh_flagB80 : 1;
- uint8 m_veh_flagC1 : 1;
+ uint8 bTakeLessDamage : 1; // This vehicle is stronger (takes about 1/4 of damage)
uint8 bIsDamaged : 1; // This vehicle has been damaged and is displaying all its components
- uint8 m_veh_flagC4 : 1;
- uint8 m_veh_flagC8 : 1;
+ uint8 bHasBeenOwnedByPlayer : 1;// To work out whether stealing it is a crime
+ uint8 bFadeOut : 1; // Fade vehicle out
uint8 m_veh_flagC10 : 1;
uint8 m_veh_flagC20 : 1;
uint8 bCanBeDamaged : 1; // Set to FALSE during cut scenes to avoid explosions
@@ -188,17 +201,17 @@ public:
uint8 m_nAmmoInClip; // Used to make the guns on boat do a reload (20 by default)
int8 field_1FB;
int8 field_1FC[4];
- float m_fHealth; // 1000.0f = full health. 0 -> explode
+ float m_fHealth; // 1000.0f = full health. 250.0f = fire. 0 -> explode
uint8 m_nCurrentGear;
int8 field_205[3];
- int field_208;
+ float m_fChangeGearTime;
uint32 m_nGunFiringTime; // last time when gun on vehicle was fired (used on boats)
uint32 m_nTimeOfDeath;
int16 field_214;
int16 m_nBombTimer; // goes down with each frame
- CPed *m_pWhoSetMeOnFire;
- float field_21C;
- float field_220;
+ CEntity *m_pBlowUpEntity;
+ float field_21C; // front Z?
+ float field_220; // rear Z?
eCarLock m_nDoorLock;
int8 m_nLastWeaponDamage; // see eWeaponType, -1 if no damage
int8 m_nRadioStation;
@@ -207,7 +220,7 @@ public:
uint8 m_nCarHornTimer;
int8 field_22D;
bool m_bSirenOrAlarm;
- int8 field_22F;
+ int8 m_comedyControlState;
CStoredCollPoly m_aCollPolys[2]; // poly which is under front/rear part of car
float m_fSteerRatio;
eVehicleType m_vehType;
@@ -277,6 +290,8 @@ public:
void RemoveDriver(void);
void ProcessCarAlarm(void);
bool IsSphereTouchingVehicle(float sx, float sy, float sz, float radius);
+
+ bool IsAlarmOn(void) { return m_nAlarmState != 0 && m_nAlarmState != -1; }
static bool &bWheelsOnlyCheat;
static bool &bAllDodosCheat;
@@ -305,3 +320,19 @@ inline uint8 GetVehDoorFlag(int32 carnode) {
return 0;
}
}
+
+class cTransmission;
+
+class cVehicleParams
+{
+public:
+ char m_bDistanceCalculated;
+ char gap_1[3];
+ float m_fDistance;
+ CVehicle *m_pVehicle;
+ cTransmission *m_pTransmission;
+ int m_nIndex;
+ float m_fVelocityChange;
+};
+
+static_assert(sizeof(cVehicleParams) == 0x18, "CVehicle: error");
diff --git a/src/weapons/Weapon.cpp b/src/weapons/Weapon.cpp
index 90a6408b..0fc89637 100644
--- a/src/weapons/Weapon.cpp
+++ b/src/weapons/Weapon.cpp
@@ -5,7 +5,9 @@
#include "WeaponInfo.h"
WRAPPER bool CWeapon::Fire(CEntity*, CVector*) { EAXJMP(0x55C380); }
+WRAPPER void CWeapon::FireFromCar(CAutomobile *car, bool left) { EAXJMP(0x55C940); }
WRAPPER void CWeapon::AddGunshell(CEntity*, CVector const&, CVector2D const&, float) { EAXJMP(0x55F770); }
+WRAPPER void CWeapon::Update(int32 audioEntity) { EAXJMP(0x563A10); }
void
CWeapon::Initialise(eWeaponType type, int ammo)
@@ -36,6 +38,12 @@ CWeapon::Reload(void)
}
bool
+CWeapon::IsType2Handed(void)
+{
+ return m_eWeaponType >= WEAPONTYPE_SHOTGUN && m_eWeaponType <= WEAPONTYPE_FLAMETHROWER && m_eWeaponType != WEAPONTYPE_ROCKETLAUNCHER;
+}
+
+bool
CWeapon::IsTypeMelee(void)
{
return m_eWeaponType == WEAPONTYPE_UNARMED || m_eWeaponType == WEAPONTYPE_BASEBALLBAT;
diff --git a/src/weapons/Weapon.h b/src/weapons/Weapon.h
index 81516c4e..71fe1f45 100644
--- a/src/weapons/Weapon.h
+++ b/src/weapons/Weapon.h
@@ -1,5 +1,4 @@
#pragma once
-#include "Entity.h"
enum eWeaponType
{
@@ -46,6 +45,9 @@ enum eWeaponState
WEAPONSTATE_MELEE_MADECONTACT
};
+class CEntity;
+class CAutomobile;
+
class CWeapon
{
public:
@@ -61,9 +63,12 @@ public:
}
void Initialise(eWeaponType type, int ammo);
+ void Update(int32 audioEntity);
void Reload(void);
bool Fire(CEntity*, CVector*);
+ void FireFromCar(CAutomobile *car, bool left);
void AddGunshell(CEntity*, CVector const&, CVector2D const&, float);
bool IsTypeMelee(void);
+ bool IsType2Handed(void);
};
static_assert(sizeof(CWeapon) == 0x18, "CWeapon: error");