diff options
Diffstat (limited to '')
141 files changed, 6878 insertions, 917 deletions
diff --git a/src/animation/AnimBlendNode.cpp b/src/animation/AnimBlendNode.cpp index 3d3d80ec..be5fcc9c 100644 --- a/src/animation/AnimBlendNode.cpp +++ b/src/animation/AnimBlendNode.cpp @@ -125,8 +125,8 @@ CAnimBlendNode::CalcDeltas(void) float cos = DotProduct(kfA->rotation, kfB->rotation); if(cos > 1.0f) cos = 1.0f; - theta = acos(cos); - invSin = theta == 0.0f ? 0.0f : 1.0f/sin(theta); + theta = Acos(cos); + invSin = theta == 0.0f ? 0.0f : 1.0f/Sin(theta); } void diff --git a/src/animation/AnimBlendNode.h b/src/animation/AnimBlendNode.h index ea75fbfa..361a4134 100644 --- a/src/animation/AnimBlendNode.h +++ b/src/animation/AnimBlendNode.h @@ -10,7 +10,7 @@ class CAnimBlendNode public: // for slerp float theta; // angle between quaternions - float invSin; // 1/sin(theta) + float invSin; // 1/Sin(theta) // indices into array in sequence int32 frameA; // next key frame int32 frameB; // previous key frame diff --git a/src/animation/FrameUpdate.cpp b/src/animation/FrameUpdate.cpp index 62300527..dcb71944 100644 --- a/src/animation/FrameUpdate.cpp +++ b/src/animation/FrameUpdate.cpp @@ -53,7 +53,7 @@ FrameUpdateCallBack(AnimBlendFrameData *frame, void *arg) if(norm == 0.0f) rot.w = 1.0f; else - rot *= 1.0f/sqrt(norm); + rot *= 1.0f/Sqrt(norm); rot.Get(mat); } @@ -127,7 +127,7 @@ FrameUpdateCallBackWithVelocityExtraction(AnimBlendFrameData *frame, void *arg) if(norm == 0.0f) rot.w = 1.0f; else - rot *= 1.0f/sqrt(norm); + rot *= 1.0f/Sqrt(norm); rot.Get(mat); } @@ -206,7 +206,7 @@ FrameUpdateCallBackWith3dVelocityExtraction(AnimBlendFrameData *frame, void *arg if(norm == 0.0f) rot.w = 1.0f; else - rot *= 1.0f/sqrt(norm); + rot *= 1.0f/Sqrt(norm); rot.Get(mat); } diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp index 76ef8244..51f45e16 100644 --- a/src/audio/AudioManager.cpp +++ b/src/audio/AudioManager.cpp @@ -91,9 +91,249 @@ enum eVehicleModel cAudioManager &AudioManager = *(cAudioManager *)0x880FC0; constexpr int totalAudioEntitiesSlots = 200; +constexpr int maxVolume = 127; char &g_nMissionAudioPlayingStatus = *(char *)0x60ED88; +void +cAudioManager::AddSampleToRequestedQueue() +{ + int32 calculatedVolume; + tActiveSample *sample; + int32 unknown1; + uint8 unknown2; + 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) + return; + } else { + ++m_bSampleRequestQueuesStatus[m_bActiveSampleQueue]; + } + m_sQueueSample.calculatedVolume = calculatedVolume; + m_sQueueSample.m_bLoopEnded = 0; + if(m_sQueueSample.m_bIsDistant) { + m_sQueueSample.m_bRequireReflection = 0; + m_sQueueSample.m_bLoopsRemaining = 0; + } + if(m_bDynamicAcousticModelingStatus && m_sQueueSample.m_nLoopCount) { + bReflections = m_sQueueSample.m_bRequireReflection; + } else { + bReflections = false; + m_sQueueSample.m_bLoopsRemaining = 0; + } + m_sQueueSample.m_bRequireReflection = 0; + + if(!m_bDynamicAcousticModelingStatus) m_sQueueSample.m_bReverbFlag = 0; + + sample = &m_asSamples[27 * m_bActiveSampleQueue + unknown2]; + sample->m_nEntityIndex = m_sQueueSample.m_nEntityIndex; + sample->field_4 = m_sQueueSample.field_4; + sample->m_nSampleIndex = m_sQueueSample.m_nSampleIndex; + sample->m_bBankIndex = m_sQueueSample.m_bBankIndex; + sample->m_bIsDistant = m_sQueueSample.m_bIsDistant; + sample->field_16 = m_sQueueSample.field_16; + sample->m_nFrequency = m_sQueueSample.m_nFrequency; + sample->m_bVolume = m_sQueueSample.m_bVolume; + sample->m_fDistance = m_sQueueSample.m_fDistance; + sample->m_nLoopCount = m_sQueueSample.m_nLoopCount; + sample->m_nLoopStart = m_sQueueSample.m_nLoopStart; + sample->m_nLoopEnd = m_sQueueSample.m_nLoopEnd; + sample->m_bEmittingVolume = m_sQueueSample.m_bEmittingVolume; + sample->field_48 = m_sQueueSample.field_48; + sample->m_fSoundIntensity = m_sQueueSample.m_fSoundIntensity; + sample->field_56 = m_sQueueSample.field_56; + sample->m_vecPos = m_sQueueSample.m_vecPos; + sample->m_bReverbFlag = m_sQueueSample.m_bReverbFlag; + sample->m_bLoopsRemaining = m_sQueueSample.m_bLoopsRemaining; + sample->m_bRequireReflection = m_sQueueSample.m_bRequireReflection; + sample->m_bOffset = m_sQueueSample.m_bOffset; + sample->field_76 = m_sQueueSample.field_76; + sample->m_bIsProcessed = m_sQueueSample.m_bIsProcessed; + sample->m_bLoopEnded = m_sQueueSample.m_bLoopEnded; + sample->calculatedVolume = m_sQueueSample.calculatedVolume; + sample->field_88 = m_sQueueSample.field_88; + + AddDetailsToRequestedOrderList(unknown2); + if(bReflections) AddReflectionsToRequestedQueue(); + } +} + +void +cAudioManager::AddDetailsToRequestedOrderList(uint8 sample) +{ + 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); + } + } + m_abSampleQueueIndexTable[27 * m_bActiveSampleQueue + i] = sample; +} + +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 * 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(); + } + } + } + } +} + +uint32 +cAudioManager::ComputeVolume(int emittingVolume, float soundIntensity, float distance) +{ + float newSoundIntensity; + if(soundIntensity <= 0.0f) return 0; + if((soundIntensity * 0.2f) <= distance) { + newSoundIntensity = soundIntensity * 0.2f; + emittingVolume = + sq((soundIntensity - distance) / (soundIntensity - newSoundIntensity)) * + emittingVolume; + } + return emittingVolume; +} + +void +cAudioManager::Initialise() +{ + if(!m_bIsInitialised) { + PreInitialiseGameSpecificSetup(); + m_bIsInitialised = cSampleManager.Initialise(); + if(m_bIsInitialised) { + m_bActiveSamples = cSampleManager.GetActiveSamples(); + if(m_bActiveSamples <= 1u) { + Terminate(); + } else { + --m_bActiveSamples; + PostInitialiseGameSpecificSetup(); + InitialisePoliceRadioZones(); + InitialisePoliceRadio(); + MusicManager.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_nCollisionEntity = CreateEntity(AUDIOTYPE_COLLISION, (CPhysical *)1); + if(m_nCollisionEntity >= 0) cAudioManager::SetEntityStatus(m_nCollisionEntity, 1); + + m_nFrontEndEntity = CreateEntity(AUDIOTYPE_FRONTEND, (CPhysical *)1); + if(m_nFrontEndEntity >= 0) cAudioManager::SetEntityStatus(m_nFrontEndEntity, 1); + + m_nProjectileEntity = CreateEntity(AUDIOTYPE_PROJECTILE, (CPhysical *)1); + if(m_nProjectileEntity >= 0) cAudioManager::SetEntityStatus(m_nProjectileEntity, 1); + + m_nWaterCannonEntity = CreateEntity(AUDIOTYPE_WATER_CANNON, (CPhysical *)1); + if(m_nWaterCannonEntity >= 0) cAudioManager::SetEntityStatus(m_nWaterCannonEntity, 1); + + m_nPoliceChannelEntity = CreateEntity(AUDIOTYPE_D, (CPhysical *)1); + if(m_nPoliceChannelEntity >= 0) cAudioManager::SetEntityStatus(m_nPoliceChannelEntity, 1); + + m_nBridgeEntity = CreateEntity(AUDIOTYPE_BRIDGE, (CPhysical *)1); + if(m_nBridgeEntity >= 0) cAudioManager::SetEntityStatus(m_nBridgeEntity, 1); + + 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 = 0; + m_sMissionAudio.field_12 = 1; + m_sMissionAudio.field_24 = 0; + ResetAudioLogicTimers((int32)CTimer::GetTimeInMilliseconds); +} + +WRAPPER +void +cAudioManager::InitialisePoliceRadioZones() +{ + EAXJMP(0x57EAC0); +} + +WRAPPER +void +cAudioManager::ResetAudioLogicTimers(int32 timer) +{ + EAXJMP(0x569650); +} + +void +cAudioManager::Terminate() +{ + if(m_bIsInitialised) { + MusicManager.Terminate(); + + for(uint32 i = 0; i < totalAudioEntitiesSlots; i++) { + m_asAudioEntities[i].m_bIsUsed = 0; + m_anAudioEntityIndices[i] = 200; + } + + m_nAudioEntitiesTotal = 0; + m_nScriptObjectEntityTotal = 0; + PreTerminateGameSpecificShutdown(); + + for(uint32 i = 0; i < 2; i++) { + if(cSampleManager.IsSampleBankLoaded(i)) cSampleManager.UnloadSampleBank(i); + } + + cSampleManager.Terminate(); + + m_bIsInitialised = 0; + PostTerminateGameSpecificShutdown(); + } +} + char cAudioManager::GetMissionScriptPoliceAudioPlayingStatus() { @@ -205,7 +445,7 @@ void cAudioManager::CalculateDistance(bool *ptr, float dist) { if(*ptr == false) { - m_sQueueSample.m_fDistance = sqrt(dist); + m_sQueueSample.m_fDistance = Sqrt(dist); *ptr = true; } } @@ -313,20 +553,16 @@ cAudioManager::ResetPoliceRadio() void cAudioManager::InterrogateAudioEntities() { - int32 i = 0; - int32 next; - - while(i < m_nAudioEntitiesTotal) { + for(int32 i = 0; i < m_nAudioEntitiesTotal; i++) { ProcessEntity(m_anAudioEntityIndices[i]); - next = m_anAudioEntityIndices[i++]; - m_asAudioEntities[next].field_24 = 0; + m_asAudioEntities[m_anAudioEntityIndices[i]].field_24 = 0; } } void cAudioManager::ClearRequestedQueue() { - for(uint32 i = 0; i < m_bActiveSamples; i++) { + for(int32 i = 0; i < m_bActiveSamples; i++) { m_abSampleQueueIndexTable[i + 27 * m_bActiveSampleQueue] = m_bActiveSamples; } m_bSampleRequestQueuesStatus[m_bActiveSampleQueue] = 0; @@ -340,14 +576,14 @@ cAudioManager::ClearRequestedQueue() bool cAudioManager::UsesReverseWarning(int32 model) { - return model == LINERUN || fabs(model - FIRETRUK) <= 1 || model == BUS || + return model == LINERUN || model == FIRETRUK || model == TRASH || model == BUS || model == COACH; // fix } bool cAudioManager::HasAirBrakes(int32 model) { - return model == LINERUN || fabs(model - FIRETRUK) <= 1 || model == BUS || + return model == LINERUN || model == FIRETRUK || model == TRASH || model == BUS || model == COACH; // fix } @@ -436,7 +672,7 @@ cAudioManager::RandomDisplacement(uint32 seed) int32 value; static bool bIsEven = true; - static uint8 base = 0; + static uint32 base = 0; if(!seed) return 0; @@ -473,17 +709,17 @@ cAudioManager::IsAudioInitialised() const } int32 -cAudioManager::CreateEntity(int32 type, CPhysical *memory) +cAudioManager::CreateEntity(int32 type, CPhysical *entity) { if(!m_bIsInitialised) return -4; - if(!memory) return -2; + 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 = memory; + 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; @@ -502,7 +738,7 @@ cAudioManager::DestroyEntity(int32 id) if(m_bIsInitialised && id >= 0 && id < totalAudioEntitiesSlots && m_asAudioEntities[id].m_bIsUsed) { m_asAudioEntities[id].m_bIsUsed = 0; - for(uint32 i = 0; i < m_nAudioEntitiesTotal; ++i) { + for(int32 i = 0; i < m_nAudioEntitiesTotal; ++i) { if(id == m_anAudioEntityIndices[i]) { if(i < totalAudioEntitiesSlots - 1) memmove(&m_anAudioEntityIndices[i], @@ -2724,6 +2960,17 @@ cAudioManager::Service() } STARTPATCHES +InjectHook(0x57B070, &cAudioManager::AddSampleToRequestedQueue, PATCH_JUMP); +InjectHook(0x57B210, &cAudioManager::AddDetailsToRequestedOrderList, PATCH_JUMP); +InjectHook(0x57B300, &cAudioManager::AddReflectionsToRequestedQueue, PATCH_JUMP); +InjectHook(0x57ABB0, &cAudioManager::ComputeVolume, 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(0x57A150, &cAudioManager::Terminate, PATCH_JUMP); + InjectHook(0x57F050, &cAudioManager::GetMissionScriptPoliceAudioPlayingStatus, PATCH_JUMP); InjectHook(0x5795D0, &cAudioManager::GetMissionAudioLoadingStatus, PATCH_JUMP); diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h index 24dae2ce..7a2dc9c5 100644 --- a/src/audio/AudioManager.h +++ b/src/audio/AudioManager.h @@ -44,7 +44,7 @@ public: char m_bLoopEnded; char field_82; char field_83; - int field_84; + int calculatedVolume; char field_88; char field_89; char field_90; @@ -218,6 +218,20 @@ public: char field_19195; int m_nTimeOfRecentCrime; + void AddSampleToRequestedQueue(); + + void AddDetailsToRequestedOrderList(uint8 sample); + void AddReflectionsToRequestedQueue(); + + uint32 ComputeVolume(int emittingVolume, float soundIntensity, float distance); + + void Initialise(); + void PostInitialiseGameSpecificSetup(); + void InitialisePoliceRadioZones(); // @todo + void ResetAudioLogicTimers(int32 timer); // @todo + + void Terminate(); + char GetMissionScriptPoliceAudioPlayingStatus(); bool GetMissionAudioLoadingStatus(); @@ -261,7 +275,7 @@ public: void InterrogateAudioEntities(); void ClearRequestedQueue(); -// void AgeCrimes(); + // void AgeCrimes(); //todo bool UsesReverseWarning(int32 model); bool HasAirBrakes(int32 model); @@ -274,7 +288,7 @@ public: void ProcessPlane(void *); // todo void ClearMissionAudio(); -// void ProcessReverb(); + // void ProcessReverb(); // todo bool IsMissionAudioSampleFinished(); @@ -282,8 +296,6 @@ public: void InitialisePoliceRadio(); - // done - int32 RandomDisplacement(uint32 seed); void ReleaseDigitalHandle(); @@ -292,7 +304,7 @@ public: bool IsAudioInitialised() const; - int32 CreateEntity(int32 type, CPhysical *memory); + int32 CreateEntity(int32 type, CPhysical *entity); void DestroyEntity(int32 id); void SetEntityStatus(int32 id, bool status); diff --git a/src/audio/DMAudio.cpp b/src/audio/DMAudio.cpp index 60454bdd..b4fee67f 100644 --- a/src/audio/DMAudio.cpp +++ b/src/audio/DMAudio.cpp @@ -19,7 +19,7 @@ WRAPPER void cDMAudio::ChangeMusicMode(uint8 mode) { EAXJMP(0x57CCF0); } 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, uint16, float) { EAXJMP(0x57C840); } +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); } diff --git a/src/audio/DMAudio.h b/src/audio/DMAudio.h index 72e8d316..8be09ac6 100644 --- a/src/audio/DMAudio.h +++ b/src/audio/DMAudio.h @@ -190,7 +190,7 @@ public: void PlayFrontEndSound(uint32, uint32); void PlayFrontEndTrack(uint32, uint32); void StopFrontEndTrack(); - void PlayOneShot(int32, uint16, float); + void PlayOneShot(int32 audioentity, uint16 sound/*eSound*/, float); void SetMusicMasterVolume(int8); void SetEffectsMasterVolume(int8); int8 SetCurrent3DProvider(int8); diff --git a/src/audio/MusicManager.cpp b/src/audio/MusicManager.cpp index 7b7c1182..dcd4ae93 100644 --- a/src/audio/MusicManager.cpp +++ b/src/audio/MusicManager.cpp @@ -174,3 +174,17 @@ void cMusicManager::DisplayRadioStationName() } } #endif + +WRAPPER +void +cMusicManager::Initialise() +{ + EAXJMP(0x57CF70); +} + +WRAPPER +void +cMusicManager::Terminate() +{ + EAXJMP(0x57D140); +} diff --git a/src/audio/MusicManager.h b/src/audio/MusicManager.h index dcb34daf..944fd16e 100644 --- a/src/audio/MusicManager.h +++ b/src/audio/MusicManager.h @@ -264,6 +264,9 @@ public: uint8 field_2395; public: + void Initialise(); + void Terminate(); + char *Get3DProviderName(char); bool PlayerInCar(); void DisplayRadioStationName(); diff --git a/src/audio/SampleManager.cpp b/src/audio/SampleManager.cpp index 7af3446b..fbeb49ed 100644 --- a/src/audio/SampleManager.cpp +++ b/src/audio/SampleManager.cpp @@ -12,6 +12,33 @@ bool CSampleManager::IsMP3RadioChannelAvailable() { return nNumOfMp3Files != 0; } +WRAPPER +bool CSampleManager::IsSampleBankLoaded(uint8) { EAXJMP(0x567130); } + +WRAPPER +void CSampleManager::UnloadSampleBank(uint8) { EAXJMP(0x567110); } + +WRAPPER +void +CSampleManager::Terminate() +{ + EAXJMP(0x566DC0); +} + +WRAPPER +bool +CSampleManager::Initialise() +{ + EAXJMP(0x566530); +} + +WRAPPER +int32 +CSampleManager::GetActiveSamples() +{ + EAXJMP(0x565970); +} + WRAPPER void CSampleManager::ReleaseDigitalHandle() { @@ -87,6 +114,7 @@ CSampleManager::StopChannel(int32 id) { EAXJMP(0x567BE0); } + STARTPATCHES InjectHook(0x566490, CSampleManager::IsMP3RadioChannelAvailable, PATCH_JUMP); ENDPATCHES
\ No newline at end of file diff --git a/src/audio/SampleManager.h b/src/audio/SampleManager.h index 1bee1775..f0245d4e 100644 --- a/src/audio/SampleManager.h +++ b/src/audio/SampleManager.h @@ -11,6 +11,13 @@ struct tSample { class CSampleManager { public: + bool IsSampleBankLoaded(uint8); + void UnloadSampleBank(uint8); + void Terminate(); + + bool Initialise(); + int32 GetActiveSamples(); + void ReleaseDigitalHandle(); void RequireDigitalHandle(); diff --git a/src/control/AutoPilot.h b/src/control/AutoPilot.h index 97b02f5c..364cb633 100644 --- a/src/control/AutoPilot.h +++ b/src/control/AutoPilot.h @@ -59,9 +59,9 @@ enum eCarDrivingStyle : uint8 class CAutoPilot { public: - void *m_currentAddress; - void *m_startingRouteNode; - void *m_PreviousRouteNode; + uint32 m_nCurrentRouteNode; + uint32 m_nNextRouteNode; + uint32 m_nPrevRouteNode; uint32 m_nTotalSpeedScaleFactor; uint32 m_nSpeedScaleFactor; uint32 m_nCurrentPathNodeInfo; @@ -80,10 +80,41 @@ public: uint8 m_nAnimationTime; float m_fMaxTrafficSpeed; uint8 m_nCruiseSpeed; - uint8 m_nCarCtrlFlags; + uint8 m_flag1 : 1; + uint8 m_flag2 : 1; + uint8 m_flag4 : 1; + uint8 m_flag8 : 1; + uint8 m_flag10 : 1; CVector m_vecDestinationCoors; void *m_aPathFindNodesInfo[8]; uint16 m_nPathFindNodesCount; CVehicle *m_pTargetCar; + + CAutoPilot(void) { + m_nPrevRouteNode = 0; + m_nNextRouteNode = m_nPrevRouteNode; + m_nCurrentRouteNode = m_nNextRouteNode; + m_nTotalSpeedScaleFactor = 0; + m_nSpeedScaleFactor = 1000; + m_nPreviousPathNodeInfo = 0; + m_nNextPathNodeInfo = m_nPreviousPathNodeInfo; + m_nCurrentPathNodeInfo = m_nNextPathNodeInfo; + m_nNextDirection = 1; + m_nCurrentDirecton = m_nNextDirection; + m_nCurrentPathDirection = 0; + m_nPreviousPathDirection = m_nCurrentPathDirection; + m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS; + m_nCarMission = MISSION_NONE; + m_nAnimationId = TEMPACT_NONE; + m_nCruiseSpeed = 10; + m_fMaxTrafficSpeed = 10.0f; + m_flag2 = false; + m_flag1 = false; + m_nPathFindNodesCount = 0; + m_pTargetCar = 0; + m_nTimeToStartMission = CTimer::GetTimeInMilliseconds(); + m_nTimeSwitchedToRealPhysics = m_nTimeToStartMission; + m_flag8 = false; + } }; static_assert(sizeof(CAutoPilot) == 0x70, "CAutoPilot: error"); diff --git a/src/control/Darkel.cpp b/src/control/Darkel.cpp index 32d975e0..ab28f96e 100644 --- a/src/control/Darkel.cpp +++ b/src/control/Darkel.cpp @@ -1,12 +1,338 @@ #include "common.h" #include "patcher.h" +#include "main.h" #include "Darkel.h" +#include "Timer.h" +#include "DMAudio.h" +#include "Population.h" +#include "Weapon.h" +#include "World.h" +#include "PlayerPed.h" +#include "Stats.h" +#include "Font.h" +#include "Text.h" +int32 &CDarkel::TimeLimit = *(int32*)0x885BAC; +int32 &CDarkel::PreviousTime = *(int32*)0x885B00; +int32 &CDarkel::TimeOfFrenzyStart = *(int32*)0x9430D8; +int32 &CDarkel::WeaponType = *(int32*)0x9430F0; +int32 &CDarkel::AmmoInterruptedWeapon = *(int32*)0x8E29C8; +int32 &CDarkel::KillsNeeded = *(int32*)0x8F1AB8; +int8 &CDarkel::InterruptedWeapon = *(int8*)0x95CD60; +int8 &CDarkel::bStandardSoundAndMessages = *(int8*)0x95CDB6; +int8 &CDarkel::bNeedHeadShot = *(int8*)0x95CDCA; +int8 &CDarkel::bProperKillFrenzy = *(int8*)0x95CD98; +eKillFrenzyStatus &CDarkel::Status = *(eKillFrenzyStatus*)0x95CCB4; +int16 *CDarkel::RegisteredKills = (int16*)0x6EDBE0; +int32 &CDarkel::ModelToKill = *(int32*)0x8F2C78; +int32 &CDarkel::ModelToKill2 = *(int32*)0x885B40; +int32 &CDarkel::ModelToKill3 = *(int32*)0x885B3C; +int32 &CDarkel::ModelToKill4 = *(int32*)0x885B34; +wchar *CDarkel::pStartMessage = (wchar*)0x8F2C08; + +int32 CDarkel::CalcFade(uint32 time, int32 start, uint32 end) { + if (time >= start && time <= end) { + if (time >= start + 500) { + if (time <= end - 500) + return 255; + else + return 255 * (end - time) / 500; + } + else + return 255 * (time - start) / 500; + } + else + return 0; +} + +// This function has been cleaned up from unused stuff. +#if 0 WRAPPER void CDarkel::DrawMessages(void) { EAXJMP(0x420920); } +#else +void CDarkel::DrawMessages() +{ + bool DisplayTimers = false; + + switch (Status) { + case KILLFRENZY_ONGOING: + assert(pStartMessage != nil); + DisplayTimers = true; + break; + case KILLFRENZY_PASSED: + case KILLFRENZY_FAILED: + DisplayTimers = false; + break; + }; + + if (DisplayTimers) { + CFont::SetPropOn(); + CFont::SetBackgroundOff(); + CFont::SetBackGroundOnlyTextOn(); + CFont::SetAlignment(ALIGN_RIGHT); + CFont::SetRightJustifyWrap(-SCREEN_WIDTH); + CFont::SetFontStyle(FONT_HEADING); + CFont::SetScale(SCREEN_SCALE_X(0.8f), SCREEN_SCALE_Y(1.35f)); + + float AlignToHUD = SCREEN_SCALE_X(-10.0f); + int32 a = (TimeLimit - (CTimer::GetTimeInMilliseconds() - TimeOfFrenzyStart)); + if (CTimer::GetFrameCounter() & 8 || a > 4000) { + sprintf(gString, "%d:%02d", a / 60000, a % 60000 / 1000); + AsciiToUnicode(gString, gUString); + CFont::SetColor(CRGBA(0, 0, 0, 255)); + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(25.0f) + AlignToHUD, SCREEN_SCALE_Y(112.0f), gUString); + + CFont::SetColor(CRGBA(150, 100, 255, 255)); + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(27.0f) + AlignToHUD, SCREEN_SCALE_Y(110.0f), gUString); + } + + if (KillsNeeded <= 0) + KillsNeeded = 0; + + sprintf((char *)gString, "%d", KillsNeeded); + AsciiToUnicode(gString, gUString); + + CFont::SetColor(CRGBA(0, 0, 0, 255)); + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(25.0f) + AlignToHUD, SCREEN_SCALE_Y(134.0f), gUString); + + CFont::SetColor(CRGBA(255, 128, 128, 255)); + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(27.0f) + AlignToHUD, SCREEN_SCALE_Y(132.0f), gUString); + } +} +#endif + +void CDarkel::Init() +{ + Status = KILLFRENZY_NONE; +} + +int16 CDarkel::QueryModelsKilledByPlayer(int32 modelId) +{ + return RegisteredKills[modelId]; +} -bool CDarkel::Status = *(bool*)0x95CCB4; bool CDarkel::FrenzyOnGoing() { - return Status == 1; -}
\ No newline at end of file + return Status == KILLFRENZY_ONGOING; +} + + +eKillFrenzyStatus CDarkel::ReadStatus() +{ + return Status; +} + +#if 1 +WRAPPER void CDarkel::RegisterCarBlownUpByPlayer(CVehicle *vehicle) { EAXJMP(0x421070); } +#else +int32 CDarkel::RegisterCarBlownUpByPlayer(CVehicle *vehicle) +{ + return 0; +} +#endif + +#if 1 +WRAPPER void CDarkel::RegisterKillByPlayer(CPed *victim, eWeaponType weapontype, bool headshot) { EAXJMP(0x420F60); } +#else +void CDarkel::RegisterKillByPlayer(CPed *victim, eWeaponType weapontype, bool headshot) +{ + + +} +#endif + +void CDarkel::RegisterKillNotByPlayer() +{ + ++CStats::NumberKillFrenziesPassed; +} + +void CDarkel::ResetModelsKilledByPlayer() +{ + for (int i = 0; i < 200; i++) + RegisteredKills[i] = 0; +} + +#if 0 +WRAPPER void CDarkel::ResetOnPlayerDeath() { EAXJMP(0x420E70); } +#else +void CDarkel::ResetOnPlayerDeath() +{ + if (Status != KILLFRENZY_ONGOING) + return; + + CPopulation::m_AllRandomPedsThisType = -1; + Status = KILLFRENZY_FAILED; + TimeOfFrenzyStart = CTimer::GetTimeInMilliseconds(); + + if (WeaponType == WEAPONTYPE_UZI_DRIVEBY) + WeaponType = WEAPONTYPE_UZI; + + if (WeaponType < WEAPONTYPE_TOTALWEAPONS) { + FindPlayerPed()->m_bWeaponSlot = InterruptedWeapon; + CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_weapons[CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_currentWeapon].m_nAmmoTotal = AmmoInterruptedWeapon; + } + + if (FindPlayerVehicle()) { + FindPlayerPed()->RemoveWeaponModel(CWeaponInfo::GetWeaponInfo(FindPlayerPed()->GetWeapon()->m_eWeaponType)->m_nModelId); + FindPlayerPed()->m_currentWeapon = CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_weapons[CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_currentWeapon].m_eWeaponType; + FindPlayerPed()->MakeChangesForNewWeapon(FindPlayerPed()->m_currentWeapon); + } + + + CPopulation::m_AllRandomPedsThisType = -1; + Status = KILLFRENZY_FAILED; + TimeOfFrenzyStart = CTimer::GetTimeInMilliseconds(); + + if (WeaponType == WEAPONTYPE_UZI_DRIVEBY) + WeaponType = WEAPONTYPE_UZI; + + if (WeaponType < WEAPONTYPE_TOTALWEAPONS) { + FindPlayerPed()->m_bWeaponSlot = InterruptedWeapon; + CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_weapons[CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_currentWeapon].m_nAmmoTotal = AmmoInterruptedWeapon; + } + + if (FindPlayerVehicle()) { + FindPlayerPed()->RemoveWeaponModel(CWeaponInfo::GetWeaponInfo(FindPlayerPed()->GetWeapon()->m_eWeaponType)->m_nModelId); + FindPlayerPed()->m_currentWeapon = CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_weapons[CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_currentWeapon].m_eWeaponType; + FindPlayerPed()->MakeChangesForNewWeapon(FindPlayerPed()->m_currentWeapon); + } +} +#endif + +#if 0 +WRAPPER void CDarkel::StartFrenzy(eWeaponType weaponType, int32 time, int16 kill, int32 modelId0, wchar *text, int32 modelId2, int32 modelId3, int32 modelId4, bool standardSound, bool needHeadShot) { EAXJMP(0x4210E0); } +#else +void CDarkel::StartFrenzy(eWeaponType weaponType, int32 time, int16 kill, int32 modelId0, wchar *text, int32 modelId2, int32 modelId3, int32 modelId4, bool standardSound, bool needHeadShot) +{ + if (weaponType == WEAPONTYPE_UZI_DRIVEBY) + weaponType = WEAPONTYPE_UZI; + + WeaponType = weaponType; + Status = KILLFRENZY_ONGOING; + KillsNeeded = kill; + ModelToKill = modelId0; + ModelToKill2 = modelId2; + ModelToKill3 = modelId3; + ModelToKill4 = modelId4; + pStartMessage = text; + + if (text == TheText.Get("PAGE_00")) { + CDarkel::bProperKillFrenzy = 1; + CDarkel::pStartMessage = 0; + } + else + bProperKillFrenzy = 0; + + bStandardSoundAndMessages = standardSound; + bNeedHeadShot = needHeadShot; + TimeOfFrenzyStart = CTimer::GetTimeInMilliseconds(); + TimeLimit = time; + PreviousTime = time / 1000; + + if (weaponType < WEAPONTYPE_TOTALWEAPONS) { + InterruptedWeapon = FindPlayerPed()->m_currentWeapon; + FindPlayerPed()->GiveWeapon(weaponType, 0); + AmmoInterruptedWeapon = CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_weapons[CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_currentWeapon].m_nAmmoTotal; + FindPlayerPed()->GiveWeapon(weaponType, 30000); + FindPlayerPed()->m_bWeaponSlot = CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_weapons[CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_currentWeapon].m_eWeaponType; + FindPlayerPed()->MakeChangesForNewWeapon(FindPlayerPed()->m_bWeaponSlot); + + if (FindPlayerVehicle()) { + FindPlayerPed()->m_currentWeapon = CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_weapons[CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_currentWeapon].m_eWeaponType; + if (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_weapons[CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_currentWeapon].m_nAmmoTotal <= CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_weapons[CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_currentWeapon].m_nAmmoInClip) + CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_weapons[CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_currentWeapon].m_nAmmoInClip = CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_weapons[CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_currentWeapon].m_nAmmoTotal; + + FindPlayerPed()->ClearWeaponTarget(); + } + } + if (CDarkel::bStandardSoundAndMessages) + DMAudio.PlayFrontEndSound(SOUND_RAMPAGE_START, 0); +} +#endif + +void CDarkel::Update() +{ + if (Status != KILLFRENZY_ONGOING) + return; + + int32 FrameTime = TimeLimit - (CTimer::GetTimeInMilliseconds() - TimeOfFrenzyStart); + if ((TimeLimit - (CTimer::GetTimeInMilliseconds() - TimeOfFrenzyStart)) > 0 || TimeLimit < 0) { + DMAudio.PlayFrontEndSound(SOUND_RAMPAGE_ONGOING, FrameTime); + + int32 PrevTime = FrameTime / 1000; + + if (PrevTime != PreviousTime) { + if (PreviousTime < 12) + DMAudio.PlayFrontEndSound(SOUND_CLOCK_TICK, PrevTime); + PreviousTime = PrevTime; + } + + } + else { + CPopulation::m_AllRandomPedsThisType = -1; + Status = KILLFRENZY_FAILED; + TimeOfFrenzyStart = CTimer::GetTimeInMilliseconds(); + + if (WeaponType == WEAPONTYPE_UZI_DRIVEBY) + WeaponType = WEAPONTYPE_UZI; + + if (WeaponType < WEAPONTYPE_TOTALWEAPONS) { + FindPlayerPed()->m_bWeaponSlot = InterruptedWeapon; + CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_weapons[CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_currentWeapon].m_nAmmoTotal = AmmoInterruptedWeapon; + } + + if (FindPlayerVehicle()) { + FindPlayerPed()->RemoveWeaponModel(CWeaponInfo::GetWeaponInfo(FindPlayerPed()->GetWeapon()->m_eWeaponType)->m_nModelId); + FindPlayerPed()->m_currentWeapon = CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_weapons[CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_currentWeapon].m_eWeaponType; + FindPlayerPed()->MakeChangesForNewWeapon(FindPlayerPed()->m_currentWeapon); + } + + if (bStandardSoundAndMessages) + DMAudio.PlayFrontEndSound(SOUND_RAMPAGE_FAILED, 0); + } + + if (KillsNeeded <= 0) { + CPopulation::m_AllRandomPedsThisType = -1; + Status = KILLFRENZY_PASSED; + + if (bProperKillFrenzy) + CStats::AnotherKillFrenzyPassed(); + + TimeOfFrenzyStart = CTimer::GetTimeInMilliseconds(); + + FindPlayerPed()->m_pWanted->SetWantedLevel(NOTWANTED); + + if (WeaponType == WEAPONTYPE_UZI_DRIVEBY) + WeaponType = WEAPONTYPE_UZI; + + if (WeaponType < WEAPONTYPE_TOTALWEAPONS) { + FindPlayerPed()->m_bWeaponSlot = InterruptedWeapon; + CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_weapons[CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_currentWeapon].m_nAmmoTotal = AmmoInterruptedWeapon; + } + + if (FindPlayerVehicle()) { + FindPlayerPed()->RemoveWeaponModel(CWeaponInfo::GetWeaponInfo(FindPlayerPed()->GetWeapon()->m_eWeaponType)->m_nModelId); + FindPlayerPed()->m_currentWeapon = CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_weapons[CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_currentWeapon].m_eWeaponType; + FindPlayerPed()->MakeChangesForNewWeapon(FindPlayerPed()->m_currentWeapon); + } + + if (bStandardSoundAndMessages) + DMAudio.PlayFrontEndSound(SOUND_RAMPAGE_PASSED, 0); + } +} + +STARTPATCHES + /*InjectHook(0x421380, CDarkel::CalcFade, PATCH_JUMP); + InjectHook(0x420920, CDarkel::DrawMessages, PATCH_JUMP); + InjectHook(0x420E60, CDarkel::FrenzyOnGoing, PATCH_JUMP); + InjectHook(0x420650, CDarkel::Init, PATCH_JUMP); + InjectHook(0x421370, CDarkel::QueryModelsKilledByPlayer, PATCH_JUMP); + InjectHook(0x420E50, CDarkel::ReadStatus, PATCH_JUMP); + InjectHook(0x421070, CDarkel::RegisterCarBlownUpByPlayer, PATCH_JUMP); + InjectHook(0x420F60, CDarkel::RegisterKillByPlayer, PATCH_JUMP); + InjectHook(0x421060, CDarkel::RegisterKillNotByPlayer, PATCH_JUMP); + InjectHook(0x421310, CDarkel::ResetModelsKilledByPlayer, PATCH_JUMP); + InjectHook(0x420E70, CDarkel::ResetOnPlayerDeath, PATCH_JUMP); + InjectHook(0x4210E0, CDarkel::StartFrenzy, PATCH_JUMP); + InjectHook(0x420660, CDarkel::Update, PATCH_JUMP);*/ +ENDPATCHES
\ No newline at end of file diff --git a/src/control/Darkel.h b/src/control/Darkel.h index ed78d4e1..35d849d2 100644 --- a/src/control/Darkel.h +++ b/src/control/Darkel.h @@ -1,11 +1,51 @@ #pragma once +#include "Weapon.h" + +class CVehicle; +class CPed; + +enum eKillFrenzyStatus +{ + KILLFRENZY_NONE, + KILLFRENZY_ONGOING, + KILLFRENZY_PASSED, + KILLFRENZY_FAILED, +}; class CDarkel { private: - static bool Status; + static int32 &TimeLimit; + static int32 &PreviousTime; + static int32 &TimeOfFrenzyStart; + static int32 &WeaponType; + static int32 &AmmoInterruptedWeapon; + static int32 &KillsNeeded; + static int8 &InterruptedWeapon; + static int8 &bStandardSoundAndMessages; + static int8 &bNeedHeadShot; + static int8 &bProperKillFrenzy; + static eKillFrenzyStatus &Status; + static int16 *RegisteredKills; + static int32 &ModelToKill; + static int32 &ModelToKill2; + static int32 &ModelToKill3; + static int32 &ModelToKill4; + static wchar *pStartMessage; public: + static int32 CalcFade(uint32 time, int32 min, uint32 max); static void DrawMessages(void); static bool FrenzyOnGoing(); + static void Init(); + static int16 QueryModelsKilledByPlayer(int32 modelId); + static eKillFrenzyStatus ReadStatus(); + static void RegisterCarBlownUpByPlayer(CVehicle *vehicle); + static void RegisterKillByPlayer(CPed *victim, eWeaponType weapontype, bool headshot = false); + static void RegisterKillNotByPlayer(); + 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); + static void Update(); + }; diff --git a/src/control/PathFind.cpp b/src/control/PathFind.cpp index f9ce7f35..a92882db 100644 --- a/src/control/PathFind.cpp +++ b/src/control/PathFind.cpp @@ -146,8 +146,8 @@ CPathFind::PreparePathData(void) numExtern++; if(InfoForTileCars[k].numLeftLanes + InfoForTileCars[k].numRightLanes > numLanes) numLanes = InfoForTileCars[k].numLeftLanes + InfoForTileCars[k].numRightLanes; - maxX = max(maxX, fabs(InfoForTileCars[k].x)); - maxY = max(maxY, fabs(InfoForTileCars[k].y)); + maxX = max(maxX, Abs(InfoForTileCars[k].x)); + maxY = max(maxY, Abs(InfoForTileCars[k].y)); }else if(InfoForTileCars[k].type == NodeTypeIntern) numIntern++; } @@ -327,10 +327,10 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor if(tempnodes[k].linkState != 1) continue; dx = tempnodes[k].pos.x - CoorsXFormed.x; - if(fabs(dx) < nearestDist){ + if(Abs(dx) < nearestDist){ dy = tempnodes[k].pos.y - CoorsXFormed.y; - if(fabs(dy) < nearestDist){ - nearestDist = max(fabs(dx), fabs(dy)); + if(Abs(dy) < nearestDist){ + nearestDist = max(Abs(dx), Abs(dy)); nearestId = k; } } @@ -369,7 +369,7 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor dx = m_pathNodes[tempnodes[nearestId].link1].pos.x - m_pathNodes[tempnodes[nearestId].link2].pos.x; dy = m_pathNodes[tempnodes[nearestId].link1].pos.y - m_pathNodes[tempnodes[nearestId].link2].pos.y; tempnodes[nearestId].pos = (tempnodes[nearestId].pos + CoorsXFormed)*0.5f; - mag = sqrt(dx*dx + dy*dy); + mag = Sqrt(dx*dx + dy*dy); tempnodes[nearestId].dirX = dx/mag; tempnodes[nearestId].dirY = dy/mag; // do something when number of lanes doesn't agree @@ -464,7 +464,7 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor posy = (m_pathNodes[i].pos.y + m_pathNodes[j].pos.y)*0.5f; dx = m_pathNodes[j].pos.x - m_pathNodes[i].pos.x; dy = m_pathNodes[j].pos.y - m_pathNodes[i].pos.y; - mag = sqrt(dx*dx + dy*dy); + mag = Sqrt(dx*dx + dy*dy); dx /= mag; dy /= mag; if(i < j){ diff --git a/src/control/Phones.cpp b/src/control/Phones.cpp index fa4f83e5..028d80a9 100644 --- a/src/control/Phones.cpp +++ b/src/control/Phones.cpp @@ -1,6 +1,130 @@ #include "common.h" #include "patcher.h" #include "Phones.h" +#include "Pools.h" + +CPhoneInfo &gPhoneInfo = *(CPhoneInfo*)0x732A20; + +bool &CPhoneInfo::isPhonePickedUp = *(bool*)0x6283AC; +bool &CPhoneInfo::isPhoneBeingPickedUp = *(bool*)0x6283B4; +CPhone *&CPhoneInfo::pickedUpPhone = *(CPhone**)0x6283B0; + +int +CPhoneInfo::FindNearestFreePhone(CVector *pos) +{ + int nearestPhoneId = -1; + float nearestPhoneDist = 60.0f; + + for (int phoneId = 0; phoneId < m_nMax; phoneId++) { + + if (gPhoneInfo.m_aPhones[phoneId].m_nState == PHONE_STATE_FREE) { + float phoneDist = (m_aPhones[phoneId].m_vecPos - *pos).Magnitude2D(); + + if (phoneDist < nearestPhoneDist) { + nearestPhoneDist = phoneDist; + nearestPhoneId = phoneId; + } + } + } + return nearestPhoneId; +} + +bool +CPhoneInfo::PhoneAtThisPosition(CVector pos) +{ + for (int phoneId = 0; phoneId < m_nMax; phoneId++) { + if (pos.x == m_aPhones[phoneId].m_vecPos.x && pos.y == m_aPhones[phoneId].m_vecPos.y) + return true; + } + return false; +} + +bool +CPhoneInfo::HasMessageBeenDisplayed(int phoneId) +{ + if (isPhonePickedUp) + return false; + + int state = m_aPhones[phoneId].m_nState; + + return state == PHONE_STATE_REPEATED_MESSAGE_SHOWN_ONCE || + state == PHONE_STATE_ONETIME_MESSAGE_SHOWN || + state == PHONE_STATE_REPEATED_MESSAGE_SHOWN; +} + +bool +CPhoneInfo::IsMessageBeingDisplayed(int phoneId) +{ + return pickedUpPhone == &m_aPhones[phoneId]; +} + +void +CPhoneInfo::Load(CPhoneInfo *source, uint8 buffer) +{ + // Buffer isn't used. + + m_nMax = source->m_nMax; + m_nNum = source->m_nNum; + for (int phoneId = 0; phoneId < 50; phoneId++) { + 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); + m_aPhones[phoneId].m_pEntity = phone->m_pEntity; + m_aPhones[phoneId].m_nState = phone->m_nState; + m_aPhones[phoneId].field_30 = phone->field_30; + + 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; + } + } +} + +void +CPhoneInfo::SetPhoneMessage_JustOnce(int phoneId, uint16 *msg1, uint16 *msg2, uint16 *msg3, uint16 *msg4, uint16 *msg5, uint16 *msg6) +{ + // If there is at least one message, it should be msg1. + if (msg1) { + m_aPhones[phoneId].m_apMessages[0] = msg1; + m_aPhones[phoneId].m_apMessages[1] = msg2; + m_aPhones[phoneId].m_apMessages[2] = msg3; + m_aPhones[phoneId].m_apMessages[3] = msg4; + m_aPhones[phoneId].m_apMessages[4] = msg5; + m_aPhones[phoneId].m_apMessages[5] = msg6; + m_aPhones[phoneId].m_nState = PHONE_STATE_ONETIME_MESSAGE_SET; + } else { + m_aPhones[phoneId].m_nState = PHONE_STATE_MESSAGE_REMOVED; + } +} + +void +CPhoneInfo::SetPhoneMessage_Repeatedly(int phoneId, uint16 *msg1, uint16 *msg2, uint16 *msg3, uint16 *msg4, uint16 *msg5, uint16 *msg6) +{ + // If there is at least one message, it should be msg1. + if (msg1) { + m_aPhones[phoneId].m_apMessages[0] = msg1; + m_aPhones[phoneId].m_apMessages[1] = msg2; + m_aPhones[phoneId].m_apMessages[2] = msg3; + m_aPhones[phoneId].m_apMessages[3] = msg4; + m_aPhones[phoneId].m_apMessages[4] = msg5; + m_aPhones[phoneId].m_apMessages[5] = msg6; + m_aPhones[phoneId].m_nState = PHONE_STATE_REPEATED_MESSAGE_SET; + } else { + m_aPhones[phoneId].m_nState = PHONE_STATE_MESSAGE_REMOVED; + } +} + +STARTPATCHES + InjectHook(0x42F720, &CPhoneInfo::FindNearestFreePhone, PATCH_JUMP); + InjectHook(0x42FD50, &CPhoneInfo::PhoneAtThisPosition, PATCH_JUMP); + InjectHook(0x42FFF0, &CPhoneInfo::HasMessageBeenDisplayed, PATCH_JUMP); + InjectHook(0x430030, &CPhoneInfo::IsMessageBeingDisplayed, PATCH_JUMP); + 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); } diff --git a/src/control/Phones.h b/src/control/Phones.h index a29043ed..74f24d25 100644 --- a/src/control/Phones.h +++ b/src/control/Phones.h @@ -1,6 +1,55 @@ #pragma once +#include "Physical.h" #include "AnimBlendAssociation.h" +enum { + PHONE_STATE_FREE, + PHONE_STATE_1, + PHONE_STATE_2, + PHONE_STATE_MESSAGE_REMOVED, + PHONE_STATE_ONETIME_MESSAGE_SET, + PHONE_STATE_REPEATED_MESSAGE_SET, + PHONE_STATE_REPEATED_MESSAGE_SHOWN_ONCE, + PHONE_STATE_ONETIME_MESSAGE_SHOWN, + PHONE_STATE_REPEATED_MESSAGE_SHOWN, + PHONE_STATE_9 +}; + +struct CPhone +{ + CVector m_vecPos; + uint16 *m_apMessages[6]; + uint32 m_lastTimeRepeatedMsgShown; + CEntity *m_pEntity; // it's building pool index in save files + int32 m_nState; + uint8 field_30; +}; + +static_assert(sizeof(CPhone) == 0x34, "CPhone: error"); + +class CPhoneInfo { + static bool &isPhonePickedUp; + static bool &isPhoneBeingPickedUp; + static CPhone *&pickedUpPhone; +public: + int32 m_nMax; + int32 m_nNum; + CPhone m_aPhones[50]; + + CPhoneInfo() { } + ~CPhoneInfo() { } + + int FindNearestFreePhone(CVector*); + bool PhoneAtThisPosition(CVector); + 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); +}; + +extern CPhoneInfo &gPhoneInfo; + void PhonePutDownCB(CAnimBlendAssociation *assoc, void *arg); void PhonePickUpCB(CAnimBlendAssociation *assoc, void *arg);
\ No newline at end of file diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp index 06995663..3ce9085f 100644 --- a/src/control/Replay.cpp +++ b/src/control/Replay.cpp @@ -290,14 +290,14 @@ void CReplay::RecordThisFrame(void) CPed* p = peds->GetSlot(i); if (!p || !p->m_rwObject) continue; - if (!p->bRecordedForReplay){ + if (!p->bHasAlreadyBeenRecorded){ tPedHeaderPacket* ph = (tPedHeaderPacket*)&Record.m_pBase[Record.m_nOffset]; ph->type = REPLAYPACKET_PED_HEADER; ph->index = i; ph->mi = p->GetModelIndex(); ph->pedtype = p->m_nPedType; Record.m_nOffset += sizeof(*ph); - p->bRecordedForReplay = true; + p->bHasAlreadyBeenRecorded = true; } StorePedUpdate(p, i); } @@ -469,7 +469,7 @@ void CReplay::ProcessPedUpdate(CPed *ped, float interpolation, CAddressInReplayB CMatrix ped_matrix; pp->matrix.DecompressIntoFullMatrix(ped_matrix); ped->GetMatrix() = ped->GetMatrix() * CMatrix(1.0f - interpolation); - *ped->GetMatrix().GetPosition() *= (1.0f - interpolation); + ped->GetMatrix().GetPosition() *= (1.0f - interpolation); ped->GetMatrix() += CMatrix(interpolation) * ped_matrix; if (pp->vehicle_index) { ped->m_pMyVehicle = CPools::GetVehiclePool()->GetSlot(pp->vehicle_index - 1); @@ -666,7 +666,7 @@ void CReplay::ProcessCarUpdate(CVehicle *vehicle, float interpolation, CAddressI CMatrix vehicle_matrix; vp->matrix.DecompressIntoFullMatrix(vehicle_matrix); vehicle->GetMatrix() = vehicle->GetMatrix() * CMatrix(1.0f - interpolation); - *vehicle->GetMatrix().GetPosition() *= (1.0f - interpolation); + vehicle->GetMatrix().GetPosition() *= (1.0f - interpolation); vehicle->GetMatrix() += CMatrix(interpolation) * vehicle_matrix; vehicle->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); vehicle->m_fHealth = 4 * vp->health; @@ -686,8 +686,8 @@ void CReplay::ProcessCarUpdate(CVehicle *vehicle, float interpolation, CAddressI car->m_aSuspensionSpringRatio[i] = vp->wheel_susp_dist[i] / 50.0f; car->m_aWheelRotation[i] = vp->wheel_rotation[i] * M_PI / 128.0f; } - car->Doors[2].m_fAngle = car->Doors[2].m_fPreviousAngle = vp->door_angles[0] * M_PI / 127.0f; - car->Doors[3].m_fAngle = car->Doors[3].m_fPreviousAngle = vp->door_angles[1] * M_PI / 127.0f; + car->Doors[2].m_fAngle = car->Doors[2].m_fPrevAngle = vp->door_angles[0] * M_PI / 127.0f; + car->Doors[3].m_fAngle = car->Doors[3].m_fPrevAngle = vp->door_angles[1] * M_PI / 127.0f; if (vp->door_angles[0]) car->Damage.SetDoorStatus(2, 2); if (vp->door_angles[1]) @@ -847,7 +847,7 @@ bool CReplay::PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, flo { tGeneralPacket* pg = (tGeneralPacket*)&ptr[offset]; TheCamera.GetMatrix() = TheCamera.GetMatrix() * CMatrix(split); - *TheCamera.GetMatrix().GetPosition() *= split; + TheCamera.GetMatrix().GetPosition() *= split; TheCamera.GetMatrix() += CMatrix(interpolation) * pg->camera_pos; RwMatrix* pm = RwFrameGetMatrix(RwCameraGetFrame(TheCamera.m_pRwCamera)); pm->pos = *(RwV3d*)TheCamera.GetMatrix().GetPosition(); @@ -979,40 +979,40 @@ 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.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); 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.GetMatrix().GetPosition(); + pm->at = *(RwV3d*)&TheCamera.GetMatrix().GetForward(); + pm->up = *(RwV3d*)&TheCamera.GetMatrix().GetUp(); + pm->right = *(RwV3d*)&TheCamera.GetMatrix().GetRight(); break; } case REPLAYCAMMODE_FIXED: { - *TheCamera.GetMatrix().GetPosition() = CVector(CameraFixedX, CameraFixedY, CameraFixedZ); + TheCamera.GetMatrix().GetPosition() = CVector(CameraFixedX, CameraFixedY, CameraFixedZ); CVector forward(CameraFocusX - CameraFixedX, CameraFocusY - CameraFixedY, CameraFocusZ - CameraFixedZ); forward.Normalise(); CVector right = CrossProduct(CVector(0.0f, 0.0f, 1.0f), forward); right.Normalise(); CVector up = CrossProduct(forward, right); up.Normalise(); - *TheCamera.GetMatrix().GetForward() = forward; - *TheCamera.GetMatrix().GetUp() = up; - *TheCamera.GetMatrix().GetRight() = right; + TheCamera.GetMatrix().GetForward() = forward; + TheCamera.GetMatrix().GetUp() = up; + TheCamera.GetMatrix().GetRight() = right; 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.GetMatrix().GetPosition(); + pm->at = *(RwV3d*)&TheCamera.GetMatrix().GetForward(); + pm->up = *(RwV3d*)&TheCamera.GetMatrix().GetUp(); + pm->right = *(RwV3d*)&TheCamera.GetMatrix().GetRight(); break; } default: break; } - TheCamera.m_vecGameCamPos = *TheCamera.GetMatrix().GetPosition(); + TheCamera.m_vecGameCamPos = TheCamera.GetMatrix().GetPosition(); TheCamera.CalculateDerivedValues(); RwMatrixUpdate(RwFrameGetMatrix(RwCameraGetFrame(TheCamera.m_pRwCamera))); RwFrameUpdateObjects(RwCameraGetFrame(TheCamera.m_pRwCamera)); @@ -1189,7 +1189,7 @@ void CReplay::RestoreStuffFromMem(void) CMatrix tmp1; tmp1.Attach(RwFrameGetMatrix(dodo->m_aCarNodes[CAR_WHEEL_RF]), false); CMatrix tmp2(RwFrameGetMatrix(dodo->m_aCarNodes[CAR_WHEEL_LF]), false); - *tmp1.GetPosition() += CVector(tmp2.GetPosition()->x + 0.1f, 0.0f, tmp2.GetPosition()->z); + tmp1.GetPosition() += CVector(tmp2.GetPosition().x + 0.1f, 0.0f, tmp2.GetPosition().z); tmp1.UpdateRW(); } if (vehicle->IsCar()){ @@ -1346,14 +1346,14 @@ void CReplay::MarkEverythingAsNew(void) CVehicle* v = CPools::GetVehiclePool()->GetSlot(i); if (!v) continue; - v->bRecordedForReplay = false; + v->bHasAlreadyBeenRecorded = false; } i = CPools::GetPedPool()->GetSize(); while (i--) { CPed* p = CPools::GetPedPool()->GetSlot(i); if (!p) continue; - p->bRecordedForReplay = false; + p->bHasAlreadyBeenRecorded = false; } } #endif @@ -1505,9 +1505,9 @@ void CReplay::ProcessLookAroundCam(void) else fAlphaAngleLookAroundCam = max(0.1f, min(1.5f, fAlphaAngleLookAroundCam + y_moved)); CVector camera_pt( - fDistanceLookAroundCam * sin(fBetaAngleLookAroundCam) * cos(fAlphaAngleLookAroundCam), - fDistanceLookAroundCam * cos(fBetaAngleLookAroundCam) * cos(fAlphaAngleLookAroundCam), - fDistanceLookAroundCam * sin(fAlphaAngleLookAroundCam) + fDistanceLookAroundCam * Sin(fBetaAngleLookAroundCam) * Cos(fAlphaAngleLookAroundCam), + fDistanceLookAroundCam * Cos(fBetaAngleLookAroundCam) * Cos(fAlphaAngleLookAroundCam), + fDistanceLookAroundCam * Sin(fAlphaAngleLookAroundCam) ); CVector focus = CVector(CameraFocusX, CameraFocusY, CameraFocusZ); camera_pt += focus; @@ -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.GetMatrix().GetForward() = forward; + TheCamera.GetMatrix().GetUp() = up; + TheCamera.GetMatrix().GetRight() = right; + TheCamera.GetMatrix().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.GetMatrix().GetPosition(); + pm->at = *(RwV3d*)&TheCamera.GetMatrix().GetForward(); + pm->up = *(RwV3d*)&TheCamera.GetMatrix().GetUp(); + pm->right = *(RwV3d*)&TheCamera.GetMatrix().GetRight(); TheCamera.CalculateDerivedValues(); RwMatrixUpdate(RwFrameGetMatrix(RwCameraGetFrame(TheCamera.m_pRwCamera))); RwFrameUpdateObjects(RwCameraGetFrame(TheCamera.m_pRwCamera)); diff --git a/src/control/Script.cpp b/src/control/Script.cpp index 5e7f4936..b50c101e 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -2,33 +2,66 @@ #include "patcher.h" #include "Script.h" +#include "ScriptCommands.h" #include "Camera.h" #include "CarCtrl.h" #include "DMAudio.h" +#include "FileMgr.h" #include "Hud.h" +#include "Messages.h" #include "ModelIndices.h" +#include "Pad.h" #include "PlayerInfo.h" #include "PlayerPed.h" #include "Pools.h" #include "Population.h" +#include "Replay.h" #include "Streaming.h" #include "User.h" #include "Weather.h" #include "World.h" -uint8 (&CTheScripts::ScriptSpace)[160 * 1024] = *(uint8(*)[160 * 1024])*(uintptr*)0x74B248; -CTextLine (&CTheScripts::IntroTextLines)[2] = *(CTextLine (*)[2])*(uintptr*)0x70EA74; -CScriptRectangle (&CTheScripts::IntroRectangles)[16] = *(CScriptRectangle (*)[16])*(uintptr*)0x72D108; -CSprite2d (&CTheScripts::ScriptSprites)[16] = *(CSprite2d(*)[16])*(uintptr*)0x72B090; +uint8 (&CTheScripts::ScriptSpace)[SIZE_SCRIPT_SPACE] = *(uint8(*)[SIZE_SCRIPT_SPACE])*(uintptr*)0x74B248; +CRunningScript(&CTheScripts::ScriptsArray)[MAX_NUM_SCRIPTS] = *(CRunningScript(*)[MAX_NUM_SCRIPTS])*(uintptr*)0x6F5C08; +int32(&CTheScripts::BaseBriefIdForContact)[MAX_NUM_CONTACTS] = *(int32(*)[MAX_NUM_CONTACTS])*(uintptr*)0x880200; +int32(&CTheScripts::OnAMissionForContactFlag)[MAX_NUM_CONTACTS] = *(int32(*)[MAX_NUM_CONTACTS])*(uintptr*)0x8622F0; +CTextLine (&CTheScripts::IntroTextLines)[MAX_NUM_INTRO_TEXT_LINES] = *(CTextLine (*)[MAX_NUM_INTRO_TEXT_LINES])*(uintptr*)0x70EA68; +CScriptRectangle (&CTheScripts::IntroRectangles)[MAX_NUM_INTRO_RECTANGLES] = *(CScriptRectangle (*)[MAX_NUM_INTRO_RECTANGLES])*(uintptr*)0x72D108; +CSprite2d (&CTheScripts::ScriptSprites)[MAX_NUM_SCRIPT_SRPITES] = *(CSprite2d(*)[MAX_NUM_SCRIPT_SRPITES])*(uintptr*)0x72B090; +CScriptSphere(&CTheScripts::ScriptSphereArray)[MAX_NUM_SCRIPT_SPHERES] = *(CScriptSphere(*)[MAX_NUM_SCRIPT_SPHERES])*(uintptr*)0x727D60; +tCollectiveData(&CTheScripts::CollectiveArray)[MAX_NUM_COLLECTIVES] = *(tCollectiveData(*)[MAX_NUM_COLLECTIVES])*(uintptr*)0x6FA008; +tUsedObject(&CTheScripts::UsedObjectArray)[MAX_NUM_USED_OBJECTS] = *(tUsedObject(*)[MAX_NUM_USED_OBJECTS])*(uintptr*)0x6E69C8; +int32(&CTheScripts::MultiScriptArray)[MAX_NUM_MISSION_SCRIPTS] = *(int32(*)[MAX_NUM_MISSION_SCRIPTS])*(uintptr*)0x6F0558; +tBuildingSwap(&CTheScripts::BuildingSwapArray)[MAX_NUM_BUILDING_SWAPS] = *(tBuildingSwap(*)[MAX_NUM_BUILDING_SWAPS])*(uintptr*)0x880E30; +CEntity*(&CTheScripts::InvisibilitySettingArray)[MAX_NUM_INVISIBILITY_SETTINGS] = *(CEntity*(*)[MAX_NUM_INVISIBILITY_SETTINGS])*(uintptr*)0x8620F0; bool &CTheScripts::DbgFlag = *(bool*)0x95CD87; -uint32 &CTheScripts::OnAMissionFlag = *(uint32*)0x8F2A24; +uint32 &CTheScripts::OnAMissionFlag = *(uint32*)0x8F1B64; int32 &CTheScripts::StoreVehicleIndex = *(int32*)0x8F5F3C; bool &CTheScripts::StoreVehicleWasRandom = *(bool*)0x95CDBC; - -CMissionCleanup(&CTheScripts::MissionCleanup) = *(CMissionCleanup*)0x8F2AD8; -CUpsideDownCarCheck(&CTheScripts::UpsideDownCars) = *(CUpsideDownCarCheck*)0x6EE450; -CStuckCarCheck(&CTheScripts::StuckCars) = *(CStuckCarCheck*)0x87C588; +CRunningScript *&CTheScripts::pIdleScripts = *(CRunningScript**)0x9430D4; +CRunningScript *&CTheScripts::pActiveScripts = *(CRunningScript**)0x8E2BF4; +uint32 &CTheScripts::NextFreeCollectiveIndex = *(uint32*)0x942F98; +int32 &CTheScripts::LastRandomPedId = *(int32*)0x8F251C; +uint16 &CTheScripts::NumberOfUsedObjects = *(uint16*)0x95CC72; +bool &CTheScripts::bAlreadyRunningAMissionScript = *(bool*)0x95CDB3; +bool &CTheScripts::bUsingAMultiScriptFile = *(bool*)0x95CD55; +uint16 &CTheScripts::NumberOfMissionScripts = *(uint16*)0x95CC9A; +uint32 &CTheScripts::LargestMissionScriptSize = *(uint32*)0x9414C8; +uint32 &CTheScripts::MainScriptSize = *(uint32*)0x9405A4; +uint8 &CTheScripts::FailCurrentMission = *(uint8*)0x95CD41; +uint8 &CTheScripts::CountdownToMakePlayerUnsafe = *(uint8*)0x95CD51; +uint8 &CTheScripts::DelayMakingPlayerUnsafeThisTime = *(uint8*)0x95CD88; +uint16 &CTheScripts::NumScriptDebugLines = *(uint16*)0x95CC42; +uint16 &CTheScripts::NumberOfIntroRectanglesThisFrame = *(uint16*)0x95CC88; +uint16 &CTheScripts::NumberOfIntroTextLinesThisFrame = *(uint16*)0x95CC32; +bool &CTheScripts::UseTextCommands = *(bool*)0x95CD57; +CMissionCleanup (&CTheScripts::MissionCleanup) = *(CMissionCleanup*)0x8F2A24; +CUpsideDownCarCheck (&CTheScripts::UpsideDownCars) = *(CUpsideDownCarCheck*)0x6EE450; +CStuckCarCheck (&CTheScripts::StuckCars) = *(CStuckCarCheck*)0x87C588; +uint16 &CTheScripts::CommandsExecuted = *(uint16*)0x95CCA6; +uint16 &CTheScripts::ScriptsUpdated = *(uint16*)0x95CC5E; +int32(&ScriptParams)[32] = *(int32(*)[32])*(uintptr*)0x6ED460; CMissionCleanup::CMissionCleanup() { @@ -66,7 +99,7 @@ void CMissionCleanup::AddEntityToList(int32 id, uint8 type) void CMissionCleanup::RemoveEntityFromList(int32 id, uint8 type) { for (int i = 0; i < MAX_CLEANUP; i++){ - if (m_sEntities[i].type == type && m_sEntities[i].id == 0){ + if (m_sEntities[i].type == type && m_sEntities[i].id == id){ m_sEntities[i].id = 0; m_sEntities[i].type = CLEANUP_UNUSED; } @@ -277,11 +310,1095 @@ bool CStuckCarCheck::HasCarBeenStuckForAWhile(int32 id) return false; } +void CRunningScript::CollectParameters(uint32* pIp, int16 total) +{ + for (int16 i = 0; i < total; i++){ + float tmp; + switch (CTheScripts::Read1ByteFromScript(pIp)) + { + case ARGUMENT_INT32: + ScriptParams[i] = CTheScripts::Read4BytesFromScript(pIp); + break; + case ARGUMENT_GLOBALVAR: + ScriptParams[i] = *((int32*)&CTheScripts::ScriptSpace[CTheScripts::Read2BytesFromScript(pIp)]); + break; + case ARGUMENT_LOCALVAR: + ScriptParams[i] = m_anLocalVariables[CTheScripts::Read2BytesFromScript(pIp)]; + break; + case ARGUMENT_INT8: + ScriptParams[i] = CTheScripts::Read1ByteFromScript(pIp); + break; + case ARGUMENT_INT16: + ScriptParams[i] = CTheScripts::Read2BytesFromScript(pIp); + break; + case ARGUMENT_FLOAT: + tmp = CTheScripts::ReadFloatFromScript(pIp); + ScriptParams[i] = *(int32*)&tmp; + break; + default: + assert(0); + break; + } + } +} + +int32 CRunningScript::CollectNextParameterWithoutIncreasingPC(uint32 ip) +{ + uint32* pIp = &ip; + float tmp; + switch (CTheScripts::Read1ByteFromScript(pIp)) + { + case ARGUMENT_INT32: + return CTheScripts::Read4BytesFromScript(pIp); + case ARGUMENT_GLOBALVAR: + return *((int32*)&CTheScripts::ScriptSpace[CTheScripts::Read2BytesFromScript(pIp)]); + case ARGUMENT_LOCALVAR: + return m_anLocalVariables[CTheScripts::Read2BytesFromScript(pIp)]; + case ARGUMENT_INT8: + return CTheScripts::Read1ByteFromScript(pIp); + case ARGUMENT_INT16: + return CTheScripts::Read2BytesFromScript(pIp); + case ARGUMENT_FLOAT: + tmp = CTheScripts::ReadFloatFromScript(pIp); + return *(int32*)&tmp; + default: + assert(0); + } + return -1; +} + +void CRunningScript::StoreParameters(uint32* pIp, int16 number) +{ + for (int16 i = 0; i < number; i++){ + switch (CTheScripts::Read1ByteFromScript(pIp)) { + case ARGUMENT_GLOBALVAR: + *(int32*)&CTheScripts::ScriptSpace[CTheScripts::Read2BytesFromScript(pIp)] = ScriptParams[i]; + break; + case ARGUMENT_LOCALVAR: + m_anLocalVariables[CTheScripts::Read2BytesFromScript(pIp)] = ScriptParams[i]; + break; + default: + assert(0); + } + } +} + +int32 *CRunningScript::GetPointerToScriptVariable(uint32* pIp, int16 type) +{ + switch (CTheScripts::Read1ByteFromScript(pIp)) + { + case ARGUMENT_GLOBALVAR: + assert(type == VAR_GLOBAL); + return (int32*)&CTheScripts::ScriptSpace[CTheScripts::Read2BytesFromScript(pIp)]; + case ARGUMENT_LOCALVAR: + assert(type == VAR_LOCAL); + return &m_anLocalVariables[CTheScripts::Read2BytesFromScript(pIp)]; + default: + assert(0); + } + return nil; +} + +void CRunningScript::Init() +{ + strcpy(m_abScriptName, "noname"); + next = prev = nil; + m_nIp = 0; + for (int i = 0; i < MAX_STACK_DEPTH; i++) + m_anStack[i] = 0; + m_nStackPointer = 0; + m_nWakeTime = 0; + m_bCondResult = false; + m_bIsMissionScript = false; + m_bSkipWakeTime = false; + for (int i = 0; i < NUM_LOCAL_VARS + NUM_TIMERS; i++) + m_anLocalVariables[i] = 0; + m_nAndOrState = 0; + m_bNotFlag = false; + m_bWBCheckEnabled = true; + m_bWBChecked = false; + m_bMissionFlag = false; +} + +#ifdef USE_DEBUG_SCRIPT_LOADER +int open_script() +{ + static int scriptToLoad = 1; + + if (GetAsyncKeyState('G') & 0x8000) + scriptToLoad = 0; + if (GetAsyncKeyState('R') & 0x8000) + scriptToLoad = 1; + if (GetAsyncKeyState('D') & 0x8000) + scriptToLoad = 2; + + switch (scriptToLoad) { + case 0: return CFileMgr::OpenFile("main.scm", "rb"); + case 1: return CFileMgr::OpenFile("main_freeroam.scm", "rb"); + case 2: return CFileMgr::OpenFile("main_d.scm", "rb"); + } + return CFileMgr::OpenFile("main.scm", "rb"); +} +#endif + +void CTextLine::Reset() +{ + m_fScaleX = 0.48f; + m_fScaleY = 1.12f; + m_sColor = CRGBA(225, 225, 225, 255); + m_bJustify = false; + m_bRightJustify = false; + m_bCentered = false; + m_bBackground = false; + m_bBackgroundOnly = false; + m_fWrapX = 182.0f; /* TODO: scaling as bugfix */ + m_fCenterSize = 640.0f; /* --||-- */ + m_sBackgroundColor = CRGBA(128, 128, 128, 128); + m_bTextProportional = true; + m_bTextBeforeFade = false; + m_nFont = 2; /* enum? */ + m_fAtX = 0.0f; + m_fAtY = 0.0f; + memset(&m_Text, 0, sizeof(m_Text)); +} + +void CTheScripts::Init() +{ + for (int i = 0; i < SIZE_SCRIPT_SPACE; i++) + ScriptSpace[i] = 0; + pActiveScripts = pIdleScripts = nil; + for (int i = 0; i < MAX_NUM_SCRIPTS; i++){ + ScriptsArray[i].Init(); + ScriptsArray[i].AddScriptToList(&pIdleScripts); + } + MissionCleanup.Init(); + UpsideDownCars.Init(); + StuckCars.Init(); + CFileMgr::SetDir("data"); +#ifdef USE_DEBUG_SCRIPT_LOADER + int mainf = open_script(); +#else + int mainf = CFileMgr::OpenFile("main.scm", "rb"); +#endif + CFileMgr::Read(mainf, (char*)ScriptSpace, SIZE_MAIN_SCRIPT); + CFileMgr::CloseFile(mainf); + CFileMgr::SetDir(""); + StoreVehicleIndex = -1; + StoreVehicleWasRandom = true; + OnAMissionFlag = 0; + for (int i = 0; i < MAX_NUM_CONTACTS; i++){ + BaseBriefIdForContact[i] = 0; + OnAMissionForContactFlag[i] = 0; + } + for (int i = 0; i < MAX_NUM_COLLECTIVES; i++){ + CollectiveArray[i].index = -1; + CollectiveArray[i].unk_data = 0; + } + NextFreeCollectiveIndex = 0; + LastRandomPedId = -1; + for (int i = 0; i < MAX_NUM_USED_OBJECTS; i++){ + memset(&UsedObjectArray[i].name, 0, sizeof(UsedObjectArray[i].name)); + UsedObjectArray[i].index = 0; + } + NumberOfUsedObjects = 0; + ReadObjectNamesFromScript(); + UpdateObjectIndices(); + bAlreadyRunningAMissionScript = false; + bUsingAMultiScriptFile = true; + for (int i = 0; i < MAX_NUM_MISSION_SCRIPTS; i++) + MultiScriptArray[i] = 0; + NumberOfMissionScripts = 0; + LargestMissionScriptSize = 0; + MainScriptSize = 0; + ReadMultiScriptFileOffsetsFromScript(); + FailCurrentMission = 0; + CountdownToMakePlayerUnsafe = 0; + DbgFlag = 0; + DelayMakingPlayerUnsafeThisTime = 0; + NumScriptDebugLines = 0; + for (int i = 0; i < MAX_NUM_SCRIPT_SPHERES; i++){ + ScriptSphereArray[i].m_bInUse = false; + ScriptSphereArray[i].m_Index = 1; + ScriptSphereArray[i].m_Id = 0; + ScriptSphereArray[i].m_vecCenter = CVector(0.0f, 0.0f, 0.0f); + ScriptSphereArray[i].m_fRadius = 0.0f; + } + for (int i = 0; i < MAX_NUM_INTRO_TEXT_LINES; i++){ + IntroTextLines[i].Reset(); + } + NumberOfIntroTextLinesThisFrame = 0; + UseTextCommands = false; + for (int i = 0; i < MAX_NUM_INTRO_RECTANGLES; i++){ + IntroRectangles[i].m_bIsUsed = false; + IntroRectangles[i].m_bBeforeFade = false; + IntroRectangles[i].m_nTextureId = -1; + IntroRectangles[i].m_sRect = CRect(0.0f, 0.0f, 0.0f, 0.0f); + IntroRectangles[i].m_sColor = CRGBA(255, 255, 255, 255); + } + NumberOfIntroRectanglesThisFrame = 0; + for (int i = 0; i < MAX_NUM_BUILDING_SWAPS; i++){ + BuildingSwapArray[i].m_pBuilding = nil; + BuildingSwapArray[i].m_nNewModel = -1; + BuildingSwapArray[i].m_nOldModel = -1; + } + for (int i = 0; i < MAX_NUM_INVISIBILITY_SETTINGS; i++) + InvisibilitySettingArray[i] = nil; +} + +void CRunningScript::RemoveScriptFromList(CRunningScript** ppScript) +{ + if (prev) + prev->next = next; + else + *ppScript = next; + if (next) + next->prev = prev; +} + +void CRunningScript::AddScriptToList(CRunningScript** ppScript) +{ + next = *ppScript; + prev = nil; + if (*ppScript) + (*ppScript)->prev = this; + *ppScript = this; +} + +CRunningScript* CTheScripts::StartNewScript(uint32 ip) +{ + CRunningScript* pNew = pIdleScripts; + assert(pNew); + pNew->RemoveScriptFromList(&pIdleScripts); + pNew->Init(); + pNew->SetIP(ip); + pNew->AddScriptToList(&pActiveScripts); + return pNew; +} + +void CTheScripts::Process() +{ + if (CReplay::IsPlayingBack()) + return; + CommandsExecuted = 0; + ScriptsUpdated = 0; + float timeStep = CTimer::GetTimeStepInMilliseconds(); + UpsideDownCars.UpdateTimers(); + StuckCars.Process(); + DrawScriptSpheres(); + if (FailCurrentMission) + --FailCurrentMission; + if (CountdownToMakePlayerUnsafe){ + if (--CountdownToMakePlayerUnsafe == 0) + CWorld::Players[0].MakePlayerSafe(false); + } + if (UseTextCommands){ + for (int i = 0; i < MAX_NUM_INTRO_TEXT_LINES; i++) + IntroTextLines[i].Reset(); + NumberOfIntroRectanglesThisFrame = 0; + for (int i = 0; i < MAX_NUM_INTRO_RECTANGLES; i++){ + IntroRectangles[i].m_bIsUsed = false; + IntroRectangles[i].m_bBeforeFade = false; + } + NumberOfIntroRectanglesThisFrame = 0; + if (UseTextCommands == 1) + UseTextCommands = 0; + } + CRunningScript* script = pActiveScripts; + while (script != nil){ + CRunningScript* next = script->GetNext(); + ++ScriptsUpdated; + script->UpdateTimers(timeStep); + script->Process(); + script = next; + } + DbgFlag = false; +} + +CRunningScript* CTheScripts::StartTestScript() +{ + return StartNewScript(0); +} + +bool CTheScripts::IsPlayerOnAMission() +{ + return OnAMissionFlag && *(int32*)&ScriptSpace[OnAMissionFlag] == 1; +} + +void CRunningScript::Process() +{ + if (m_bIsMissionScript) + DoDeatharrestCheck(); + if (m_bMissionFlag && CTheScripts::FailCurrentMission == 1 && m_nStackPointer == 1) + m_nIp = m_anStack[--m_nStackPointer]; + if (CTimer::GetTimeInMilliseconds() >= m_nWakeTime){ + while (!ProcessOneCommand()) + ; + return; + } + if (!m_bSkipWakeTime) + return; + if (!CPad::GetPad(0)->GetCrossJustDown()) + return; + m_nWakeTime = 0; + for (int i = 0; i < 6; i++){ /* TODO: add constant for number of messages */ + if (CMessages::BIGMessages[i].m_Current.m_pText) + CMessages::BIGMessages[i].m_Current.m_nStartTime = 0; + if (CMessages::BriefMessages[0].m_pText) + CMessages::BriefMessages[0].m_nStartTime = 0; + } +} + +int8 CRunningScript::ProcessOneCommand() +{ + ++CTheScripts::CommandsExecuted; + int32 command = CTheScripts::Read2BytesFromScript(&m_nIp); + m_bNotFlag = (command & 0x8000); + command &= 0x7FFF; + if (command < 100) + return ProcessCommandsFrom0To99(command); + if (command < 200) + return ProcessCommandsFrom100To199(command); + if (command < 300) + return ProcessCommandsFrom200To299(command); + if (command < 400) + return ProcessCommandsFrom300To399(command); + if (command < 500) + return ProcessCommandsFrom400To499(command); + if (command < 600) + return ProcessCommandsFrom500To599(command); + if (command < 700) + return ProcessCommandsFrom600To699(command); + if (command < 800) + return ProcessCommandsFrom700To799(command); + if (command < 900) + return ProcessCommandsFrom800To899(command); + if (command < 1000) + return ProcessCommandsFrom900To999(command); + if (command < 1100) + return ProcessCommandsFrom1000To1099(command); + if (command < 1200) + return ProcessCommandsFrom1100To1199(command); + return -1; +} + +int8 CRunningScript::ProcessCommandsFrom0To99(int32 command) +{ + switch (command) { + case COMMAND_NOP: + return 0; + case COMMAND_WAIT: + CollectParameters(&m_nIp, 1); + m_nWakeTime = CTimer::GetTimeInMilliseconds() + ScriptParams[0]; + return 1; + case COMMAND_GOTO: + CollectParameters(&m_nIp, 1); + SetIP(ScriptParams[0] >= 0 ? ScriptParams[0] : SIZE_MAIN_SCRIPT - ScriptParams[0]); + /* Known issue: GOTO to 0. It might have been "better" to use > instead of >= */ + /* simply because it never makes sense to jump to start of the script */ + /* but jumping to start of a custom mission is an issue for simple mission-like scripts */ + /* However, it's not an issue for actual mission scripts, because they follow a structure */ + /* and never start with a loop. */ + return 0; + case COMMAND_SHAKE_CAM: + CollectParameters(&m_nIp, 1); + TheCamera.CamShake(ScriptParams[0] / 1000.0f); + return 0; + case COMMAND_SET_VAR_INT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + *ptr = ScriptParams[0]; + return 0; + } + case COMMAND_SET_VAR_FLOAT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + *(float*)ptr = *(float*)&ScriptParams[0]; + return 0; + } + case COMMAND_SET_LVAR_INT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + *ptr = ScriptParams[0]; + return 0; + } + case COMMAND_SET_LVAR_FLOAT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + *(float*)ptr = *(float*)&ScriptParams[0]; + return 0; + } + case COMMAND_ADD_VAL_TO_INT_VAR: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + *ptr += ScriptParams[0]; + return 0; + } + case COMMAND_ADD_VAL_TO_FLOAT_VAR: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + *(float*)ptr += *(float*)&ScriptParams[0]; + return 0; + } + case COMMAND_ADD_VAL_TO_INT_LVAR: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + *ptr += ScriptParams[0]; + return 0; + } + case COMMAND_ADD_VAL_TO_FLOAT_LVAR: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + *(float*)ptr += *(float*)&ScriptParams[0]; + return 0; + } + case COMMAND_SUB_VAL_FROM_INT_VAR: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + *ptr -= ScriptParams[0]; + return 0; + } + case COMMAND_SUB_VAL_FROM_FLOAT_VAR: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + *(float*)ptr -= *(float*)&ScriptParams[0]; + return 0; + } + case COMMAND_SUB_VAL_FROM_INT_LVAR: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + *ptr -= ScriptParams[0]; + return 0; + } + case COMMAND_SUB_VAL_FROM_FLOAT_LVAR: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + *(float*)ptr -= *(float*)&ScriptParams[0]; + return 0; + } + case COMMAND_MULT_INT_VAR_BY_VAL: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + *ptr *= ScriptParams[0]; + return 0; + } + case COMMAND_MULT_FLOAT_VAR_BY_VAL: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + *(float*)ptr *= *(float*)&ScriptParams[0]; + return 0; + } + case COMMAND_MULT_INT_LVAR_BY_VAL: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + *ptr *= ScriptParams[0]; + return 0; + } + case COMMAND_MULT_FLOAT_LVAR_BY_VAL: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + *(float*)ptr *= *(float*)&ScriptParams[0]; + return 0; + } + case COMMAND_DIV_INT_VAR_BY_VAL: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + *ptr /= ScriptParams[0]; + return 0; + } + case COMMAND_DIV_FLOAT_VAR_BY_VAL: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + *(float*)ptr /= *(float*)&ScriptParams[0]; + return 0; + } + case COMMAND_DIV_INT_LVAR_BY_VAL: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + *ptr /= ScriptParams[0]; + return 0; + } + case COMMAND_DIV_FLOAT_LVAR_BY_VAL: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + *(float*)ptr /= *(float*)&ScriptParams[0]; + return 0; + } + case COMMAND_IS_INT_VAR_GREATER_THAN_NUMBER: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(*ptr > ScriptParams[0]); + return 0; + } + case COMMAND_IS_INT_LVAR_GREATER_THAN_NUMBER: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(*ptr > ScriptParams[0]); + return 0; + } + case COMMAND_IS_NUMBER_GREATER_THAN_INT_VAR: + { + CollectParameters(&m_nIp, 1); + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + UpdateCompareFlag(ScriptParams[0] > *ptr); + return 0; + } + case COMMAND_IS_NUMBER_GREATER_THAN_INT_LVAR: + { + CollectParameters(&m_nIp, 1); + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + UpdateCompareFlag(ScriptParams[0] > *ptr); + return 0; + } + case COMMAND_IS_INT_VAR_GREATER_THAN_INT_VAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + UpdateCompareFlag(*ptr1 > *ptr2); + return 0; + } + case COMMAND_IS_INT_LVAR_GREATER_THAN_INT_VAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + UpdateCompareFlag(*ptr1 > *ptr2); + return 0; + } + case COMMAND_IS_INT_VAR_GREATER_THAN_INT_LVAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + UpdateCompareFlag(*ptr1 > *ptr2); + return 0; + } + case COMMAND_IS_INT_LVAR_GREATER_THAN_INT_LVAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + UpdateCompareFlag(*ptr1 > *ptr2); + return 0; + } + case COMMAND_IS_FLOAT_VAR_GREATER_THAN_NUMBER: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(*(float*)ptr > *(float*)&ScriptParams[0]); + return 0; + } + case COMMAND_IS_FLOAT_LVAR_GREATER_THAN_NUMBER: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(*(float*)ptr > *(float*)&ScriptParams[0]); + return 0; + } + case COMMAND_IS_NUMBER_GREATER_THAN_FLOAT_VAR: + { + CollectParameters(&m_nIp, 1); + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + UpdateCompareFlag(*(float*)&ScriptParams[0] > *(float*)ptr); + return 0; + } + case COMMAND_IS_NUMBER_GREATER_THAN_FLOAT_LVAR: + { + CollectParameters(&m_nIp, 1); + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + UpdateCompareFlag(*(float*)&ScriptParams[0] > *(float*)ptr); + return 0; + } + case COMMAND_IS_FLOAT_VAR_GREATER_THAN_FLOAT_VAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + UpdateCompareFlag(*(float*)ptr1 > *(float*)ptr2); + return 0; + } + case COMMAND_IS_FLOAT_LVAR_GREATER_THAN_FLOAT_VAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + UpdateCompareFlag(*(float*)ptr1 > *(float*)ptr2); + return 0; + } + case COMMAND_IS_FLOAT_VAR_GREATER_THAN_FLOAT_LVAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + UpdateCompareFlag(*(float*)ptr1 > *(float*)ptr2); + return 0; + } + case COMMAND_IS_FLOAT_LVAR_GREATER_THAN_FLOAT_LVAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + UpdateCompareFlag(*(float*)ptr1 > *(float*)ptr2); + return 0; + } + case COMMAND_IS_INT_VAR_GREATER_OR_EQUAL_TO_NUMBER: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(*ptr >= ScriptParams[0]); + return 0; + } + case COMMAND_IS_INT_LVAR_GREATER_OR_EQUAL_TO_NUMBER: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(*ptr >= ScriptParams[0]); + return 0; + } + case COMMAND_IS_NUMBER_GREATER_OR_EQUAL_TO_INT_VAR: + { + CollectParameters(&m_nIp, 1); + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + UpdateCompareFlag(ScriptParams[0] >= *ptr); + return 0; + } + case COMMAND_IS_NUMBER_GREATER_OR_EQUAL_TO_INT_LVAR: + { + CollectParameters(&m_nIp, 1); + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + UpdateCompareFlag(ScriptParams[0] >= *ptr); + return 0; + } + case COMMAND_IS_INT_VAR_GREATER_OR_EQUAL_TO_INT_VAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + UpdateCompareFlag(*ptr1 >= *ptr2); + return 0; + } + case COMMAND_IS_INT_LVAR_GREATER_OR_EQUAL_TO_INT_VAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + UpdateCompareFlag(*ptr1 >= *ptr2); + return 0; + } + case COMMAND_IS_INT_VAR_GREATER_OR_EQUAL_TO_INT_LVAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + UpdateCompareFlag(*ptr1 >= *ptr2); + return 0; + } + case COMMAND_IS_INT_LVAR_GREATER_OR_EQUAL_TO_INT_LVAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + UpdateCompareFlag(*ptr1 >= *ptr2); + return 0; + } + case COMMAND_IS_FLOAT_VAR_GREATER_OR_EQUAL_TO_NUMBER: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(*(float*)ptr >= *(float*)&ScriptParams[0]); + return 0; + } + case COMMAND_IS_FLOAT_LVAR_GREATER_OR_EQUAL_TO_NUMBER: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(*(float*)ptr >= *(float*)&ScriptParams[0]); + return 0; + } + case COMMAND_IS_NUMBER_GREATER_OR_EQUAL_TO_FLOAT_VAR: + { + CollectParameters(&m_nIp, 1); + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + UpdateCompareFlag(*(float*)&ScriptParams[0] >= *(float*)ptr); + return 0; + } + case COMMAND_IS_NUMBER_GREATER_OR_EQUAL_TO_FLOAT_LVAR: + { + CollectParameters(&m_nIp, 1); + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + UpdateCompareFlag(*(float*)&ScriptParams[0] >= *(float*)ptr); + return 0; + } + case COMMAND_IS_FLOAT_VAR_GREATER_OR_EQUAL_TO_FLOAT_VAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + UpdateCompareFlag(*(float*)ptr1 >= *(float*)ptr2); + return 0; + } + case COMMAND_IS_FLOAT_LVAR_GREATER_OR_EQUAL_TO_FLOAT_VAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + UpdateCompareFlag(*(float*)ptr1 >= *(float*)ptr2); + return 0; + } + case COMMAND_IS_FLOAT_VAR_GREATER_OR_EQUAL_TO_FLOAT_LVAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + UpdateCompareFlag(*(float*)ptr1 >= *(float*)ptr2); + return 0; + } + case COMMAND_IS_FLOAT_LVAR_GREATER_OR_EQUAL_TO_FLOAT_LVAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + UpdateCompareFlag(*(float*)ptr1 >= *(float*)ptr2); + return 0; + } + case COMMAND_IS_INT_VAR_EQUAL_TO_NUMBER: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(*ptr == ScriptParams[0]); + return 0; + } + case COMMAND_IS_INT_LVAR_EQUAL_TO_NUMBER: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(*ptr == ScriptParams[0]); + return 0; + } + case COMMAND_IS_INT_VAR_EQUAL_TO_INT_VAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + UpdateCompareFlag(*ptr1 == *ptr2); + return 0; + } + case COMMAND_IS_INT_VAR_EQUAL_TO_INT_LVAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + UpdateCompareFlag(*ptr1 == *ptr2); + return 0; + } + case COMMAND_IS_INT_LVAR_EQUAL_TO_INT_LVAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + UpdateCompareFlag(*ptr1 == *ptr2); + return 0; + } + case COMMAND_IS_FLOAT_VAR_EQUAL_TO_NUMBER: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(*(float*)ptr == *(float*)&ScriptParams[0]); + return 0; + } + case COMMAND_IS_FLOAT_LVAR_EQUAL_TO_NUMBER: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(*(float*)ptr == *(float*)&ScriptParams[0]); + return 0; + } + case COMMAND_IS_FLOAT_VAR_EQUAL_TO_FLOAT_VAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + UpdateCompareFlag(*(float*)ptr1 == *(float*)ptr2); + return 0; + } + case COMMAND_IS_FLOAT_VAR_EQUAL_TO_FLOAT_LVAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + UpdateCompareFlag(*(float*)ptr1 == *(float*)ptr2); + return 0; + } + case COMMAND_IS_FLOAT_LVAR_EQUAL_TO_FLOAT_LVAR: + { + int32* ptr1 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + int32* ptr2 = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + UpdateCompareFlag(*(float*)ptr1 == *(float*)ptr2); + return 0; + } + case COMMAND_GOTO_IF_TRUE: + CollectParameters(&m_nIp, 1); + if (m_bCondResult) + SetIP(ScriptParams[0] >= 0 ? ScriptParams[0] : SIZE_MAIN_SCRIPT - ScriptParams[0]); + /* Check COMMAND_GOTO note. */ + return 0; + case COMMAND_GOTO_IF_FALSE: + CollectParameters(&m_nIp, 1); + if (!m_bCondResult) + SetIP(ScriptParams[0] >= 0 ? ScriptParams[0] : SIZE_MAIN_SCRIPT - ScriptParams[0]); + /* Check COMMAND_GOTO note. */ + return 0; + case COMMAND_TERMINATE_THIS_SCRIPT: + if (m_bMissionFlag) + CTheScripts::bAlreadyRunningAMissionScript = false; + RemoveScriptFromList(&CTheScripts::pActiveScripts); + AddScriptToList(&CTheScripts::pIdleScripts); + return 1; + case COMMAND_START_NEW_SCRIPT: + { + CollectParameters(&m_nIp, 1); + assert(ScriptParams[0] >= 0); + CRunningScript* pNew = CTheScripts::StartNewScript(ScriptParams[0]); + int8 type = CTheScripts::Read1ByteFromScript(&m_nIp); + float tmp; + for (int i = 0; type != ARGUMENT_END; type = CTheScripts::Read1ByteFromScript(&m_nIp), i++) { + switch (type) { + case ARGUMENT_INT32: + pNew->m_anLocalVariables[i] = CTheScripts::Read4BytesFromScript(&m_nIp); + break; + case ARGUMENT_GLOBALVAR: + pNew->m_anLocalVariables[i] = *(int32*)&CTheScripts::ScriptSpace[CTheScripts::Read2BytesFromScript(&m_nIp)]; + break; + case ARGUMENT_LOCALVAR: + pNew->m_anLocalVariables[i] = m_anLocalVariables[CTheScripts::Read2BytesFromScript(&m_nIp)]; + break; + case ARGUMENT_INT8: + pNew->m_anLocalVariables[i] = CTheScripts::Read1ByteFromScript(&m_nIp); + break; + case ARGUMENT_INT16: + pNew->m_anLocalVariables[i] = CTheScripts::Read2BytesFromScript(&m_nIp); + break; + case ARGUMENT_FLOAT: + tmp = CTheScripts::ReadFloatFromScript(&m_nIp); + pNew->m_anLocalVariables[i] = *(int32*)&tmp; + break; + default: + break; + } + } + return 0; + } + case COMMAND_GOSUB: + CollectParameters(&m_nIp, 1); + assert(m_nStackPointer < MAX_STACK_DEPTH); + m_anStack[m_nStackPointer++] = m_nIp; + SetIP(ScriptParams[0] >= 0 ? ScriptParams[0] : SIZE_MAIN_SCRIPT - ScriptParams[0]); + return 0; + case COMMAND_RETURN: + assert(m_nStackPointer > 0); /* No more SSU */ + SetIP(m_anStack[--m_nStackPointer]); + return 0; + case COMMAND_LINE: + CollectParameters(&m_nIp, 6); + /* Something must have been here */ + return 0; + case COMMAND_CREATE_PLAYER: + { + CollectParameters(&m_nIp, 4); + int32 index = ScriptParams[0]; + assert(index < 1); /* Constant? Also no more double player glitch */ + debug("&&&&&&&&&&&&&Creating player: %d\n", index); + if (!CStreaming::HasModelLoaded(MI_PLAYER)) { + CStreaming::RequestSpecialModel(MI_PLAYER, "player", STREAMFLAGS_DONT_REMOVE | STREAMFLAGS_DEPENDENCY); + CStreaming::LoadAllRequestedModels(false); + } + CPlayerPed::SetupPlayerPed(index); + CWorld::Players[index].m_pPed->CharCreatedBy = MISSION_CHAR; + CPlayerPed::DeactivatePlayerPed(index); + CVector pos = *(CVector*)&ScriptParams[1]; + if (pos.z <= -100.0f) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + pos.z += CWorld::Players[index].m_pPed->GetDistanceFromCentreOfMassToBaseOfModel(); + CWorld::Players[index].m_pPed->GetPosition() = pos; + CTheScripts::ClearSpaceForMissionEntity(pos, CWorld::Players[index].m_pPed); + CPlayerPed::ReactivatePlayerPed(index); + ScriptParams[0] = index; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_GET_PLAYER_COORDINATES: + { + CVector pos; + CollectParameters(&m_nIp, 1); + if (CWorld::Players[ScriptParams[0]].m_pPed->bInVehicle) + pos = CWorld::Players[ScriptParams[0]].m_pPed->m_pMyVehicle->GetPosition(); + else + pos = CWorld::Players[ScriptParams[0]].m_pPed->GetPosition(); + *(CVector*)&ScriptParams[0] = pos; + StoreParameters(&m_nIp, 3); + return 0; + } + case COMMAND_SET_PLAYER_COORDINATES: + { + CollectParameters(&m_nIp, 4); + CVector pos = *(CVector*)&ScriptParams[1]; + int index = ScriptParams[0]; + if (pos.z <= -100.0f) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + CPlayerPed* ped = CWorld::Players[index].m_pPed; + if (!ped->bInVehicle) { + pos.z += ped->GetDistanceFromCentreOfMassToBaseOfModel(); + ped->Teleport(pos); + CTheScripts::ClearSpaceForMissionEntity(pos, ped); + return 0; + } + pos.z += ped->m_pMyVehicle->GetDistanceFromCentreOfMassToBaseOfModel(); + if (ped->m_pMyVehicle->IsBoat()) + ped->m_pMyVehicle->Teleport(pos); + else + ped->m_pMyVehicle->Teleport(pos); + /* I'll keep this condition here but obviously it is absolutely pointless */ + /* It's clearly present in disassembly so it had to be in original code */ + CTheScripts::ClearSpaceForMissionEntity(pos, ped->m_pMyVehicle); + return 0; + } + case COMMAND_IS_PLAYER_IN_AREA_2D: + { + CollectParameters(&m_nIp, 6); + CPlayerPed* ped = CWorld::Players[ScriptParams[0]].m_pPed; + float x1, y1, x2, y2; + x1 = *(float*)&ScriptParams[1]; + y1 = *(float*)&ScriptParams[2]; + x2 = *(float*)&ScriptParams[3]; + y2 = *(float*)&ScriptParams[4]; + if (!ped->bInVehicle) + UpdateCompareFlag(ped->IsWithinArea(x1, y1, x2, y2)); + else + UpdateCompareFlag(ped->m_pMyVehicle->IsWithinArea(x1, y1, x2, y2)); + if (!ScriptParams[5]) + return 0; + 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_PLAYER_IN_AREA_3D: + { + CollectParameters(&m_nIp, 8); + CPlayerPed* ped = CWorld::Players[ScriptParams[0]].m_pPed; + 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 (ped->bInVehicle) + UpdateCompareFlag(ped->m_pMyVehicle->IsWithinArea(x1, y1, z1, x2, y2, z2)); + else + UpdateCompareFlag(ped->IsWithinArea(x1, y1, z1, x2, y2, z2)); + if (!ScriptParams[7]) + return 0; + 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_ADD_INT_VAR_TO_INT_VAR: + *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) += *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_ADD_INT_LVAR_TO_INT_VAR: + *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) += *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_ADD_INT_VAR_TO_INT_LVAR: + *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) += *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_ADD_INT_LVAR_TO_INT_LVAR: + *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) += *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_ADD_FLOAT_VAR_TO_FLOAT_VAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) += *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_ADD_FLOAT_LVAR_TO_FLOAT_VAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) += *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_ADD_FLOAT_VAR_TO_FLOAT_LVAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) += *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_ADD_FLOAT_LVAR_TO_FLOAT_LVAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) += *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_SUB_INT_VAR_FROM_INT_VAR: + *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) -= *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_SUB_INT_LVAR_FROM_INT_LVAR: + *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) -= *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_SUB_FLOAT_VAR_FROM_FLOAT_VAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) -= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_SUB_FLOAT_LVAR_FROM_FLOAT_LVAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) -= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + default: + break; + } + return -1; +} + +void CRunningScript::UpdateCompareFlag(bool flag) +{ + if (m_bNotFlag) + flag = !flag; + if (m_nAndOrState == 0){ + m_bCondResult = flag; + return; + } + if (m_nAndOrState >= 1 && m_nAndOrState <= 8) { /* Maybe enums?*/ + m_bCondResult &= flag; + if (m_nAndOrState == 1){ + m_nAndOrState = 0; + return; + } + }else if (m_nAndOrState >= 21 && m_nAndOrState <= 28){ + m_bCondResult |= flag; + if (m_nAndOrState == 21) { + m_nAndOrState = 0; + return; + } + }else{ + return; + } + m_nAndOrState--; +} + + +WRAPPER int8 CRunningScript::ProcessCommandsFrom100To199(int32 command) { EAXJMP(0x43AEA0); } +WRAPPER int8 CRunningScript::ProcessCommandsFrom200To299(int32 command) { EAXJMP(0x43D530); } +WRAPPER int8 CRunningScript::ProcessCommandsFrom300To399(int32 command) { EAXJMP(0x43ED30); } +WRAPPER int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) { EAXJMP(0x440CB0); } +WRAPPER int8 CRunningScript::ProcessCommandsFrom500To599(int32 command) { EAXJMP(0x4429C0); } +WRAPPER int8 CRunningScript::ProcessCommandsFrom600To699(int32 command) { EAXJMP(0x444B20); } +WRAPPER int8 CRunningScript::ProcessCommandsFrom700To799(int32 command) { EAXJMP(0x4458A0); } +WRAPPER int8 CRunningScript::ProcessCommandsFrom800To899(int32 command) { EAXJMP(0x448240); } +WRAPPER int8 CRunningScript::ProcessCommandsFrom900To999(int32 command) { EAXJMP(0x44CB80); } +WRAPPER int8 CRunningScript::ProcessCommandsFrom1000To1099(int32 command) { EAXJMP(0x588490); } +WRAPPER int8 CRunningScript::ProcessCommandsFrom1100To1199(int32 command) { EAXJMP(0x589D00); } + +WRAPPER void CTheScripts::DrawScriptSpheres() { EAXJMP(0x44FAC0); } +WRAPPER void CRunningScript::DoDeatharrestCheck() { EAXJMP(0x452A30); } +WRAPPER void CTheScripts::DrawDebugSquare(float, float, float, float) { EAXJMP(0x452D00); } +WRAPPER void CTheScripts::DrawDebugCube(float, float, float, float, float, float) { EAXJMP(0x453100); } +WRAPPER void CTheScripts::ScriptDebugLine3D(float x1, float y1, float z1, float x2, float y2, float z2, int col, int col2) { EAXJMP(0x4534E0); } +WRAPPER void CTheScripts::ClearSpaceForMissionEntity(const CVector&, CEntity*) { EAXJMP(0x454060); } +WRAPPER void CTheScripts::HighlightImportantArea(uint32, float, float, float, float, float) { EAXJMP(0x454320); } WRAPPER void CTheScripts::CleanUpThisVehicle(CVehicle*) { EAXJMP(0x4548D0); } WRAPPER void CTheScripts::CleanUpThisPed(CPed*) { EAXJMP(0x4547A0); } WRAPPER void CTheScripts::CleanUpThisObject(CObject*) { EAXJMP(0x454910); } -WRAPPER bool CTheScripts::IsPlayerOnAMission() { EAXJMP(0x439410); } -WRAPPER void CTheScripts::ScriptDebugLine3D(float x1, float y1, float z1, float x2, float y2, float z2, int col, int col2) { EAXJMP(0x4534E0); } +WRAPPER void CTheScripts::ReadObjectNamesFromScript() { EAXJMP(0x454960); } +WRAPPER void CTheScripts::UpdateObjectIndices() { EAXJMP(0x454AD0); } +WRAPPER void CTheScripts::ReadMultiScriptFileOffsetsFromScript() { EAXJMP(0x454BC0); } STARTPATCHES InjectHook(0x437AE0, &CMissionCleanup::Init, PATCH_JUMP); @@ -299,4 +1416,13 @@ InjectHook(0x4380A0, &CStuckCarCheck::Process, PATCH_JUMP); InjectHook(0x4381C0, &CStuckCarCheck::AddCarToCheck, PATCH_JUMP); InjectHook(0x438240, &CStuckCarCheck::RemoveCarFromCheck, PATCH_JUMP); InjectHook(0x4382A0, &CStuckCarCheck::HasCarBeenStuckForAWhile, PATCH_JUMP); +InjectHook(0x4382E0, &CRunningScript::CollectParameters, PATCH_JUMP); +InjectHook(0x438460, &CRunningScript::CollectNextParameterWithoutIncreasingPC, PATCH_JUMP); +InjectHook(0x4385A0, &CRunningScript::StoreParameters, PATCH_JUMP); +InjectHook(0x438640, &CRunningScript::GetPointerToScriptVariable, PATCH_JUMP); +InjectHook(0x438790, &CTheScripts::Init, PATCH_JUMP); +InjectHook(0x439000, &CTheScripts::StartNewScript, PATCH_JUMP); +InjectHook(0x439040, &CTheScripts::Process, PATCH_JUMP); +InjectHook(0x439400, &CTheScripts::StartTestScript, PATCH_JUMP); +InjectHook(0x439410, &CTheScripts::IsPlayerOnAMission, PATCH_JUMP); ENDPATCHES
\ No newline at end of file diff --git a/src/control/Script.h b/src/control/Script.h index 42e41c70..0cbd40c0 100644 --- a/src/control/Script.h +++ b/src/control/Script.h @@ -1,18 +1,28 @@ #pragma once -#include "Ped.h" -#include "Object.h" +#include "common.h" #include "Sprite2d.h" -#include "Vehicle.h" + +class CEntity; +class CBuilding; +class CVehicle; +class CPed; +class CObject; struct CScriptRectangle { - bool m_bIsUsed; - bool m_bIsAntialiased; - uint16 m_wTextureId; + int8 m_bIsUsed; + bool m_bBeforeFade; + int16 m_nTextureId; CRect m_sRect; CRGBA m_sColor; }; +static_assert(sizeof(CScriptRectangle) == 0x18, "Script.h: error"); + +enum { + SCRIPT_TEXT_MAX_LENGTH = 500 +}; + struct CTextLine { float m_fScaleX; @@ -26,33 +36,83 @@ struct CTextLine float m_fCenterSize; CRGBA m_sBackgroundColor; bool m_bTextProportional; - int32 field_29; + bool m_bTextBeforeFade; bool m_bRightJustify; - int32 field_31; int32 m_nFont; - float field_36; - float field_40; - wchar m_awText[500]; + float m_fAtX; + float m_fAtY; + wchar m_Text[SCRIPT_TEXT_MAX_LENGTH]; + + void Reset(); }; -struct CRunningScript +static_assert(sizeof(CTextLine) == 0x414, "Script.h: error"); + +struct CScriptSphere +{ + bool m_bInUse; + uint16 m_Index; + uint32 m_Id; + CVector m_vecCenter; + float m_fRadius; +}; + +enum { + MAX_STACK_DEPTH = 6, + NUM_LOCAL_VARS = 16, + NUM_TIMERS = 2 +}; + +class CRunningScript { CRunningScript *next; CRunningScript *prev; - uint8 m_abScriptName[8]; + char m_abScriptName[8]; uint32 m_nIp; - uint32 m_anStack[6]; + uint32 m_anStack[MAX_STACK_DEPTH]; uint16 m_nStackPointer; - void* m_anLocalVariables[18]; + int32 m_anLocalVariables[NUM_LOCAL_VARS + NUM_TIMERS]; bool m_bCondResult; - bool m_bIsMissionThread; + bool m_bIsMissionScript; bool m_bSkipWakeTime; uint32 m_nWakeTime; - uint16 m_wIfOp; + uint16 m_nAndOrState; bool m_bNotFlag; - bool m_bWBCheck; - bool m_bWastedOrBusted; + bool m_bWBCheckEnabled; + bool m_bWBChecked; bool m_bMissionFlag; + +public: + void SetIP(uint32 ip) { m_nIp = ip; } + CRunningScript* GetNext() { return next; } + void UpdateTimers(float timeStep){ + m_anLocalVariables[NUM_LOCAL_VARS] += timeStep; + m_anLocalVariables[NUM_LOCAL_VARS + 1] += timeStep; + } + + void CollectParameters(uint32*, int16); + int32 CollectNextParameterWithoutIncreasingPC(uint32); + int32* GetPointerToScriptVariable(uint32*, int16); + void StoreParameters(uint32*, int16); + void Init(); + void RemoveScriptFromList(CRunningScript**); + void AddScriptToList(CRunningScript**); + void Process(); + int8 ProcessOneCommand(); + void DoDeatharrestCheck(); + int8 ProcessCommandsFrom0To99(int32); + int8 ProcessCommandsFrom100To199(int32); + int8 ProcessCommandsFrom200To299(int32); + int8 ProcessCommandsFrom300To399(int32); + int8 ProcessCommandsFrom400To499(int32); + int8 ProcessCommandsFrom500To599(int32); + int8 ProcessCommandsFrom600To699(int32); + int8 ProcessCommandsFrom700To799(int32); + int8 ProcessCommandsFrom800To899(int32); + int8 ProcessCommandsFrom900To999(int32); + int8 ProcessCommandsFrom1000To1099(int32); + int8 ProcessCommandsFrom1100To1199(int32); + void UpdateCompareFlag(bool); }; enum { @@ -133,13 +193,81 @@ public: bool HasCarBeenStuckForAWhile(int32); }; +enum { + ARGUMENT_END = 0, + ARGUMENT_INT32, + ARGUMENT_GLOBALVAR, + ARGUMENT_LOCALVAR, + ARGUMENT_INT8, + ARGUMENT_INT16, + ARGUMENT_FLOAT +}; + +struct tCollectiveData +{ + int32 index; + uint32 unk_data; +}; + +enum { + USED_OBJECT_NAME_LENGTH = 24 +}; + +struct tUsedObject +{ + char name[USED_OBJECT_NAME_LENGTH]; + int32 index; +}; + +struct tBuildingSwap +{ + CBuilding* m_pBuilding; + int32 m_nNewModel; + int32 m_nOldModel; +}; + + +enum { + VAR_LOCAL = 1, + VAR_GLOBAL = 2, +}; + +enum { + SIZE_MAIN_SCRIPT = 128 * 1024, + SIZE_MISSION_SCRIPT = 32 * 1024, + SIZE_SCRIPT_SPACE = SIZE_MAIN_SCRIPT + SIZE_MISSION_SCRIPT +}; + +enum { + MAX_NUM_SCRIPTS = 128, + MAX_NUM_CONTACTS = 16, + MAX_NUM_INTRO_TEXT_LINES = 2, + MAX_NUM_INTRO_RECTANGLES = 16, + MAX_NUM_SCRIPT_SRPITES = 16, + MAX_NUM_SCRIPT_SPHERES = 16, + MAX_NUM_COLLECTIVES = 32, + MAX_NUM_USED_OBJECTS = 200, + MAX_NUM_MISSION_SCRIPTS = 120, + MAX_NUM_BUILDING_SWAPS = 25, + MAX_NUM_INVISIBILITY_SETTINGS = 20 +}; + class CTheScripts { public: - static uint8(&ScriptSpace)[160 * 1024]; - static CTextLine(&IntroTextLines)[2]; - static CScriptRectangle(&IntroRectangles)[16]; - static CSprite2d(&ScriptSprites)[16]; + static uint8(&ScriptSpace)[SIZE_SCRIPT_SPACE]; + static CRunningScript(&ScriptsArray)[MAX_NUM_SCRIPTS]; + static int32(&BaseBriefIdForContact)[MAX_NUM_CONTACTS]; + static int32(&OnAMissionForContactFlag)[MAX_NUM_CONTACTS]; + static CTextLine(&IntroTextLines)[MAX_NUM_INTRO_TEXT_LINES]; + static CScriptRectangle(&IntroRectangles)[MAX_NUM_INTRO_RECTANGLES]; + static CSprite2d(&ScriptSprites)[MAX_NUM_SCRIPT_SRPITES]; + static CScriptSphere(&ScriptSphereArray)[MAX_NUM_SCRIPT_SPHERES]; + static tCollectiveData(&CollectiveArray)[MAX_NUM_COLLECTIVES]; + static tUsedObject(&UsedObjectArray)[MAX_NUM_USED_OBJECTS]; + static int32(&MultiScriptArray)[MAX_NUM_MISSION_SCRIPTS]; + static tBuildingSwap(&BuildingSwapArray)[MAX_NUM_BUILDING_SWAPS]; + static CEntity*(&InvisibilitySettingArray)[MAX_NUM_INVISIBILITY_SETTINGS]; static bool &DbgFlag; static uint32 &OnAMissionFlag; static CMissionCleanup &MissionCleanup; @@ -147,11 +275,67 @@ public: static CUpsideDownCarCheck &UpsideDownCars; static int32 &StoreVehicleIndex; static bool &StoreVehicleWasRandom; - + static CRunningScript *&pIdleScripts; + static CRunningScript *&pActiveScripts; + static uint32 &NextFreeCollectiveIndex; + static int32 &LastRandomPedId; + static uint16 &NumberOfUsedObjects; + static bool &bAlreadyRunningAMissionScript; + static bool &bUsingAMultiScriptFile; + static uint16 &NumberOfMissionScripts; + static uint32 &LargestMissionScriptSize; + static uint32 &MainScriptSize; + static uint8 &FailCurrentMission; + static uint8 &CountdownToMakePlayerUnsafe; + static uint8 &DelayMakingPlayerUnsafeThisTime; + static uint16 &NumScriptDebugLines; + static uint16 &NumberOfIntroRectanglesThisFrame; + static uint16 &NumberOfIntroTextLinesThisFrame; + static bool &UseTextCommands; + static uint16 &CommandsExecuted; + static uint16 &ScriptsUpdated; public: - static bool IsPlayerOnAMission(); static void ScriptDebugLine3D(float x1, float y1, float z1, float x2, float y2, float z2, int col, int col2); static void CleanUpThisVehicle(CVehicle*); static void CleanUpThisPed(CPed*); static void CleanUpThisObject(CObject*); + static void Init(); + static CRunningScript* StartNewScript(uint32); + static void Process(); + static CRunningScript* StartTestScript(); + static bool IsPlayerOnAMission(); + + static void ReadObjectNamesFromScript(); + static void UpdateObjectIndices(); + static void ReadMultiScriptFileOffsetsFromScript(); + static void DrawScriptSpheres(); + static void ClearSpaceForMissionEntity(const CVector&, CEntity*); + static void HighlightImportantArea(uint32, float, float, float, float, float); + static void DrawDebugSquare(float, float, float, float); + static void DrawDebugCube(float, float, float, float, float, float); + + static int32 Read4BytesFromScript(uint32* pIp){ + int32 retval = 0; + for (int i = 0; i < 4; i++){ + retval |= ScriptSpace[(*pIp)++] << (8 * i); + } + return retval; + } + static int16 Read2BytesFromScript(uint32* pIp){ + int16 retval = 0; + for (int i = 0; i < 2; i++){ + retval |= ScriptSpace[(*pIp)++] << (8 * i); + } + return retval; + } + static int8 Read1ByteFromScript(uint32* pIp){ + int8 retval = 0; + for (int i = 0; i < 1; i++){ + retval |= ScriptSpace[(*pIp)++] << (8 * i); + } + return retval; + } + static float ReadFloatFromScript(uint32* pIp){ + return Read2BytesFromScript(pIp) / 16.0f; + } }; diff --git a/src/control/ScriptCommands.h b/src/control/ScriptCommands.h new file mode 100644 index 00000000..55ac4439 --- /dev/null +++ b/src/control/ScriptCommands.h @@ -0,0 +1,1158 @@ +#pragma once + +enum { + COMMAND_NOP = 0, + COMMAND_WAIT, + COMMAND_GOTO, + COMMAND_SHAKE_CAM, + COMMAND_SET_VAR_INT, + COMMAND_SET_VAR_FLOAT, + COMMAND_SET_LVAR_INT, + COMMAND_SET_LVAR_FLOAT, + COMMAND_ADD_VAL_TO_INT_VAR, + COMMAND_ADD_VAL_TO_FLOAT_VAR, + COMMAND_ADD_VAL_TO_INT_LVAR, + COMMAND_ADD_VAL_TO_FLOAT_LVAR, + COMMAND_SUB_VAL_FROM_INT_VAR, + COMMAND_SUB_VAL_FROM_FLOAT_VAR, + COMMAND_SUB_VAL_FROM_INT_LVAR, + COMMAND_SUB_VAL_FROM_FLOAT_LVAR, + COMMAND_MULT_INT_VAR_BY_VAL, + COMMAND_MULT_FLOAT_VAR_BY_VAL, + COMMAND_MULT_INT_LVAR_BY_VAL, + COMMAND_MULT_FLOAT_LVAR_BY_VAL, + COMMAND_DIV_INT_VAR_BY_VAL, + COMMAND_DIV_FLOAT_VAR_BY_VAL, + COMMAND_DIV_INT_LVAR_BY_VAL, + COMMAND_DIV_FLOAT_LVAR_BY_VAL, + COMMAND_IS_INT_VAR_GREATER_THAN_NUMBER, + COMMAND_IS_INT_LVAR_GREATER_THAN_NUMBER, + COMMAND_IS_NUMBER_GREATER_THAN_INT_VAR, + COMMAND_IS_NUMBER_GREATER_THAN_INT_LVAR, + COMMAND_IS_INT_VAR_GREATER_THAN_INT_VAR, + COMMAND_IS_INT_LVAR_GREATER_THAN_INT_LVAR, + COMMAND_IS_INT_VAR_GREATER_THAN_INT_LVAR, + COMMAND_IS_INT_LVAR_GREATER_THAN_INT_VAR, + COMMAND_IS_FLOAT_VAR_GREATER_THAN_NUMBER, + COMMAND_IS_FLOAT_LVAR_GREATER_THAN_NUMBER, + COMMAND_IS_NUMBER_GREATER_THAN_FLOAT_VAR, + COMMAND_IS_NUMBER_GREATER_THAN_FLOAT_LVAR, + COMMAND_IS_FLOAT_VAR_GREATER_THAN_FLOAT_VAR, + COMMAND_IS_FLOAT_LVAR_GREATER_THAN_FLOAT_LVAR, + COMMAND_IS_FLOAT_VAR_GREATER_THAN_FLOAT_LVAR, + COMMAND_IS_FLOAT_LVAR_GREATER_THAN_FLOAT_VAR, + COMMAND_IS_INT_VAR_GREATER_OR_EQUAL_TO_NUMBER, + COMMAND_IS_INT_LVAR_GREATER_OR_EQUAL_TO_NUMBER, + COMMAND_IS_NUMBER_GREATER_OR_EQUAL_TO_INT_VAR, + COMMAND_IS_NUMBER_GREATER_OR_EQUAL_TO_INT_LVAR, + COMMAND_IS_INT_VAR_GREATER_OR_EQUAL_TO_INT_VAR, + COMMAND_IS_INT_LVAR_GREATER_OR_EQUAL_TO_INT_LVAR, + COMMAND_IS_INT_VAR_GREATER_OR_EQUAL_TO_INT_LVAR, + COMMAND_IS_INT_LVAR_GREATER_OR_EQUAL_TO_INT_VAR, + COMMAND_IS_FLOAT_VAR_GREATER_OR_EQUAL_TO_NUMBER, + COMMAND_IS_FLOAT_LVAR_GREATER_OR_EQUAL_TO_NUMBER, + COMMAND_IS_NUMBER_GREATER_OR_EQUAL_TO_FLOAT_VAR, + COMMAND_IS_NUMBER_GREATER_OR_EQUAL_TO_FLOAT_LVAR, + COMMAND_IS_FLOAT_VAR_GREATER_OR_EQUAL_TO_FLOAT_VAR, + COMMAND_IS_FLOAT_LVAR_GREATER_OR_EQUAL_TO_FLOAT_LVAR, + COMMAND_IS_FLOAT_VAR_GREATER_OR_EQUAL_TO_FLOAT_LVAR, + COMMAND_IS_FLOAT_LVAR_GREATER_OR_EQUAL_TO_FLOAT_VAR, + COMMAND_IS_INT_VAR_EQUAL_TO_NUMBER, + COMMAND_IS_INT_LVAR_EQUAL_TO_NUMBER, + COMMAND_IS_INT_VAR_EQUAL_TO_INT_VAR, + COMMAND_IS_INT_LVAR_EQUAL_TO_INT_LVAR, + COMMAND_IS_INT_VAR_EQUAL_TO_INT_LVAR, + COMMAND_IS_INT_VAR_NOT_EQUAL_TO_NUMBER, + COMMAND_IS_INT_LVAR_NOT_EQUAL_TO_NUMBER, + COMMAND_IS_INT_VAR_NOT_EQUAL_TO_INT_VAR, + COMMAND_IS_INT_LVAR_NOT_EQUAL_TO_INT_LVAR, + COMMAND_IS_INT_VAR_NOT_EQUAL_TO_INT_LVAR, + COMMAND_IS_FLOAT_VAR_EQUAL_TO_NUMBER, + COMMAND_IS_FLOAT_LVAR_EQUAL_TO_NUMBER, + COMMAND_IS_FLOAT_VAR_EQUAL_TO_FLOAT_VAR, + COMMAND_IS_FLOAT_LVAR_EQUAL_TO_FLOAT_LVAR, + COMMAND_IS_FLOAT_VAR_EQUAL_TO_FLOAT_LVAR, + COMMAND_IS_FLOAT_VAR_NOT_EQUAL_TO_NUMBER, + COMMAND_IS_FLOAT_LVAR_NOT_EQUAL_TO_NUMBER, + COMMAND_IS_FLOAT_VAR_NOT_EQUAL_TO_FLOAT_VAR, + COMMAND_IS_FLOAT_LVAR_NOT_EQUAL_TO_FLOAT_LVAR, + COMMAND_IS_FLOAT_VAR_NOT_EQUAL_TO_FLOAT_LVAR, + COMMAND_GOTO_IF_TRUE, + COMMAND_GOTO_IF_FALSE, + COMMAND_TERMINATE_THIS_SCRIPT, + COMMAND_START_NEW_SCRIPT, + COMMAND_GOSUB, + COMMAND_RETURN, + COMMAND_LINE, + COMMAND_CREATE_PLAYER, + COMMAND_GET_PLAYER_COORDINATES, + COMMAND_SET_PLAYER_COORDINATES, + COMMAND_IS_PLAYER_IN_AREA_2D, + COMMAND_IS_PLAYER_IN_AREA_3D, + COMMAND_ADD_INT_VAR_TO_INT_VAR, + COMMAND_ADD_FLOAT_VAR_TO_FLOAT_VAR, + COMMAND_ADD_INT_LVAR_TO_INT_LVAR, + COMMAND_ADD_FLOAT_LVAR_TO_FLOAT_LVAR, + COMMAND_ADD_INT_VAR_TO_INT_LVAR, + COMMAND_ADD_FLOAT_VAR_TO_FLOAT_LVAR, + COMMAND_ADD_INT_LVAR_TO_INT_VAR, + COMMAND_ADD_FLOAT_LVAR_TO_FLOAT_VAR, + COMMAND_SUB_INT_VAR_FROM_INT_VAR, + COMMAND_SUB_FLOAT_VAR_FROM_FLOAT_VAR, + COMMAND_SUB_INT_LVAR_FROM_INT_LVAR, + COMMAND_SUB_FLOAT_LVAR_FROM_FLOAT_LVAR, + COMMAND_SUB_INT_VAR_FROM_INT_LVAR, + COMMAND_SUB_FLOAT_VAR_FROM_FLOAT_LVAR, + COMMAND_SUB_INT_LVAR_FROM_INT_VAR, + COMMAND_SUB_FLOAT_LVAR_FROM_FLOAT_VAR, + COMMAND_MULT_INT_VAR_BY_INT_VAR, + COMMAND_MULT_FLOAT_VAR_BY_FLOAT_VAR, + COMMAND_MULT_INT_LVAR_BY_INT_LVAR, + COMMAND_MULT_FLOAT_LVAR_BY_FLOAT_LVAR, + COMMAND_MULT_INT_VAR_BY_INT_LVAR, + COMMAND_MULT_FLOAT_VAR_BY_FLOAT_LVAR, + COMMAND_MULT_INT_LVAR_BY_INT_VAR, + COMMAND_MULT_FLOAT_LVAR_BY_FLOAT_VAR, + COMMAND_DIV_INT_VAR_BY_INT_VAR, + COMMAND_DIV_FLOAT_VAR_BY_FLOAT_VAR, + COMMAND_DIV_INT_LVAR_BY_INT_LVAR, + COMMAND_DIV_FLOAT_LVAR_BY_FLOAT_LVAR, + COMMAND_DIV_INT_VAR_BY_INT_LVAR, + COMMAND_DIV_FLOAT_VAR_BY_FLOAT_LVAR, + COMMAND_DIV_INT_LVAR_BY_INT_VAR, + COMMAND_DIV_FLOAT_LVAR_BY_FLOAT_VAR, + COMMAND_ADD_TIMED_VAL_TO_FLOAT_VAR, + COMMAND_ADD_TIMED_VAL_TO_FLOAT_LVAR, + COMMAND_ADD_TIMED_FLOAT_VAR_TO_FLOAT_VAR, + COMMAND_ADD_TIMED_FLOAT_LVAR_TO_FLOAT_LVAR, + COMMAND_ADD_TIMED_FLOAT_LVAR_TO_FLOAT_VAR, + COMMAND_ADD_TIMED_FLOAT_VAR_TO_FLOAT_LVAR, + COMMAND_SUB_TIMED_VAL_FROM_FLOAT_VAR, + COMMAND_SUB_TIMED_VAL_FROM_FLOAT_LVAR, + COMMAND_SUB_TIMED_FLOAT_VAR_FROM_FLOAT_VAR, + COMMAND_SUB_TIMED_FLOAT_LVAR_FROM_FLOAT_LVAR, + COMMAND_SUB_TIMED_FLOAT_LVAR_FROM_FLOAT_VAR, + COMMAND_SUB_TIMED_FLOAT_VAR_FROM_FLOAT_LVAR, + COMMAND_SET_VAR_INT_TO_VAR_INT, + COMMAND_SET_LVAR_INT_TO_LVAR_INT, + COMMAND_SET_VAR_FLOAT_TO_VAR_FLOAT, + COMMAND_SET_LVAR_FLOAT_TO_LVAR_FLOAT, + COMMAND_SET_VAR_FLOAT_TO_LVAR_FLOAT, + COMMAND_SET_LVAR_FLOAT_TO_VAR_FLOAT, + COMMAND_SET_VAR_INT_TO_LVAR_INT, + COMMAND_SET_LVAR_INT_TO_VAR_INT, + COMMAND_CSET_VAR_INT_TO_VAR_FLOAT, + COMMAND_CSET_VAR_FLOAT_TO_VAR_INT, + COMMAND_CSET_LVAR_INT_TO_VAR_FLOAT, + COMMAND_CSET_LVAR_FLOAT_TO_VAR_INT, + COMMAND_CSET_VAR_INT_TO_LVAR_FLOAT, + COMMAND_CSET_VAR_FLOAT_TO_LVAR_INT, + COMMAND_CSET_LVAR_INT_TO_LVAR_FLOAT, + COMMAND_CSET_LVAR_FLOAT_TO_LVAR_INT, + COMMAND_ABS_VAR_INT, + COMMAND_ABS_LVAR_INT, + COMMAND_ABS_VAR_FLOAT, + COMMAND_ABS_LVAR_FLOAT, + COMMAND_GENERATE_RANDOM_FLOAT, + COMMAND_GENERATE_RANDOM_INT, + COMMAND_CREATE_CHAR, + COMMAND_DELETE_CHAR, + COMMAND_CHAR_WANDER_DIR, + COMMAND_CHAR_WANDER_RANGE, + COMMAND_CHAR_FOLLOW_PATH, + COMMAND_CHAR_SET_IDLE, + COMMAND_GET_CHAR_COORDINATES, + COMMAND_SET_CHAR_COORDINATES, + COMMAND_IS_CHAR_STILL_ALIVE, + COMMAND_IS_CHAR_IN_AREA_2D, + COMMAND_IS_CHAR_IN_AREA_3D, + COMMAND_CREATE_CAR, + COMMAND_DELETE_CAR, + COMMAND_CAR_GOTO_COORDINATES, + COMMAND_CAR_WANDER_RANDOMLY, + COMMAND_CAR_SET_IDLE, + COMMAND_GET_CAR_COORDINATES, + COMMAND_SET_CAR_COORDINATES, + COMMAND_IS_CAR_STILL_ALIVE, + COMMAND_SET_CAR_CRUISE_SPEED, + COMMAND_SET_CAR_DRIVING_STYLE, + COMMAND_SET_CAR_MISSION, + COMMAND_IS_CAR_IN_AREA_2D, + COMMAND_IS_CAR_IN_AREA_3D, + COMMAND_SPECIAL_0, + COMMAND_SPECIAL_1, + COMMAND_SPECIAL_2, + COMMAND_SPECIAL_3, + COMMAND_SPECIAL_4, + COMMAND_SPECIAL_5, + COMMAND_SPECIAL_6, + COMMAND_SPECIAL_7, + COMMAND_PRINT_BIG, + COMMAND_PRINT, + COMMAND_PRINT_NOW, + COMMAND_PRINT_SOON, + COMMAND_CLEAR_PRINTS, + COMMAND_GET_TIME_OF_DAY, + COMMAND_SET_TIME_OF_DAY, + COMMAND_GET_MINUTES_TO_TIME_OF_DAY, + COMMAND_IS_POINT_ON_SCREEN, + COMMAND_DEBUG_ON, + COMMAND_DEBUG_OFF, + COMMAND_RETURN_TRUE, + COMMAND_RETURN_FALSE, + COMMAND_VAR_INT, + COMMAND_VAR_FLOAT, + COMMAND_LVAR_INT, + COMMAND_LVAR_FLOAT, + COMMAND_LBRACKET, + COMMAND_RBRACKET, + COMMAND_REPEAT, + COMMAND_ENDREPEAT, + COMMAND_IF_, + COMMAND_IFNOT, + COMMAND_ELSE, + COMMAND_ENDIF, + COMMAND_WHILE, + COMMAND_WHILENOT, + COMMAND_ENDWHILE, + COMMAND_ANDOR, + COMMAND_LAUNCH_MISSION, + COMMAND_MISSION_HAS_FINISHED, + COMMAND_STORE_CAR_CHAR_IS_IN, + COMMAND_STORE_CAR_PLAYER_IS_IN, + COMMAND_IS_CHAR_IN_CAR, + COMMAND_IS_PLAYER_IN_CAR, + COMMAND_IS_CHAR_IN_MODEL, + COMMAND_IS_PLAYER_IN_MODEL, + COMMAND_IS_CHAR_IN_ANY_CAR, + COMMAND_IS_PLAYER_IN_ANY_CAR, + COMMAND_IS_BUTTON_PRESSED, + COMMAND_GET_PAD_STATE, + COMMAND_LOCATE_PLAYER_ANY_MEANS_2D, + COMMAND_LOCATE_PLAYER_ON_FOOT_2D, + COMMAND_LOCATE_PLAYER_IN_CAR_2D, + COMMAND_LOCATE_STOPPED_PLAYER_ANY_MEANS_2D, + COMMAND_LOCATE_STOPPED_PLAYER_ON_FOOT_2D, + COMMAND_LOCATE_STOPPED_PLAYER_IN_CAR_2D, + COMMAND_LOCATE_PLAYER_ANY_MEANS_CHAR_2D, + COMMAND_LOCATE_PLAYER_ON_FOOT_CHAR_2D, + COMMAND_LOCATE_PLAYER_IN_CAR_CHAR_2D, + COMMAND_LOCATE_CHAR_ANY_MEANS_2D, + COMMAND_LOCATE_CHAR_ON_FOOT_2D, + COMMAND_LOCATE_CHAR_IN_CAR_2D, + COMMAND_LOCATE_STOPPED_CHAR_ANY_MEANS_2D, + COMMAND_LOCATE_STOPPED_CHAR_ON_FOOT_2D, + COMMAND_LOCATE_STOPPED_CHAR_IN_CAR_2D, + COMMAND_LOCATE_CHAR_ANY_MEANS_CHAR_2D, + COMMAND_LOCATE_CHAR_ON_FOOT_CHAR_2D, + COMMAND_LOCATE_CHAR_IN_CAR_CHAR_2D, + COMMAND_LOCATE_PLAYER_ANY_MEANS_3D, + COMMAND_LOCATE_PLAYER_ON_FOOT_3D, + COMMAND_LOCATE_PLAYER_IN_CAR_3D, + COMMAND_LOCATE_STOPPED_PLAYER_ANY_MEANS_3D, + COMMAND_LOCATE_STOPPED_PLAYER_ON_FOOT_3D, + COMMAND_LOCATE_STOPPED_PLAYER_IN_CAR_3D, + COMMAND_LOCATE_PLAYER_ANY_MEANS_CHAR_3D, + COMMAND_LOCATE_PLAYER_ON_FOOT_CHAR_3D, + COMMAND_LOCATE_PLAYER_IN_CAR_CHAR_3D, + COMMAND_LOCATE_CHAR_ANY_MEANS_3D, + COMMAND_LOCATE_CHAR_ON_FOOT_3D, + COMMAND_LOCATE_CHAR_IN_CAR_3D, + COMMAND_LOCATE_STOPPED_CHAR_ANY_MEANS_3D, + COMMAND_LOCATE_STOPPED_CHAR_ON_FOOT_3D, + COMMAND_LOCATE_STOPPED_CHAR_IN_CAR_3D, + COMMAND_LOCATE_CHAR_ANY_MEANS_CHAR_3D, + COMMAND_LOCATE_CHAR_ON_FOOT_CHAR_3D, + COMMAND_LOCATE_CHAR_IN_CAR_CHAR_3D, + COMMAND_CREATE_OBJECT, + COMMAND_DELETE_OBJECT, + COMMAND_ADD_SCORE, + COMMAND_IS_SCORE_GREATER, + COMMAND_STORE_SCORE, + COMMAND_GIVE_REMOTE_CONTROLLED_CAR_TO_PLAYER, + COMMAND_ALTER_WANTED_LEVEL, + COMMAND_ALTER_WANTED_LEVEL_NO_DROP, + COMMAND_IS_WANTED_LEVEL_GREATER, + COMMAND_CLEAR_WANTED_LEVEL, + COMMAND_SET_DEATHARREST_STATE, + COMMAND_HAS_DEATHARREST_BEEN_EXECUTED, + COMMAND_ADD_AMMO_TO_PLAYER, + COMMAND_ADD_AMMO_TO_CHAR, + COMMAND_ADD_AMMO_TO_CAR, + COMMAND_IS_PLAYER_STILL_ALIVE, + COMMAND_IS_PLAYER_DEAD, + COMMAND_IS_CHAR_DEAD, + COMMAND_IS_CAR_DEAD, + COMMAND_SET_CHAR_THREAT_SEARCH, + COMMAND_SET_CHAR_THREAT_REACTION, + COMMAND_SET_CHAR_OBJ_NO_OBJ, + COMMAND_ORDER_DRIVER_OUT_OF_CAR, + COMMAND_ORDER_CHAR_TO_DRIVE_CAR, + COMMAND_ADD_PATROL_POINT, + COMMAND_IS_PLAYER_IN_GANGZONE, + COMMAND_IS_PLAYER_IN_ZONE, + COMMAND_IS_PLAYER_PRESSING_HORN, + COMMAND_HAS_CHAR_SPOTTED_PLAYER, + COMMAND_ORDER_CHAR_TO_BACKDOOR, + COMMAND_ADD_CHAR_TO_GANG, + COMMAND_IS_CHAR_OBJECTIVE_PASSED, + COMMAND_SET_CHAR_DRIVE_AGGRESSION, + COMMAND_SET_CHAR_MAX_DRIVESPEED, + COMMAND_CREATE_CHAR_INSIDE_CAR, + COMMAND_WARP_PLAYER_FROM_CAR_TO_COORD, + COMMAND_MAKE_CHAR_DO_NOTHING, + COMMAND_SET_CHAR_INVINCIBLE, + COMMAND_SET_PLAYER_INVINCIBLE, + COMMAND_SET_CHAR_GRAPHIC_TYPE, + COMMAND_SET_PLAYER_GRAPHIC_TYPE, + COMMAND_HAS_PLAYER_BEEN_ARRESTED, + COMMAND_STOP_CHAR_DRIVING, + COMMAND_KILL_CHAR, + COMMAND_SET_FAVOURITE_CAR_MODEL_FOR_CHAR, + COMMAND_SET_CHAR_OCCUPATION, + COMMAND_CHANGE_CAR_LOCK, + COMMAND_SHAKE_CAM_WITH_POINT, + COMMAND_IS_CAR_MODEL, + COMMAND_IS_CAR_REMAP, + COMMAND_HAS_CAR_JUST_SUNK, + COMMAND_SET_CAR_NO_COLLIDE, + COMMAND_IS_CAR_DEAD_IN_AREA_2D, + COMMAND_IS_CAR_DEAD_IN_AREA_3D, + COMMAND_IS_TRAILER_ATTACHED, + COMMAND_IS_CAR_ON_TRAILER, + COMMAND_HAS_CAR_GOT_WEAPON, + COMMAND_PARK, + COMMAND_HAS_PARK_FINISHED, + COMMAND_KILL_ALL_PASSENGERS, + COMMAND_SET_CAR_BULLETPROOF, + COMMAND_SET_CAR_FLAMEPROOF, + COMMAND_SET_CAR_ROCKETPROOF, + COMMAND_IS_CARBOMB_ACTIVE, + COMMAND_GIVE_CAR_ALARM, + COMMAND_PUT_CAR_ON_TRAILER, + COMMAND_IS_CAR_CRUSHED, + COMMAND_CREATE_GANG_CAR, + COMMAND_CREATE_CAR_GENERATOR, + COMMAND_SWITCH_CAR_GENERATOR, + COMMAND_ADD_PAGER_MESSAGE, + COMMAND_DISPLAY_ONSCREEN_TIMER, + COMMAND_CLEAR_ONSCREEN_TIMER, + COMMAND_DISPLAY_ONSCREEN_COUNTER, + COMMAND_CLEAR_ONSCREEN_COUNTER, + COMMAND_SET_ZONE_CAR_INFO, + COMMAND_IS_CHAR_IN_GANG_ZONE, + COMMAND_IS_CHAR_IN_ZONE, + COMMAND_SET_CAR_DENSITY, + COMMAND_SET_PED_DENSITY, + COMMAND_POINT_CAMERA_AT_PLAYER, + COMMAND_POINT_CAMERA_AT_CAR, + COMMAND_POINT_CAMERA_AT_CHAR, + COMMAND_RESTORE_CAMERA, + COMMAND_SHAKE_PAD, + COMMAND_SET_ZONE_PED_INFO, + COMMAND_SET_TIME_SCALE, + COMMAND_IS_CAR_IN_AIR, + COMMAND_SET_FIXED_CAMERA_POSITION, + COMMAND_POINT_CAMERA_AT_POINT, + COMMAND_ADD_BLIP_FOR_CAR_OLD, + COMMAND_ADD_BLIP_FOR_CHAR_OLD, + COMMAND_ADD_BLIP_FOR_OBJECT_OLD, + COMMAND_REMOVE_BLIP, + COMMAND_CHANGE_BLIP_COLOUR, + COMMAND_DIM_BLIP, + COMMAND_ADD_BLIP_FOR_COORD_OLD, + COMMAND_CHANGE_BLIP_SCALE, + COMMAND_SET_FADING_COLOUR, + COMMAND_DO_FADE, + COMMAND_GET_FADING_STATUS, + COMMAND_ADD_HOSPITAL_RESTART, + COMMAND_ADD_POLICE_RESTART, + COMMAND_OVERRIDE_NEXT_RESTART, + COMMAND_DRAW_SHADOW, + COMMAND_GET_PLAYER_HEADING, + COMMAND_SET_PLAYER_HEADING, + COMMAND_GET_CHAR_HEADING, + COMMAND_SET_CHAR_HEADING, + COMMAND_GET_CAR_HEADING, + COMMAND_SET_CAR_HEADING, + COMMAND_GET_OBJECT_HEADING, + COMMAND_SET_OBJECT_HEADING, + COMMAND_IS_PLAYER_TOUCHING_OBJECT, + COMMAND_IS_CHAR_TOUCHING_OBJECT, + COMMAND_SET_PLAYER_AMMO, + COMMAND_SET_CHAR_AMMO, + COMMAND_SET_CAR_AMMO, + COMMAND_LOAD_CAMERA_SPLINE, + COMMAND_MOVE_CAMERA_ALONG_SPLINE, + COMMAND_GET_CAMERA_POSITION_ALONG_SPLINE, + COMMAND_DECLARE_MISSION_FLAG, + COMMAND_DECLARE_MISSION_FLAG_FOR_CONTACT, + COMMAND_DECLARE_BASE_BRIEF_ID_FOR_CONTACT, + COMMAND_IS_PLAYER_HEALTH_GREATER, + COMMAND_IS_CHAR_HEALTH_GREATER, + COMMAND_IS_CAR_HEALTH_GREATER, + COMMAND_ADD_BLIP_FOR_CAR, + COMMAND_ADD_BLIP_FOR_CHAR, + COMMAND_ADD_BLIP_FOR_OBJECT, + COMMAND_ADD_BLIP_FOR_CONTACT_POINT, + COMMAND_ADD_BLIP_FOR_COORD, + COMMAND_CHANGE_BLIP_DISPLAY, + COMMAND_ADD_ONE_OFF_SOUND, + COMMAND_ADD_CONTINUOUS_SOUND, + COMMAND_REMOVE_SOUND, + COMMAND_IS_CAR_STUCK_ON_ROOF, + COMMAND_ADD_UPSIDEDOWN_CAR_CHECK, + COMMAND_REMOVE_UPSIDEDOWN_CAR_CHECK, + COMMAND_SET_CHAR_OBJ_WAIT_ON_FOOT, + COMMAND_SET_CHAR_OBJ_FLEE_ON_FOOT_TILL_SAFE, + COMMAND_SET_CHAR_OBJ_GUARD_SPOT, + COMMAND_SET_CHAR_OBJ_GUARD_AREA, + COMMAND_SET_CHAR_OBJ_WAIT_IN_CAR, + COMMAND_IS_PLAYER_IN_AREA_ON_FOOT_2D, + COMMAND_IS_PLAYER_IN_AREA_IN_CAR_2D, + COMMAND_IS_PLAYER_STOPPED_IN_AREA_2D, + COMMAND_IS_PLAYER_STOPPED_IN_AREA_ON_FOOT_2D, + COMMAND_IS_PLAYER_STOPPED_IN_AREA_IN_CAR_2D, + COMMAND_IS_PLAYER_IN_AREA_ON_FOOT_3D, + COMMAND_IS_PLAYER_IN_AREA_IN_CAR_3D, + COMMAND_IS_PLAYER_STOPPED_IN_AREA_3D, + COMMAND_IS_PLAYER_STOPPED_IN_AREA_ON_FOOT_3D, + COMMAND_IS_PLAYER_STOPPED_IN_AREA_IN_CAR_3D, + COMMAND_IS_CHAR_IN_AREA_ON_FOOT_2D, + COMMAND_IS_CHAR_IN_AREA_IN_CAR_2D, + COMMAND_IS_CHAR_STOPPED_IN_AREA_2D, + COMMAND_IS_CHAR_STOPPED_IN_AREA_ON_FOOT_2D, + COMMAND_IS_CHAR_STOPPED_IN_AREA_IN_CAR_2D, + COMMAND_IS_CHAR_IN_AREA_ON_FOOT_3D, + COMMAND_IS_CHAR_IN_AREA_IN_CAR_3D, + COMMAND_IS_CHAR_STOPPED_IN_AREA_3D, + COMMAND_IS_CHAR_STOPPED_IN_AREA_ON_FOOT_3D, + COMMAND_IS_CHAR_STOPPED_IN_AREA_IN_CAR_3D, + COMMAND_IS_CAR_STOPPED_IN_AREA_2D, + COMMAND_IS_CAR_STOPPED_IN_AREA_3D, + COMMAND_LOCATE_CAR_2D, + COMMAND_LOCATE_STOPPED_CAR_2D, + COMMAND_LOCATE_CAR_3D, + COMMAND_LOCATE_STOPPED_CAR_3D, + COMMAND_GIVE_WEAPON_TO_PLAYER, + COMMAND_GIVE_WEAPON_TO_CHAR, + COMMAND_GIVE_WEAPON_TO_CAR, + COMMAND_SET_PLAYER_CONTROL, + COMMAND_FORCE_WEATHER, + COMMAND_FORCE_WEATHER_NOW, + COMMAND_RELEASE_WEATHER, + COMMAND_SET_CURRENT_PLAYER_WEAPON, + COMMAND_SET_CURRENT_CHAR_WEAPON, + COMMAND_SET_CURRENT_CAR_WEAPON, + COMMAND_GET_OBJECT_COORDINATES, + COMMAND_SET_OBJECT_COORDINATES, + COMMAND_GET_GAME_TIMER, + COMMAND_TURN_CHAR_TO_FACE_COORD, + COMMAND_TURN_PLAYER_TO_FACE_COORD, + COMMAND_STORE_WANTED_LEVEL, + COMMAND_IS_CAR_STOPPED, + COMMAND_MARK_CHAR_AS_NO_LONGER_NEEDED, + COMMAND_MARK_CAR_AS_NO_LONGER_NEEDED, + COMMAND_MARK_OBJECT_AS_NO_LONGER_NEEDED, + COMMAND_DONT_REMOVE_CHAR, + COMMAND_DONT_REMOVE_CAR, + COMMAND_DONT_REMOVE_OBJECT, + COMMAND_CREATE_CHAR_AS_PASSENGER, + COMMAND_SET_CHAR_OBJ_KILL_CHAR_ON_FOOT, + COMMAND_SET_CHAR_OBJ_KILL_PLAYER_ON_FOOT, + COMMAND_SET_CHAR_OBJ_KILL_CHAR_ANY_MEANS, + COMMAND_SET_CHAR_OBJ_KILL_PLAYER_ANY_MEANS, + COMMAND_SET_CHAR_OBJ_FLEE_CHAR_ON_FOOT_TILL_SAFE, + COMMAND_SET_CHAR_OBJ_FLEE_PLAYER_ON_FOOT_TILL_SAFE, + COMMAND_SET_CHAR_OBJ_FLEE_CHAR_ON_FOOT_ALWAYS, + COMMAND_SET_CHAR_OBJ_FLEE_PLAYER_ON_FOOT_ALWAYS, + COMMAND_SET_CHAR_OBJ_GOTO_CHAR_ON_FOOT, + COMMAND_SET_CHAR_OBJ_GOTO_PLAYER_ON_FOOT, + COMMAND_SET_CHAR_OBJ_LEAVE_CAR, + COMMAND_SET_CHAR_OBJ_ENTER_CAR_AS_PASSENGER, + COMMAND_SET_CHAR_OBJ_ENTER_CAR_AS_DRIVER, + COMMAND_SET_CHAR_OBJ_FOLLOW_CAR_IN_CAR, + COMMAND_SET_CHAR_OBJ_FIRE_AT_OBJECT_FROM_VEHICLE, + COMMAND_SET_CHAR_OBJ_DESTROY_OBJECT, + COMMAND_SET_CHAR_OBJ_DESTROY_CAR, + COMMAND_SET_CHAR_OBJ_GOTO_AREA_ON_FOOT, + COMMAND_SET_CHAR_OBJ_GOTO_AREA_IN_CAR, + COMMAND_SET_CHAR_OBJ_FOLLOW_CAR_ON_FOOT_WITH_OFFSET, + COMMAND_SET_CHAR_OBJ_GUARD_ATTACK, + COMMAND_SET_CHAR_AS_LEADER, + COMMAND_SET_PLAYER_AS_LEADER, + COMMAND_LEAVE_GROUP, + COMMAND_SET_CHAR_OBJ_FOLLOW_ROUTE, + COMMAND_ADD_ROUTE_POINT, + COMMAND_PRINT_WITH_NUMBER_BIG, + COMMAND_PRINT_WITH_NUMBER, + COMMAND_PRINT_WITH_NUMBER_NOW, + COMMAND_PRINT_WITH_NUMBER_SOON, + COMMAND_SWITCH_ROADS_ON, + COMMAND_SWITCH_ROADS_OFF, + COMMAND_GET_NUMBER_OF_PASSENGERS, + COMMAND_GET_MAXIMUM_NUMBER_OF_PASSENGERS, + COMMAND_SET_CAR_DENSITY_MULTIPLIER, + COMMAND_SET_CAR_HEAVY, + COMMAND_CLEAR_CHAR_THREAT_SEARCH, + COMMAND_ACTIVATE_CRANE, + COMMAND_DEACTIVATE_CRANE, + COMMAND_SET_MAX_WANTED_LEVEL, + COMMAND_SAVE_VAR_INT, + COMMAND_SAVE_VAR_FLOAT, + COMMAND_IS_CAR_IN_AIR_PROPER, + COMMAND_IS_CAR_UPSIDEDOWN, + COMMAND_GET_PLAYER_CHAR, + COMMAND_CANCEL_OVERRIDE_RESTART, + COMMAND_SET_POLICE_IGNORE_PLAYER, + COMMAND_ADD_PAGER_MESSAGE_WITH_NUMBER, + COMMAND_START_KILL_FRENZY, + COMMAND_READ_KILL_FRENZY_STATUS, + COMMAND_SQRT, + COMMAND_LOCATE_PLAYER_ANY_MEANS_CAR_2D, + COMMAND_LOCATE_PLAYER_ON_FOOT_CAR_2D, + COMMAND_LOCATE_PLAYER_IN_CAR_CAR_2D, + COMMAND_LOCATE_PLAYER_ANY_MEANS_CAR_3D, + COMMAND_LOCATE_PLAYER_ON_FOOT_CAR_3D, + COMMAND_LOCATE_PLAYER_IN_CAR_CAR_3D, + COMMAND_LOCATE_CHAR_ANY_MEANS_CAR_2D, + COMMAND_LOCATE_CHAR_ON_FOOT_CAR_2D, + COMMAND_LOCATE_CHAR_IN_CAR_CAR_2D, + COMMAND_LOCATE_CHAR_ANY_MEANS_CAR_3D, + COMMAND_LOCATE_CHAR_ON_FOOT_CAR_3D, + COMMAND_LOCATE_CHAR_IN_CAR_CAR_3D, + COMMAND_GENERATE_RANDOM_FLOAT_IN_RANGE, + COMMAND_GENERATE_RANDOM_INT_IN_RANGE, + COMMAND_LOCK_CAR_DOORS, + COMMAND_EXPLODE_CAR, + COMMAND_ADD_EXPLOSION, + COMMAND_IS_CAR_UPRIGHT, + COMMAND_TURN_CHAR_TO_FACE_CHAR, + COMMAND_TURN_CHAR_TO_FACE_PLAYER, + COMMAND_TURN_PLAYER_TO_FACE_CHAR, + COMMAND_SET_CHAR_OBJ_GOTO_COORD_ON_FOOT, + COMMAND_SET_CHAR_OBJ_GOTO_COORD_IN_CAR, + COMMAND_CREATE_PICKUP, + COMMAND_HAS_PICKUP_BEEN_COLLECTED, + COMMAND_REMOVE_PICKUP, + COMMAND_SET_TAXI_LIGHTS, + COMMAND_PRINT_BIG_Q, + COMMAND_PRINT_WITH_NUMBER_BIG_Q, + COMMAND_SET_GARAGE, + COMMAND_SET_GARAGE_WITH_CAR_MODEL, + COMMAND_SET_TARGET_CAR_FOR_MISSION_GARAGE, + COMMAND_IS_CAR_IN_MISSION_GARAGE, + COMMAND_SET_FREE_BOMBS, + COMMAND_SET_POWERPOINT, + COMMAND_SET_ALL_TAXI_LIGHTS, + COMMAND_IS_CAR_ARMED_WITH_ANY_BOMB, + COMMAND_APPLY_BRAKES_TO_PLAYERS_CAR, + COMMAND_SET_PLAYER_HEALTH, + COMMAND_SET_CHAR_HEALTH, + COMMAND_SET_CAR_HEALTH, + COMMAND_GET_PLAYER_HEALTH, + COMMAND_GET_CHAR_HEALTH, + COMMAND_GET_CAR_HEALTH, + COMMAND_IS_CAR_ARMED_WITH_BOMB, + COMMAND_CHANGE_CAR_COLOUR, + COMMAND_SWITCH_PED_ROADS_ON, + COMMAND_SWITCH_PED_ROADS_OFF, + COMMAND_CHAR_LOOK_AT_CHAR_ALWAYS, + COMMAND_CHAR_LOOK_AT_PLAYER_ALWAYS, + COMMAND_PLAYER_LOOK_AT_CHAR_ALWAYS, + COMMAND_STOP_CHAR_LOOKING, + COMMAND_STOP_PLAYER_LOOKING, + COMMAND_SWITCH_HELICOPTER, + COMMAND_SET_GANG_ATTITUDE, + COMMAND_SET_GANG_GANG_ATTITUDE, + COMMAND_SET_GANG_PLAYER_ATTITUDE, + COMMAND_SET_GANG_PED_MODELS, + COMMAND_SET_GANG_CAR_MODEL, + COMMAND_SET_GANG_WEAPONS, + COMMAND_SET_CHAR_OBJ_RUN_TO_AREA, + COMMAND_SET_CHAR_OBJ_RUN_TO_COORD, + COMMAND_IS_PLAYER_TOUCHING_OBJECT_ON_FOOT, + COMMAND_IS_CHAR_TOUCHING_OBJECT_ON_FOOT, + COMMAND_LOAD_SPECIAL_CHARACTER, + COMMAND_HAS_SPECIAL_CHARACTER_LOADED, + COMMAND_FLASH_CAR, + COMMAND_FLASH_CHAR, + COMMAND_FLASH_OBJECT, + COMMAND_IS_PLAYER_IN_REMOTE_MODE, + COMMAND_ARM_CAR_WITH_BOMB, + COMMAND_SET_CHAR_PERSONALITY, + COMMAND_SET_CUTSCENE_OFFSET, + COMMAND_SET_ANIM_GROUP_FOR_CHAR, + COMMAND_SET_ANIM_GROUP_FOR_PLAYER, + COMMAND_REQUEST_MODEL, + COMMAND_HAS_MODEL_LOADED, + COMMAND_MARK_MODEL_AS_NO_LONGER_NEEDED, + COMMAND_GRAB_PHONE, + COMMAND_SET_REPEATED_PHONE_MESSAGE, + COMMAND_SET_PHONE_MESSAGE, + COMMAND_HAS_PHONE_DISPLAYED_MESSAGE, + COMMAND_TURN_PHONE_OFF, + COMMAND_DRAW_CORONA, + COMMAND_DRAW_LIGHT, + COMMAND_STORE_WEATHER, + COMMAND_RESTORE_WEATHER, + COMMAND_STORE_CLOCK, + COMMAND_RESTORE_CLOCK, + COMMAND_RESTART_CRITICAL_MISSION, + COMMAND_IS_PLAYER_PLAYING, + COMMAND_SET_COLL_OBJ_NO_OBJ, + COMMAND_SET_COLL_OBJ_WAIT_ON_FOOT, + COMMAND_SET_COLL_OBJ_FLEE_ON_FOOT_TILL_SAFE, + COMMAND_SET_COLL_OBJ_GUARD_SPOT, + COMMAND_SET_COLL_OBJ_GUARD_AREA, + COMMAND_SET_COLL_OBJ_WAIT_IN_CAR, + COMMAND_SET_COLL_OBJ_KILL_CHAR_ON_FOOT, + COMMAND_SET_COLL_OBJ_KILL_PLAYER_ON_FOOT, + COMMAND_SET_COLL_OBJ_KILL_CHAR_ANY_MEANS, + COMMAND_SET_COLL_OBJ_KILL_PLAYER_ANY_MEANS, + COMMAND_SET_COLL_OBJ_FLEE_CHAR_ON_FOOT_TILL_SAFE, + COMMAND_SET_COLL_OBJ_FLEE_PLAYER_ON_FOOT_TILL_SAFE, + COMMAND_SET_COLL_OBJ_FLEE_CHAR_ON_FOOT_ALWAYS, + COMMAND_SET_COLL_OBJ_FLEE_PLAYER_ON_FOOT_ALWAYS, + COMMAND_SET_COLL_OBJ_GOTO_CHAR_ON_FOOT, + COMMAND_SET_COLL_OBJ_GOTO_PLAYER_ON_FOOT, + COMMAND_SET_COLL_OBJ_LEAVE_CAR, + COMMAND_SET_COLL_OBJ_ENTER_CAR_AS_PASSENGER, + COMMAND_SET_COLL_OBJ_ENTER_CAR_AS_DRIVER, + COMMAND_SET_COLL_OBJ_FOLLOW_CAR_IN_CAR, + COMMAND_SET_COLL_OBJ_FIRE_AT_OBJECT_FROM_VEHICLE, + COMMAND_SET_COLL_OBJ_DESTROY_OBJECT, + COMMAND_SET_COLL_OBJ_DESTROY_CAR, + COMMAND_SET_COLL_OBJ_GOTO_AREA_ON_FOOT, + COMMAND_SET_COLL_OBJ_GOTO_AREA_IN_CAR, + COMMAND_SET_COLL_OBJ_FOLLOW_CAR_ON_FOOT_WITH_OFFSET, + COMMAND_SET_COLL_OBJ_GUARD_ATTACK, + COMMAND_SET_COLL_OBJ_FOLLOW_ROUTE, + COMMAND_SET_COLL_OBJ_GOTO_COORD_ON_FOOT, + COMMAND_SET_COLL_OBJ_GOTO_COORD_IN_CAR, + COMMAND_SET_COLL_OBJ_RUN_TO_AREA, + COMMAND_SET_COLL_OBJ_RUN_TO_COORD, + COMMAND_ADD_PEDS_IN_AREA_TO_COLL, + COMMAND_ADD_PEDS_IN_VEHICLE_TO_COLL, + COMMAND_CLEAR_COLL, + COMMAND_IS_COLL_IN_CARS, + COMMAND_LOCATE_COLL_ANY_MEANS_2D, + COMMAND_LOCATE_COLL_ON_FOOT_2D, + COMMAND_LOCATE_COLL_IN_CAR_2D, + COMMAND_LOCATE_STOPPED_COLL_ANY_MEANS_2D, + COMMAND_LOCATE_STOPPED_COLL_ON_FOOT_2D, + COMMAND_LOCATE_STOPPED_COLL_IN_CAR_2D, + COMMAND_LOCATE_COLL_ANY_MEANS_CHAR_2D, + COMMAND_LOCATE_COLL_ON_FOOT_CHAR_2D, + COMMAND_LOCATE_COLL_IN_CAR_CHAR_2D, + COMMAND_LOCATE_COLL_ANY_MEANS_CAR_2D, + COMMAND_LOCATE_COLL_ON_FOOT_CAR_2D, + COMMAND_LOCATE_COLL_IN_CAR_CAR_2D, + COMMAND_LOCATE_COLL_ANY_MEANS_PLAYER_2D, + COMMAND_LOCATE_COLL_ON_FOOT_PLAYER_2D, + COMMAND_LOCATE_COLL_IN_CAR_PLAYER_2D, + COMMAND_IS_COLL_IN_AREA_2D, + COMMAND_IS_COLL_IN_AREA_ON_FOOT_2D, + COMMAND_IS_COLL_IN_AREA_IN_CAR_2D, + COMMAND_IS_COLL_STOPPED_IN_AREA_2D, + COMMAND_IS_COLL_STOPPED_IN_AREA_ON_FOOT_2D, + COMMAND_IS_COLL_STOPPED_IN_AREA_IN_CAR_2D, + COMMAND_GET_NUMBER_OF_PEDS_IN_COLL, + COMMAND_SET_CHAR_HEED_THREATS, + COMMAND_SET_PLAYER_HEED_THREATS, + COMMAND_GET_CONTROLLER_MODE, + COMMAND_SET_CAN_RESPRAY_CAR, + COMMAND_IS_TAXI, + COMMAND_UNLOAD_SPECIAL_CHARACTER, + COMMAND_RESET_NUM_OF_MODELS_KILLED_BY_PLAYER, + COMMAND_GET_NUM_OF_MODELS_KILLED_BY_PLAYER, + COMMAND_ACTIVATE_GARAGE, + COMMAND_SWITCH_TAXI_TIMER, + COMMAND_CREATE_OBJECT_NO_OFFSET, + COMMAND_IS_BOAT, + COMMAND_SET_CHAR_OBJ_GOTO_AREA_ANY_MEANS, + COMMAND_SET_COLL_OBJ_GOTO_AREA_ANY_MEANS, + COMMAND_IS_PLAYER_STOPPED, + COMMAND_IS_CHAR_STOPPED, + COMMAND_MESSAGE_WAIT, + COMMAND_ADD_PARTICLE_EFFECT, + COMMAND_SWITCH_WIDESCREEN, + COMMAND_ADD_SPRITE_BLIP_FOR_CAR, + COMMAND_ADD_SPRITE_BLIP_FOR_CHAR, + COMMAND_ADD_SPRITE_BLIP_FOR_OBJECT, + COMMAND_ADD_SPRITE_BLIP_FOR_CONTACT_POINT, + COMMAND_ADD_SPRITE_BLIP_FOR_COORD, + COMMAND_SET_CHAR_ONLY_DAMAGED_BY_PLAYER, + COMMAND_SET_CAR_ONLY_DAMAGED_BY_PLAYER, + COMMAND_SET_CHAR_PROOFS, + COMMAND_SET_CAR_PROOFS, + COMMAND_IS_PLAYER_IN_ANGLED_AREA_2D, + COMMAND_IS_PLAYER_IN_ANGLED_AREA_ON_FOOT_2D, + COMMAND_IS_PLAYER_IN_ANGLED_AREA_IN_CAR_2D, + COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_2D, + COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_ON_FOOT_2D, + COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_IN_CAR_2D, + COMMAND_IS_PLAYER_IN_ANGLED_AREA_3D, + COMMAND_IS_PLAYER_IN_ANGLED_AREA_ON_FOOT_3D, + COMMAND_IS_PLAYER_IN_ANGLED_AREA_IN_CAR_3D, + COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_3D, + COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_ON_FOOT_3D, + COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_IN_CAR_3D, + COMMAND_DEACTIVATE_GARAGE, + COMMAND_GET_NUMBER_OF_CARS_COLLECTED_BY_GARAGE, + COMMAND_HAS_CAR_BEEN_TAKEN_TO_GARAGE, + COMMAND_SET_SWAT_REQUIRED, + COMMAND_SET_FBI_REQUIRED, + COMMAND_SET_ARMY_REQUIRED, + COMMAND_IS_CAR_IN_WATER, + COMMAND_GET_CLOSEST_CHAR_NODE, + COMMAND_GET_CLOSEST_CAR_NODE, + COMMAND_CAR_GOTO_COORDINATES_ACCURATE, + COMMAND_START_PACMAN_RACE, + COMMAND_START_PACMAN_RECORD, + COMMAND_GET_NUMBER_OF_POWER_PILLS_EATEN, + COMMAND_CLEAR_PACMAN, + COMMAND_START_PACMAN_SCRAMBLE, + COMMAND_GET_NUMBER_OF_POWER_PILLS_CARRIED, + COMMAND_CLEAR_NUMBER_OF_POWER_PILLS_CARRIED, + COMMAND_IS_CAR_ON_SCREEN, + COMMAND_IS_CHAR_ON_SCREEN, + COMMAND_IS_OBJECT_ON_SCREEN, + COMMAND_GOSUB_FILE, + COMMAND_GET_GROUND_Z_FOR_3D_COORD, + COMMAND_START_SCRIPT_FIRE, + COMMAND_IS_SCRIPT_FIRE_EXTINGUISHED, + COMMAND_REMOVE_SCRIPT_FIRE, + COMMAND_SET_COMEDY_CONTROLS, + COMMAND_BOAT_GOTO_COORDS, + COMMAND_BOAT_STOP, + COMMAND_IS_PLAYER_SHOOTING_IN_AREA, + COMMAND_IS_CHAR_SHOOTING_IN_AREA, + COMMAND_IS_CURRENT_PLAYER_WEAPON, + COMMAND_IS_CURRENT_CHAR_WEAPON, + COMMAND_CLEAR_NUMBER_OF_POWER_PILLS_EATEN, + COMMAND_ADD_POWER_PILL, + COMMAND_SET_BOAT_CRUISE_SPEED, + COMMAND_GET_RANDOM_CHAR_IN_AREA, + COMMAND_GET_RANDOM_CHAR_IN_ZONE, + COMMAND_IS_PLAYER_IN_TAXI, + COMMAND_IS_PLAYER_SHOOTING, + COMMAND_IS_CHAR_SHOOTING, + COMMAND_CREATE_MONEY_PICKUP, + COMMAND_SET_CHAR_ACCURACY, + COMMAND_GET_CAR_SPEED, + COMMAND_LOAD_CUTSCENE, + COMMAND_CREATE_CUTSCENE_OBJECT, + COMMAND_SET_CUTSCENE_ANIM, + COMMAND_START_CUTSCENE, + COMMAND_GET_CUTSCENE_TIME, + COMMAND_HAS_CUTSCENE_FINISHED, + COMMAND_CLEAR_CUTSCENE, + COMMAND_RESTORE_CAMERA_JUMPCUT, + COMMAND_CREATE_COLLECTABLE1, + COMMAND_SET_COLLECTABLE1_TOTAL, + COMMAND_IS_PROJECTILE_IN_AREA, + COMMAND_DESTROY_PROJECTILES_IN_AREA, + COMMAND_DROP_MINE, + COMMAND_DROP_NAUTICAL_MINE, + COMMAND_IS_CHAR_MODEL, + COMMAND_LOAD_SPECIAL_MODEL, + COMMAND_CREATE_CUTSCENE_HEAD, + COMMAND_SET_CUTSCENE_HEAD_ANIM, + COMMAND_SIN, + COMMAND_COS, + COMMAND_GET_CAR_FORWARD_X, + COMMAND_GET_CAR_FORWARD_Y, + COMMAND_CHANGE_GARAGE_TYPE, + COMMAND_ACTIVATE_CRUSHER_CRANE, + COMMAND_PRINT_WITH_2_NUMBERS, + COMMAND_PRINT_WITH_2_NUMBERS_NOW, + COMMAND_PRINT_WITH_2_NUMBERS_SOON, + COMMAND_PRINT_WITH_3_NUMBERS, + COMMAND_PRINT_WITH_3_NUMBERS_NOW, + COMMAND_PRINT_WITH_3_NUMBERS_SOON, + COMMAND_PRINT_WITH_4_NUMBERS, + COMMAND_PRINT_WITH_4_NUMBERS_NOW, + COMMAND_PRINT_WITH_4_NUMBERS_SOON, + COMMAND_PRINT_WITH_5_NUMBERS, + COMMAND_PRINT_WITH_5_NUMBERS_NOW, + COMMAND_PRINT_WITH_5_NUMBERS_SOON, + COMMAND_PRINT_WITH_6_NUMBERS, + COMMAND_PRINT_WITH_6_NUMBERS_NOW, + COMMAND_PRINT_WITH_6_NUMBERS_SOON, + COMMAND_SET_CHAR_OBJ_FOLLOW_CHAR_IN_FORMATION, + COMMAND_PLAYER_MADE_PROGRESS, + COMMAND_SET_PROGRESS_TOTAL, + COMMAND_REGISTER_JUMP_DISTANCE, + COMMAND_REGISTER_JUMP_HEIGHT, + COMMAND_REGISTER_JUMP_FLIPS, + COMMAND_REGISTER_JUMP_SPINS, + COMMAND_REGISTER_JUMP_STUNT, + COMMAND_REGISTER_UNIQUE_JUMP_FOUND, + COMMAND_SET_UNIQUE_JUMPS_TOTAL, + COMMAND_REGISTER_PASSENGER_DROPPED_OFF_TAXI, + COMMAND_REGISTER_MONEY_MADE_TAXI, + COMMAND_REGISTER_MISSION_GIVEN, + COMMAND_REGISTER_MISSION_PASSED, + COMMAND_SET_CHAR_RUNNING, + COMMAND_REMOVE_ALL_SCRIPT_FIRES, + COMMAND_IS_FIRST_CAR_COLOUR, + COMMAND_IS_SECOND_CAR_COLOUR, + COMMAND_HAS_CHAR_BEEN_DAMAGED_BY_WEAPON, + COMMAND_HAS_CAR_BEEN_DAMAGED_BY_WEAPON, + COMMAND_IS_CHAR_IN_CHARS_GROUP, + COMMAND_IS_CHAR_IN_PLAYERS_GROUP, + COMMAND_EXPLODE_CHAR_HEAD, + COMMAND_EXPLODE_PLAYER_HEAD, + COMMAND_ANCHOR_BOAT, + COMMAND_SET_ZONE_GROUP, + COMMAND_START_CAR_FIRE, + COMMAND_START_CHAR_FIRE, + COMMAND_GET_RANDOM_CAR_OF_TYPE_IN_AREA, + COMMAND_GET_RANDOM_CAR_OF_TYPE_IN_ZONE, + COMMAND_HAS_RESPRAY_HAPPENED, + COMMAND_SET_CAMERA_ZOOM, + COMMAND_CREATE_PICKUP_WITH_AMMO, + COMMAND_SET_CAR_RAM_CAR, + COMMAND_SET_CAR_BLOCK_CAR, + COMMAND_SET_CHAR_OBJ_CATCH_TRAIN, + COMMAND_SET_COLL_OBJ_CATCH_TRAIN, + COMMAND_SET_PLAYER_NEVER_GETS_TIRED, + COMMAND_SET_PLAYER_FAST_RELOAD, + COMMAND_SET_CHAR_BLEEDING, + COMMAND_SET_CAR_FUNNY_SUSPENSION, + COMMAND_SET_CAR_BIG_WHEELS, + COMMAND_SET_FREE_RESPRAYS, + COMMAND_SET_PLAYER_VISIBLE, + COMMAND_SET_CHAR_VISIBLE, + COMMAND_SET_CAR_VISIBLE, + COMMAND_IS_AREA_OCCUPIED, + COMMAND_START_DRUG_RUN, + COMMAND_HAS_DRUG_RUN_BEEN_COMPLETED, + COMMAND_HAS_DRUG_PLANE_BEEN_SHOT_DOWN, + COMMAND_SAVE_PLAYER_FROM_FIRES, + COMMAND_DISPLAY_TEXT, + COMMAND_SET_TEXT_SCALE, + COMMAND_SET_TEXT_COLOUR, + COMMAND_SET_TEXT_JUSTIFY, + COMMAND_SET_TEXT_CENTRE, + COMMAND_SET_TEXT_WRAPX, + COMMAND_SET_TEXT_CENTRE_SIZE, + COMMAND_SET_TEXT_BACKGROUND, + COMMAND_SET_TEXT_BACKGROUND_COLOUR, + COMMAND_SET_TEXT_BACKGROUND_ONLY_TEXT, + COMMAND_SET_TEXT_PROPORTIONAL, + COMMAND_SET_TEXT_FONT, + COMMAND_INDUSTRIAL_PASSED, + COMMAND_COMMERCIAL_PASSED, + COMMAND_SUBURBAN_PASSED, + COMMAND_ROTATE_OBJECT, + COMMAND_SLIDE_OBJECT, + COMMAND_REMOVE_CHAR_ELEGANTLY, + COMMAND_SET_CHAR_STAY_IN_SAME_PLACE, + COMMAND_IS_NASTY_GAME, + COMMAND_UNDRESS_CHAR, + COMMAND_DRESS_CHAR, + COMMAND_START_CHASE_SCENE, + COMMAND_STOP_CHASE_SCENE, + COMMAND_IS_EXPLOSION_IN_AREA, + COMMAND_IS_EXPLOSION_IN_ZONE, + COMMAND_START_DRUG_DROP_OFF, + COMMAND_HAS_DROP_OFF_PLANE_BEEN_SHOT_DOWN, + COMMAND_FIND_DROP_OFF_PLANE_COORDINATES, + COMMAND_CREATE_FLOATING_PACKAGE, + COMMAND_PLACE_OBJECT_RELATIVE_TO_CAR, + COMMAND_MAKE_OBJECT_TARGETTABLE, + COMMAND_ADD_ARMOUR_TO_PLAYER, + COMMAND_ADD_ARMOUR_TO_CHAR, + COMMAND_OPEN_GARAGE, + COMMAND_CLOSE_GARAGE, + COMMAND_WARP_CHAR_FROM_CAR_TO_COORD, + COMMAND_SET_VISIBILITY_OF_CLOSEST_OBJECT_OF_TYPE, + COMMAND_HAS_CHAR_SPOTTED_CHAR, + COMMAND_SET_CHAR_OBJ_HAIL_TAXI, + COMMAND_HAS_OBJECT_BEEN_DAMAGED, + COMMAND_START_KILL_FRENZY_HEADSHOT, + COMMAND_ACTIVATE_MILITARY_CRANE, + COMMAND_WARP_PLAYER_INTO_CAR, + COMMAND_WARP_CHAR_INTO_CAR, + COMMAND_SWITCH_CAR_RADIO, + COMMAND_SET_AUDIO_STREAM, + COMMAND_PRINT_WITH_2_NUMBERS_BIG, + COMMAND_PRINT_WITH_3_NUMBERS_BIG, + COMMAND_PRINT_WITH_4_NUMBERS_BIG, + COMMAND_PRINT_WITH_5_NUMBERS_BIG, + COMMAND_PRINT_WITH_6_NUMBERS_BIG, + COMMAND_SET_CHAR_WAIT_STATE, + COMMAND_SET_CAMERA_BEHIND_PLAYER, + COMMAND_SET_MOTION_BLUR, + COMMAND_PRINT_STRING_IN_STRING, + COMMAND_CREATE_RANDOM_CHAR, + COMMAND_SET_CHAR_OBJ_STEAL_ANY_CAR, + COMMAND_SET_2_REPEATED_PHONE_MESSAGES, + COMMAND_SET_2_PHONE_MESSAGES, + COMMAND_SET_3_REPEATED_PHONE_MESSAGES, + COMMAND_SET_3_PHONE_MESSAGES, + COMMAND_SET_4_REPEATED_PHONE_MESSAGES, + COMMAND_SET_4_PHONE_MESSAGES, + COMMAND_IS_SNIPER_BULLET_IN_AREA, + COMMAND_GIVE_PLAYER_DETONATOR, + COMMAND_SET_COLL_OBJ_STEAL_ANY_CAR, + COMMAND_SET_OBJECT_VELOCITY, + COMMAND_SET_OBJECT_COLLISION, + COMMAND_IS_ICECREAM_JINGLE_ON, + COMMAND_PRINT_STRING_IN_STRING_NOW, + COMMAND_PRINT_STRING_IN_STRING_SOON, + COMMAND_SET_5_REPEATED_PHONE_MESSAGES, + COMMAND_SET_5_PHONE_MESSAGES, + COMMAND_SET_6_REPEATED_PHONE_MESSAGES, + COMMAND_SET_6_PHONE_MESSAGES, + COMMAND_IS_POINT_OBSCURED_BY_A_MISSION_ENTITY, + COMMAND_LOAD_ALL_MODELS_NOW, + COMMAND_ADD_TO_OBJECT_VELOCITY, + COMMAND_DRAW_SPRITE, + COMMAND_DRAW_RECT, + COMMAND_LOAD_SPRITE, + COMMAND_LOAD_TEXTURE_DICTIONARY, + COMMAND_REMOVE_TEXTURE_DICTIONARY, + COMMAND_SET_OBJECT_DYNAMIC, + COMMAND_SET_CHAR_ANIM_SPEED, + COMMAND_PLAY_MISSION_PASSED_TUNE, + COMMAND_CLEAR_AREA, + COMMAND_FREEZE_ONSCREEN_TIMER, + COMMAND_SWITCH_CAR_SIREN, + COMMAND_SWITCH_PED_ROADS_ON_ANGLED, + COMMAND_SWITCH_PED_ROADS_OFF_ANGLED, + COMMAND_SWITCH_ROADS_ON_ANGLED, + COMMAND_SWITCH_ROADS_OFF_ANGLED, + COMMAND_SET_CAR_WATERTIGHT, + COMMAND_ADD_MOVING_PARTICLE_EFFECT, + COMMAND_SET_CHAR_CANT_BE_DRAGGED_OUT, + COMMAND_TURN_CAR_TO_FACE_COORD, + COMMAND_IS_CRANE_LIFTING_CAR, + COMMAND_DRAW_SPHERE, + COMMAND_SET_CAR_STATUS, + COMMAND_IS_CHAR_MALE, + COMMAND_SCRIPT_NAME, + COMMAND_CHANGE_GARAGE_TYPE_WITH_CAR_MODEL, + COMMAND_FIND_DRUG_PLANE_COORDINATES, + COMMAND_SAVE_INT_TO_DEBUG_FILE, + COMMAND_SAVE_FLOAT_TO_DEBUG_FILE, + COMMAND_SAVE_NEWLINE_TO_DEBUG_FILE, + COMMAND_POLICE_RADIO_MESSAGE, + COMMAND_SET_CAR_STRONG, + COMMAND_REMOVE_ROUTE, + COMMAND_SWITCH_RUBBISH, + COMMAND_REMOVE_PARTICLE_EFFECTS_IN_AREA, + COMMAND_SWITCH_STREAMING, + COMMAND_IS_GARAGE_OPEN, + COMMAND_IS_GARAGE_CLOSED, + COMMAND_START_CATALINA_HELI, + COMMAND_CATALINA_HELI_TAKE_OFF, + COMMAND_REMOVE_CATALINA_HELI, + COMMAND_HAS_CATALINA_HELI_BEEN_SHOT_DOWN, + COMMAND_SWAP_NEAREST_BUILDING_MODEL, + COMMAND_SWITCH_WORLD_PROCESSING, + COMMAND_REMOVE_ALL_PLAYER_WEAPONS, + COMMAND_GRAB_CATALINA_HELI, + COMMAND_CLEAR_AREA_OF_CARS, + COMMAND_SET_ROTATING_GARAGE_DOOR, + COMMAND_ADD_SPHERE, + COMMAND_REMOVE_SPHERE, + COMMAND_CATALINA_HELI_FLY_AWAY, + COMMAND_SET_EVERYONE_IGNORE_PLAYER, + COMMAND_STORE_CAR_CHAR_IS_IN_NO_SAVE, + COMMAND_STORE_CAR_PLAYER_IS_IN_NO_SAVE, + COMMAND_IS_PHONE_DISPLAYING_MESSAGE, + COMMAND_DISPLAY_ONSCREEN_TIMER_WITH_STRING, + COMMAND_DISPLAY_ONSCREEN_COUNTER_WITH_STRING, + COMMAND_CREATE_RANDOM_CAR_FOR_CAR_PARK, + COMMAND_IS_COLLISION_IN_MEMORY, + COMMAND_SET_WANTED_MULTIPLIER, + COMMAND_SET_CAMERA_IN_FRONT_OF_PLAYER, + COMMAND_IS_CAR_VISIBLY_DAMAGED, + COMMAND_DOES_OBJECT_EXIST, + COMMAND_LOAD_SCENE, + COMMAND_ADD_STUCK_CAR_CHECK, + COMMAND_REMOVE_STUCK_CAR_CHECK, + COMMAND_IS_CAR_STUCK, + COMMAND_LOAD_MISSION_AUDIO, + COMMAND_HAS_MISSION_AUDIO_LOADED, + COMMAND_PLAY_MISSION_AUDIO, + COMMAND_HAS_MISSION_AUDIO_FINISHED, + COMMAND_GET_CLOSEST_CAR_NODE_WITH_HEADING, + COMMAND_HAS_IMPORT_GARAGE_SLOT_BEEN_FILLED, + COMMAND_CLEAR_THIS_PRINT, + COMMAND_CLEAR_THIS_BIG_PRINT, + COMMAND_SET_MISSION_AUDIO_POSITION, + COMMAND_ACTIVATE_SAVE_MENU, + COMMAND_HAS_SAVE_GAME_FINISHED, + COMMAND_NO_SPECIAL_CAMERA_FOR_THIS_GARAGE, + COMMAND_ADD_BLIP_FOR_PICKUP_OLD, + COMMAND_ADD_BLIP_FOR_PICKUP, + COMMAND_ADD_SPRITE_BLIP_FOR_PICKUP, + COMMAND_SET_PED_DENSITY_MULTIPLIER, + COMMAND_FORCE_RANDOM_PED_TYPE, + COMMAND_SET_TEXT_DRAW_BEFORE_FADE, + COMMAND_GET_COLLECTABLE1S_COLLECTED, + COMMAND_REGISTER_EL_BURRO_TIME, + COMMAND_SET_SPRITES_DRAW_BEFORE_FADE, + COMMAND_SET_TEXT_RIGHT_JUSTIFY, + COMMAND_PRINT_HELP, + COMMAND_CLEAR_HELP, + COMMAND_FLASH_HUD_OBJECT, + COMMAND_FLASH_RADAR_BLIP, + COMMAND_IS_CHAR_IN_CONTROL, + COMMAND_SET_GENERATE_CARS_AROUND_CAMERA, + COMMAND_CLEAR_SMALL_PRINTS, + COMMAND_HAS_MILITARY_CRANE_COLLECTED_ALL_CARS, + COMMAND_SET_UPSIDEDOWN_CAR_NOT_DAMAGED, + COMMAND_CAN_PLAYER_START_MISSION, + COMMAND_MAKE_PLAYER_SAFE_FOR_CUTSCENE, + COMMAND_USE_TEXT_COMMANDS, + COMMAND_SET_THREAT_FOR_PED_TYPE, + COMMAND_CLEAR_THREAT_FOR_PED_TYPE, + COMMAND_GET_CAR_COLOURS, + COMMAND_SET_ALL_CARS_CAN_BE_DAMAGED, + COMMAND_SET_CAR_CAN_BE_DAMAGED, + COMMAND_MAKE_PLAYER_UNSAFE, + COMMAND_LOAD_COLLISION, + COMMAND_GET_BODY_CAST_HEALTH, + COMMAND_SET_CHARS_CHATTING, + COMMAND_MAKE_PLAYER_SAFE, + COMMAND_SET_CAR_STAYS_IN_CURRENT_LEVEL, + COMMAND_SET_CHAR_STAYS_IN_CURRENT_LEVEL, + COMMAND_REGISTER_4X4_ONE_TIME, + COMMAND_REGISTER_4X4_TWO_TIME, + COMMAND_REGISTER_4X4_THREE_TIME, + COMMAND_REGISTER_4X4_MAYHEM_TIME, + COMMAND_REGISTER_LIFE_SAVED, + COMMAND_REGISTER_CRIMINAL_CAUGHT, + COMMAND_REGISTER_AMBULANCE_LEVEL, + COMMAND_REGISTER_FIRE_EXTINGUISHED, + COMMAND_TURN_PHONE_ON, + COMMAND_REGISTER_LONGEST_DODO_FLIGHT, + COMMAND_REGISTER_DEFUSE_BOMB_TIME, + COMMAND_SET_TOTAL_NUMBER_OF_KILL_FRENZIES, + COMMAND_BLOW_UP_RC_BUGGY, + COMMAND_REMOVE_CAR_FROM_CHASE, + COMMAND_IS_FRENCH_GAME, + COMMAND_IS_GERMAN_GAME, + COMMAND_CLEAR_MISSION_AUDIO, + COMMAND_SET_FADE_IN_AFTER_NEXT_ARREST, + COMMAND_SET_FADE_IN_AFTER_NEXT_DEATH, + COMMAND_SET_GANG_PED_MODEL_PREFERENCE, + COMMAND_SET_CHAR_USE_PEDNODE_SEEK, + COMMAND_SWITCH_VEHICLE_WEAPONS, + COMMAND_SET_GET_OUT_OF_JAIL_FREE, + COMMAND_SET_FREE_HEALTH_CARE, + COMMAND_IS_CAR_DOOR_CLOSED, + COMMAND_LOAD_AND_LAUNCH_MISSION, + COMMAND_LOAD_AND_LAUNCH_MISSION_INTERNAL, + COMMAND_SET_OBJECT_DRAW_LAST, + COMMAND_GET_AMMO_IN_PLAYER_WEAPON, + COMMAND_GET_AMMO_IN_CHAR_WEAPON, + COMMAND_REGISTER_KILL_FRENZY_PASSED, + COMMAND_SET_CHAR_SAY, + COMMAND_SET_NEAR_CLIP, + COMMAND_SET_RADIO_CHANNEL, + COMMAND_OVERRIDE_HOSPITAL_LEVEL, + COMMAND_OVERRIDE_POLICE_STATION_LEVEL, + COMMAND_FORCE_RAIN, + COMMAND_DOES_GARAGE_CONTAIN_CAR, + COMMAND_SET_CAR_TRACTION, + COMMAND_ARE_MEASUREMENTS_IN_METRES, + COMMAND_CONVERT_METRES_TO_FEET, + COMMAND_MARK_ROADS_BETWEEN_LEVELS, + COMMAND_MARK_PED_ROADS_BETWEEN_LEVELS, + COMMAND_SET_CAR_AVOID_LEVEL_TRANSITIONS, + COMMAND_SET_CHAR_AVOID_LEVEL_TRANSITIONS, + COMMAND_IS_THREAT_FOR_PED_TYPE, + COMMAND_CLEAR_AREA_OF_CHARS, + COMMAND_SET_TOTAL_NUMBER_OF_MISSIONS, + COMMAND_CONVERT_METRES_TO_FEET_INT, + COMMAND_REGISTER_FASTEST_TIME, + COMMAND_REGISTER_HIGHEST_SCORE, + COMMAND_WARP_CHAR_INTO_CAR_AS_PASSENGER, + COMMAND_IS_CAR_PASSENGER_SEAT_FREE, + COMMAND_GET_CHAR_IN_CAR_PASSENGER_SEAT, + COMMAND_SET_CHAR_IS_CHRIS_CRIMINAL, + COMMAND_START_CREDITS, + COMMAND_STOP_CREDITS, + COMMAND_ARE_CREDITS_FINISHED, + COMMAND_CREATE_SINGLE_PARTICLE, + COMMAND_SET_CHAR_IGNORE_LEVEL_TRANSITIONS, + COMMAND_GET_CHASE_CAR, + COMMAND_START_BOAT_FOAM_ANIMATION, + COMMAND_UPDATE_BOAT_FOAM_ANIMATION, + COMMAND_SET_MUSIC_DOES_FADE, + COMMAND_SET_INTRO_IS_PLAYING, + COMMAND_SET_PLAYER_HOOKER, + COMMAND_PLAY_END_OF_GAME_TUNE, + COMMAND_STOP_END_OF_GAME_TUNE, + COMMAND_GET_CAR_MODEL, + COMMAND_IS_PLAYER_SITTING_IN_CAR, + COMMAND_IS_PLAYER_SITTING_IN_ANY_CAR, + COMMAND_SET_SCRIPT_FIRE_AUDIO, + COMMAND_ARE_ANY_CAR_CHEATS_ACTIVATED, + COMMAND_SET_CHAR_SUFFERS_CRITICAL_HITS, + COMMAND_IS_PLAYER_LIFTING_A_PHONE, + COMMAND_IS_CHAR_SITTING_IN_CAR, + COMMAND_IS_CHAR_SITTING_IN_ANY_CAR, + COMMAND_IS_PLAYER_ON_FOOT, + COMMAND_IS_CHAR_ON_FOOT, + COMMAND_LOAD_COLLISION_WITH_SCREEN, + COMMAND_LOAD_SPLASH_SCREEN, + COMMAND_SET_CAR_IGNORE_LEVEL_TRANSITIONS, + COMMAND_MAKE_CRAIGS_CAR_A_BIT_STRONGER, + COMMAND_SET_JAMES_CAR_ON_PATH_TO_PLAYER, + COMMAND_LOAD_END_OF_GAME_TUNE, + COMMAND_ENABLE_PLAYER_CONTROL_CAMERA, + COMMAND_SET_OBJECT_ROTATION, + COMMAND_GET_DEBUG_CAMERA_COORDINATES, + COMMAND_GET_DEBUG_CAMERA_FRONT_VECTOR, + COMMAND_IS_PLAYER_TARGETTING_ANY_CHAR, + COMMAND_IS_PLAYER_TARGETTING_CHAR, + COMMAND_IS_PLAYER_TARGETTING_OBJECT, + COMMAND_TERMINATE_ALL_SCRIPTS_WITH_THIS_NAME, + COMMAND_DISPLAY_TEXT_WITH_NUMBER, + COMMAND_DISPLAY_TEXT_WITH_2_NUMBERS, + COMMAND_FAIL_CURRENT_MISSION, + COMMAND_GET_CLOSEST_OBJECT_OF_TYPE, + COMMAND_PLACE_OBJECT_RELATIVE_TO_OBJECT, + COMMAND_SET_ALL_OCCUPANTS_OF_CAR_LEAVE_CAR, + COMMAND_SET_INTERPOLATION_PARAMETERS, + COMMAND_GET_CLOSEST_CAR_NODE_WITH_HEADING_TOWARDS_POINT, + COMMAND_GET_CLOSEST_CAR_NODE_WITH_HEADING_AWAY_POINT, + COMMAND_GET_DEBUG_CAMERA_POINT_AT, + COMMAND_ATTACH_CHAR_TO_CAR, + COMMAND_DETACH_CHAR_FROM_CAR, + COMMAND_SET_CAR_CHANGE_LANE, + COMMAND_CLEAR_CHAR_LAST_WEAPON_DAMAGE, + COMMAND_CLEAR_CAR_LAST_WEAPON_DAMAGE, + COMMAND_GET_RANDOM_COP_IN_AREA, + COMMAND_GET_RANDOM_COP_IN_ZONE, + COMMAND_SET_CHAR_OBJ_FLEE_CAR, + COMMAND_GET_DRIVER_OF_CAR, + COMMAND_GET_NUMBER_OF_FOLLOWERS, + COMMAND_GIVE_REMOTE_CONTROLLED_MODEL_TO_PLAYER, + COMMAND_GET_CURRENT_PLAYER_WEAPON, + COMMAND_GET_CURRENT_CHAR_WEAPON, + COMMAND_LOCATE_CHAR_ANY_MEANS_OBJECT_2D, + COMMAND_LOCATE_CHAR_ON_FOOT_OBJECT_2D, + COMMAND_LOCATE_CHAR_IN_CAR_OBJECT_2D, + COMMAND_LOCATE_CHAR_ANY_MEANS_OBJECT_3D, + COMMAND_LOCATE_CHAR_ON_FOOT_OBJECT_3D, + COMMAND_LOCATE_CHAR_IN_CAR_OBJECT_3D, + COMMAND_SET_CAR_TEMP_ACTION, + COMMAND_SET_CAR_HANDBRAKE_TURN_RIGHT, + COMMAND_SET_CAR_HANDBRAKE_STOP, + COMMAND_IS_CHAR_ON_ANY_BIKE, + COMMAND_LOCATE_SNIPER_BULLET_2D, + COMMAND_LOCATE_SNIPER_BULLET_3D, + COMMAND_GET_NUMBER_OF_SEATS_IN_MODEL, + COMMAND_IS_PLAYER_ON_ANY_BIKE, + COMMAND_IS_CHAR_LYING_DOWN, + COMMAND_CAN_CHAR_SEE_DEAD_CHAR, + COMMAND_SET_ENTER_CAR_RANGE_MULTIPLIER, +};
\ No newline at end of file diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp index 660be333..c06ee48b 100644 --- a/src/core/Camera.cpp +++ b/src/core/Camera.cpp @@ -18,10 +18,12 @@ const float DefaultFOV = 70.0f; // beta: 80.0f CCamera &TheCamera = *(CCamera*)0x6FACF8; bool &CCamera::m_bUseMouse3rdPerson = *(bool *)0x5F03D8; +WRAPPER void CCamera::CamShake(float strength, float x, float y, float z) { EAXJMP(0x46B200); } WRAPPER void CCamera::DrawBordersForWideScreen(void) { EAXJMP(0x46B430); } WRAPPER void CCamera::CalculateDerivedValues(void) { EAXJMP(0x46EEA0); } WRAPPER void CCamera::Restore(void) { EAXJMP(0x46F990); } WRAPPER void CCamera::SetWidescreenOff(void) { EAXJMP(0x46FF10); } +WRAPPER void CCamera::CamShake(float) { EAXJMP(0x46B100); } bool CCamera::IsSphereVisible(const CVector ¢er, float radius, const CMatrix *mat) @@ -136,6 +138,15 @@ CCamera::RenderMotionBlur(void) m_motionBlur, m_BlurType, m_imotionBlurAddAlpha); } +void +CCamera::ClearPlayerWeaponMode() +{ + PlayerWeaponMode.Mode = 0; + PlayerWeaponMode.MaxZoom = 1; + PlayerWeaponMode.MinZoom = -1; + PlayerWeaponMode.Duration = 0.0f; +} + /* * @@ -159,9 +170,9 @@ WellBufferMe(float Target, float *CurrentValue, float *CurrentSpeed, float MaxSp float TargetSpeed = Delta * MaxSpeed; // Add or subtract absolute depending on sign, genius! // if(TargetSpeed - *CurrentSpeed > 0.0f) -// *CurrentSpeed += Acceleration * fabs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep(); +// *CurrentSpeed += Acceleration * Abs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep(); // else -// *CurrentSpeed -= Acceleration * fabs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep(); +// *CurrentSpeed -= Acceleration * Abs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep(); // this is simpler: *CurrentSpeed += Acceleration * (TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep(); @@ -238,14 +249,14 @@ CCam::GetPedBetaAngleForClearView(const CVector &Target, float Dist, float BetaO for(a = 0.0f; a <= PI; a += DEGTORAD(5.0f)){ if(BetaOffset <= 0.0f){ - ToSource = CVector(cos(Beta + BetaOffset + a), sin(Beta + BetaOffset + a), 0.0f)*Dist; + ToSource = CVector(Cos(Beta + BetaOffset + a), Sin(Beta + BetaOffset + a), 0.0f)*Dist; if(!CWorld::ProcessLineOfSight(Target, Target + ToSource, point, ent, checkBuildings, checkVehicles, checkPeds, checkObjects, checkDummies, true, true)) return a; } if(BetaOffset >= 0.0f){ - ToSource = CVector(cos(Beta + BetaOffset - a), sin(Beta + BetaOffset - a), 0.0f)*Dist; + ToSource = CVector(Cos(Beta + BetaOffset - a), Sin(Beta + BetaOffset - a), 0.0f)*Dist; if(!CWorld::ProcessLineOfSight(Target, Target + ToSource, point, ent, checkBuildings, checkVehicles, checkPeds, checkObjects, checkDummies, true, true)) @@ -344,8 +355,8 @@ CCam::Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, fl // TODO: what's transition beta? if(TheCamera.m_bUseTransitionBeta && ResetStatics){ CVector VecDistance; - IdealSource.x = TargetCoors.x + GroundDist*cos(m_fTransitionBeta); - IdealSource.y = TargetCoors.y + GroundDist*sin(m_fTransitionBeta); + IdealSource.x = TargetCoors.x + GroundDist*Cos(m_fTransitionBeta); + IdealSource.y = TargetCoors.y + GroundDist*Sin(m_fTransitionBeta); Beta = CGeneral::GetATanOfXY(IdealSource.x - TargetCoors.x, IdealSource.y - TargetCoors.y); }else Beta = CGeneral::GetATanOfXY(Source.x - TargetCoors.x, Source.y - TargetCoors.y); @@ -489,7 +500,7 @@ CCam::Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, fl CVector PlayerPos = FindPlayerPed()->GetPosition(); float RotationDist = (AngleToGoTo == Center ? CenterDist : LateralDist) * RealGroundDist; // What's going on here? - AngleToGoTo? - CVector RotatedSource = PlayerPos + CVector(cos(Beta - AngleToGoTo), sin(Beta - AngleToGoTo), 0.0f) * RotationDist; + CVector RotatedSource = PlayerPos + CVector(Cos(Beta - AngleToGoTo), Sin(Beta - AngleToGoTo), 0.0f) * RotationDist; CColPoint colpoint; CEntity *entity; @@ -573,9 +584,9 @@ CCam::Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, fl float ReqSpeed = DeltaBeta * MaxSpeed; // Add or subtract absolute depending on sign, genius! if(ReqSpeed - BetaSpeed > 0.0f) - BetaSpeed += SpeedStep * fabs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep(); + BetaSpeed += SpeedStep * Abs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep(); else - BetaSpeed -= SpeedStep * fabs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep(); + BetaSpeed -= SpeedStep * Abs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep(); // this would be simpler: // BetaSpeed += SpeedStep * (ReqSpeed - BetaSpeed) * CTimer::ms_fTimeStep; @@ -593,14 +604,14 @@ CCam::Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, fl BetaSpeed = 0.0f; } - Source.x = TargetCoors.x + Distance * cos(Beta); - Source.y = TargetCoors.y + Distance * sin(Beta); + Source.x = TargetCoors.x + Distance * Cos(Beta); + Source.y = TargetCoors.y + Distance * Sin(Beta); // Check if we can stop rotating DeltaBeta = FixedTargetOrientation - Beta; while(DeltaBeta >= PI) DeltaBeta -= 2*PI; while(DeltaBeta < -PI) DeltaBeta += 2*PI; - if(fabs(DeltaBeta) < DEGTORAD(1.0f) && !bBehindPlayerDesired){ + if(Abs(DeltaBeta) < DEGTORAD(1.0f) && !bBehindPlayerDesired){ // Stop rotation PickedASide = false; Rotating = false; @@ -613,18 +624,18 @@ CCam::Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, fl HackPlayerOnStoppingTrain || Rotating){ if(TheCamera.m_bCamDirectlyBehind){ Beta = TargetOrientation + PI; - Source.x = TargetCoors.x + Distance * cos(Beta); - Source.y = TargetCoors.y + Distance * sin(Beta); + Source.x = TargetCoors.x + Distance * Cos(Beta); + Source.y = TargetCoors.y + Distance * Sin(Beta); } if(TheCamera.m_bCamDirectlyInFront){ Beta = TargetOrientation; - Source.x = TargetCoors.x + Distance * cos(Beta); - Source.y = TargetCoors.y + Distance * sin(Beta); + Source.x = TargetCoors.x + Distance * Cos(Beta); + Source.y = TargetCoors.y + Distance * Sin(Beta); } if(HackPlayerOnStoppingTrain){ Beta = TargetOrientation + PI; - Source.x = TargetCoors.x + Distance * cos(Beta); - Source.y = TargetCoors.y + Distance * sin(Beta); + Source.x = TargetCoors.x + Distance * Cos(Beta); + Source.y = TargetCoors.y + Distance * Sin(Beta); m_fDimensionOfHighestNearCar = 0.0f; m_fCamBufferedHeight = 0.0f; m_fCamBufferedHeightSpeed = 0.0f; @@ -669,9 +680,13 @@ CCam::Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, fl else if(TargetZOffSet == m_fUnknownZOffSet && TargetZOffSet > m_fCamBufferedHeight){ // TODO: figure this out bool foo = false; - switch(((CPhysical*)CamTargetEntity)->m_nLastCollType) - case 2: case 3: case 5: - case 11: case 23: case 26: + switch(((CPhysical*)CamTargetEntity)->m_nSurfaceTouched) + case SURFACE_GRASS: + case SURFACE_DIRT: + case SURFACE_PAVEMENT: + case SURFACE_STEEL: + case SURFACE_TIRE: + case SURFACE_STONE: foo = true; if(foo) WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.4f, 0.05f, false); @@ -784,7 +799,7 @@ CCam::WorkOutCamHeightWeeCar(CVector &TargetCoors, float TargetOrientation) if(CCullZones::CamNoRain() || CCullZones::PlayerNoRain()) AlphaTarget = DEGTORAD(14.0f); WellBufferMe(AlphaTarget, &Alpha, &AlphaSpeed, 0.1f, 0.05f, true); - Source.z = TargetCoors.z + CA_MAX_DISTANCE*sin(Alpha); + Source.z = TargetCoors.z + CA_MAX_DISTANCE*Sin(Alpha); if(FindPlayerVehicle()){ m_fUnknownZOffSet = 0.0f; @@ -889,7 +904,7 @@ CCam::WorkOutCamHeight(const CVector &TargetCoors, float TargetOrientation, floa while(deltaBeta >= PI) deltaBeta -= 2*PI; while(deltaBeta < -PI) deltaBeta += 2*PI; - float BehindCarNess = cos(deltaBeta); // 1 if behind car, 0 if side, -1 if in front + float BehindCarNess = Cos(deltaBeta); // 1 if behind car, 0 if side, -1 if in front CarAlpha = -CarAlpha * BehindCarNess; if(CarAlpha < -0.01f) CarAlpha = -0.01f; @@ -924,13 +939,13 @@ CCam::WorkOutCamHeight(const CVector &TargetCoors, float TargetOrientation, floa Forward = CamTargetEntity->GetForward(); // we actually still have that... Forward.Normalise(); // shouldn't be necessary float CarSideAngle = CGeneral::GetATanOfXY(Forward.x, Forward.y) + PI/2.0f; - float SideX = 2.5f * cos(CarSideAngle); - float SideY = 2.5f * sin(CarSideAngle); + float SideX = 2.5f * Cos(CarSideAngle); + float SideY = 2.5f * Sin(CarSideAngle); CWorld::FindRoofZFor3DCoord(TargetCoors.x + SideX, TargetCoors.y + SideY, CarBottom, &FoundRoofSide1); CWorld::FindRoofZFor3DCoord(TargetCoors.x - SideX, TargetCoors.y - SideY, CarBottom, &FoundRoofSide2); // Now find out at what height we'd like to place the camera - float CamGround = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, TargetCoors.z + Length*sin(Alpha + ModeAlpha) + m_fCloseInCarHeightOffset, &FoundCamGround); + float CamGround = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, TargetCoors.z + Length*Sin(Alpha + ModeAlpha) + m_fCloseInCarHeightOffset, &FoundCamGround); float CamTargetZ = 0.0f; if(FoundCamGround){ // This is the normal case @@ -977,7 +992,7 @@ CCam::WorkOutCamHeight(const CVector &TargetCoors, float TargetOrientation, floa } // Now do things if CamClear...but what is that anyway? - float CamZ = TargetCoors.z + Length*sin(Alpha + DeltaAlpha + ModeAlpha) + m_fCloseInCarHeightOffset; + float CamZ = TargetCoors.z + Length*Sin(Alpha + DeltaAlpha + ModeAlpha) + m_fCloseInCarHeightOffset; bool FoundGround, FoundRoof; float CamGround2 = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, CamZ, &FoundGround); if(FoundGround){ @@ -1027,7 +1042,7 @@ CCam::WorkOutCamHeight(const CVector &TargetCoors, float TargetOrientation, floa WellBufferMe(LastTargetAlphaWithCollisionOn, &Alpha, &AlphaSpeed, LastTopAlphaSpeed, LastAlphaSpeedStep, true); - Source.z = TargetCoors.z + sin(Alpha + ModeAlpha)*Length + m_fCloseInCarHeightOffset; + Source.z = TargetCoors.z + Sin(Alpha + ModeAlpha)*Length + m_fCloseInCarHeightOffset; } // Rotate cam behind the car when the car is moving forward @@ -1047,7 +1062,7 @@ CCam::RotCamIfInFrontCar(CVector &TargetCoors, float TargetOrientation) while(DeltaBeta >= PI) DeltaBeta -= 2*PI; while(DeltaBeta < -PI) DeltaBeta += 2*PI; - if(fabs(DeltaBeta) > DEGTORAD(20.0f) && MovingForward && TheCamera.m_uiTransitionState == 0) + if(Abs(DeltaBeta) > DEGTORAD(20.0f) && MovingForward && TheCamera.m_uiTransitionState == 0) m_bFixingBeta = true; CPad *pad = CPad::GetPad(0); @@ -1073,14 +1088,14 @@ CCam::RotCamIfInFrontCar(CVector &TargetCoors, float TargetOrientation) if(TheCamera.m_bUseTransitionBeta && &TheCamera.Cams[TheCamera.ActiveCam] == this) Beta = m_fTransitionBeta; - Source.x = TargetCoors.x - cos(Beta)*Dist; - Source.y = TargetCoors.y - sin(Beta)*Dist; + Source.x = TargetCoors.x - Cos(Beta)*Dist; + Source.y = TargetCoors.y - Sin(Beta)*Dist; // Check if we're done DeltaBeta = TargetOrientation - Beta; while(DeltaBeta >= PI) DeltaBeta -= 2*PI; while(DeltaBeta < -PI) DeltaBeta += 2*PI; - if(fabs(DeltaBeta) < DEGTORAD(2.0f)) + if(Abs(DeltaBeta) < DEGTORAD(2.0f)) m_bFixingBeta = false; } TheCamera.m_bCamDirectlyBehind = false; @@ -1123,8 +1138,8 @@ CCam::FixCamIfObscured(CVector &TargetCoors, float TargetHeight, float TargetOri Obscured1 = CWorld::ProcessLineOfSight(EntityPos, TempSource, colPoint, ent, true, false, false, true, false, true, true); }else if(m_bFixingBeta){ float d = (TempSource - Target).Magnitude(); - TempSource.x = Target.x - d*cos(TargetOrientation); - TempSource.y = Target.y - d*sin(TargetOrientation); + TempSource.x = Target.x - d*Cos(TargetOrientation); + TempSource.y = Target.y - d*Sin(TargetOrientation); // same check again Obscured2 = CWorld::ProcessLineOfSight(Target, TempSource, colPoint, ent, true, false, false, true, false, true, true); @@ -1142,14 +1157,14 @@ CCam::FixCamIfObscured(CVector &TargetCoors, float TargetHeight, float TargetOri return false; if(Fix1){ - Source.x = Target.x - cos(Beta)*Dist1; - Source.y = Target.y - sin(Beta)*Dist1; + Source.x = Target.x - Cos(Beta)*Dist1; + Source.y = Target.y - Sin(Beta)*Dist1; if(Mode == MODE_BEHINDCAR) Source = colPoint.point; }else{ WellBufferMe(Dist2, &m_fDistanceBeforeChanges, &DistanceSpeed, 0.2f, 0.025f, false); - Source.x = Target.x - cos(Beta)*m_fDistanceBeforeChanges; - Source.y = Target.y - sin(Beta)*m_fDistanceBeforeChanges; + Source.x = Target.x - Cos(Beta)*m_fDistanceBeforeChanges; + Source.y = Target.y - Sin(Beta)*m_fDistanceBeforeChanges; } if(ResetStatics){ diff --git a/src/core/Camera.h b/src/core/Camera.h index 84c3060b..c0309b5f 100644 --- a/src/core/Camera.h +++ b/src/core/Camera.h @@ -454,14 +454,18 @@ int m_iModeObbeCamIsInForCar; void ProcessMusicFade(void); void SetFadeColour(uint8 r, uint8 g, uint8 b); + void CamShake(float strength, float x, float y, float z); + void SetMotionBlur(int r, int g, int b, int a, int type); void SetMotionBlurAlpha(int a); void RenderMotionBlur(void); + void ClearPlayerWeaponMode(); void CalculateDerivedValues(void); void DrawBordersForWideScreen(void); void Restore(void); void SetWidescreenOff(void); + void CamShake(float); void dtor(void) { this->CCamera::~CCamera(); } }; diff --git a/src/core/Collision.cpp b/src/core/Collision.cpp index d15ccca5..1ed08867 100644 --- a/src/core/Collision.cpp +++ b/src/core/Collision.cpp @@ -457,7 +457,7 @@ CCollision::TestLineSphere(const CColLine &line, const CColSphere &sph) // I leave in the strange -2 factors even though they serve no real purpose float projline = -2.0f * DotProduct(v01, v0c); // project v0c onto line // Square of tangent from p0 multiplied by line length so we can compare with projline. - // The length of the tangent would be this: sqrt((c-p0)^2 - r^2). + // The length of the tangent would be this: Sqrt((c-p0)^2 - r^2). // Negative if p0 is inside the sphere! This breaks the test! float tansq = 4.0f * linesq * (sph.center.MagnitudeSqr() - 2.0f*DotProduct(sph.center, line.p0) + line.p0.MagnitudeSqr() - sph.radius*sph.radius); @@ -467,10 +467,10 @@ CCollision::TestLineSphere(const CColLine &line, const CColSphere &sph) return false; // projline (negative in GTA for some reason) is the point on the line // in the middle of the two intersection points (startin from p0). - // sqrt(diffsq) somehow works out to be the distance from that + // Sqrt(diffsq) somehow works out to be the distance from that // midpoint to the intersection points. // So subtract that and get rid of the awkward scaling: - float f = (-projline - sqrt(diffsq)) / (2.0f*linesq); + float f = (-projline - Sqrt(diffsq)) / (2.0f*linesq); // f should now be in range [0, 1] for [p0, p1] return f >= 0.0f && f <= 1.0f; } @@ -480,7 +480,7 @@ CCollision::TestSphereTriangle(const CColSphere &sphere, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane) { // If sphere and plane don't intersect, no collision - if(fabs(plane.CalcPoint(sphere.center)) > sphere.radius) + if(Abs(plane.CalcPoint(sphere.center)) > sphere.radius) return false; const CVector &va = verts[tri.a]; @@ -627,7 +627,7 @@ CCollision::ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoin dist = sph.center - p; float lensq = dist.MagnitudeSqr(); if(lensq < mindistsq){ - point.normal = dist * (1.0f/sqrt(lensq)); + point.normal = dist * (1.0f/Sqrt(lensq)); point.point = sph.center - point.normal; point.surfaceA = sph.surface; point.pieceA = sph.piece; @@ -669,7 +669,7 @@ CCollision::ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoin dist = sph.center - p; float lensq = dist.MagnitudeSqr(); if(lensq < mindistsq){ - float len = sqrt(lensq); + float len = Sqrt(lensq); point.point = p; point.normal = dist * (1.0f/len); point.surfaceA = sph.surface; @@ -816,7 +816,7 @@ CCollision::ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CC if(diffsq < 0.0f) return false; // point of first intersection, in range [0,1] between p0 and p1 - float t = (projline - sqrt(diffsq)) / linesq; + float t = (projline - Sqrt(diffsq)) / linesq; // if not on line or beyond mindist, no intersection if(t < 0.0f || t > 1.0f || t >= mindist) return false; @@ -1010,7 +1010,7 @@ CCollision::ProcessSphereTriangle(const CColSphere &sphere, // If sphere and plane don't intersect, no collision float planedist = plane.CalcPoint(sphere.center); float distsq = planedist*planedist; - if(fabs(planedist) > sphere.radius || distsq > mindistsq) + if(Abs(planedist) > sphere.radius || distsq > mindistsq) return false; const CVector &va = verts[tri.a]; @@ -1057,7 +1057,7 @@ CCollision::ProcessSphereTriangle(const CColSphere &sphere, else assert(0); }else if(testcase == 3){ // center is in triangle - dist = fabs(planedist); + dist = Abs(planedist); p = sphere.center - normal*planedist; }else assert(0); // front fell off @@ -1173,7 +1173,7 @@ enum { // This checks model A's spheres and lines against model B's spheres, boxes and triangles. // Returns the number of A's spheres that collide. // Returned ColPoints are in world space. -// NB: lines do not seem to be supported very well, use with caution +// NB: only vehicles can have col models with lines, exactly 4, one for each wheel int32 CCollision::ProcessColModels(const CMatrix &matrixA, CColModel &modelA, const CMatrix &matrixB, CColModel &modelB, @@ -1333,7 +1333,7 @@ CCollision::DistToLine(const CVector *l0, const CVector *l1, const CVector *poin if(dot >= lensq) return (*point - *l1).Magnitude(); // distance to line - return sqrt((*point - *l0).MagnitudeSqr() - dot*dot/lensq); + return Sqrt((*point - *l0).MagnitudeSqr() - dot*dot/lensq); } // same as above but also return the point on the line @@ -1641,7 +1641,7 @@ CColTrianglePlane::Set(const CVector *v, CColTriangle &tri) normal = CrossProduct(vc-va, vb-va); normal.Normalise(); dist = DotProduct(normal, va); - CVector an(fabs(normal.x), fabs(normal.y), fabs(normal.z)); + CVector an(Abs(normal.x), Abs(normal.y), Abs(normal.z)); // find out largest component and its direction if(an.x > an.y && an.x > an.z) dir = normal.x < 0.0f ? DIR_X_NEG : DIR_X_POS; diff --git a/src/core/Collision.h b/src/core/Collision.h index 5a9058d3..b2fe6564 100644 --- a/src/core/Collision.h +++ b/src/core/Collision.h @@ -147,7 +147,7 @@ public: static bool ProcessSphereTriangle(const CColSphere &sph, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindistsq); static bool ProcessLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough); static bool ProcessVerticalLine(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly); - static int32 ProcessColModels(const CMatrix &matrix1, CColModel &model1, const CMatrix &matrix2, CColModel &model2, CColPoint *point1, CColPoint *point2, float *linedists); + static int32 ProcessColModels(const CMatrix &matrixA, CColModel &modelA, const CMatrix &matrixB, CColModel &modelB, CColPoint *spherepoints, CColPoint *linepoints, float *linedists); // TODO: // CCollision::IsStoredPolyStillValidVerticalLine diff --git a/src/core/ControllerConfig.cpp b/src/core/ControllerConfig.cpp index d7567ac4..e3a586b2 100644 --- a/src/core/ControllerConfig.cpp +++ b/src/core/ControllerConfig.cpp @@ -21,6 +21,7 @@ WRAPPER void CControllerConfigManager::InitDefaultControlConfigJoyPad(unsigned i WRAPPER void CControllerConfigManager::ClearSimButtonPressCheckers() { EAXJMP(0x58D220); } WRAPPER void CControllerConfigManager::AffectPadFromKeyBoard() { EAXJMP(0x58D0C0); } WRAPPER void CControllerConfigManager::AffectPadFromMouse() { EAXJMP(0x58D1A0); } +WRAPPER void CControllerConfigManager::ClearSettingsAssociatedWithAction(int, int) { EAXJMP(0x58EB40); } void CControllerConfigManager::LoadSettings(int32 file) { diff --git a/src/core/ControllerConfig.h b/src/core/ControllerConfig.h index 581efe05..8a434245 100644 --- a/src/core/ControllerConfig.h +++ b/src/core/ControllerConfig.h @@ -50,7 +50,8 @@ public: void ClearSimButtonPressCheckers(); void AffectPadFromKeyBoard(); void AffectPadFromMouse(); - + void ClearSettingsAssociatedWithAction(int, int); + }; VALIDATE_SIZE(CControllerConfigManager, 0x143C); diff --git a/src/core/Explosion.cpp b/src/core/Explosion.cpp new file mode 100644 index 00000000..f55cbcd6 --- /dev/null +++ b/src/core/Explosion.cpp @@ -0,0 +1,5 @@ +#include "common.h" +#include "patcher.h" +#include "Explosion.h" + +WRAPPER void CExplosion::AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type, const CVector &pos, uint32) { EAXJMP(0x5591C0); } diff --git a/src/core/Explosion.h b/src/core/Explosion.h new file mode 100644 index 00000000..69508490 --- /dev/null +++ b/src/core/Explosion.h @@ -0,0 +1,15 @@ +#pragma once + +class CEntity; + +enum eExplosionType +{ + EXPLOSION_3 = 3, + EXPLOSION_4 +}; + +class CExplosion +{ +public: + static void AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type, const CVector &pos, uint32); +}; diff --git a/src/core/FileLoader.cpp b/src/core/FileLoader.cpp index fdc3b9d7..0c53ae66 100644 --- a/src/core/FileLoader.cpp +++ b/src/core/FileLoader.cpp @@ -262,9 +262,9 @@ CFileLoader::LoadCollisionModel(uint8 *buf, CColModel &model, char *modelname) model.vertices = (CVector*)RwMalloc(numVertices*sizeof(CVector)); for(i = 0; i < numVertices; i++){ model.vertices[i] = *(CVector*)buf; - if(fabs(model.vertices[i].x) >= 256.0f || - fabs(model.vertices[i].y) >= 256.0f || - fabs(model.vertices[i].z) >= 256.0f) + if(Abs(model.vertices[i].x) >= 256.0f || + Abs(model.vertices[i].y) >= 256.0f || + Abs(model.vertices[i].z) >= 256.0f) printf("%s:Collision volume too big\n", modelname); buf += 12; } @@ -813,6 +813,7 @@ CFileLoader::LoadPedObject(const char *line) if(strcmp(animGroup, CAnimManager::GetAnimGroupName((AssocGroupId)animGroupId)) == 0) break; mi->m_animGroup = animGroupId; + mi->m_carsCanDrive = carsCanDrive; // ??? CModelInfo::GetModelInfo(MI_LOPOLYGUY)->SetColModel(&CTempColModels::ms_colModelPed1); diff --git a/src/core/Fire.cpp b/src/core/Fire.cpp index 05d72199..bc59de2f 100644 --- a/src/core/Fire.cpp +++ b/src/core/Fire.cpp @@ -2,4 +2,8 @@ #include "patcher.h" #include "Fire.h" -WRAPPER void CFire::Extinguish(void) { EAXJMP(0x479D40); }
\ No newline at end of file +CFireManager &gFireManager = *(CFireManager*)0x8F31D0; + +WRAPPER void CFire::Extinguish(void) { EAXJMP(0x479D40); } + +WRAPPER void CFireManager::StartFire(CEntity *entityOnFire, CEntity *culprit, float, uint32) { EAXJMP(0x479590); } diff --git a/src/core/Fire.h b/src/core/Fire.h index c7f83fd8..9c9e1dec 100644 --- a/src/core/Fire.h +++ b/src/core/Fire.h @@ -1,13 +1,13 @@ #pragma once -#include "common.h" -#include "Entity.h" + +class CEntity; class CFire { - char m_bIsOngoing; - char m_bExists; - char m_bPropogationFlag; - char m_bAudioSet; + bool m_bIsOngoing; + bool m_bExists; + bool m_bPropogationFlag; + bool m_bAudioSet; CVector m_vecPos; CEntity *m_pEntity; CEntity *m_pSource; @@ -20,4 +20,11 @@ class CFire public: void Extinguish(void); -};
\ No newline at end of file +}; + +class CFireManager +{ +public: + void StartFire(CEntity *entityOnFire, CEntity *culprit, float, uint32); +}; +extern CFireManager &gFireManager; diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index fdb2420b..77666b12 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -24,6 +24,10 @@ #include "Vehicle.h" #include "MBlur.h" #include "PlayerSkin.h" +#include "PlayerInfo.h" +#include "World.h" + +#define ALL_ORIGINAL_FRONTEND 1 int32 &CMenuManager::OS_Language = *(int32*)0x5F2F78; int8 &CMenuManager::m_PrefsUseVibration = *(int8*)0x95CD92; @@ -50,7 +54,9 @@ int8 &CMenuManager::m_bFrontEnd_ReloadObrTxtGxt = *(int8*)0x628CFC; int32 &CMenuManager::m_PrefsMusicVolume = *(int32*)0x5F2E4C; int32 &CMenuManager::m_PrefsSfxVolume = *(int32*)0x5F2E48; -uint8 *CMenuManager::m_PrefsSkinFile = (uint8*)0x5F2E74; +char *CMenuManager::m_PrefsSkinFile = (char*)0x5F2E74; + +int32 &CMenuManager::m_KeyPressedCode = *(int32*)0x5F2E70; CMenuManager &FrontEndMenuManager = *(CMenuManager*)0x8F59D8; @@ -58,14 +64,17 @@ CMenuManager &FrontEndMenuManager = *(CMenuManager*)0x8F59D8; float lodMultiplier = *(float*)0x5F726C; // Stuff not in CMenuManager: -int VibrationTime; -char* pEditString; -int32 pControlEdit; -int8 DisplayComboButtonErrMsg; -bool MouseButtonJustClicked; -bool JoyButtonJustClicked; +uint32 &VibrationTime = *(uint32*)0x628CF8; +char* pEditString = (char*)0x628D00; +int32 *&pControlEdit = *(int32**)0x628D08; +bool &DisplayComboButtonErrMsg = *(bool*)0x628D14; +int32 &MouseButtonJustClicked = *(int32*)0x628D0C; +int32 &JoyButtonJustClicked = *(int32*)0x628D10; +int32 &nTimeForSomething = *(int32*)0x628D54; +//int32 *pControlTemp = 0; // Frontend inputs. + bool GetPadBack(); bool GetPadExitEnter(); bool GetPadForward(); @@ -73,6 +82,11 @@ bool GetPadMoveUp(); bool GetPadMoveDown(); bool GetPadMoveLeft(); bool GetPadMoveRight(); +bool GetMouseClickLeft(); +bool GetMouseClickRight(); +bool GetMouseClickMiddle(); +bool GetMouseWheelUp(); +bool GetMouseWheelDown(); bool GetMouseForward(); bool GetMouseBack(); bool GetMousePos(); @@ -135,16 +149,35 @@ char *MenuFilenames[] = { nil, nil }; -#if 1 -WRAPPER void CMenuManager::BuildStatLine(char *, void *, uint16, void *) { EAXJMP(0x483870); } +#if ALL_ORIGINAL_FRONTEND +WRAPPER void CMenuManager::BuildStatLine(char *text, float *stat, bool aFloat, float* stat2) { EAXJMP(0x483870); } #else -void CMenuManager::BuildStatLine(char *, void *, uint16, void *) +void CMenuManager::BuildStatLine(char *text, float *stat, bool aFloat, float* stat2) { + if (!text) + return; + + if (stat2) { + if (aFloat) + sprintf(gString2, " %.2f %s %.2f", *stat, UnicodeToAscii(TheText.Get("FEST_OO")), *stat2); + else + sprintf(gString2, " %d %s %d", *(int*)stat, UnicodeToAscii(TheText.Get("FEST_OO")), *(int*)stat2); + } + else if (stat) { + if (aFloat) + sprintf(gString2, " %.2f", *stat); + else + sprintf(gString2, " %d", *(int*)stat); + } + else + gString2[0] = '\0'; + UnicodeStrcpy(gUString, TheText.Get(text)); + AsciiToUnicode(gString2, gUString2); } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::CentreMousePointer() { EAXJMP(0x48ACE0); } #else void CMenuManager::CentreMousePointer() @@ -164,15 +197,15 @@ void CMenuManager::CentreMousePointer() #endif #if 1 -WRAPPER void CMenuManager::CheckCodesForControls(int, int) { EAXJMP(0x48A950); } +WRAPPER int CMenuManager::CheckCodesForControls(int32) { EAXJMP(0x48A950); } #else -void CMenuManager::CheckCodesForControls() +void CMenuManager::CheckCodesForControls(int, int) { - + DisplayComboButtonErrMsg = 0; } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER bool CMenuManager::CheckHover(int, int, int, int) { EAXJMP(0x48ACA0); } #else bool CMenuManager::CheckHover(int x1, int x2, int y1, int y2) @@ -251,7 +284,7 @@ void CMenuManager::CheckSliderMovement(int value) TheCamera.m_fMouseAccelVertical = fMouseSens; SaveSettings(); break; - }; + } } #if 1 @@ -263,7 +296,7 @@ int CMenuManager::CostructStatLine(int) } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::DisplayHelperText() { EAXJMP(0x48B490); } #else void CMenuManager::DisplayHelperText() @@ -303,7 +336,7 @@ void CMenuManager::DisplayHelperText() break; default: break; - }; + } CFont::SetAlignment(ALIGN_CENTER); CFont::SetScale(SCREEN_SCALE_X(0.4f), SCREEN_SCALE_Y(0.6f)); @@ -316,7 +349,7 @@ void CMenuManager::DisplayHelperText() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER float CMenuManager::DisplaySlider(float, float, float, float, float, float) { EAXJMP(0x488420); } #else float CMenuManager::DisplaySlider(float x, float y, float leftSize, float rightSize, float rectSize, float progress) @@ -342,12 +375,12 @@ float CMenuManager::DisplaySlider(float x, float y, float leftSize, float rightS float _s = SCREEN_SCALE_X(2.0f); CSprite2d::DrawRect(CRect(_x + _s, _y + _s, _w + _s, _h + _s), CRGBA(0, 0, 0, FadeIn(255))); // Shadow CSprite2d::DrawRect(CRect(i * rectSize/16.0f + x, y + sizeRange - ((16 - i) * leftSize + i * rightSize)/16.0f, SCREEN_SCALE_X(10.0f) + i * rectSize/16.0f + x, y + sizeRange), color); - }; + } return input; } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::DoSettingsBeforeStartingAGame() { EAXJMP(0x48AB40); } #else void CMenuManager::DoSettingsBeforeStartingAGame() @@ -366,7 +399,7 @@ void CMenuManager::DoSettingsBeforeStartingAGame() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::Draw() { EAXJMP(0x47AE00); } #else void CMenuManager::Draw() @@ -427,7 +460,7 @@ void CMenuManager::Draw() default: str = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[0].m_EntryName); break; - }; + } CFont::SetDropShadowPosition(MENUDROP_COLOR_SIZE); CFont::SetDropColor(CRGBA(0, 0, 0, FadeIn(MENUDROP_COLOR_A))); @@ -480,7 +513,7 @@ void CMenuManager::Draw() case 3: textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEC_CF4"); break; - }; + } break; case MENUACTION_CTRLDISPLAY: break; @@ -510,7 +543,7 @@ void CMenuManager::Draw() case AR_16_9: textToPrint[MENUCOLUMN_RIGHT] = (wchar*)L"16:9"; break; - }; + } #endif break; case MENUACTION_RADIO: @@ -560,7 +593,7 @@ void CMenuManager::Draw() case 2: textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEA_4SP"); break; - }; + } } break; case MENUACTION_CTRLMETHOD: @@ -571,7 +604,7 @@ void CMenuManager::Draw() case 1: textToPrint[MENUCOLUMN_LEFT] = TheText.Get("FET_CCN"); break; - }; + } break; case MENUACTION_DYNAMICACOUSTIC: textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_PrefsDMA ? "FEM_ON" : "FEM_OFF"); @@ -579,7 +612,7 @@ void CMenuManager::Draw() case MENUACTION_MOUSESTEER: textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_bDisableMouseSteering ? "FEM_ON" : "FEM_OFF"); break; - }; + } CFont::SetDropShadowPosition(MENUDROP_COLOR_SIZE); CFont::SetDropColor(CRGBA(0, 0, 0, FadeIn(MENUDROP_COLOR_A))); @@ -667,7 +700,7 @@ void CMenuManager::Draw() default: vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_MID_Y); break; - }; + } } if (i > 0) @@ -719,9 +752,9 @@ void CMenuManager::Draw() m_nPrevOption = m_nCurrOption; if (GetMouseForward()) - m_nHoverOption = IGNORE_OPTION; + m_nHoverOption = HOVEROPTION_NULL; else - m_nHoverOption = ACTIVATE_OPTION; + m_nHoverOption = HOVEROPTION_DEFAULT; } } } @@ -744,7 +777,7 @@ void CMenuManager::Draw() 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); break; - }; + } // Radio icons. float fIconSpacing = 59.52f; @@ -793,9 +826,9 @@ void CMenuManager::Draw() case MENUPAGE_MOUSE_CONTROLS: DisplayHelperText(); break; - }; + } } - }; + } } #endif @@ -826,7 +859,7 @@ void CMenuManager::DrawControllerSetupScreen() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::DrawFrontEnd(void) { EAXJMP(0x47A540); } #else void CMenuManager::DrawFrontEnd() @@ -850,7 +883,7 @@ void CMenuManager::DrawFrontEnd() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::DrawFrontEndNormal(void) { EAXJMP(0x47A5B0); } #else void CMenuManager::DrawFrontEndNormal() @@ -904,7 +937,7 @@ void CMenuManager::DrawFrontEndNormal() case MENUPAGE_OPTIONS: previousSprite = MENUSPRITE_PLAYERSET; break; - }; + } if (m_nPrevScreen == MENUPAGE_NONE) CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(0, 0, 0, 255)); @@ -949,7 +982,7 @@ void CMenuManager::DrawFrontEndNormal() case MENUPAGE_OPTIONS: currentSprite = MENUSPRITE_PLAYERSET; break; - }; + } uint32 savedShade; uint32 savedAlpha; @@ -993,7 +1026,7 @@ void CMenuManager::DrawFrontEndNormal() default: CMenuManager::Draw(); break; - }; + } CFont::DrawFonts(); @@ -1012,7 +1045,7 @@ void CMenuManager::DrawPlayerSetupScreen() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER int CMenuManager::FadeIn(int alpha) { EAXJMP(0x48AC60); } #else int CMenuManager::FadeIn(int alpha) @@ -1047,7 +1080,7 @@ int CMenuManager::GetStartOptionsCntrlConfigScreens() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::InitialiseChangedLanguageSettings() { EAXJMP(0x47A4D0); } #else void CMenuManager::InitialiseChangedLanguageSettings() @@ -1069,12 +1102,12 @@ void CMenuManager::InitialiseChangedLanguageSettings() break; default: break; - }; + } } } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::LoadAllTextures() { EAXJMP(0x47A230); } #else void CMenuManager::LoadAllTextures() @@ -1110,7 +1143,7 @@ void CMenuManager::LoadAllTextures() for (int i = 0; i < ARRAY_SIZE(FrontendFilenames); i++) { m_aFrontEndSprites[i].SetTexture(FrontendFilenames[i]); m_aFrontEndSprites[i].SetAddressing(rwTEXTUREADDRESSBORDER); - }; + } CTxdStore::PopCurrentTxd(); @@ -1123,7 +1156,7 @@ void CMenuManager::LoadAllTextures() for (int i = 0; i < ARRAY_SIZE(MenuFilenames)/2; i++) { m_aMenuSprites[i].SetTexture(MenuFilenames[i*2], MenuFilenames[i*2+1]); m_aMenuSprites[i].SetAddressing(rwTEXTUREADDRESSBORDER); - }; + } CTxdStore::PopCurrentTxd(); @@ -1132,7 +1165,7 @@ void CMenuManager::LoadAllTextures() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::LoadSettings() { EAXJMP(0x488EE0); } #else void CMenuManager::LoadSettings() @@ -1151,13 +1184,13 @@ void CMenuManager::LoadSettings() 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(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); @@ -1253,7 +1286,7 @@ void CMenuManager::PrintBriefs() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::PrintErrorMessage() { EAXJMP(0x484F70); } #else void CMenuManager::PrintErrorMessage() @@ -1286,22 +1319,31 @@ void CMenuManager::PrintStats() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::Process(void) { EAXJMP(0x485100); } #else void CMenuManager::Process(void) { - if (m_bSaveMenuActive && TheCamera.GetScreenFadeStatus()) + field_112 = 0; + + if (!m_bSaveMenuActive && TheCamera.GetScreenFadeStatus() != FADE_0) return; - field_113 = 0; + m_bStartGameLoading = false; InitialiseChangedLanguageSettings(); + if (CPad::GetPad(0)->GetEscapeJustDown()) + RequestFrontEndStartUp(); + SwitchMenuOnAndOff(); + // Be able to re-open menu correctly. if (m_bMenuActive) { + + // Load frontend textures. LoadAllTextures(); + // Set save/delete game pages. if (m_nCurrScreen == MENUPAGE_DELETING) { bool SlotPopulated = false; @@ -1350,25 +1392,113 @@ void CMenuManager::Process(void) } ProcessButtonPresses(); + + // Set binding keys. + if (pEditString && CPad::EditString(pEditString, 0) == nil) { + if (*pEditString == 0) + strcpy(pEditString, "NoName"); + pEditString = nil; + SaveSettings(); + } + + if (field_113) { + if (field_456) + field_456 = 0; + else { + pControlEdit = CPad::EditCodesForControls(pControlEdit, 1); + JoyButtonJustClicked = 0; + MouseButtonJustClicked = 0; + + if (GetMouseClickLeft()) + MouseButtonJustClicked = 1; + else if (GetMouseClickRight()) + MouseButtonJustClicked = 3; + else if (GetMouseClickMiddle()) + MouseButtonJustClicked = 2; + else if (GetMouseWheelUp()) + MouseButtonJustClicked = 4; + else if (GetMouseWheelDown()) + MouseButtonJustClicked = 5; + //XXX two more buttons + + JoyButtonJustClicked = ControlsManager.GetJoyButtonJustDown(); + + int32 TypeOfControl = 0; + if (JoyButtonJustClicked) + TypeOfControl = 3; + if (MouseButtonJustClicked) + TypeOfControl = 2; + if (*pControlEdit != rsNULL) + TypeOfControl = 0; + + if (!field_534) { + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_FAIL, 0); + pControlEdit = nil; + field_113 = 0; + m_KeyPressedCode = -1; + field_456 = 0; + } + else if (!m_bKeyChangeNotProcessed) { + if (*pControlEdit != rsNULL || MouseButtonJustClicked || JoyButtonJustClicked) + CheckCodesForControls(TypeOfControl); + + field_535 = 1; + } + else { + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0); + for (int i = 0; i < 4; i++) + ControlsManager.ClearSettingsAssociatedWithAction(m_CurrCntrlAction, i); + field_534 = false; + m_bKeyChangeNotProcessed = false; + pControlEdit = nil; + field_113 = 0; + m_KeyPressedCode = -1; + field_456 = 0; + } + } + } + + if ((m_nCurrScreen == MENUPAGE_13 || m_nCurrScreen == MENUPAGE_16) && CTimer::GetTimeInMillisecondsPauseMode() > field_558) { + m_nCurrScreen = m_nPrevScreen; + m_nCurrOption = 0; + } + + // Reset pad shaking. + if (VibrationTime && CTimer::GetTimeInMillisecondsPauseMode() > VibrationTime) { + CPad::StopPadsShaking(); + VibrationTime = 0; + } } else { - if (GetPadExitEnter()) - RequestFrontEndStartUp(); - UnloadTextures(); - m_nPrevScreen = MENUPAGE_NONE; + field_452 = 0; + *(bool*)0x5F33E4 = true; + // byte_5F33E4 = 1; // unused + m_nPrevScreen = 0; m_nCurrScreen = m_nPrevScreen; - m_nCurrOption = MENUROW_0; + m_nCurrOption = 0; + pEditString = nil; + field_113 = 0; + } + + if (!m_bStartGameLoading) { + if (m_bGameNotLoaded) + DMAudio.Service(); } } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::ProcessButtonPresses() { EAXJMP(0x4856F0); } #else void CMenuManager::ProcessButtonPresses() { - // Update Mouse Position + if(pEditString) + return; + if(pControlEdit) + return; + + // Update mouse position m_nMouseOldPosX = m_nMousePosX; m_nMouseOldPosY = m_nMousePosY; @@ -1390,6 +1520,70 @@ void CMenuManager::ProcessButtonPresses() else if (GetPadInput()) 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_KEYBOARD_CONTROLS) { + field_440 = m_ControlMethod ? 30 : 25; + + if (field_44C > field_440) + field_44C = field_440 - 1; + } + + if (!GetPadBack() || m_nCurrScreen != MENUPAGE_KEYBOARD_CONTROLS || field_535) + field_535 = 0; + else if (field_536 == 19) { + m_nHoverOption = 42; + field_113 = 1; + field_456 = 1; + m_bKeyChangeNotProcessed = 1; + pControlEdit = &m_KeyPressedCode; + } + + if (GetPadForward()) { + switch (field_536) { + case 19: + if (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) { + field_113 = 1; + field_456 = 1; + pControlEdit = &m_KeyPressedCode; + } + if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) { + strcpy(m_PrefsSkinFile, m_aSkinName); + CWorld::Players->SetPlayerSkin(m_PrefsSkinFile); + field_536 = 9; + } + + m_nHoverOption = HOVEROPTION_NULL; + SaveSettings(); + break; + case 21: + strcpy(m_PrefsSkinFile, m_aSkinName); + CWorld::Players->SetPlayerSkin(m_PrefsSkinFile); + field_536 = 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. uint8 NumberOfMenuOptions = GetNumberOfMenuOptions(); @@ -1436,29 +1630,54 @@ void CMenuManager::ProcessButtonPresses() RequestFrontEndShutdown(); PlayEscSound = true; break; + case MENUPAGE_KEYBOARD_CONTROLS: + if (!m_bKeyChangeNotProcessed) { + m_bKeyChangeNotProcessed = true; + field_534 = 0; + } + else + SwitchToNewScreen(aScreens[m_nCurrScreen].m_PreviousPage[0]); + break; default: SwitchToNewScreen(aScreens[m_nCurrScreen].m_PreviousPage[0]); PlayEscSound = true; break; - }; + } if (PlayEscSound) DMAudio.PlayFrontEndSound(SOUND_FRONTEND_EXIT, 0); } - // TODO: finish hover options. - // Set mouse buttons. + // Set hover options, how it is supposed to be used isn't really clear yet. if (GetMouseForward()) { switch (m_nHoverOption) { - case ACTIVATE_OPTION: + case HOVEROPTION_DEFAULT: if (m_nCurrOption || m_nCurrScreen != MENUPAGE_PAUSE_MENU) m_nCurrOption = m_nPrevOption; - m_nHoverOption = ACTIVATE_OPTION; + m_nHoverOption = HOVEROPTION_DEFAULT; + break; + case HOVEROPTION_12: + m_nHoverOption = HOVEROPTION_14; + break; + case HOVEROPTION_13: + m_nHoverOption = HOVEROPTION_15; + break; + case HOVEROPTION_19: + m_nHoverOption = HOVEROPTION_20; + break; + case HOVEROPTION_CHANGESKIN: + if (m_nSkinsTotal > 0) { + m_pSelectedSkin = m_sSkin.field_304; + strcpy(m_PrefsSkinFile, m_aSkinName); + CWorld::Players->SetPlayerSkin(m_PrefsSkinFile); + SaveSettings(); + } break; default: + m_nHoverOption = HOVEROPTION_NULL; break; - }; + } } // Process all menu options here, but first check if it's an option or a redirect. @@ -1494,19 +1713,11 @@ void CMenuManager::ProcessButtonPresses() break; default: break; - }; - - // Reset pad shaking. - if (VibrationTime != 0) { - if (CTimer::GetTimeInMillisecondsPauseMode() > VibrationTime) { - CPad::GetPad(0)->StopShaking(0); - VibrationTime = 0; - } } } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::ProcessOnOffMenuOptions() { EAXJMP(0x48AE60); } #else void CMenuManager::ProcessOnOffMenuOptions() @@ -1567,7 +1778,7 @@ void CMenuManager::ProcessOnOffMenuOptions() case AR_16_9: m_PrefsUseWideScreen = AR_AUTO; break; - }; + } } else { switch (m_PrefsUseWideScreen) { @@ -1580,7 +1791,7 @@ void CMenuManager::ProcessOnOffMenuOptions() case AR_16_9: m_PrefsUseWideScreen = AR_4_3; break; - }; + } } #endif SaveSettings(); @@ -1683,6 +1894,9 @@ void CMenuManager::ProcessOnOffMenuOptions() case MENUACTION_UPDATEMEMCARDSAVE: RequestFrontEndShutdown(); break; + case MENUACTION_GETKEY: + //*pControlEdit = m_KeyPressedCode; + break; case MENUACTION_INVVERT: MousePointerStateHelper.bInvertVertically = MousePointerStateHelper.bInvertVertically == false; return; @@ -1823,7 +2037,7 @@ void CMenuManager::ProcessOnOffMenuOptions() case 2: m_PrefsSpeakers = 0; break; - }; + } } else { switch (m_PrefsSpeakers) { @@ -1836,7 +2050,7 @@ void CMenuManager::ProcessOnOffMenuOptions() case 2: m_PrefsSpeakers = 1; break; - }; + } } DMAudio.SetSpeakerConfig(m_PrefsSpeakers); @@ -1864,11 +2078,11 @@ void CMenuManager::ProcessOnOffMenuOptions() case MENUACTION_MOUSESTEER: m_bDisableMouseSteering = m_bDisableMouseSteering == false; return; - }; + } } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::RequestFrontEndShutdown() { EAXJMP(0x488750); } #else void CMenuManager::RequestFrontEndShutdown() @@ -1878,7 +2092,7 @@ void CMenuManager::RequestFrontEndShutdown() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::RequestFrontEndStartUp() { EAXJMP(0x488770); } #else void CMenuManager::RequestFrontEndStartUp() @@ -1887,7 +2101,7 @@ void CMenuManager::RequestFrontEndStartUp() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::ResetHelperText() { EAXJMP(0x48B470); } #else void CMenuManager::ResetHelperText() @@ -1897,7 +2111,7 @@ void CMenuManager::ResetHelperText() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::SaveLoadFileError_SetUpErrorScreen() { EAXJMP(0x488930); } #else void CMenuManager::SaveLoadFileError_SetUpErrorScreen() @@ -1940,8 +2154,8 @@ void CMenuManager::SaveLoadFileError_SetUpErrorScreen() } #endif -#if 0 -WRAPPER void CMenuManager::SetHelperText() { EAXJMP(0x48B450); } +#if ALL_ORIGINAL_FRONTEND +WRAPPER void CMenuManager::SetHelperText(int text) { EAXJMP(0x48B450); } #else void CMenuManager::SetHelperText(int text) { @@ -1950,7 +2164,7 @@ void CMenuManager::SetHelperText(int text) } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::SaveSettings() { EAXJMP(0x488CC0); } #else void CMenuManager::SaveSettings() @@ -1997,7 +2211,7 @@ void CMenuManager::SaveSettings() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::ShutdownJustMenu() { EAXJMP(0x488920); } #else void CMenuManager::ShutdownJustMenu() @@ -2008,7 +2222,7 @@ void CMenuManager::ShutdownJustMenu() #endif // We won't ever use this again. -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER float CMenuManager::StretchX(float) { EAXJMP(0x48ABE0); } #else float CMenuManager::StretchX(float x) @@ -2020,7 +2234,7 @@ float CMenuManager::StretchX(float x) } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER float CMenuManager::StretchY(float) { EAXJMP(0x48AC20); } #else float CMenuManager::StretchY(float y) @@ -2032,7 +2246,7 @@ float CMenuManager::StretchY(float y) } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::SwitchMenuOnAndOff() { EAXJMP(0x488790); } #else void CMenuManager::SwitchMenuOnAndOff() @@ -2054,7 +2268,7 @@ void CMenuManager::SwitchMenuOnAndOff() ShutdownJustMenu(); SaveSettings(); m_bStartUpFrontEndRequested = false; - pControlEdit = 0; + pControlEdit = nil; m_bShutDownFrontEndRequested = false; DisplayComboButtonErrMsg = 0; CPad::GetPad(0)->Clear(0); @@ -2078,7 +2292,7 @@ void CMenuManager::SwitchMenuOnAndOff() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::UnloadTextures() { EAXJMP(0x47A440); } #else void CMenuManager::UnloadTextures() @@ -2103,7 +2317,7 @@ void CMenuManager::UnloadTextures() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::WaitForUserCD(void) { EAXJMP(0x48ADD0); } #else void CMenuManager::WaitForUserCD() @@ -2131,7 +2345,7 @@ uint8 CMenuManager::GetNumberOfMenuOptions() break; ++Rows; - }; + } return Rows; } @@ -2204,7 +2418,7 @@ void CMenuManager::SetDefaultPreferences(int8 screen) m_PrefsVsync = true; m_PrefsLOD = 1.2f; m_PrefsVsyncDisp = true; - lodMultiplier = 1.2; + lodMultiplier = 1.2f; CMBlur::BlurOn = true; CMBlur::MotionBlurOpen(Scene.camera); m_PrefsUseVibration = false; @@ -2230,7 +2444,7 @@ void CMenuManager::SetDefaultPreferences(int8 screen) CVehicle::m_bDisableMouseSteering = true; TheCamera.m_bHeadBob = false; break; - }; + } } // Frontend inputs. @@ -2261,7 +2475,7 @@ bool GetPadMoveUp() return (CPad::GetPad(0)->NewState.DPadUp && !CPad::GetPad(0)->OldState.DPadUp) || (CPad::GetPad(0)->NewKeyState.UP && !CPad::GetPad(0)->OldKeyState.UP) || - (CPad::GetPad(0)->NewState.LeftStickY < 0 && !CPad::GetPad(0)->OldState.LeftStickY < 0); + (CPad::GetPad(0)->NewState.LeftStickY < 0 && !(CPad::GetPad(0)->OldState.LeftStickY < 0)); } bool GetPadMoveDown() @@ -2269,7 +2483,7 @@ bool GetPadMoveDown() 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); + (CPad::GetPad(0)->NewState.LeftStickY > 0 && !(CPad::GetPad(0)->OldState.LeftStickY > 0)); } bool GetPadMoveLeft() @@ -2277,7 +2491,7 @@ bool GetPadMoveLeft() return (CPad::GetPad(0)->NewState.DPadLeft && !CPad::GetPad(0)->OldState.DPadLeft) || (CPad::GetPad(0)->NewKeyState.LEFT && !CPad::GetPad(0)->OldKeyState.LEFT) || - (CPad::GetPad(0)->NewState.LeftStickX < 0 && !CPad::GetPad(0)->OldState.LeftStickX < 0); + (CPad::GetPad(0)->NewState.LeftStickX < 0 && !(CPad::GetPad(0)->OldState.LeftStickX < 0)); } bool GetPadMoveRight() @@ -2285,21 +2499,50 @@ bool GetPadMoveRight() return (CPad::GetPad(0)->NewState.DPadRight && !CPad::GetPad(0)->OldState.DPadRight) || (CPad::GetPad(0)->NewKeyState.RIGHT && !CPad::GetPad(0)->OldKeyState.RIGHT) || - (CPad::GetPad(0)->NewState.LeftStickX > 0 && !CPad::GetPad(0)->OldState.LeftStickX > 0); + (CPad::GetPad(0)->NewState.LeftStickX > 0 && !(CPad::GetPad(0)->OldState.LeftStickX > 0)); } -bool GetMouseForward() +bool GetMouseClickLeft() { return (CPad::GetPad(0)->NewMouseControllerState.LMB && !CPad::GetPad(0)->OldMouseControllerState.LMB); } -bool GetMouseBack() +bool GetMouseClickRight() { return (CPad::GetPad(0)->NewMouseControllerState.RMB && !CPad::GetPad(0)->OldMouseControllerState.RMB); } +bool GetMouseClickMiddle() +{ + return + (CPad::GetPad(0)->NewMouseControllerState.MMB && !CPad::GetPad(0)->OldMouseControllerState.MMB); +} + +bool GetMouseWheelUp() +{ + return + (CPad::GetPad(0)->NewMouseControllerState.WHEELUP && !CPad::GetPad(0)->OldMouseControllerState.WHEELUP); +} + +bool GetMouseWheelDown() +{ + return + (CPad::GetPad(0)->NewMouseControllerState.WHEELDN && !CPad::GetPad(0)->OldMouseControllerState.WHEELDN); +} + + +bool GetMouseForward() +{ + return GetMouseClickLeft(); +} + +bool GetMouseBack() +{ + return GetMouseClickRight; +} + bool GetMousePos() { return @@ -2308,14 +2551,12 @@ bool GetMousePos() bool GetMouseMoveLeft() { - return - (CPad::GetPad(0)->NewMouseControllerState.WHEELDN && !CPad::GetPad(0)->OldMouseControllerState.WHEELDN != 0.0f); + return GetMouseWheelDown(); } bool GetMouseMoveRight() { - return - (CPad::GetPad(0)->NewMouseControllerState.WHEELUP && !CPad::GetPad(0)->OldMouseControllerState.WHEELUP != 0.0f); + return GetMouseWheelUp(); } bool GetPadInput() @@ -2340,6 +2581,7 @@ bool GetMouseInput() } STARTPATCHES +#ifndef ALL_ORIGINAL_FRONTEND InjectHook(0x47A230, &CMenuManager::LoadAllTextures, PATCH_JUMP); InjectHook(0x47A440, &CMenuManager::UnloadTextures, PATCH_JUMP); InjectHook(0x485100, &CMenuManager::Process, PATCH_JUMP); @@ -2350,4 +2592,5 @@ STARTPATCHES for (int i = 1; i < ARRAY_SIZE(aScreens); i++) Patch(0x611930 + sizeof(CMenuScreen) * i, aScreens[i]); +#endif ENDPATCHES
\ No newline at end of file diff --git a/src/core/Frontend.h b/src/core/Frontend.h index 9b9377da..9a3cdd50 100644 --- a/src/core/Frontend.h +++ b/src/core/Frontend.h @@ -306,8 +306,29 @@ enum eMenuAction enum eCheckHover { - ACTIVATE_OPTION = 2, - IGNORE_OPTION = 42, + HOVEROPTION_0, + HOVEROPTION_1, + HOVEROPTION_DEFAULT, + HOVEROPTION_3, + HOVEROPTION_4, + HOVEROPTION_5, + HOVEROPTION_6, + HOVEROPTION_7, + HOVEROPTION_8, + HOVEROPTION_9, + HOVEROPTION_10, + HOVEROPTION_11, + HOVEROPTION_12, + HOVEROPTION_13, + HOVEROPTION_14, + HOVEROPTION_15, + HOVEROPTION_16, + HOVEROPTION_17, + HOVEROPTION_18, + HOVEROPTION_19, + HOVEROPTION_20, + HOVEROPTION_CHANGESKIN, + HOVEROPTION_NULL = 42, }; enum eMenuColumns @@ -348,7 +369,7 @@ struct tSkinInfo char skinName[256]; char currSkinName[256]; char date[256]; - int field_304; + tSkinInfo *field_304; }; struct CMenuScreen @@ -388,7 +409,7 @@ public: int32 m_nMouseTempPosX; int32 m_nMouseTempPosY; bool m_bShowMouse; - tSkinInfo field_12C; + tSkinInfo m_sSkin; tSkinInfo *m_pSelectedSkin; tSkinInfo *field_438; float field_43C; @@ -427,7 +448,7 @@ public: int m_nCurrOption; int m_nPrevOption; int m_nPrevScreen; - int field_558; + uint32 field_558; int m_nCurrSaveSlot; int m_nScreenChangeDelayTimer; @@ -450,16 +471,17 @@ public: static int8 &m_bFrontEnd_ReloadObrTxtGxt; static int32 &m_PrefsMusicVolume; static int32 &m_PrefsSfxVolume; - static uint8 *m_PrefsSkinFile; + static char *m_PrefsSkinFile; + static int32 &m_KeyPressedCode; static bool &m_bStartUpFrontEndRequested; static bool &m_bShutDownFrontEndRequested; static bool &m_PrefsAllowNastyGame; public: - void BuildStatLine(char *, void *, uint16, void *); + void BuildStatLine(char *text, float *stat, bool aFloat, float* stat2); static void CentreMousePointer(); - void CheckCodesForControls(int, int); + int CheckCodesForControls(int32); bool CheckHover(int x1, int x2, int y1, int y2); void CheckSliderMovement(int); int CostructStatLine(int); diff --git a/src/core/General.h b/src/core/General.h index cae1caa0..64613478 100644 --- a/src/core/General.h +++ b/src/core/General.h @@ -6,32 +6,32 @@ public: static float GetATanOfXY(float x, float y){ if(x == 0.0f && y == 0.0f) return 0.0f; - float xabs = fabs(x); - float yabs = fabs(y); + float xabs = Abs(x); + float yabs = Abs(y); if(xabs < yabs){ if(y > 0.0f){ if(x > 0.0f) - return 0.5f*PI - atan2(x / y, 1.0f); + return 0.5f*PI - Atan2(x / y, 1.0f); else - return 0.5f*PI + atan2(-x / y, 1.0f); + return 0.5f*PI + Atan2(-x / y, 1.0f); }else{ if(x > 0.0f) - return 1.5f*PI + atan2(x / -y, 1.0f); + return 1.5f*PI + Atan2(x / -y, 1.0f); else - return 1.5f*PI - atan2(-x / -y, 1.0f); + return 1.5f*PI - Atan2(-x / -y, 1.0f); } }else{ if(y > 0.0f){ if(x > 0.0f) - return atan2(y / x, 1.0f); + return Atan2(y / x, 1.0f); else - return PI - atan2(y / -x, 1.0f); + return PI - Atan2(y / -x, 1.0f); }else{ if(x > 0.0f) - return 2.0f*PI - atan2(-y / x, 1.0f); + return 2.0f*PI - Atan2(-y / x, 1.0f); else - return PI + atan2(-y / -x, 1.0f); + return PI + Atan2(-y / -x, 1.0f); } } } @@ -68,14 +68,14 @@ public: if (x > 0.0f) { if (y > 0.0f) - return PI - atan2(x / y, 1.0f); + return PI - Atan2(x / y, 1.0f); else - return -atan2(x / y, 1.0f); + return -Atan2(x / y, 1.0f); } else { if (y > 0.0f) - return -(PI + atan2(x / y, 1.0f)); + return -(PI + Atan2(x / y, 1.0f)); else - return -atan2(x / y, 1.0f); + return -Atan2(x / y, 1.0f); } } diff --git a/src/core/Instance.cpp b/src/core/Instance.cpp new file mode 100644 index 00000000..5426605f --- /dev/null +++ b/src/core/Instance.cpp @@ -0,0 +1,13 @@ +#include "common.h" +#include "patcher.h" +#include "Instance.h" + +class CInstance_ : public CInstance +{ +public: + void dtor() { CInstance::~CInstance(); } +}; + +STARTPATCHES + InjectHook(0x50BE90, &CInstance_::dtor, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/Instance.h b/src/core/Instance.h new file mode 100644 index 00000000..1038c005 --- /dev/null +++ b/src/core/Instance.h @@ -0,0 +1,10 @@ +#pragma once + +#include "Placeable.h" + +// unused + +class CInstance : CPlaceable +{ +public: +}; diff --git a/src/core/MenuScreens.h b/src/core/MenuScreens.h index 2da81f1d..866dfc03 100644 --- a/src/core/MenuScreens.h +++ b/src/core/MenuScreens.h @@ -43,7 +43,7 @@ const CMenuScreen aScreens[] = { { "FET_DIS", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_2, MENUROW_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, + MENUACTION_FRAMESYNC, "FEM_VSC", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, MENUACTION_FRAMELIMIT, "FEM_FRM", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, MENUACTION_TRAILS, "FED_TRA", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, MENUACTION_SUBTITLES, "FED_SUB", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, @@ -273,7 +273,7 @@ const CMenuScreen aScreens[] = { MENUACTION_CHANGEMENU, "FET_AUD", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, MENUACTION_CHANGEMENU, "FET_DIS", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, MENUACTION_CHANGEMENU, "FET_LAN", SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS, - //MENUACTION_CHANGEMENU, "FET_PSU", SAVESLOT_NONE, MENUPAGE_SKIN_SELECT, + MENUACTION_CHANGEMENU, "FET_PSU", SAVESLOT_NONE, MENUPAGE_SKIN_SELECT, MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, }, diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp index 002e7180..9c5e1c8a 100644 --- a/src/core/Pad.cpp +++ b/src/core/Pad.cpp @@ -670,7 +670,7 @@ int16 CPad::GetSteeringLeftRight(void) int16 axis = NewState.LeftStickX; int16 dpad = (NewState.DPadRight - NewState.DPadLeft) / 2; - if ( abs(axis) > abs(dpad) ) + if ( Abs(axis) > Abs(dpad) ) return axis; else return dpad; @@ -703,7 +703,7 @@ int16 CPad::GetSteeringUpDown(void) int16 axis = NewState.LeftStickY; int16 dpad = (NewState.DPadUp - NewState.DPadDown) / 2; - if ( abs(axis) > abs(dpad) ) + if ( Abs(axis) > Abs(dpad) ) return axis; else return dpad; @@ -790,7 +790,7 @@ int16 CPad::GetPedWalkLeftRight(void) int16 axis = NewState.LeftStickX; int16 dpad = (NewState.DPadRight - NewState.DPadLeft) / 2; - if ( abs(axis) > abs(dpad) ) + if ( Abs(axis) > Abs(dpad) ) return axis; else return dpad; @@ -824,7 +824,7 @@ int16 CPad::GetPedWalkUpDown(void) int16 axis = NewState.LeftStickY; int16 dpad = (NewState.DPadDown - NewState.DPadUp) / 2; - if ( abs(axis) > abs(dpad) ) + if ( Abs(axis) > Abs(dpad) ) return axis; else return dpad; @@ -854,7 +854,7 @@ int16 CPad::GetAnalogueUpDown(void) int16 axis = NewState.LeftStickY; int16 dpad = (NewState.DPadDown - NewState.DPadUp) / 2; - if ( abs(axis) > abs(dpad) ) + if ( Abs(axis) > Abs(dpad) ) return axis; else return dpad; @@ -1683,7 +1683,7 @@ int16 CPad::SniperModeLookLeftRight(void) int16 axis = NewState.LeftStickX; int16 dpad = (NewState.DPadRight - NewState.DPadLeft) / 2; - if ( abs(axis) > abs(dpad) ) + if ( Abs(axis) > Abs(dpad) ) return axis; else return dpad; @@ -1694,7 +1694,7 @@ int16 CPad::SniperModeLookUpDown(void) int16 axis = NewState.LeftStickY; int16 dpad = (NewState.DPadUp - NewState.DPadDown) / 2; - if ( abs(axis) > abs(dpad) ) + if ( Abs(axis) > Abs(dpad) ) return axis; else return dpad; @@ -1704,11 +1704,11 @@ int16 CPad::LookAroundLeftRight(void) { float axis = GetPad(0)->NewState.RightStickX; - if ( fabs(axis) > 85 && !GetLookBehindForPed() ) + if ( Abs(axis) > 85 && !GetLookBehindForPed() ) return (int16) ( (axis + ( ( axis > 0 ) ? -85 : 85) ) * (127.0f / 32.0f) ); // 3.96875f - else if ( TheCamera.Cams[0].Using3rdPersonMouseCam() && fabs(axis) > 10 ) + else if ( TheCamera.Cams[0].Using3rdPersonMouseCam() && Abs(axis) > 10 ) return (int16) ( (axis + ( ( axis > 0 ) ? -10 : 10) ) * (127.0f / 64.0f) ); // 1.984375f @@ -1719,11 +1719,11 @@ int16 CPad::LookAroundUpDown(void) { int16 axis = GetPad(0)->NewState.RightStickY; - if ( abs(axis) > 85 && !GetLookBehindForPed() ) + if ( Abs(axis) > 85 && !GetLookBehindForPed() ) return (int16) ( (axis + ( ( axis > 0 ) ? -85 : 85) ) * (127.0f / 32.0f) ); // 3.96875f - else if ( TheCamera.Cams[0].Using3rdPersonMouseCam() && abs(axis) > 40 ) + else if ( TheCamera.Cams[0].Using3rdPersonMouseCam() && Abs(axis) > 40 ) return (int16) ( (axis + ( ( axis > 0 ) ? -40 : 40) ) * (127.0f / 64.0f) ); // 1.984375f diff --git a/src/core/Placeable.cpp b/src/core/Placeable.cpp index b4b2a37b..c1fe705e 100644 --- a/src/core/Placeable.cpp +++ b/src/core/Placeable.cpp @@ -63,9 +63,17 @@ CPlaceable::IsWithinArea(float x1, float y1, float z1, float x2, float y2, float z1 <= GetPosition().z && GetPosition().z <= z2; } +class CPlaceable_ : public CPlaceable +{ +public: + CPlaceable *ctor(void) { return ::new (this) CPlaceable(); } + void dtor(void) { CPlaceable::~CPlaceable(); } +}; + STARTPATCHES - InjectHook(0x49F9A0, &CPlaceable::ctor, PATCH_JUMP); - InjectHook(0x49F9E0, &CPlaceable::dtor, PATCH_JUMP); + InjectHook(0x49F9A0, &CPlaceable_::ctor, PATCH_JUMP); + InjectHook(0x49F9E0, &CPlaceable_::dtor, PATCH_JUMP); + InjectHook(0x49FA00, &CPlaceable::SetHeading, PATCH_JUMP); InjectHook(0x49FA50, (bool (CPlaceable::*)(float, float, float, float))&CPlaceable::IsWithinArea, PATCH_JUMP); InjectHook(0x49FAF0, (bool (CPlaceable::*)(float, float, float, float, float, float))&CPlaceable::IsWithinArea, PATCH_JUMP); diff --git a/src/core/Placeable.h b/src/core/Placeable.h index 868ca9e7..648b315c 100644 --- a/src/core/Placeable.h +++ b/src/core/Placeable.h @@ -10,17 +10,19 @@ public: CPlaceable(void); virtual ~CPlaceable(void); - CVector &GetPosition(void) { return *m_matrix.GetPosition(); } - CVector &GetRight(void) { return *m_matrix.GetRight(); } - CVector &GetForward(void) { return *m_matrix.GetForward(); } - CVector &GetUp(void) { return *m_matrix.GetUp(); } + CVector &GetPosition(void) { return m_matrix.GetPosition(); } + CVector &GetRight(void) { return m_matrix.GetRight(); } + CVector &GetForward(void) { return m_matrix.GetForward(); } + CVector &GetUp(void) { return m_matrix.GetUp(); } CMatrix &GetMatrix(void) { return m_matrix; } void SetTransform(RwMatrix *m) { m_matrix = CMatrix(m, false); } void SetHeading(float angle); + void SetOrientation(float x, float y, float z){ + CVector pos = m_matrix.GetPosition(); + m_matrix.SetRotate(x, y, z); + m_matrix.Translate(pos); + } bool IsWithinArea(float x1, float y1, float x2, float y2); bool IsWithinArea(float x1, float y1, float z1, float x2, float y2, float z2); - - CPlaceable *ctor(void) { return ::new (this) CPlaceable(); } - void dtor(void) { this->CPlaceable::~CPlaceable(); } }; static_assert(sizeof(CPlaceable) == 0x4C, "CPlaceable: error"); diff --git a/src/core/PlayerInfo.cpp b/src/core/PlayerInfo.cpp index 59efe2ae..81c7a199 100644 --- a/src/core/PlayerInfo.cpp +++ b/src/core/PlayerInfo.cpp @@ -1,5 +1,14 @@ #include "common.h" #include "patcher.h" #include "PlayerInfo.h" +#include "Frontend.h" -WRAPPER void CPlayerInfo::MakePlayerSafe(bool) { EAXJMP(0x4A1400); }
\ No newline at end of file +WRAPPER void CPlayerInfo::MakePlayerSafe(bool) { EAXJMP(0x4A1400); } +WRAPPER void CPlayerInfo::LoadPlayerSkin() { EAXJMP(0x4A1700); } +WRAPPER void CPlayerInfo::AwardMoneyForExplosion(CVehicle *vehicle) { EAXJMP(0x4A15F0); } + +void CPlayerInfo::SetPlayerSkin(char *skin) +{ + strncpy(m_aSkinName, skin, 32); + LoadPlayerSkin(); +} diff --git a/src/core/PlayerInfo.h b/src/core/PlayerInfo.h index e2b42fe7..d8128424 100644 --- a/src/core/PlayerInfo.h +++ b/src/core/PlayerInfo.h @@ -63,10 +63,13 @@ public: bool m_bFastReload; bool m_bGetOutOfJailFree; bool m_bGetOutOfHospitalFree; - uint8 m_aSkinName[32]; + char m_aSkinName[32]; RwTexture *m_pSkinTexture; void MakePlayerSafe(bool); + void LoadPlayerSkin(); + void AwardMoneyForExplosion(CVehicle *vehicle); + void SetPlayerSkin(char* skin); }; static_assert(sizeof(CPlayerInfo) == 0x13C, "CPlayerInfo: error"); diff --git a/src/core/Radar.cpp b/src/core/Radar.cpp index a071b96b..ea7a7ffa 100644 --- a/src/core/Radar.cpp +++ b/src/core/Radar.cpp @@ -469,8 +469,8 @@ void CRadar::DrawRadarMask() // Then generate a quarter of the circle for (int j = 0; j < 7; j++) { - in.x = corners[i].x * cos(j * (PI / 2.0f / 6.0f)); - in.y = corners[i].y * sin(j * (PI / 2.0f / 6.0f)); + in.x = corners[i].x * Cos(j * (PI / 2.0f / 6.0f)); + in.y = corners[i].y * Sin(j * (PI / 2.0f / 6.0f)); TransformRadarPointToScreenSpace(out[j + 1], in); }; @@ -562,8 +562,8 @@ void CRadar::DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float for (uint32 i = 0; i < 4; i++) { oldPosn[i] = curPosn[i]; - curPosn[i].x = x + (oldPosn[i].x - x) * cosf(angle) + (oldPosn[i].y - y) * sinf(angle); - curPosn[i].y = y - (oldPosn[i].x - x) * sinf(angle) + (oldPosn[i].y - y) * cosf(angle); + curPosn[i].x = x + (oldPosn[i].x - x) * Cos(angle) + (oldPosn[i].y - y) * Sin(angle); + curPosn[i].y = y - (oldPosn[i].x - x) * Sin(angle) + (oldPosn[i].y - y) * Cos(angle); } sprite->Draw(curPosn[2].x, curPosn[2].y, curPosn[3].x, curPosn[3].y, curPosn[0].x, curPosn[0].y, curPosn[1].x, curPosn[1].y, CRGBA(255, 255, 255, alpha)); @@ -868,8 +868,8 @@ void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D { float s, c; - s = -sin(TheCamera.GetForward().Heading()); - c = cos(TheCamera.GetForward().Heading()); + s = -Sin(TheCamera.GetForward().Heading()); + c = Cos(TheCamera.GetForward().Heading()); if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN1 || TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWNPED) { s = 0.0f; @@ -885,8 +885,8 @@ void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D else forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].SourceBeforeLookBehind; - s = -sin(forward.Heading()); - c = cos(forward.Heading()); + s = -Sin(forward.Heading()); + c = Cos(forward.Heading()); } out.x = s * in.y + c * in.x; @@ -915,8 +915,8 @@ void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D c = 1.0f; } else if (TheCamera.GetLookDirection() == LOOKING_FORWARD) { - s = sin(TheCamera.GetForward().Heading()); - c = cos(TheCamera.GetForward().Heading()); + s = Sin(TheCamera.GetForward().Heading()); + c = Cos(TheCamera.GetForward().Heading()); } else { CVector forward; @@ -928,8 +928,8 @@ void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D else forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].SourceBeforeLookBehind; - s = sin(forward.Heading()); - c = cos(forward.Heading()); + s = Sin(forward.Heading()); + c = Cos(forward.Heading()); } float x = (in.x - vec2DRadarOrigin.x) * (1.0f / m_RadarRange); diff --git a/src/core/Stats.cpp b/src/core/Stats.cpp index 3c5b55e4..921586bb 100644 --- a/src/core/Stats.cpp +++ b/src/core/Stats.cpp @@ -1,6 +1,13 @@ #include "common.h" #include "Stats.h" -int32& CStats::DaysPassed = *(int32*)0x8F2BB8; -int32& CStats::HeadShots = *(int32*)0x8F647C; -bool& CStats::CommercialPassed = *(bool*)0x8F4334;
\ No newline at end of file +int32 &CStats::DaysPassed = *(int32*)0x8F2BB8; +int32 &CStats::HeadShots = *(int32*)0x8F647C; +bool& CStats::CommercialPassed = *(bool*)0x8F4334; +int32 &CStats::NumberKillFrenziesPassed = *(int32*)0x8E287C; +int32 &CStats::PeopleKilledByOthers = *(int32*)0x8E2C50; + +void CStats::AnotherKillFrenzyPassed() +{ + ++NumberKillFrenziesPassed; +}
\ No newline at end of file diff --git a/src/core/Stats.h b/src/core/Stats.h index 39b0e184..30058a59 100644 --- a/src/core/Stats.h +++ b/src/core/Stats.h @@ -3,7 +3,12 @@ class CStats { public: - static int32& DaysPassed; - static int32& HeadShots; + static int32 &DaysPassed; + static int32 &HeadShots; static bool& CommercialPassed; + static int32 &NumberKillFrenziesPassed; + static int32 &PeopleKilledByOthers; + +public: + static void AnotherKillFrenzyPassed(); };
\ No newline at end of file diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp index f8ab19d4..a23e35be 100644 --- a/src/core/Streaming.cpp +++ b/src/core/Streaming.cpp @@ -2131,8 +2131,8 @@ CStreaming::DeleteRwObjectsAfterDeath(const CVector &pos) for(x = 0; x < NUMSECTORS_X; x++) for(y = 0; y < NUMSECTORS_Y; y++) - if(fabs(ix - x) > 3.0f && - fabs(iy - y) > 3.0f){ + if(Abs(ix - x) > 3.0f && + Abs(iy - y) > 3.0f){ sect = CWorld::GetSector(x, y); DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS]); DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS_OVERLAP]); @@ -2158,7 +2158,7 @@ CStreaming::DeleteRwObjectsBehindCamera(int32 mem) ix = CWorld::GetSectorIndexX(TheCamera.GetPosition().x); iy = CWorld::GetSectorIndexX(TheCamera.GetPosition().y); - if(fabs(TheCamera.GetForward().x) > fabs(TheCamera.GetForward().y)){ + if(Abs(TheCamera.GetForward().x) > Abs(TheCamera.GetForward().y)){ // looking west/east ymin = max(iy - 10, 0); @@ -2312,13 +2312,13 @@ CStreaming::DeleteRwObjectsInOverlapSectorList(CPtrList &list, int32 x, int32 y) e = (CEntity*)node->item; if(e->m_rwObject && !e->bStreamingDontDelete && !e->bImBeingRendered){ // Now this is pretty weird... - if(fabs(CWorld::GetSectorIndexX(e->GetPosition().x) - x) >= 2.0f) + if(Abs(CWorld::GetSectorIndexX(e->GetPosition().x) - x) >= 2.0f) // { e->DeleteRwObject(); // return; // BUG? // } else // FIX? - if(fabs(CWorld::GetSectorIndexY(e->GetPosition().y) - y) >= 2.0f) + if(Abs(CWorld::GetSectorIndexY(e->GetPosition().y) - y) >= 2.0f) e->DeleteRwObject(); } } diff --git a/src/core/Text.cpp b/src/core/Text.cpp index d7d63467..dfa9815c 100644 --- a/src/core/Text.cpp +++ b/src/core/Text.cpp @@ -210,12 +210,56 @@ AsciiToUnicode(const char *src, uint16 *dst) while((*dst++ = *src++) != '\0'); } +char* +UnicodeToAscii(wchar *src) +{ + static char aStr[256]; + int len; + for(len = 0; src && *src != 0 && len < 256-1; len++, src++) + if(*src < 256) + aStr[len] = *src; + else + aStr[len] = '#'; + aStr[len] = '\0'; + return aStr; +} + +char* +UnicodeToAsciiForSaveLoad(wchar *src) +{ + // exact same code as above + static char aStr[256]; + int len; + for(len = 0; src && *src != 0 && len < 256-1; len++, src++) + if(*src < 256) + aStr[len] = *src; + else + aStr[len] = '#'; + aStr[len] = '\0'; + return aStr; +} + +void +UnicodeStrcpy(wchar *dst, const wchar *src) +{ + while((*dst++ = *src++) != '\0'); +} + +int +UnicodeStrlen(const wchar *str) +{ + int len; + for(len = 0; *str != 0; len++, str++); + return len; +} + void TextCopy(wchar *dst, const wchar *src) { while((*dst++ = *src++) != '\0'); } + STARTPATCHES InjectHook(0x52C3C0, &CText::Load, PATCH_JUMP); InjectHook(0x52C580, &CText::Unload, PATCH_JUMP); diff --git a/src/core/Text.h b/src/core/Text.h index 2592e6b8..f554628c 100644 --- a/src/core/Text.h +++ b/src/core/Text.h @@ -1,6 +1,10 @@ #pragma once void AsciiToUnicode(const char *src, wchar *dst); +char *UnicodeToAscii(wchar *src); +char *UnicodeToAsciiForSaveLoad(wchar *src); +void UnicodeStrcpy(wchar *dst, const wchar *src); +int UnicodeStrlen(const wchar *str); void TextCopy(wchar *dst, const wchar *src); struct CKeyEntry diff --git a/src/core/Wanted.cpp b/src/core/Wanted.cpp index ece68e64..4608bfef 100644 --- a/src/core/Wanted.cpp +++ b/src/core/Wanted.cpp @@ -2,6 +2,8 @@ #include "patcher.h" #include "Wanted.h" +int32 &CWanted::MaximumWantedLevel = *(int32*)0x5F7714; + bool CWanted::AreSwatRequired() { return m_nWantedLevel >= 4; @@ -32,5 +34,102 @@ int CWanted::NumOfHelisRequired() return 2; default: return 0; - }; + } +} + +void CWanted::SetWantedLevel(int32 level) +{ + ClearQdCrimes(); + switch (level) { + case NOTWANTED: + m_nChaos = 0; + break; + case WANTEDLEVEL_1: + m_nChaos = 60; + break; + case WANTEDLEVEL_2: + m_nChaos = 220; + break; + case WANTEDLEVEL_3: + m_nChaos = 420; + break; + case WANTEDLEVEL_4: + m_nChaos = 820; + break; + case WANTEDLEVEL_5: + m_nChaos = 1620; + break; + case WANTEDLEVEL_6: + m_nChaos = 3220; + break; + default: + if (level > MaximumWantedLevel) + m_nChaos = MaximumWantedLevel; + break; + } + UpdateWantedLevel(); +} + +void CWanted::SetWantedLevelNoDrop(int32 level) +{ + if (level > m_nWantedLevel) + SetWantedLevel(level); +} + +void CWanted::ClearQdCrimes() +{ + for (int i = 0; i < 16; i++) { + m_sCrimes[i].m_eCrimeType = CRIME_NONE; + } +} + +void CWanted::UpdateWantedLevel() +{ + int32 CurrWantedLevel = m_nWantedLevel; + + if (m_nChaos >= 0 && m_nChaos < 40) { + m_nWantedLevel = NOTWANTED; + m_MaximumLawEnforcerVehicles = 0; + m_MaxCops = 0; + m_RoadblockDensity = 0; + } + else if (m_nChaos >= 40 && m_nChaos < 200) { + m_nWantedLevel = WANTEDLEVEL_1; + m_MaximumLawEnforcerVehicles = 1; + m_MaxCops = 1; + m_RoadblockDensity = 0; + } + else if (m_nChaos >= 200 && m_nChaos < 400) { + m_nWantedLevel = WANTEDLEVEL_2; + m_MaximumLawEnforcerVehicles = 2; + m_MaxCops = 3; + m_RoadblockDensity = 0; + } + else if (m_nChaos >= 400 && m_nChaos < 800) { + m_nWantedLevel = WANTEDLEVEL_3; + m_MaximumLawEnforcerVehicles = 2; + m_MaxCops = 4; + m_RoadblockDensity = 4; + } + else if (m_nChaos >= 800 && m_nChaos < 1600) { + m_nWantedLevel = WANTEDLEVEL_4; + m_MaximumLawEnforcerVehicles = 2; + m_MaxCops = 6; + m_RoadblockDensity = 8; + } + else if (m_nChaos >= 1600 && m_nChaos < 3200) { + m_nWantedLevel = WANTEDLEVEL_5; + m_MaximumLawEnforcerVehicles = 3; + m_MaxCops = 8; + m_RoadblockDensity = 10; + } + else if (m_nChaos >= 3200) { + m_nWantedLevel = WANTEDLEVEL_6; + m_MaximumLawEnforcerVehicles = 3; + m_MaxCops = 10; + m_RoadblockDensity = 12; + } + + if (CurrWantedLevel != m_nWantedLevel) + m_nLastWantedLevelChange = CTimer::GetTimeInMilliseconds(); }
\ No newline at end of file diff --git a/src/core/Wanted.h b/src/core/Wanted.h index aafa9ac0..d3f6638b 100644 --- a/src/core/Wanted.h +++ b/src/core/Wanted.h @@ -20,11 +20,11 @@ public: int32 m_nLastUpdateTime; int32 m_nLastWantedLevelChange; float m_fCrimeSensitivity; - uint8 m_bCurrentCops; - uint8 m_bMaxCops; - uint8 m_bMaximumLawEnforcerVehicles; + uint8 m_CurrentCops; + uint8 m_MaxCops; + uint8 m_MaximumLawEnforcerVehicles; int8 field_19; - int16 m_wRoadblockDensity; + int16 m_RoadblockDensity; uint8 m_IsIgnoredByCops : 1; uint8 m_IsIgnoredByEveryOne : 1; uint8 m_IsSwatRequired : 1; @@ -34,12 +34,17 @@ public: int32 m_nWantedLevel; CCrime m_sCrimes[16]; CCopPed *m_pCops[10]; + static int32 &MaximumWantedLevel; public: bool AreSwatRequired(); bool AreFbiRequired(); bool AreArmyRequired(); int NumOfHelisRequired(); + void SetWantedLevel(int32); + void SetWantedLevelNoDrop(int32 level); + void ClearQdCrimes(); + void UpdateWantedLevel(); }; static_assert(sizeof(CWanted) == 0x204, "CWanted: error"); diff --git a/src/core/World.cpp b/src/core/World.cpp index 538e15c5..a31f87a7 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -564,6 +564,82 @@ CWorld::GetIsLineOfSightSectorListClear(CPtrList &list, const CColLine &line, bo return true; } +void +CWorld::FindObjectsInRangeSectorList(CPtrList &list, CVector ¢re, float distance, bool ignoreZ, short *nextObject, short lastObject, CEntity **objects) +{ + float distSqr = distance * distance; + float objDistSqr; + + for (CPtrNode *node = list.first; node; node = node->next) { + CEntity *object = (CEntity*)node->item; + if (object->m_scanCode != CWorld::GetCurrentScanCode()) { + object->m_scanCode = CWorld::GetCurrentScanCode(); + + CVector diff = centre - object->GetPosition(); + if (ignoreZ) + objDistSqr = diff.MagnitudeSqr2D(); + else + objDistSqr = diff.MagnitudeSqr(); + + if (objDistSqr < distSqr && *nextObject < lastObject) { + if (objects) { + objects[*nextObject] = object; + } + (*nextObject)++; + } + } + } +} + +void +CWorld::FindObjectsInRange(CVector ¢re, float distance, bool ignoreZ, short *nextObject, short lastObject, CEntity **objects, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies) +{ + 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 >= 100) + maxX = 100; + + int maxY = GetSectorIndexY(centre.y + distance); + if (maxY >= 100) + maxY = 100; + + AdvanceCurrentScanCode(); + + *nextObject = 0; + for(int curY = minY; curY <= maxY; curY++) { + 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); + } + 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); + } + 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); + } + 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); + } + 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); + } + } + } +} + float CWorld::FindGroundZForCoord(float x, float y) { @@ -712,6 +788,8 @@ STARTPATCHES InjectHook(0x4B2000, CWorld::GetIsLineOfSightSectorClear, PATCH_JUMP); InjectHook(0x4B2160, CWorld::GetIsLineOfSightSectorListClear, PATCH_JUMP); + InjectHook(0x4B2200, CWorld::FindObjectsInRange, PATCH_JUMP); + InjectHook(0x4B2540, CWorld::FindObjectsInRangeSectorList, 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 3b7090da..d6063d70 100644 --- a/src/core/World.h +++ b/src/core/World.h @@ -93,7 +93,9 @@ public: static bool GetIsLineOfSightClear(const CVector &point1, const CVector &point2, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false); static bool GetIsLineOfSightSectorClear(CSector §or, 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 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); diff --git a/src/core/common.h b/src/core/common.h index 33ebcdbb..4b7bcb0a 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -97,6 +97,7 @@ 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" diff --git a/src/core/config.h b/src/core/config.h index 8cb02190..b1efd4b6 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -30,6 +30,8 @@ enum Config { NUMDUMMIES = 2802, // 2368 on PS2 NUMAUDIOSCRIPTOBJECTS = 256, + NUMTEMPOBJECTS = 30, + // Link list lengths // TODO: alpha list NUMCOLCACHELINKS = 200, @@ -114,3 +116,4 @@ enum Config { #define FIX_BUGS // fix bugs in the game, TODO: use this more #define KANGAROO_CHEAT #define ASPECT_RATIO_SCALE +#define USE_DEBUG_SCRIPT_LOADER
\ No newline at end of file diff --git a/src/core/main.cpp b/src/core/main.cpp index e7f42780..ffde80bb 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -48,14 +48,20 @@ #include "RpAnimBlend.h" #include "Frontend.h" -#define DEFAULT_VIEWWINDOW (tan(DEGTORAD(CDraw::GetFOV() * 0.5f))) +#define DEFAULT_VIEWWINDOW (Tan(DEGTORAD(CDraw::GetFOV() * 0.5f))) GlobalScene &Scene = *(GlobalScene*)0x726768; uint8 work_buff[55000]; -char gString[256]; +//char gString[256]; +//char gString2[512]; +//wchar gUString[256]; +//wchar gUString2[256]; +char *gString = (char*)0x711B40; +char *gString2 = (char*)0x878A40; wchar *gUString = (wchar*)0x74B018; +wchar *gUString2 = (wchar*)0x6EDD70; bool &b_FoundRecentSavedGameWantToLoad = *(bool*)0x95CDA8; diff --git a/src/core/main.h b/src/core/main.h index bdb0e008..dabc0f7b 100644 --- a/src/core/main.h +++ b/src/core/main.h @@ -8,8 +8,14 @@ struct GlobalScene extern GlobalScene &Scene; extern uint8 work_buff[55000]; -extern char gString[256]; +//extern char gString[256]; +//extern char gString2[512]; +//extern wchar gUString[256]; +//extern wchar gUString2[256]; +extern char *gString; +extern char *gString2; extern wchar *gUString; +extern wchar *gUString2; extern bool &b_FoundRecentSavedGameWantToLoad; class CSprite2d; diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 9dc39d46..8bb9caee 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -57,27 +57,6 @@ mysrand(unsigned int seed) myrand_seed = seed; } -int (*open_script_orig)(const char *path, const char *mode); -int -open_script(const char *path, const char *mode) -{ - static int scriptToLoad = 1; - - if(GetAsyncKeyState('G') & 0x8000) - scriptToLoad = 0; - if(GetAsyncKeyState('R') & 0x8000) - scriptToLoad = 1; - if(GetAsyncKeyState('D') & 0x8000) - scriptToLoad = 2; - - switch(scriptToLoad){ - case 0: return open_script_orig(path, mode); - case 1: return open_script_orig("main_freeroam.scm", mode); - case 2: return open_script_orig("main_d.scm", mode); - } - return open_script_orig(path, mode); -} - int gDbgSurf; void (*DebugMenuProcess)(void); @@ -176,6 +155,19 @@ spawnCar(int id) #endif void +FixCar(void) +{ + CVehicle *veh = FindPlayerVehicle(); + if(veh == nil) + return; + veh->m_fHealth = 1000.0f; + if(!veh->IsCar()) + return; + ((CAutomobile*)veh)->Damage.SetEngineStatus(0); + ((CAutomobile*)veh)->Fix(); +} + +void DebugMenuPopulate(void) { if(DebugMenuLoad()){ @@ -219,6 +211,7 @@ DebugMenuPopulate(void) DebugMenuAddCmd("Cheats", "Strong grip", StrongGripCheat); DebugMenuAddCmd("Cheats", "Nasty limbs", NastyLimbsCheat); + DebugMenuAddCmd("Debug", "Fix Car", FixCar); DebugMenuAddVarBool8("Debug", "Show Ped Road Groups", (int8*)&gbShowPedRoadGroups, nil); DebugMenuAddVarBool8("Debug", "Show Car Road Groups", (int8*)&gbShowCarRoadGroups, nil); DebugMenuAddVarBool8("Debug", "Show Collision Polys", (int8*)&gbShowCollisionPolys, nil); @@ -356,7 +349,7 @@ patch() Patch<WORD>(0x5382BF, 0x0EEB); InjectHook(0x5382EC, HeadlightsFix, PATCH_JUMP); - InterceptCall(&open_script_orig, open_script, 0x438869); +// InterceptCall(&open_script_orig, open_script, 0x438869); // InterceptCall(&RsEventHandler_orig, delayedPatches10, 0x58275E); } diff --git a/src/entities/Building.cpp b/src/entities/Building.cpp index b9fca96f..188cbfe7 100644 --- a/src/entities/Building.cpp +++ b/src/entities/Building.cpp @@ -21,8 +21,15 @@ CBuilding::ReplaceWithNewModel(int32 id) CStreaming::RequestModel(id, STREAMFLAGS_DONT_REMOVE); } +class CBuilding_ : public CBuilding +{ +public: + CBuilding *ctor(void) { return ::new (this) CBuilding(); } + void dtor(void) { CBuilding::~CBuilding(); } +}; + STARTPATCHES - InjectHook(0x4057D0, &CBuilding::ctor, PATCH_JUMP); - InjectHook(0x405800, &CBuilding::dtor, PATCH_JUMP); + InjectHook(0x4057D0, &CBuilding_::ctor, PATCH_JUMP); + InjectHook(0x405800, &CBuilding_::dtor, PATCH_JUMP); InjectHook(0x405850, &CBuilding::ReplaceWithNewModel, PATCH_JUMP); ENDPATCHES diff --git a/src/entities/Building.h b/src/entities/Building.h index 89d0a460..7b837f46 100644 --- a/src/entities/Building.h +++ b/src/entities/Building.h @@ -15,8 +15,5 @@ public: void ReplaceWithNewModel(int32 id); virtual bool GetIsATreadable(void) { return false; } - - CBuilding *ctor(void) { return ::new (this) CBuilding(); } - void dtor(void) { this->CBuilding::~CBuilding(); } }; static_assert(sizeof(CBuilding) == 0x64, "CBuilding: error"); diff --git a/src/entities/Dummy.cpp b/src/entities/Dummy.cpp index 5401c1fa..176e5682 100644 --- a/src/entities/Dummy.cpp +++ b/src/entities/Dummy.cpp @@ -51,8 +51,16 @@ CDummy::Remove(void) } } +class CDummy_ : public CDummy +{ +public: + void Add_(void) { CDummy::Add(); } + void Remove_(void) { CDummy::Remove(); } + void dtor(void) { CDummy::~CDummy(); } +}; + STARTPATCHES - InjectHook(0x473810, &CDummy::dtor, PATCH_JUMP); - InjectHook(0x473860, &CDummy::Add_, PATCH_JUMP); - InjectHook(0x473AD0, &CDummy::Remove_, PATCH_JUMP); + InjectHook(0x473810, &CDummy_::dtor, PATCH_JUMP); + InjectHook(0x473860, &CDummy_::Add_, PATCH_JUMP); + InjectHook(0x473AD0, &CDummy_::Remove_, PATCH_JUMP); ENDPATCHES diff --git a/src/entities/Dummy.h b/src/entities/Dummy.h index 59359bb5..fcfd23fb 100644 --- a/src/entities/Dummy.h +++ b/src/entities/Dummy.h @@ -14,10 +14,5 @@ public: static void *operator new(size_t); static void operator delete(void*, size_t); - - // to make patching virtual functions possible - void Add_(void) { CDummy::Add(); } - void Remove_(void) { CDummy::Remove(); } - void dtor(void) { this->CDummy::~CDummy(); } }; static_assert(sizeof(CDummy) == 0x68, "CDummy: error"); diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp index fac7f17f..10677bdf 100644 --- a/src/entities/Entity.cpp +++ b/src/entities/Entity.cpp @@ -632,7 +632,7 @@ CEntity::ProcessLightsForEntity(void) lightOn = true; else lightFlickering = true; - if((CTimer::GetTimeInMilliseconds()>>1 ^ m_randomSeed) & 3) + if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed) & 3) lightOn = true; break; case LIGHT_FLICKER_NIGHT: @@ -641,7 +641,7 @@ CEntity::ProcessLightsForEntity(void) lightOn = true; else lightFlickering = true; - if((CTimer::GetTimeInMilliseconds()>>1 ^ m_randomSeed) & 3) + if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed) & 3) lightOn = true; } break; @@ -680,7 +680,7 @@ CEntity::ProcessLightsForEntity(void) lightOn = true; else lightFlickering = true; - if((CTimer::GetTimeInMilliseconds()>>1 ^ m_randomSeed*8) & 3) + if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed*8) & 3) lightOn = true; } break; @@ -693,7 +693,7 @@ CEntity::ProcessLightsForEntity(void) lightOn = true; else lightFlickering = true; - if((CTimer::GetTimeInMilliseconds()>>1 ^ m_randomSeed*8) & 3) + if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed*8) & 3) lightOn = true; } } @@ -806,17 +806,17 @@ CEntity::ModifyMatrixForTreeInWind(void) }else if(CWeather::Wind >= 0.2){ t = (uintptr)this + CTimer::GetTimeInMilliseconds(); f = (t & 0xFFF)/(float)0x1000; - flutter = sin(f * 6.28f); + flutter = Sin(f * 6.28f); strength = 0.008f; }else{ t = (uintptr)this + CTimer::GetTimeInMilliseconds(); f = (t & 0xFFF)/(float)0x1000; - flutter = sin(f * 6.28f); + flutter = Sin(f * 6.28f); strength = 0.005f; } - mat.GetUp()->x = strength * flutter; - mat.GetUp()->y = mat.GetUp()->x; + mat.GetUp().x = strength * flutter; + mat.GetUp().y = mat.GetUp().x; mat.UpdateRW(); UpdateRwFrame(); @@ -847,7 +847,7 @@ CEntity::ModifyMatrixForBannerInWind(void) else strength = 0.66f; - t = ((int)(GetMatrix().GetPosition()->x + GetMatrix().GetPosition()->y) << 10) + 16*CTimer::GetTimeInMilliseconds(); + t = ((int)(GetMatrix().GetPosition().x + GetMatrix().GetPosition().y) << 10) + 16*CTimer::GetTimeInMilliseconds(); f = (t & 0x7FF)/(float)0x800; flutter = f * BannerWindTabel[(t>>11)+1 & 0x1F] + (1.0f - f) * BannerWindTabel[(t>>11) & 0x1F]; @@ -857,7 +857,7 @@ CEntity::ModifyMatrixForBannerInWind(void) right.z = 0.0f; right.Normalise(); up = right * flutter; - up.z = sqrt(sq(1.0f) - sq(flutter)); + up.z = Sqrt(sq(1.0f) - sq(flutter)); GetRight() = CrossProduct(GetForward(), up); GetUp() = up; @@ -865,10 +865,35 @@ CEntity::ModifyMatrixForBannerInWind(void) UpdateRwFrame(); } +class CEntity_ : public CEntity +{ +public: + CEntity *ctor(void) { return ::new (this) CEntity(); } + void dtor(void) { this->CEntity::~CEntity(); } + void Add_(void) { CEntity::Add(); } + void Remove_(void) { CEntity::Remove(); } + void SetModelIndex_(uint32 i) { CEntity::SetModelIndex(i); } + void CreateRwObject_(void) { CEntity::CreateRwObject(); } + void DeleteRwObject_(void) { CEntity::DeleteRwObject(); } + CRect GetBoundRect_(void) { return CEntity::GetBoundRect(); } + void PreRender_(void) { CEntity::PreRender(); } + void Render_(void) { CEntity::Render(); } + bool SetupLighting_(void) { return CEntity::SetupLighting(); } +}; + STARTPATCHES - InjectHook(0x473C30, &CEntity::ctor, PATCH_JUMP); - InjectHook(0x473E40, &CEntity::dtor, PATCH_JUMP); - InjectHook(0x473E70, &CEntity::SetModelIndex_, PATCH_JUMP); + InjectHook(0x473C30, &CEntity_::ctor, PATCH_JUMP); + InjectHook(0x473E40, &CEntity_::dtor, PATCH_JUMP); + InjectHook(0x473E70, &CEntity_::SetModelIndex_, PATCH_JUMP); + InjectHook(0x475080, &CEntity_::Add_, PATCH_JUMP); + InjectHook(0x475310, &CEntity_::Remove_, PATCH_JUMP); + InjectHook(0x473EA0, &CEntity_::CreateRwObject_, PATCH_JUMP); + InjectHook(0x473F90, &CEntity_::DeleteRwObject_, PATCH_JUMP); + InjectHook(0x474000, &CEntity_::GetBoundRect_, PATCH_JUMP); + InjectHook(0x474350, &CEntity_::PreRender_, PATCH_JUMP); + InjectHook(0x474BD0, &CEntity_::Render_, PATCH_JUMP); + InjectHook(0x4A7C60, &CEntity_::SetupLighting_, PATCH_JUMP); + InjectHook(0x4742C0, (void (CEntity::*)(CVector&))&CEntity::GetBoundCentre, PATCH_JUMP); InjectHook(0x474310, &CEntity::GetBoundRadius, PATCH_JUMP); InjectHook(0x474C10, &CEntity::GetIsTouching, PATCH_JUMP); @@ -889,13 +914,4 @@ STARTPATCHES InjectHook(0x475670, &CEntity::ModifyMatrixForTreeInWind, PATCH_JUMP); InjectHook(0x475830, &CEntity::ModifyMatrixForBannerInWind, PATCH_JUMP); InjectHook(0x4FA530, &CEntity::ProcessLightsForEntity, PATCH_JUMP); - - InjectHook(0x475080, &CEntity::Add_, PATCH_JUMP); - InjectHook(0x475310, &CEntity::Remove_, PATCH_JUMP); - InjectHook(0x473EA0, &CEntity::CreateRwObject_, PATCH_JUMP); - InjectHook(0x473F90, &CEntity::DeleteRwObject_, PATCH_JUMP); - InjectHook(0x474000, &CEntity::GetBoundRect_, PATCH_JUMP); - InjectHook(0x474350, &CEntity::PreRender_, PATCH_JUMP); - InjectHook(0x474BD0, &CEntity::Render_, PATCH_JUMP); - InjectHook(0x4A7C60, &CEntity::SetupLighting_, PATCH_JUMP); ENDPATCHES diff --git a/src/entities/Entity.h b/src/entities/Entity.h index 92c4c351..12a631d2 100644 --- a/src/entities/Entity.h +++ b/src/entities/Entity.h @@ -94,13 +94,15 @@ public: uint16 m_level; // int16 CReference *m_pFirstReference; + CColModel *GetColModel(void) { return CModelInfo::GetModelInfo(m_modelIndex)->GetColModel(); } + CEntity(void); - virtual ~CEntity(void); + ~CEntity(void); virtual void Add(void); virtual void Remove(void); - virtual void SetModelIndex(uint32 i) { m_modelIndex = i; CreateRwObject(); } - virtual void SetModelIndexNoCreate(uint32 i) { m_modelIndex = i; } + virtual void SetModelIndex(uint32 id) { m_modelIndex = id; CreateRwObject(); } + virtual void SetModelIndexNoCreate(uint32 id) { m_modelIndex = id; } virtual void CreateRwObject(void); virtual void DeleteRwObject(void); virtual CRect GetBoundRect(void); @@ -145,19 +147,5 @@ public: void ModifyMatrixForTreeInWind(void); void ModifyMatrixForBannerInWind(void); void ProcessLightsForEntity(void); - - - // to make patching virtual functions possible - CEntity *ctor(void) { return ::new (this) CEntity(); } - void dtor(void) { this->CEntity::~CEntity(); } - void Add_(void) { CEntity::Add(); } - void Remove_(void) { CEntity::Remove(); } - void SetModelIndex_(uint32 i) { CEntity::SetModelIndex(i); } - void CreateRwObject_(void) { CEntity::CreateRwObject(); } - void DeleteRwObject_(void) { CEntity::DeleteRwObject(); } - CRect GetBoundRect_(void) { return CEntity::GetBoundRect(); } - void PreRender_(void) { CEntity::PreRender(); } - void Render_(void) { CEntity::Render(); } - bool SetupLighting_(void) { return CEntity::SetupLighting(); } }; static_assert(sizeof(CEntity) == 0x64, "CEntity: error"); diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp index d6a82658..55ed5380 100644 --- a/src/entities/Physical.cpp +++ b/src/entities/Physical.cpp @@ -3,6 +3,7 @@ #include "World.h" #include "Timer.h" #include "ModelIndices.h" +#include "Treadable.h" #include "Vehicle.h" #include "Ped.h" #include "Object.h" @@ -32,7 +33,7 @@ CPhysical::CPhysical(void) m_nCollisionRecords = 0; for(i = 0; i < 6; i++) - m_aCollisionRecords[0] = nil; + m_aCollisionRecords[i] = nil; field_EF = false; @@ -61,7 +62,7 @@ CPhysical::CPhysical(void) m_phy_flagA10 = false; m_phy_flagA20 = false; - m_nLastCollType = 0; + m_nSurfaceTouched = SURFACE_DEFAULT; } CPhysical::~CPhysical(void) @@ -456,7 +457,7 @@ CPhysical::ApplySpringCollision(float springConst, CVector &springDir, CVector & float compression = 1.0f - springRatio; if(compression > 0.0f){ float step = min(CTimer::GetTimeStep(), 3.0f); - float impulse = -0.008f*m_fMass*step * springConst * compression * bias*2.0f; + float impulse = -GRAVITY*m_fMass*step * springConst * compression * bias*2.0f; ApplyMoveForce(springDir*impulse); ApplyTurnForce(springDir*impulse, point); } @@ -475,7 +476,7 @@ CPhysical::ApplySpringDampening(float damping, CVector &springDir, CVector &poin // what is this? float a = m_fTurnMass / ((point.MagnitudeSqr() + 1.0f) * 2.0f * m_fMass); a = min(a, 1.0f); - float b = fabs(impulse / (speedB * m_fMass)); + float b = Abs(impulse / (speedB * m_fMass)); if(a < b) impulse *= a/b; @@ -488,7 +489,7 @@ void CPhysical::ApplyGravity(void) { if(bAffectedByGravity) - m_vecMoveSpeed.z -= 0.008f * CTimer::GetTimeStep(); + m_vecMoveSpeed.z -= GRAVITY * CTimer::GetTimeStep(); } void @@ -504,11 +505,11 @@ void CPhysical::ApplyAirResistance(void) { if(m_fAirResistance > 0.1f){ - float f = powf(m_fAirResistance, CTimer::GetTimeStep()); + float f = Pow(m_fAirResistance, CTimer::GetTimeStep()); m_vecMoveSpeed *= f; m_vecTurnSpeed *= f; }else{ - float f = powf(1.0f/(m_fAirResistance*0.5f*m_vecMoveSpeed.MagnitudeSqr() + 1.0f), CTimer::GetTimeStep()); + float f = Pow(1.0f/(m_fAirResistance*0.5f*m_vecMoveSpeed.MagnitudeSqr() + 1.0f), CTimer::GetTimeStep()); m_vecMoveSpeed *= f; m_vecTurnSpeed *= 0.99f; } @@ -718,7 +719,7 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl if(!B->bInfiniteMass){ if(fB.z < 0.0f){ fB.z = 0.0f; - if(fabs(speedA) < 0.01f) + if(Abs(speedA) < 0.01f) fB *= 0.5f; } if(ispedcontactA){ @@ -814,9 +815,9 @@ CPhysical::ApplyCollisionAlt(CEntity *B, CColPoint &colpoint, float &impulse, CV float minspeed = 0.0104f * CTimer::GetTimeStep(); if((IsObject() || IsVehicle() && GetUp().z < -0.3f) && !bHasContacted && - fabs(m_vecMoveSpeed.x) < minspeed && - fabs(m_vecMoveSpeed.y) < minspeed && - fabs(m_vecMoveSpeed.z) < minspeed*2.0f) + Abs(m_vecMoveSpeed.x) < minspeed && + Abs(m_vecMoveSpeed.y) < minspeed && + Abs(m_vecMoveSpeed.z) < minspeed*2.0f) e = -1.0f; else e = -(m_fElasticity + 1.0f); @@ -1149,14 +1150,14 @@ CPhysical::ProcessShiftSectorList(CPtrList *lists) shift += dir * colpoints[mostColliding].depth * 0.5f; }else if(A->IsPed() && B->IsVehicle() && ((CVehicle*)B)->IsBoat()){ CVector dir = colpoints[mostColliding].normal; - float f = min(fabs(dir.z), 0.9f); + float f = min(Abs(dir.z), 0.9f); dir.z = 0.0f; dir.Normalise(); shift += dir * colpoints[mostColliding].depth / (1.0f - f); boat = B; }else if(B->IsPed() && A->IsVehicle() && ((CVehicle*)A)->IsBoat()){ CVector dir = colpoints[mostColliding].normal * -1.0f; - float f = min(fabs(dir.z), 0.9f); + float f = min(Abs(dir.z), 0.9f); dir.z = 0.0f; dir.Normalise(); B->GetPosition() += dir * colpoints[mostColliding].depth / (1.0f - f); @@ -1497,8 +1498,8 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists) float imp = impulseA; if(A->IsVehicle() && A->GetUp().z < -0.6f && - fabs(A->m_vecMoveSpeed.x) < 0.05f && - fabs(A->m_vecMoveSpeed.y) < 0.05f) + Abs(A->m_vecMoveSpeed.x) < 0.05f && + Abs(A->m_vecMoveSpeed.y) < 0.05f) imp *= 0.1f; float turnSpeedDiff = A->m_vecTurnSpeed.MagnitudeSqr(); @@ -1518,8 +1519,8 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists) float imp = impulseA; if(A->IsVehicle() && A->GetUp().z < -0.6f && - fabs(A->m_vecMoveSpeed.x) < 0.05f && - fabs(A->m_vecMoveSpeed.y) < 0.05f) + Abs(A->m_vecMoveSpeed.x) < 0.05f && + Abs(A->m_vecMoveSpeed.y) < 0.05f) imp *= 0.1f; float turnSpeedDiff = A->m_vecTurnSpeed.MagnitudeSqr(); @@ -1556,8 +1557,8 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists) m_vecTurnSpeed += turnSpeed / numResponses; if(!CWorld::bNoMoreCollisionTorque && A->m_status == STATUS_PLAYER && A->IsVehicle() && - fabs(A->m_vecMoveSpeed.x) > 0.2f && - fabs(A->m_vecMoveSpeed.y) > 0.2f){ + Abs(A->m_vecMoveSpeed.x) > 0.2f && + Abs(A->m_vecMoveSpeed.y) > 0.2f){ A->m_vecMoveFriction.x += moveSpeed.x * -0.3f / numCollisions; A->m_vecMoveFriction.y += moveSpeed.y * -0.3f / numCollisions; A->m_vecTurnFriction += turnSpeed * -0.3f / numCollisions; @@ -1782,13 +1783,13 @@ CPhysical::ProcessShift(void) } bIsStuck = false; bIsInSafePosition = true; - m_fDistanceTravelled = (GetPosition() - *matrix.GetPosition()).Magnitude(); + m_fDistanceTravelled = (GetPosition() - matrix.GetPosition()).Magnitude(); RemoveAndAdd(); } } // x is the number of units (m) we would like to step -#define NUMSTEPS(x) ceil(sqrt(distSq) * (1.0f/(x))) +#define NUMSTEPS(x) ceil(Sqrt(distSq) * (1.0f/(x))) void CPhysical::ProcessCollision(void) @@ -1882,7 +1883,7 @@ CPhysical::ProcessCollision(void) if(IsPed() && m_vecMoveSpeed.z == 0.0f && !ped->m_ped_flagA2 && ped->bIsStanding) - savedMatrix.GetPosition()->z = GetPosition().z; + savedMatrix.GetPosition().z = GetPosition().z; GetMatrix() = savedMatrix; CTimer::SetTimeStep(savedTimeStep); return; @@ -1890,7 +1891,7 @@ CPhysical::ProcessCollision(void) if(IsPed() && m_vecMoveSpeed.z == 0.0f && !ped->m_ped_flagA2 && ped->bIsStanding) - savedMatrix.GetPosition()->z = GetPosition().z; + savedMatrix.GetPosition().z = GetPosition().z; GetMatrix() = savedMatrix; CTimer::SetTimeStep(savedTimeStep); if(IsVehicle()){ @@ -1917,14 +1918,14 @@ CPhysical::ProcessCollision(void) bHitByTrain || m_status == STATUS_PLAYER || IsPed() && ped->IsPlayer()){ if(IsVehicle()) - ((CVehicle*)this)->m_veh_flagD4 = true; + ((CVehicle*)this)->bVehicleColProcessed = true; if(CheckCollision()){ GetMatrix() = savedMatrix; return; } } bHitByTrain = false; - m_fDistanceTravelled = (GetPosition() - *savedMatrix.GetPosition()).Magnitude(); + m_fDistanceTravelled = (GetPosition() - savedMatrix.GetPosition()).Magnitude(); m_phy_flagA80 = false; bIsStuck = false; @@ -1932,16 +1933,28 @@ CPhysical::ProcessCollision(void) RemoveAndAdd(); } +class CPhysical_ : public CPhysical +{ +public: + void dtor(void) { CPhysical::~CPhysical(); } + void Add_(void) { CPhysical::Add(); } + void Remove_(void) { CPhysical::Remove(); } + CRect GetBoundRect_(void) { return CPhysical::GetBoundRect(); } + void ProcessControl_(void) { CPhysical::ProcessControl(); } + void ProcessShift_(void) { CPhysical::ProcessShift(); } + void ProcessCollision_(void) { CPhysical::ProcessCollision(); } + int32 ProcessEntityCollision_(CEntity *ent, CColPoint *point) { return CPhysical::ProcessEntityCollision(ent, point); } +}; STARTPATCHES - InjectHook(0x495130, &CPhysical::dtor, PATCH_JUMP); - InjectHook(0x4951F0, &CPhysical::Add_, PATCH_JUMP); - InjectHook(0x4954B0, &CPhysical::Remove_, PATCH_JUMP); - InjectHook(0x495540, &CPhysical::RemoveAndAdd, PATCH_JUMP); - InjectHook(0x495F10, &CPhysical::ProcessControl_, PATCH_JUMP); - InjectHook(0x496F10, &CPhysical::ProcessShift_, PATCH_JUMP); - InjectHook(0x4961A0, &CPhysical::ProcessCollision_, PATCH_JUMP); - InjectHook(0x49F790, &CPhysical::ProcessEntityCollision_, PATCH_JUMP); + InjectHook(0x495130, &CPhysical_::dtor, PATCH_JUMP); + InjectHook(0x4951F0, &CPhysical_::Add_, PATCH_JUMP); + InjectHook(0x4954B0, &CPhysical_::Remove_, PATCH_JUMP); + InjectHook(0x495540, &CPhysical_::RemoveAndAdd, PATCH_JUMP); + InjectHook(0x495F10, &CPhysical_::ProcessControl_, PATCH_JUMP); + InjectHook(0x496F10, &CPhysical_::ProcessShift_, PATCH_JUMP); + InjectHook(0x4961A0, &CPhysical_::ProcessCollision_, PATCH_JUMP); + InjectHook(0x49F790, &CPhysical_::ProcessEntityCollision_, PATCH_JUMP); InjectHook(0x4958F0, &CPhysical::AddToMovingList, PATCH_JUMP); InjectHook(0x495940, &CPhysical::RemoveFromMovingList, PATCH_JUMP); InjectHook(0x497180, &CPhysical::AddCollisionRecord, PATCH_JUMP); diff --git a/src/entities/Physical.h b/src/entities/Physical.h index 81d3d649..5bd98815 100644 --- a/src/entities/Physical.h +++ b/src/entities/Physical.h @@ -3,12 +3,15 @@ #include "Lists.h" #include "Timer.h" #include "Entity.h" -#include "Treadable.h" enum { PHYSICAL_MAX_COLLISIONRECORDS = 6 }; +#define GRAVITY (0.008f) + +class CTreadable; + class CPhysical : public CEntity { public: @@ -58,20 +61,21 @@ public: uint8 bHitByTrain : 1; // from nick uint8 m_phy_flagA80 : 1; - uint8 m_nLastCollType; + uint8 m_nSurfaceTouched; uint8 m_nZoneLevel; CPhysical(void); ~CPhysical(void); // from CEntity - virtual void Add(void); - virtual void Remove(void); - virtual CRect GetBoundRect(void); - virtual void ProcessControl(void); - virtual int32 ProcessEntityCollision(CEntity *ent, CColPoint *point); - virtual void ProcessShift(void); - virtual void ProcessCollision(void); + void Add(void); + void Remove(void); + CRect GetBoundRect(void); + void ProcessControl(void); + void ProcessShift(void); + void ProcessCollision(void); + + virtual int32 ProcessEntityCollision(CEntity *ent, CColPoint *colpoints); void RemoveAndAdd(void); void AddToMovingList(void); @@ -106,7 +110,23 @@ public: } const CVector &GetMoveSpeed() { return m_vecMoveSpeed; } + void SetMoveSpeed(float x, float y, float z) { + m_vecMoveSpeed.x = x; + m_vecMoveSpeed.y = y; + m_vecMoveSpeed.z = z; + } const CVector &GetTurnSpeed() { return m_vecTurnSpeed; } + void SetTurnSpeed(float x, float y, float z) { + m_vecTurnSpeed.x = x; + m_vecTurnSpeed.y = y; + m_vecTurnSpeed.z = z; + } + const CVector &GetCenterOfMass() { return m_vecCentreOfMass; } + void SetCenterOfMass(float x, float y, float z) { + m_vecCentreOfMass.x = x; + m_vecCentreOfMass.y = y; + m_vecCentreOfMass.z = z; + } void ApplyMoveSpeed(void); void ApplyTurnSpeed(void); @@ -137,15 +157,5 @@ public: bool ProcessCollisionSectorList(CPtrList *lists); bool CheckCollision(void); bool CheckCollision_SimpleCar(void); - - // to make patching virtual functions possible - void dtor(void) { this->CPhysical::~CPhysical(); } - void Add_(void) { CPhysical::Add(); } - void Remove_(void) { CPhysical::Remove(); } - CRect GetBoundRect_(void) { return CPhysical::GetBoundRect(); } - void ProcessControl_(void) { CPhysical::ProcessControl(); } - void ProcessShift_(void) { CPhysical::ProcessShift(); } - void ProcessCollision_(void) { CPhysical::ProcessCollision(); } - int32 ProcessEntityCollision_(CEntity *ent, CColPoint *point) { return CPhysical::ProcessEntityCollision(ent, point); } }; static_assert(sizeof(CPhysical) == 0x128, "CPhysical: error"); diff --git a/src/entities/Treadable.cpp b/src/entities/Treadable.cpp index 230d1633..ea949f00 100644 --- a/src/entities/Treadable.cpp +++ b/src/entities/Treadable.cpp @@ -7,6 +7,12 @@ void *CTreadable::operator new(size_t sz) { return CPools::GetTreadablePool()->New(); } void CTreadable::operator delete(void *p, size_t sz) { CPools::GetTreadablePool()->Delete((CTreadable*)p); } +class CTreadable_ : public CTreadable +{ +public: + void dtor(void) { CTreadable::~CTreadable(); } +}; + STARTPATCHES - InjectHook(0x405A10, &CTreadable::dtor, PATCH_JUMP); -ENDPATCHES
\ No newline at end of file + InjectHook(0x405A10, &CTreadable_::dtor, PATCH_JUMP); +ENDPATCHES diff --git a/src/entities/Treadable.h b/src/entities/Treadable.h index 2194638d..d82ff52b 100644 --- a/src/entities/Treadable.h +++ b/src/entities/Treadable.h @@ -11,7 +11,6 @@ public: int16 m_nodeIndicesCars[12]; int16 m_nodeIndicesPeds[12]; - virtual bool GetIsATreadable(void) { return true; } - void dtor(void) { this->CTreadable::~CTreadable(); } + bool GetIsATreadable(void) { return true; } }; static_assert(sizeof(CTreadable) == 0x94, "CTreadable: error"); diff --git a/src/math/Matrix.h b/src/math/Matrix.h index 6e1001cb..2c0108c1 100644 --- a/src/math/Matrix.h +++ b/src/math/Matrix.h @@ -78,10 +78,36 @@ public: return *this; } - CVector *GetPosition(void){ return (CVector*)&m_matrix.pos; } - CVector *GetRight(void) { return (CVector*)&m_matrix.right; } - CVector *GetForward(void) { return (CVector*)&m_matrix.up; } - CVector *GetUp(void) { return (CVector*)&m_matrix.at; } + CVector &GetPosition(void){ return *(CVector*)&m_matrix.pos; } + CVector &GetRight(void) { return *(CVector*)&m_matrix.right; } + CVector &GetForward(void) { return *(CVector*)&m_matrix.up; } + CVector &GetUp(void) { return *(CVector*)&m_matrix.at; } + + void SetTranslate(float x, float y, float z){ + m_matrix.right.x = 1.0f; + m_matrix.right.y = 0.0f; + m_matrix.right.z = 0.0f; + + m_matrix.up.x = 0.0f; + m_matrix.up.y = 1.0f; + m_matrix.up.z = 0.0f; + + m_matrix.at.x = 0.0f; + m_matrix.at.y = 0.0f; + m_matrix.at.z = 1.0f; + + m_matrix.pos.x = x; + m_matrix.pos.y = y; + m_matrix.pos.z = z; + } + void SetTranslate(const CVector &trans){ SetTranslate(trans.x, trans.y, trans.z); } + void Translate(float x, float y, float z){ + m_matrix.pos.x += x; + m_matrix.pos.y += y; + m_matrix.pos.z += z; + } + void Translate(const CVector &trans){ Translate(trans.x, trans.y, trans.z); } + void SetScale(float s){ m_matrix.right.x = s; m_matrix.right.y = 0.0f; @@ -99,9 +125,10 @@ public: m_matrix.pos.y = 0.0f; m_matrix.pos.z = 0.0f; } + void SetRotateXOnly(float angle){ - float c = cos(angle); - float s = sin(angle); + float c = Cos(angle); + float s = Sin(angle); m_matrix.right.x = 1.0f; m_matrix.right.y = 0.0f; @@ -122,8 +149,8 @@ public: m_matrix.pos.z = 0.0f; } void SetRotateYOnly(float angle){ - float c = cos(angle); - float s = sin(angle); + float c = Cos(angle); + float s = Sin(angle); m_matrix.right.x = c; m_matrix.right.y = 0.0f; @@ -144,8 +171,8 @@ public: m_matrix.pos.z = 0.0f; } void SetRotateZOnly(float angle){ - float c = cos(angle); - float s = sin(angle); + float c = Cos(angle); + float s = Sin(angle); m_matrix.right.x = c; m_matrix.right.y = s; @@ -166,12 +193,12 @@ public: m_matrix.pos.z = 0.0f; } void SetRotate(float xAngle, float yAngle, float zAngle) { - float cX = cos(xAngle); - float sX = sin(xAngle); - float cY = cos(yAngle); - float sY = sin(yAngle); - float cZ = cos(zAngle); - float sZ = sin(zAngle); + float cX = Cos(xAngle); + float sX = Sin(xAngle); + float cY = Cos(yAngle); + float sY = Sin(yAngle); + float cZ = Cos(zAngle); + float sZ = Sin(zAngle); m_matrix.right.x = cZ * cY - (sZ * sX) * sY; m_matrix.right.y = (cZ * sX) * sY + sZ * cY; @@ -190,9 +217,9 @@ public: m_matrix.pos.z = 0.0f; } void Reorthogonalise(void){ - CVector &r = *GetRight(); - CVector &f = *GetForward(); - CVector &u = *GetUp(); + CVector &r = GetRight(); + CVector &f = GetForward(); + CVector &u = GetUp(); u = CrossProduct(r, f); u.Normalise(); r = CrossProduct(f, u); @@ -306,6 +333,15 @@ Multiply3x3(const CMatrix &mat, const CVector &vec) mat.m_matrix.right.z * vec.x + mat.m_matrix.up.z * vec.y + mat.m_matrix.at.z * vec.z); } +inline CVector +Multiply3x3(const CVector &vec, const CMatrix &mat) +{ + return CVector( + mat.m_matrix.right.x * vec.x + mat.m_matrix.right.y * vec.y + mat.m_matrix.right.z * vec.z, + mat.m_matrix.up.x * vec.x + mat.m_matrix.up.y * vec.y + mat.m_matrix.up.z * vec.z, + mat.m_matrix.at.x * vec.x + mat.m_matrix.at.y * vec.y + mat.m_matrix.at.z * vec.z); +} + class CCompressedMatrixNotAligned { CVector m_vecPos; @@ -318,24 +354,24 @@ class CCompressedMatrixNotAligned public: void CompressFromFullMatrix(CMatrix &other) { - m_rightX = 127.0f * other.GetRight()->x; - m_rightY = 127.0f * other.GetRight()->y; - m_rightZ = 127.0f * other.GetRight()->z; - m_upX = 127.0f * other.GetForward()->x; - m_upY = 127.0f * other.GetForward()->y; - m_upZ = 127.0f * other.GetForward()->z; - m_vecPos = *other.GetPosition(); + m_rightX = 127.0f * other.GetRight().x; + m_rightY = 127.0f * other.GetRight().y; + m_rightZ = 127.0f * other.GetRight().z; + m_upX = 127.0f * other.GetForward().x; + m_upY = 127.0f * other.GetForward().y; + m_upZ = 127.0f * other.GetForward().z; + m_vecPos = other.GetPosition(); } void DecompressIntoFullMatrix(CMatrix &other) { - other.GetRight()->x = m_rightX / 127.0f; - other.GetRight()->y = m_rightY / 127.0f; - other.GetRight()->z = m_rightZ / 127.0f; - other.GetForward()->x = m_upX / 127.0f; - other.GetForward()->y = m_upY / 127.0f; - other.GetForward()->z = m_upZ / 127.0f; - *other.GetUp() = CrossProduct(*other.GetRight(), *other.GetForward()); - *other.GetPosition() = m_vecPos; + other.GetRight().x = m_rightX / 127.0f; + other.GetRight().y = m_rightY / 127.0f; + other.GetRight().z = m_rightZ / 127.0f; + other.GetForward().x = m_upX / 127.0f; + other.GetForward().y = m_upY / 127.0f; + other.GetForward().z = m_upZ / 127.0f; + other.GetUp() = CrossProduct(other.GetRight(), other.GetForward()); + other.GetPosition() = m_vecPos; other.Reorthogonalise(); } -};
\ No newline at end of file +}; diff --git a/src/math/Quaternion.h b/src/math/Quaternion.h index 702fc72f..fb37dc10 100644 --- a/src/math/Quaternion.h +++ b/src/math/Quaternion.h @@ -8,7 +8,7 @@ public: CQuaternion(void) {} CQuaternion(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {} - float Magnitude(void) const { return sqrt(x*x + y*y + z*z + w*w); } + float Magnitude(void) const { return Sqrt(x*x + y*y + z*z + w*w); } float MagnitudeSqr(void) const { return x*x + y*y + z*z + w*w; } const CQuaternion &operator+=(CQuaternion const &right) { diff --git a/src/math/Vector.h b/src/math/Vector.h index b49f00f2..de8092eb 100644 --- a/src/math/Vector.h +++ b/src/math/Vector.h @@ -22,15 +22,15 @@ public: return *((RwV3d*)this); } #endif - float Heading(void) const { return atan2(-x, y); } - float Magnitude(void) const { return sqrt(x*x + y*y + z*z); } + 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; } - float Magnitude2D(void) const { return sqrt(x*x + y*y); } + float Magnitude2D(void) const { return Sqrt(x*x + y*y); } float MagnitudeSqr2D(void) const { return x*x + y*y; } void Normalise(void) { float sq = MagnitudeSqr(); if(sq > 0.0f){ - float invsqrt = 1.0f/sqrt(sq); // CMaths::RecipSqrt + float invsqrt = 1.0f/Sqrt(sq); // CMaths::RecipSqrt x *= invsqrt; y *= invsqrt; z *= invsqrt; diff --git a/src/math/Vector2D.h b/src/math/Vector2D.h index fa32bd9b..e6b04c14 100644 --- a/src/math/Vector2D.h +++ b/src/math/Vector2D.h @@ -7,13 +7,13 @@ public: CVector2D(void) {} CVector2D(float x, float y) : x(x), y(y) {} CVector2D(const CVector &v) : x(v.x), y(v.y) {} - float Magnitude(void) const { return sqrt(x*x + y*y); } + float Magnitude(void) const { return Sqrt(x*x + y*y); } float MagnitudeSqr(void) const { return x*x + y*y; } void Normalise(void){ float sq = MagnitudeSqr(); if(sq > 0.0f){ - float invsqrt = 1.0f/sqrt(sq); + float invsqrt = 1.0f/Sqrt(sq); x *= invsqrt; y *= invsqrt; }else diff --git a/src/math/math.cpp b/src/math/math.cpp index b76db4ae..c1199fcc 100644 --- a/src/math/math.cpp +++ b/src/math/math.cpp @@ -13,11 +13,11 @@ CQuaternion::Slerp(const CQuaternion &q1, const CQuaternion &q2, float theta, fl float w1, w2; if(theta > PI/2){ theta = PI - theta; - w1 = sin((1.0f - t) * theta) * invSin; - w2 = -sin(t * theta) * invSin; + w1 = Sin((1.0f - t) * theta) * invSin; + w2 = -Sin(t * theta) * invSin; }else{ - w1 = sin((1.0f - t) * theta) * invSin; - w2 = sin(t * theta) * invSin; + w1 = Sin((1.0f - t) * theta) * invSin; + w2 = Sin(t * theta) * invSin; } *this = w1*q1 + w2*q2; } diff --git a/src/math/maths.h b/src/math/maths.h new file mode 100644 index 00000000..a1c3f109 --- /dev/null +++ b/src/math/maths.h @@ -0,0 +1,16 @@ +#pragma once + +// wrapper around float versions of functions +// in gta they are in CMaths but that makes the code rather noisy + +inline float Sin(float x) { return sinf(x); } +inline float Asin(float x) { return asinf(x); } +inline float Cos(float x) { return cosf(x); } +inline float Acos(float x) { return acosf(x); } +inline float Tan(float x) { return tanf(x); } +inline float Atan(float x) { return atanf(x); } +inline float Atan2(float y, float x) { return atan2f(y, x); } +inline float Abs(float x) { return fabs(x); } +inline float Sqrt(float x) { return sqrtf(x); } +inline float RecipSqrt(float x) { return 1.0f/Sqrt(x); } +inline float Pow(float x, float y) { return powf(x, y); } diff --git a/src/modelinfo/BaseModelInfo.cpp b/src/modelinfo/BaseModelInfo.cpp index 37f94c93..830ead51 100644 --- a/src/modelinfo/BaseModelInfo.cpp +++ b/src/modelinfo/BaseModelInfo.cpp @@ -101,9 +101,15 @@ CBaseModelInfo::Get2dEffect(int n) } +class CBaseModelInfo_ : public CBaseModelInfo +{ +public: + void Shutdown_(void) { CBaseModelInfo::Shutdown(); } +}; STARTPATCHES // can't easily replace ctor at 4F6A50 - InjectHook(0x4F6A90, &CBaseModelInfo::Shutdown_, PATCH_JUMP); + InjectHook(0x4F6A90, &CBaseModelInfo_::Shutdown_, PATCH_JUMP); + InjectHook(0x4F6AC0, &CBaseModelInfo::DeleteCollisionModel, PATCH_JUMP); InjectHook(0x4F6B70, &CBaseModelInfo::ClearTexDictionary, PATCH_JUMP); InjectHook(0x4F6BA0, &CBaseModelInfo::AddRef, PATCH_JUMP); diff --git a/src/modelinfo/BaseModelInfo.h b/src/modelinfo/BaseModelInfo.h index da72990f..a9bafb64 100644 --- a/src/modelinfo/BaseModelInfo.h +++ b/src/modelinfo/BaseModelInfo.h @@ -62,8 +62,6 @@ public: void Init2dEffects(void); void Add2dEffect(C2dEffect *fx); C2dEffect *Get2dEffect(int n); - - void Shutdown_(void) { this->CBaseModelInfo::Shutdown(); } }; static_assert(sizeof(CBaseModelInfo) == 0x30, "CBaseModelInfo: error"); diff --git a/src/modelinfo/ClumpModelInfo.cpp b/src/modelinfo/ClumpModelInfo.cpp index 24deed38..d666313b 100644 --- a/src/modelinfo/ClumpModelInfo.cpp +++ b/src/modelinfo/ClumpModelInfo.cpp @@ -139,12 +139,22 @@ CClumpModelInfo::GetFrameFromId(RpClump *clump, int32 id) } +class CClumpModelInfo_ : public CClumpModelInfo +{ +public: + void DeleteRwObject_(void) { this->CClumpModelInfo::DeleteRwObject(); } + RwObject *CreateInstance_1(void) { return CClumpModelInfo::CreateInstance(); } + RwObject *CreateInstance_2(RwMatrix *m) { return CClumpModelInfo::CreateInstance(m); } + RwObject *GetRwObject_(void) { return CClumpModelInfo::GetRwObject(); } + void SetClump_(RpClump *clump) { CClumpModelInfo::SetClump(clump); } +}; + STARTPATCHES - InjectHook(0x4F8800, &CClumpModelInfo::DeleteRwObject_, PATCH_JUMP); - InjectHook(0x4F8920, &CClumpModelInfo::CreateInstance_1, PATCH_JUMP); - InjectHook(0x4F88A0, &CClumpModelInfo::CreateInstance_2, PATCH_JUMP); - InjectHook(0x50C1C0, &CClumpModelInfo::GetRwObject_, PATCH_JUMP); - InjectHook(0x4F8830, &CClumpModelInfo::SetClump_, PATCH_JUMP); + InjectHook(0x4F8800, &CClumpModelInfo_::DeleteRwObject_, PATCH_JUMP); + InjectHook(0x4F8920, &CClumpModelInfo_::CreateInstance_1, PATCH_JUMP); + InjectHook(0x4F88A0, &CClumpModelInfo_::CreateInstance_2, PATCH_JUMP); + InjectHook(0x50C1C0, &CClumpModelInfo_::GetRwObject_, PATCH_JUMP); + InjectHook(0x4F8830, &CClumpModelInfo_::SetClump_, PATCH_JUMP); InjectHook(0x4F8940, &CClumpModelInfo::SetAtomicRendererCB, PATCH_JUMP); InjectHook(0x4F8960, &CClumpModelInfo::FindFrameFromNameCB, PATCH_JUMP); InjectHook(0x4F8A10, &CClumpModelInfo::FindFrameFromNameWithoutIdCB, PATCH_JUMP); diff --git a/src/modelinfo/ClumpModelInfo.h b/src/modelinfo/ClumpModelInfo.h index 909d241b..d491bdb9 100644 --- a/src/modelinfo/ClumpModelInfo.h +++ b/src/modelinfo/ClumpModelInfo.h @@ -49,12 +49,5 @@ public: static void FillFrameArray(RpClump *clump, RwFrame **frames); static RwFrame *FillFrameArrayCB(RwFrame *frame, void *data); static RwFrame *GetFrameFromId(RpClump *clump, int32 id); - - - void DeleteRwObject_(void) { this->CClumpModelInfo::DeleteRwObject(); } - RwObject *CreateInstance_1(void) { return this->CClumpModelInfo::CreateInstance(); } - RwObject *CreateInstance_2(RwMatrix *m) { return this->CClumpModelInfo::CreateInstance(m); } - RwObject *GetRwObject_(void) { return this->CClumpModelInfo::GetRwObject(); } - void SetClump_(RpClump *clump) { this->CClumpModelInfo::SetClump(clump); } }; static_assert(sizeof(CClumpModelInfo) == 0x34, "CClumpModelInfo: error"); diff --git a/src/modelinfo/MloInstance.cpp b/src/modelinfo/MloInstance.cpp deleted file mode 100644 index dbd83727..00000000 --- a/src/modelinfo/MloInstance.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "MloInstance.h" - -STARTPATCHES -InjectHook(0x50BE90, &CMloInstance::dtor, PATCH_JUMP); -ENDPATCHES
\ No newline at end of file diff --git a/src/modelinfo/MloInstance.h b/src/modelinfo/MloInstance.h deleted file mode 100644 index 00afc379..00000000 --- a/src/modelinfo/MloInstance.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "Placeable.h" - -class CMloInstance : CPlaceable -{ -public: - void dtor() { this->CMloInstance::~CMloInstance(); } -};
\ No newline at end of file diff --git a/src/modelinfo/ModelIndices.h b/src/modelinfo/ModelIndices.h index 95b5eb43..0d9ffb53 100644 --- a/src/modelinfo/ModelIndices.h +++ b/src/modelinfo/ModelIndices.h @@ -164,7 +164,8 @@ // expand as needed enum { - MI_COP = 1, + MI_PLAYER = 0, + MI_COP, MI_SWAT, MI_FBI, MI_ARMY, diff --git a/src/modelinfo/PedModelInfo.cpp b/src/modelinfo/PedModelInfo.cpp index 775148c9..747cbc99 100644 --- a/src/modelinfo/PedModelInfo.cpp +++ b/src/modelinfo/PedModelInfo.cpp @@ -189,9 +189,17 @@ CPedModelInfo::CreateHitColModel(void) m_hitColModel = colmodel; } + +class CPedModelInfo_ : public CPedModelInfo +{ +public: + void DeleteRwObject_(void) { CPedModelInfo::DeleteRwObject(); } + void SetClump_(RpClump *clump) { CPedModelInfo::SetClump(clump); } +}; + STARTPATCHES - InjectHook(0x510210, &CPedModelInfo::SetClump_, PATCH_JUMP); - InjectHook(0x510280, &CPedModelInfo::DeleteRwObject_, PATCH_JUMP); + InjectHook(0x510210, &CPedModelInfo_::SetClump_, PATCH_JUMP); + InjectHook(0x510280, &CPedModelInfo_::DeleteRwObject_, PATCH_JUMP); InjectHook(0x510390, &CPedModelInfo::SetLowDetailClump, PATCH_JUMP); InjectHook(0x5104D0, &CPedModelInfo::CreateHitColModel, PATCH_JUMP); ENDPATCHES diff --git a/src/modelinfo/PedModelInfo.h b/src/modelinfo/PedModelInfo.h index 7be2c195..bec46b4e 100644 --- a/src/modelinfo/PedModelInfo.h +++ b/src/modelinfo/PedModelInfo.h @@ -39,9 +39,5 @@ public: void SetLowDetailClump(RpClump*); void CreateHitColModel(void); CColModel *GetHitColModel(void) { return m_hitColModel; } - - - void DeleteRwObject_(void) { this->CPedModelInfo::DeleteRwObject(); } - void SetClump_(RpClump *clump) { this->CPedModelInfo::SetClump(clump); } }; static_assert(sizeof(CPedModelInfo) == 0x54, "CPedModelInfo: error"); diff --git a/src/modelinfo/SimpleModelInfo.cpp b/src/modelinfo/SimpleModelInfo.cpp index ea7a3f9e..dd5010fa 100644 --- a/src/modelinfo/SimpleModelInfo.cpp +++ b/src/modelinfo/SimpleModelInfo.cpp @@ -154,12 +154,20 @@ CSimpleModelInfo::SetupBigBuilding(void) } } +class CSimpleModelInfo_ : public CSimpleModelInfo +{ +public: + void DeleteRwObject_(void) { CSimpleModelInfo::DeleteRwObject(); } + RwObject *CreateInstance_1(void) { return CSimpleModelInfo::CreateInstance(); } + RwObject *CreateInstance_2(RwMatrix *m) { return CSimpleModelInfo::CreateInstance(m); } + RwObject *GetRwObject_(void) { return CSimpleModelInfo::GetRwObject(); } +}; STARTPATCHES - InjectHook(0x5179B0, &CSimpleModelInfo::DeleteRwObject_, PATCH_JUMP); - InjectHook(0x517B60, &CSimpleModelInfo::CreateInstance_1, PATCH_JUMP); - InjectHook(0x517AC0, &CSimpleModelInfo::CreateInstance_2, PATCH_JUMP); - InjectHook(0x4A9BA0, &CSimpleModelInfo::GetRwObject_, PATCH_JUMP); + InjectHook(0x5179B0, &CSimpleModelInfo_::DeleteRwObject_, PATCH_JUMP); + InjectHook(0x517B60, &CSimpleModelInfo_::CreateInstance_1, PATCH_JUMP); + InjectHook(0x517AC0, &CSimpleModelInfo_::CreateInstance_2, PATCH_JUMP); + InjectHook(0x4A9BA0, &CSimpleModelInfo_::GetRwObject_, PATCH_JUMP); InjectHook(0x517990, &CSimpleModelInfo::Init, PATCH_JUMP); InjectHook(0x517C60, &CSimpleModelInfo::IncreaseAlpha, PATCH_JUMP); InjectHook(0x517950, &CSimpleModelInfo::SetAtomic, PATCH_JUMP); diff --git a/src/modelinfo/SimpleModelInfo.h b/src/modelinfo/SimpleModelInfo.h index d5b572a6..35d48669 100644 --- a/src/modelinfo/SimpleModelInfo.h +++ b/src/modelinfo/SimpleModelInfo.h @@ -48,10 +48,5 @@ public: return (CSimpleModelInfo*)m_atomics[2]; } void SetRelatedModel(CSimpleModelInfo *m){ m_atomics[2] = (RpAtomic*)m; } - - void DeleteRwObject_(void) { this->CSimpleModelInfo::DeleteRwObject(); } - RwObject *CreateInstance_1(void) { return this->CSimpleModelInfo::CreateInstance(); } - RwObject *CreateInstance_2(RwMatrix *m) { return this->CSimpleModelInfo::CreateInstance(m); } - RwObject *GetRwObject_(void) { return this->CSimpleModelInfo::GetRwObject(); } }; static_assert(sizeof(CSimpleModelInfo) == 0x4C, "CSimpleModelInfo: error"); diff --git a/src/modelinfo/VehicleModelInfo.cpp b/src/modelinfo/VehicleModelInfo.cpp index f112d546..9b2924e9 100644 --- a/src/modelinfo/VehicleModelInfo.cpp +++ b/src/modelinfo/VehicleModelInfo.cpp @@ -414,11 +414,13 @@ CVehicleModelInfo::SetAtomicFlagCB(RwObject *object, void *data) return object; } -RpAtomic* -CVehicleModelInfo::ClearAtomicFlagCB(RpAtomic *atomic, void *data) +RwObject* +CVehicleModelInfo::ClearAtomicFlagCB(RwObject *object, void *data) { + RpAtomic *atomic = (RpAtomic*)object; + assert(RwObjectGetType(object) == rpATOMIC); CVisibilityPlugins::ClearAtomicFlag(atomic, (int)data); - return atomic; + return object; } RwObject* @@ -1098,10 +1100,18 @@ CVehicleModelInfo::GetMaximumNumberOfPassengersFromNumberOfDoors(int id) return n - 1; } +class CVehicleModelInfo_ : public CVehicleModelInfo +{ +public: + void DeleteRwObject_(void) { CVehicleModelInfo::DeleteRwObject(); } + RwObject *CreateInstance_(void) { return CVehicleModelInfo::CreateInstance(); } + void SetClump_(RpClump *clump) { CVehicleModelInfo::SetClump(clump); } +}; + STARTPATCHES - InjectHook(0x51FDC0, &CVehicleModelInfo::DeleteRwObject_, PATCH_JUMP); - InjectHook(0x51FCB0, &CVehicleModelInfo::CreateInstance_, PATCH_JUMP); - InjectHook(0x51FC60, &CVehicleModelInfo::SetClump_, PATCH_JUMP); + InjectHook(0x51FDC0, &CVehicleModelInfo_::DeleteRwObject_, PATCH_JUMP); + InjectHook(0x51FCB0, &CVehicleModelInfo_::CreateInstance_, PATCH_JUMP); + InjectHook(0x51FC60, &CVehicleModelInfo_::SetClump_, PATCH_JUMP); InjectHook(0x51FE10, &CVehicleModelInfo::CollapseFramesCB, PATCH_JUMP); InjectHook(0x51FE50, &CVehicleModelInfo::MoveObjectsCB, PATCH_JUMP); diff --git a/src/modelinfo/VehicleModelInfo.h b/src/modelinfo/VehicleModelInfo.h index 2e2f1be2..37f47489 100644 --- a/src/modelinfo/VehicleModelInfo.h +++ b/src/modelinfo/VehicleModelInfo.h @@ -10,6 +10,7 @@ enum { }; enum { + ATOMIC_FLAG_NONE = 0x0, ATOMIC_FLAG_OK = 0x1, ATOMIC_FLAG_DAM = 0x2, ATOMIC_FLAG_LEFT = 0x4, @@ -106,7 +107,7 @@ public: void SetAtomicRenderCallbacks(void); static RwObject *SetAtomicFlagCB(RwObject *object, void *data); - static RpAtomic *ClearAtomicFlagCB(RpAtomic *atomic, void *data); + static RwObject *ClearAtomicFlagCB(RwObject *atomic, void *data); void SetVehicleComponentFlags(RwFrame *frame, uint32 flags); void PreprocessHierarchy(void); void GetWheelPosn(int32 n, CVector &pos); @@ -131,9 +132,5 @@ public: static void ShutdownEnvironmentMaps(void); static int GetMaximumNumberOfPassengersFromNumberOfDoors(int id); - - void DeleteRwObject_(void) { this->CVehicleModelInfo::DeleteRwObject(); } - RwObject *CreateInstance_(void) { return this->CVehicleModelInfo::CreateInstance(); } - void SetClump_(RpClump *clump) { this->CVehicleModelInfo::SetClump(clump); } }; static_assert(sizeof(CVehicleModelInfo) == 0x1F8, "CVehicleModelInfo: error"); diff --git a/src/objects/CutsceneHead.cpp b/src/objects/CutsceneHead.cpp index a9c47777..c423d0b8 100644 --- a/src/objects/CutsceneHead.cpp +++ b/src/objects/CutsceneHead.cpp @@ -109,10 +109,19 @@ CCutsceneHead::PlayAnimation(const char *animName) } } +class CCutsceneHead_ : public CCutsceneHead +{ +public: + void CreateRwObject_(void) { CCutsceneHead::CreateRwObject(); } + void DeleteRwObject_(void) { CCutsceneHead::DeleteRwObject(); } + void ProcessControl_(void) { CCutsceneHead::ProcessControl(); } + void Render_(void) { CCutsceneHead::Render(); } +}; + STARTPATCHES - InjectHook(0x4BA650, &CCutsceneHead::CreateRwObject_, PATCH_JUMP); - InjectHook(0x4BA690, &CCutsceneHead::DeleteRwObject_, PATCH_JUMP); - InjectHook(0x4BA760, &CCutsceneHead::ProcessControl_, PATCH_JUMP); - InjectHook(0x4BA800, &CCutsceneHead::Render_, PATCH_JUMP); + InjectHook(0x4BA650, &CCutsceneHead_::CreateRwObject_, PATCH_JUMP); + InjectHook(0x4BA690, &CCutsceneHead_::DeleteRwObject_, PATCH_JUMP); + InjectHook(0x4BA760, &CCutsceneHead_::ProcessControl_, PATCH_JUMP); + InjectHook(0x4BA800, &CCutsceneHead_::Render_, PATCH_JUMP); InjectHook(0x4BA6A0, &CCutsceneHead::PlayAnimation, PATCH_JUMP); ENDPATCHES diff --git a/src/objects/CutsceneHead.h b/src/objects/CutsceneHead.h index de4f011f..52b66ede 100644 --- a/src/objects/CutsceneHead.h +++ b/src/objects/CutsceneHead.h @@ -15,10 +15,5 @@ public: void Render(void); void PlayAnimation(const char *animName); - - void CreateRwObject_(void) { CCutsceneHead::CreateRwObject(); } - void DeleteRwObject_(void) { CCutsceneHead::DeleteRwObject(); } - void ProcessControl_(void) { CCutsceneHead::ProcessControl(); } - void Render_(void) { CCutsceneHead::Render(); } }; static_assert(sizeof(CCutsceneHead) == 0x19C, "CCutsceneHead: error"); diff --git a/src/objects/CutsceneObject.cpp b/src/objects/CutsceneObject.cpp index ede5be5b..2f667a5d 100644 --- a/src/objects/CutsceneObject.cpp +++ b/src/objects/CutsceneObject.cpp @@ -89,12 +89,24 @@ CCutsceneObject::RemoveLighting(bool reset) CRenderer::RemoveVehiclePedLights(this, reset); } +class CCutsceneObject_ : public CCutsceneObject +{ +public: + void dtor(void) { this->CCutsceneObject::~CCutsceneObject(); } + void SetModelIndex_(uint32 id) { CCutsceneObject::SetModelIndex(id); } + void ProcessControl_(void) { CCutsceneObject::ProcessControl(); } + void PreRender_(void) { CCutsceneObject::PreRender(); } + void Render_(void) { CCutsceneObject::Render(); } + bool SetupLighting_(void) { return CCutsceneObject::SetupLighting(); } + void RemoveLighting_(bool reset) { CCutsceneObject::RemoveLighting(reset); } +}; + STARTPATCHES - InjectHook(0x4BA960, &CCutsceneObject::dtor, PATCH_JUMP); - InjectHook(0x4BA980, &CCutsceneObject::SetModelIndex_, PATCH_JUMP); - InjectHook(0x4BA9C0, &CCutsceneObject::ProcessControl_, PATCH_JUMP); - InjectHook(0x4BAA40, &CCutsceneObject::PreRender_, PATCH_JUMP); - InjectHook(0x4BAAA0, &CCutsceneObject::Render_, PATCH_JUMP); - InjectHook(0x4A7E70, &CCutsceneObject::SetupLighting_, PATCH_JUMP); - InjectHook(0x4A7F00, &CCutsceneObject::RemoveLighting_, PATCH_JUMP); + InjectHook(0x4BA960, &CCutsceneObject_::dtor, PATCH_JUMP); + InjectHook(0x4BA980, &CCutsceneObject_::SetModelIndex_, PATCH_JUMP); + InjectHook(0x4BA9C0, &CCutsceneObject_::ProcessControl_, PATCH_JUMP); + InjectHook(0x4BAA40, &CCutsceneObject_::PreRender_, PATCH_JUMP); + InjectHook(0x4BAAA0, &CCutsceneObject_::Render_, PATCH_JUMP); + InjectHook(0x4A7E70, &CCutsceneObject_::SetupLighting_, PATCH_JUMP); + InjectHook(0x4A7F00, &CCutsceneObject_::RemoveLighting_, PATCH_JUMP); ENDPATCHES diff --git a/src/objects/CutsceneObject.h b/src/objects/CutsceneObject.h index 9360651e..31c3a528 100644 --- a/src/objects/CutsceneObject.h +++ b/src/objects/CutsceneObject.h @@ -7,19 +7,11 @@ class CCutsceneObject : public CObject public: CCutsceneObject(void); - virtual void SetModelIndex(uint32 id); - virtual void ProcessControl(void); - virtual void PreRender(void); - virtual void Render(void); - virtual bool SetupLighting(void); - virtual void RemoveLighting(bool reset); - - void dtor(void) { this->CCutsceneObject::~CCutsceneObject(); } - void SetModelIndex_(uint32 id) { CCutsceneObject::SetModelIndex(id); } - void ProcessControl_(void) { CCutsceneObject::ProcessControl(); } - void PreRender_(void) { CCutsceneObject::PreRender(); } - void Render_(void) { CCutsceneObject::Render(); } - bool SetupLighting_(void) { return CCutsceneObject::SetupLighting(); } - void RemoveLighting_(bool reset) { CCutsceneObject::RemoveLighting(reset); } + void SetModelIndex(uint32 id); + void ProcessControl(void); + void PreRender(void); + void Render(void); + bool SetupLighting(void); + void RemoveLighting(bool reset); }; static_assert(sizeof(CCutsceneObject) == 0x198, "CCutsceneObject: error"); diff --git a/src/objects/DummyObject.cpp b/src/objects/DummyObject.cpp index 1e4b2ae0..41b15129 100644 --- a/src/objects/DummyObject.cpp +++ b/src/objects/DummyObject.cpp @@ -12,6 +12,12 @@ CDummyObject::CDummyObject(CObject *obj) m_level = obj->m_level; } +class CDummyObject_ : public CDummyObject +{ +public: + void dtor(void) { CDummyObject::~CDummyObject(); } +}; + STARTPATCHES - InjectHook(0x4BAB70, &CDummyObject::dtor, PATCH_JUMP); -ENDPATCHES
\ No newline at end of file + InjectHook(0x4BAB70, &CDummyObject_::dtor, PATCH_JUMP); +ENDPATCHES diff --git a/src/objects/DummyObject.h b/src/objects/DummyObject.h index 10554bdd..d4dce609 100644 --- a/src/objects/DummyObject.h +++ b/src/objects/DummyObject.h @@ -9,6 +9,5 @@ class CDummyObject : public CDummy public: CDummyObject(void) {} CDummyObject(CObject *obj); - void dtor(void) { this->CDummyObject::~CDummyObject(); } }; static_assert(sizeof(CDummyObject) == 0x68, "CDummyObject: error"); diff --git a/src/objects/Object.cpp b/src/objects/Object.cpp index 6712d77b..f3ba8087 100644 --- a/src/objects/Object.cpp +++ b/src/objects/Object.cpp @@ -7,8 +7,10 @@ #include "Object.h" WRAPPER void CObject::ObjectDamage(float amount) { EAXJMP(0x4BB240); } +WRAPPER void CObject::DeleteAllTempObjectInArea(CVector, float) { EAXJMP(0x4BBED0); } int16 &CObject::nNoTempObjects = *(int16*)0x95CCA2; +int16 &CObject::nBodyCastHealth = *(int16*)0x5F7D4C; // 1000 void *CObject::operator new(size_t sz) { return CPools::GetObjectPool()->New(); } void CObject::operator delete(void *p, size_t sz) { CPools::GetObjectPool()->Delete((CObject*)p); } @@ -85,9 +87,22 @@ CObject::RemoveLighting(bool reset) WorldReplaceScorchedLightsWithNormal(Scene.world); } -WRAPPER void CObject::DeleteAllTempObjectInArea(CVector, float) { EAXJMP(0x4BBED0); } + +void +CObject::RefModelInfo(int32 modelId) +{ + m_nRefModelIndex = modelId; + CModelInfo::GetModelInfo(modelId)->AddRef(); +} + +class CObject_ : public CObject +{ +public: + void dtor(void) { this->CObject::~CObject(); } + void Render_(void) { CObject::Render(); } +}; STARTPATCHES - InjectHook(0x4BAE00, &CObject::dtor, PATCH_JUMP); - InjectHook(0x4BB1E0, &CObject::Render_, PATCH_JUMP); + InjectHook(0x4BAE00, &CObject_::dtor, PATCH_JUMP); + InjectHook(0x4BB1E0, &CObject_::Render_, PATCH_JUMP); ENDPATCHES diff --git a/src/objects/Object.h b/src/objects/Object.h index de4c8e05..0ce1a3aa 100644 --- a/src/objects/Object.h +++ b/src/objects/Object.h @@ -60,6 +60,7 @@ public: int8 m_colour1, m_colour2; static int16 &nNoTempObjects; + static int16 &nBodyCastHealth; static void *operator new(size_t); static void operator delete(void*, size_t); @@ -72,10 +73,8 @@ public: void RemoveLighting(bool reset); void ObjectDamage(float amount); + void RefModelInfo(int32 modelId); static void DeleteAllTempObjectInArea(CVector, float); - - void dtor(void) { this->CObject::~CObject(); } - void Render_(void) { CObject::Render(); } }; static_assert(sizeof(CObject) == 0x198, "CObject: error"); diff --git a/src/objects/ParticleObject.cpp b/src/objects/ParticleObject.cpp index cf6e84bf..25f223e1 100644 --- a/src/objects/ParticleObject.cpp +++ b/src/objects/ParticleObject.cpp @@ -18,6 +18,12 @@ void CParticleObject::UpdateAll() ((void (__cdecl *)())0x4BCA30)(); } +class CParticleObject_ : public CParticleObject +{ +public: + void dtor() { CParticleObject::~CParticleObject(); } +}; + STARTPATCHES - InjectHook(0x4BC420, &CParticleObject::dtor, PATCH_JUMP); -ENDPATCHES
\ No newline at end of file + InjectHook(0x4BC420, &CParticleObject_::dtor, PATCH_JUMP); +ENDPATCHES diff --git a/src/objects/ParticleObject.h b/src/objects/ParticleObject.h index def7b7de..6ec090e7 100644 --- a/src/objects/ParticleObject.h +++ b/src/objects/ParticleObject.h @@ -34,6 +34,4 @@ public: static void AddObject(uint16 type, const CVector &pos, const CVector &dir, float size, bool remove); static void Initialise(); static void UpdateAll(); - - void dtor() { this->CParticleObject::~CParticleObject(); } }; diff --git a/src/objects/Projectile.cpp b/src/objects/Projectile.cpp index e21323de..c6c2d6e1 100644 --- a/src/objects/Projectile.cpp +++ b/src/objects/Projectile.cpp @@ -2,6 +2,12 @@ #include "patcher.h" #include "Projectile.h" +class CProjectile_ : public CProjectile +{ +public: + void dtor(void) { CProjectile::~CProjectile(); } +}; + STARTPATCHES - InjectHook(0x4BFED0, &CProjectile::dtor, PATCH_JUMP); -ENDPATCHES
\ No newline at end of file + InjectHook(0x4BFED0, &CProjectile_::dtor, PATCH_JUMP); +ENDPATCHES diff --git a/src/objects/Projectile.h b/src/objects/Projectile.h index a8e826b6..4d5041f8 100644 --- a/src/objects/Projectile.h +++ b/src/objects/Projectile.h @@ -7,5 +7,4 @@ class CProjectile : public CObject { public: - void dtor(void) { this->CProjectile::~CProjectile(); } }; diff --git a/src/peds/CivilianPed.cpp b/src/peds/CivilianPed.cpp index a4881e71..cf8a0580 100644 --- a/src/peds/CivilianPed.cpp +++ b/src/peds/CivilianPed.cpp @@ -13,7 +13,14 @@ CCivilianPed::CCivilianPed(int pedtype, int mi) : CPed(pedtype) } } +class CCivilianPed_ : public CCivilianPed +{ +public: + CCivilianPed *ctor(int pedtype, int mi) { return ::new (this) CCivilianPed(pedtype, mi); }; + void dtor(void) { CCivilianPed::~CCivilianPed(); } +}; + STARTPATCHES - InjectHook(0x4BFF30, &CCivilianPed::ctor, PATCH_JUMP); - InjectHook(0x4BFFC0, &CCivilianPed::dtor, PATCH_JUMP); -ENDPATCHES
\ No newline at end of file + InjectHook(0x4BFF30, &CCivilianPed_::ctor, PATCH_JUMP); + InjectHook(0x4BFFC0, &CCivilianPed_::dtor, PATCH_JUMP); +ENDPATCHES diff --git a/src/peds/CivilianPed.h b/src/peds/CivilianPed.h index 8d004ad7..14859a5c 100644 --- a/src/peds/CivilianPed.h +++ b/src/peds/CivilianPed.h @@ -6,11 +6,8 @@ class CCivilianPed : public CPed { public: CCivilianPed(int, int); - virtual ~CCivilianPed(void) { } + ~CCivilianPed(void) { } - virtual void ProcessControl(void); - - CCivilianPed *ctor(int pedtype, int mi) { return ::new (this) CCivilianPed(pedtype, mi); }; - void dtor(void) { this->CCivilianPed::~CCivilianPed(); } + void ProcessControl(void); }; static_assert(sizeof(CCivilianPed) == 0x53C, "CCivilianPed: error"); diff --git a/src/peds/CopPed.cpp b/src/peds/CopPed.cpp index 041185ee..0ac0473f 100644 --- a/src/peds/CopPed.cpp +++ b/src/peds/CopPed.cpp @@ -9,6 +9,12 @@ CCopPed::~CCopPed() WRAPPER void CCopPed::ClearPursuit(void) { EAXJMP(0x4C28C0); } +class CCopPed_ : public CCopPed +{ +public: + void dtor(void) { CCopPed::~CCopPed(); } +}; + STARTPATCHES - InjectHook(0x4C13E0, &CCopPed::dtor, PATCH_JUMP); -ENDPATCHES
\ No newline at end of file + InjectHook(0x4C13E0, &CCopPed_::dtor, PATCH_JUMP); +ENDPATCHES diff --git a/src/peds/CopPed.h b/src/peds/CopPed.h index b938dfc2..5827f9bc 100644 --- a/src/peds/CopPed.h +++ b/src/peds/CopPed.h @@ -65,7 +65,6 @@ public: int8 field_1367; ~CCopPed(); - void dtor(void) { this->CCopPed::~CCopPed(); } void ClearPursuit(void); }; diff --git a/src/peds/EmergencyPed.cpp b/src/peds/EmergencyPed.cpp index 7b847896..664bd6f6 100644 --- a/src/peds/EmergencyPed.cpp +++ b/src/peds/EmergencyPed.cpp @@ -2,6 +2,12 @@ #include "patcher.h" #include "EmergencyPed.h" +class CEmergencyPed_ : public CEmergencyPed +{ +public: + void dtor(void) { CEmergencyPed::~CEmergencyPed(); } +}; + STARTPATCHES -InjectHook(0x4C2EF0, &CEmergencyPed::dtor, PATCH_JUMP); -ENDPATCHES
\ No newline at end of file + InjectHook(0x4C2EF0, &CEmergencyPed_::dtor, PATCH_JUMP); +ENDPATCHES diff --git a/src/peds/EmergencyPed.h b/src/peds/EmergencyPed.h index fa07f3ee..f21996e8 100644 --- a/src/peds/EmergencyPed.h +++ b/src/peds/EmergencyPed.h @@ -7,7 +7,5 @@ class CEmergencyPed : public CPed public: // 0x53C uint8 stuff[24]; - - void dtor(void) { this->CEmergencyPed::~CEmergencyPed(); } }; static_assert(sizeof(CEmergencyPed) == 0x554, "CEmergencyPed: error"); diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index 80ef53ee..4ad4ac1b 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -10,6 +10,7 @@ #include "Ped.h" #include "PlayerPed.h" #include "General.h" +#include "SurfaceTable.h" #include "VisibilityPlugins.h" #include "AudioManager.h" #include "HandlingMgr.h" @@ -23,10 +24,12 @@ #include "Lights.h" #include "PointLights.h" #include "Pad.h" +#include "Phones.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); } @@ -41,6 +44,8 @@ WRAPPER void CPed::SetMoveAnim(void) { EAXJMP(0x4C5A40); } 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 bool CPed::Seek(void) { EAXJMP(0x4D1640); } bool &CPed::bNastyLimbsCheat = *(bool*)0x95CD44; bool &CPed::bPedCheat2 = *(bool*)0x95CD5A; @@ -62,7 +67,7 @@ CPed::~CPed(void) CWorld::Remove(this); CRadar::ClearBlipForEntity(BLIP_CHAR, CPools::GetPedPool()->GetIndex(this)); if (bInVehicle && m_pMyVehicle){ - uint8 door_flag = GetVehEnterExitFlag(m_vehEnterType); + uint8 door_flag = GetVehDoorFlag(m_vehEnterType); if (m_pMyVehicle->pDriver == this) m_pMyVehicle->pDriver = nil; else { @@ -308,7 +313,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) m_fRotationCur = 0.0f; m_headingRate = 15.0f; m_fRotationDest = 0.0f; - m_vehEnterType = VEHICLE_ENTER_FRONT_LEFT; + m_vehEnterType = CAR_DOOR_LF; m_walkAroundType = 0; m_pCurrentPhysSurface = nil; m_vecOffsetFromPhysSurface = CVector(0.0f, 0.0f, 0.0f); @@ -429,7 +434,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) m_ped_flagI1 = false; m_ped_flagI2 = false; m_ped_flagI4 = false; - bRecordedForReplay = false; + bHasAlreadyBeenRecorded = false; m_ped_flagI10 = false; #ifdef KANGAROO_CHEAT m_ped_flagI80 = false; @@ -456,9 +461,9 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) } m_maxWeaponTypeAllowed = 0; m_currentWeapon = 0; - m_storedWeapon = NO_STORED_WEAPON; + m_storedWeapon = WEAPONTYPE_UNIDENTIFIED; - for(int i = 0; i < NUM_PED_WEAPONTYPES; i++) + for(int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++) { CWeapon &weapon = GetWeapon(i); weapon.m_eWeaponType = WEAPONTYPE_UNARMED; @@ -546,7 +551,7 @@ CheckForPedsOnGroundToAttack(CPlayerPed *player, CPed **pedOnGround) angleToFace = CGeneral::LimitRadianAngle(angleToFace); player->m_fRotationCur = CGeneral::LimitRadianAngle(player->m_fRotationCur); - angleDiff = fabs(angleToFace - player->m_fRotationCur); + angleDiff = Abs(angleToFace - player->m_fRotationCur); if (angleDiff > PI) angleDiff = 2 * PI - angleDiff; @@ -668,7 +673,7 @@ CPed::AimGun(void) vector.y = pos.y; vector.z = pos.z; } else { - vector = *(m_pSeekTarget->GetPosition()); + vector = m_pSeekTarget->GetPosition(); } Say(SOUND_PED_ATTACK); @@ -867,7 +872,7 @@ CPed::Avoid(void) // If so, we want to avoid it, so we turn our body 45 degree and look to somewhere else. // Game converts from radians to degress and back again here, doesn't make much sense - CVector2D forward(-sin(m_fRotationCur), cos(m_fRotationCur)); + CVector2D forward(-Sin(m_fRotationCur), Cos(m_fRotationCur)); forward.Normalise(); // this is kinda pointless // Move forward 1.25 meters @@ -1333,7 +1338,7 @@ CPed::BeingDraggedFromCar(void) if (animAssoc) animAssoc->blendDelta = -1000.0f; - if (m_vehEnterType == VEHICLE_ENTER_FRONT_LEFT || m_vehEnterType == VEHICLE_ENTER_REAR_LEFT) { + if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) { if (m_ped_flagF10) { enterAnim = ANIM_CAR_QJACKED; } else if (m_pMyVehicle->bLowVehicle) { @@ -1341,7 +1346,7 @@ CPed::BeingDraggedFromCar(void) } else { enterAnim = ANIM_CAR_JACKED_LHS; } - } else if (m_vehEnterType == VEHICLE_ENTER_FRONT_RIGHT || m_vehEnterType == VEHICLE_ENTER_REAR_RIGHT) { + } else if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) { if (m_pMyVehicle->bLowVehicle) enterAnim = ANIM_CAR_LJACKED_RHS; else @@ -1388,14 +1393,14 @@ CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg) if (ped->m_nPedState != PED_ARRESTED) { ped->m_nLastPedState = PED_NONE; if (dragAssoc) - dragAssoc->blendDelta = -1000.0; + dragAssoc->blendDelta = -1000.0f; } ped->RestartNonPartialAnims(); ped->m_pVehicleAnim = nil; ped->m_pSeekTarget = nil; vehicle = ped->m_pMyVehicle; - vehicle->m_nGettingOutFlags &= ~GetVehEnterExitFlag(ped->m_vehEnterType); + vehicle->m_nGettingOutFlags &= ~GetVehDoorFlag(ped->m_vehEnterType); if (vehicle->pDriver == ped) { vehicle->RemoveDriver(); @@ -1427,9 +1432,9 @@ CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg) // Only uzi can be used on cars, so previous weapon was stored if (ped->IsPlayer() && weaponType == WEAPONTYPE_UZI) { - if (ped->m_storedWeapon != NO_STORED_WEAPON) { + if (ped->m_storedWeapon != WEAPONTYPE_UNIDENTIFIED) { ped->SetCurrentWeapon(ped->m_storedWeapon); - ped->m_storedWeapon = NO_STORED_WEAPON; + ped->m_storedWeapon = WEAPONTYPE_UNIDENTIFIED; } } else { ped->AddWeaponModel(CWeaponInfo::GetWeaponInfo(weaponType)->m_nModelId); @@ -1447,7 +1452,7 @@ CPed::GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enter float seatOffset; vehModel = (CVehicleModelInfo*) CModelInfo::GetModelInfo(veh->m_modelIndex); - if (veh->bIsVan && (enterType == VEHICLE_ENTER_REAR_LEFT || enterType == VEHICLE_ENTER_REAR_RIGHT)) { + if (veh->bIsVan && (enterType == CAR_DOOR_LR || enterType == CAR_DOOR_RR)) { seatOffset = 0.0f; vehDoorOffset = offsetToOpenVanDoor; } else { @@ -1460,7 +1465,7 @@ CPed::GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enter } switch (enterType) { - case VEHICLE_ENTER_FRONT_RIGHT: + case CAR_DOOR_RF: if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT) vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_BOAT_RUDDER]; else @@ -1470,13 +1475,13 @@ CPed::GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enter vehDoorOffset.x = -vehDoorOffset.x; break; - case VEHICLE_ENTER_REAR_RIGHT: + case CAR_DOOR_RR: vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_REAR_SEATS]; vehDoorPos.x += seatOffset; vehDoorOffset.x = -vehDoorOffset.x; break; - case VEHICLE_ENTER_FRONT_LEFT: + case CAR_DOOR_LF: if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT) vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_BOAT_RUDDER]; else @@ -1485,7 +1490,7 @@ CPed::GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enter vehDoorPos.x = -(vehDoorPos.x + seatOffset); break; - case VEHICLE_ENTER_REAR_LEFT: + case CAR_DOOR_LR: vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_REAR_SEATS]; vehDoorPos.x = -(vehDoorPos.x + seatOffset); break; @@ -1539,7 +1544,7 @@ CPed::GetPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, GetLocalPositionToOpenCarDoor(output, veh, enterType, offset); doorPos = Multiply3x3(vehMat, *output); - *output = *veh->GetPosition() + doorPos; + *output = veh->GetPosition() + doorPos; } void @@ -1583,7 +1588,7 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) if (veh->GetUp().z <= -0.8f) vehIsUpsideDown = true; - if (m_vehEnterType == VEHICLE_ENTER_FRONT_RIGHT || m_vehEnterType == VEHICLE_ENTER_REAR_RIGHT) { + if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) { if (vehIsUpsideDown) { m_fRotationDest = -PI + veh->GetForward().Heading(); } else if (veh->bIsBus) { @@ -1591,7 +1596,7 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) } else { m_fRotationDest = veh->GetForward().Heading(); } - } else if (m_vehEnterType == VEHICLE_ENTER_FRONT_LEFT || m_vehEnterType == VEHICLE_ENTER_REAR_LEFT) { + } else if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) { if (vehIsUpsideDown) { m_fRotationDest = veh->GetForward().Heading(); } else if (veh->bIsBus) { @@ -1658,7 +1663,7 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) CVector neededPos; if (phase == LINE_UP_TO_CAR_2) { - neededPos = *GetPosition(); + neededPos = GetPosition(); } else { GetPositionToOpenCarDoor(&neededPos, veh, m_vehEnterType, seatPosMult); } @@ -1762,7 +1767,7 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) CMatrix vehDoorMat(veh->GetMatrix()); GetLocalPositionToOpenCarDoor(&output, veh, m_vehEnterType, 0.0f); - *vehDoorMat.GetPosition() += Multiply3x3(vehDoorMat, output); + vehDoorMat.GetPosition() += Multiply3x3(vehDoorMat, output); GetMatrix() = vehDoorMat; } @@ -1771,12 +1776,12 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) static void particleProduceFootDust(CPed *ped, CVector *pos, float size, int times) { - switch (ped->m_nLastCollType) + switch (ped->m_nSurfaceTouched) { - case 1: // somewhere hard - case 3: // soft dirt - case 5: // pavement - case 18:// sand + case SURFACE_TARMAC: + case SURFACE_DIRT: + case SURFACE_PAVEMENT: + case SURFACE_SAND: for (int i = 0; i < times; ++i) { CVector adjustedPos = *pos; adjustedPos.x += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); @@ -1878,7 +1883,7 @@ CPed::PlayFootSteps(void) } } - if (m_nLastCollType == 19) { // Water + if (m_nSurfaceTouched == SURFACE_PUDDLE) { float pedSpeed = CVector2D(m_vecMoveSpeed).Magnitude(); if (pedSpeed > 0.03f && CTimer::GetFrameCounter() % 2 == 0 && pedSpeed > 0.13f) { float particleSize = pedSpeed * 2.0f; @@ -2054,6 +2059,7 @@ CPed::SetupLighting(void) { ActivateDirectional(); SetAmbientColoursForPedsCarsAndObjects(); + if (bRenderScorched) { WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f); } else { @@ -2086,7 +2092,7 @@ CPed::CalculateNewOrientation(void) if (CReplay::IsPlayingBack() || !IsPedInControl()) return; - CVector pos = *GetPosition(); + CVector pos = GetPosition(); GetMatrix().SetRotate(0.0f, 0.0f, m_fRotationCur); @@ -2145,10 +2151,10 @@ CPed::CalculateNewVelocity(void) } } - CVector2D forward(sin(m_fRotationCur), cos(m_fRotationCur)); + CVector2D forward(Sin(m_fRotationCur), Cos(m_fRotationCur)); - m_moved.x = CrossProduct2D(m_vecAnimMoveDelta, forward); // (m_vecAnimMoveDelta.x * cos(m_fRotationCur)) + -sin(m_fRotationCur) * m_vecAnimMoveDelta.y; - m_moved.y = DotProduct2D(m_vecAnimMoveDelta, forward); // m_vecAnimMoveDelta.y* cos(m_fRotationCur) + (m_vecAnimMoveDelta.x * sin(m_fRotationCur)); + m_moved.x = CrossProduct2D(m_vecAnimMoveDelta, forward); // (m_vecAnimMoveDelta.x * Cos(m_fRotationCur)) + -Sin(m_fRotationCur) * m_vecAnimMoveDelta.y; + m_moved.y = DotProduct2D(m_vecAnimMoveDelta, forward); // m_vecAnimMoveDelta.y* Cos(m_fRotationCur) + (m_vecAnimMoveDelta.x * Sin(m_fRotationCur)); if (CTimer::GetTimeStep() >= 0.01f) { m_moved = m_moved * (1 / CTimer::GetTimeStep()); @@ -2173,7 +2179,7 @@ CPed::CalculateNewVelocity(void) // Interestingly this part is responsible for diagonal walking. if (localWalkAngle > -DEGTORAD(50.0f) && localWalkAngle < DEGTORAD(50.0f)) { TheCamera.Cams[TheCamera.ActiveCam].m_fPlayerVelocity = pedSpeed; - m_moved = CVector2D(-sin(walkAngle), cos(walkAngle)) * pedSpeed; + m_moved = CVector2D(-Sin(walkAngle), Cos(walkAngle)) * pedSpeed; } CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_STANCE); @@ -2233,7 +2239,7 @@ CPed::CanPedDriveOff(void) bool CPed::CanPedJumpThis(int32 unused) { - CVector2D forward(-sin(m_fRotationCur), cos(m_fRotationCur)); + CVector2D forward(-Sin(m_fRotationCur), Cos(m_fRotationCur)); CVector pos = GetPosition(); // wat? CVector forwardPos( @@ -2270,7 +2276,7 @@ CPed::CanSeeEntity(CEntity *entity, float threshold) else if (ourAngle > 2 * PI) ourAngle -= 2 * PI; - float neededTurn = fabs(neededAngle - ourAngle); + float neededTurn = Abs(neededAngle - ourAngle); return neededTurn < threshold || 2 * PI - threshold < neededTurn; } @@ -2695,15 +2701,15 @@ CPed::QuitEnteringCar(void) if (veh->m_nNumGettingIn != 0) veh->m_nNumGettingIn--; - veh->m_nGettingInFlags = GetVehEnterExitFlag(m_vehEnterType); + veh->m_nGettingInFlags = ~GetVehDoorFlag(m_vehEnterType); } bUsesCollision = true; if (IsPlayer() && GetWeapon()->m_eWeaponType == WEAPONTYPE_UZI) { - if (IsPlayer() && m_storedWeapon != NO_STORED_WEAPON) { + if (IsPlayer() && m_storedWeapon != WEAPONTYPE_UNIDENTIFIED) { SetCurrentWeapon(m_storedWeapon); - m_storedWeapon = NO_STORED_WEAPON; + m_storedWeapon = WEAPONTYPE_UNIDENTIFIED; } } else { CWeaponInfo *curWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); @@ -2805,7 +2811,7 @@ CPed::TurnBody(void) float neededTurn = currentRot - limitedLookDir; m_fRotationDest = limitedLookDir; - if (fabs(neededTurn) > 0.05f) { + if (Abs(neededTurn) > 0.05f) { doneSmoothly = false; currentRot -= neededTurn * 0.2f; } @@ -2868,6 +2874,38 @@ CPed::Chat(void) } } +void +CPed::CheckAroundForPossibleCollisions(void) +{ + CVector ourCentre, objCentre; + CEntity *objects[8]; + int16 maxObject; + + if (CTimer::GetTimeInMilliseconds() <= m_nPedStateTimer) + return; + + GetBoundCentre(ourCentre); + + CWorld::FindObjectsInRange(ourCentre, 10.0f, true, &maxObject, 6, objects, false, true, false, true, false); + for (int i = 0; i < maxObject; i++) { + CEntity *object = objects[i]; + if (field_31C) { + if (gPhoneInfo.PhoneAtThisPosition(object->GetPosition())) + break; + } + object->GetBoundCentre(objCentre); + float radius = object->GetBoundRadius(); + if (radius > 4.5f || radius < 1.0f) + radius = 1.0f; + + // According to code, developers gave up calculating Z diff. later. + float diff = CVector(ourCentre - objCentre).MagnitudeSqr2D(); + + if (sq(radius + 1.0f) > diff) + m_fRotationDest += DEGTORAD(22.5f); + } +} + 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); } @@ -2892,9 +2930,28 @@ WRAPPER void CPed::PedLandCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0 WRAPPER void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4C6580); } WRAPPER void CPed::RestoreHeadingRateCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D6550); } +class CPed_ : public CPed +{ +public: + CPed* ctor(uint32 pedType) { return ::new (this) CPed(pedType); } + void dtor(void) { CPed::~CPed(); } + + void SetModelIndex_(uint32 mi) { CPed::SetModelIndex(mi); } + void FlagToDestroyWhenNextProcessed_(void) { CPed::FlagToDestroyWhenNextProcessed(); } + bool SetupLighting_(void) { return CPed::SetupLighting(); } + void RemoveLighting_(bool reset) { CPed::RemoveLighting(reset); } + void Teleport_(CVector pos) { CPed::Teleport(pos); } +}; + STARTPATCHES - InjectHook(0x4C41C0, &CPed::ctor, PATCH_JUMP); - InjectHook(0x4C50D0, &CPed::dtor, PATCH_JUMP); + InjectHook(0x4C41C0, &CPed_::ctor, PATCH_JUMP); + InjectHook(0x4C50D0, &CPed_::dtor, PATCH_JUMP); + InjectHook(0x4C52A0, &CPed_::SetModelIndex_, PATCH_JUMP); + InjectHook(0x4D6570, &CPed_::FlagToDestroyWhenNextProcessed_, PATCH_JUMP); + InjectHook(0x4A7D30, &CPed_::SetupLighting_, PATCH_JUMP); + InjectHook(0x4A7DC0, &CPed_::RemoveLighting_, PATCH_JUMP); + InjectHook(0x4D3E70, &CPed_::Teleport_, PATCH_JUMP); + InjectHook(0x4CF8F0, &CPed::AddWeaponModel, PATCH_JUMP); InjectHook(0x4C6AA0, &CPed::AimGun, PATCH_JUMP); InjectHook(0x4EB470, &CPed::ApplyHeadShot, PATCH_JUMP); @@ -2925,11 +2982,6 @@ STARTPATCHES InjectHook(0x4CC6C0, &CPed::PlayFootSteps, PATCH_JUMP); InjectHook(0x4C5350, &CPed::BuildPedLists, PATCH_JUMP); InjectHook(0x4CF9B0, &CPed::GiveWeapon, PATCH_JUMP); - InjectHook(0x4C52A0, &CPed::SetModelIndex_, PATCH_JUMP); - InjectHook(0x4D6570, &CPed::FlagToDestroyWhenNextProcessed_, PATCH_JUMP); - InjectHook(0x4A7D30, &CPed::SetupLighting_, PATCH_JUMP); - InjectHook(0x4A7DC0, &CPed::RemoveLighting_, PATCH_JUMP); - InjectHook(0x4D3E70, &CPed::Teleport_, PATCH_JUMP); InjectHook(0x4C7EA0, &CPed::CalculateNewOrientation, PATCH_JUMP); InjectHook(0x4C78F0, &CPed::WorkOutHeadingForMovingFirstPerson, PATCH_JUMP); InjectHook(0x4C73F0, &CPed::CalculateNewVelocity, PATCH_JUMP); @@ -2946,4 +2998,5 @@ STARTPATCHES InjectHook(0x4D3C80, &CPed::ClearChat, PATCH_JUMP); InjectHook(0x4D1390, &CPed::TurnBody, PATCH_JUMP); InjectHook(0x4D3AC0, &CPed::Chat, PATCH_JUMP); + InjectHook(0x4D0490, &CPed::CheckAroundForPossibleCollisions, PATCH_JUMP); ENDPATCHES diff --git a/src/peds/Ped.h b/src/peds/Ped.h index 95731e15..cd7d88af 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -13,7 +13,7 @@ struct CPathNode; -enum eWaitState : uint32 { +enum eWaitState { WAITSTATE_FALSE, WAITSTATE_TRAFFIC_LIGHTS, WAITSTATE_CROSS_ROAD, @@ -76,13 +76,6 @@ enum eObjective : uint32 { OBJECTIVE_35 }; -enum eVehEnter : uint16 { - VEHICLE_ENTER_FRONT_RIGHT = 11, - VEHICLE_ENTER_REAR_RIGHT = 12, - VEHICLE_ENTER_FRONT_LEFT = 15, - VEHICLE_ENTER_REAR_LEFT = 16, -}; - enum { RANDOM_CHAR = 1, MISSION_CHAR, @@ -258,7 +251,7 @@ public: uint8 m_ped_flagI1 : 1; uint8 m_ped_flagI2 : 1; uint8 m_ped_flagI4 : 1; - uint8 bRecordedForReplay : 1; + uint8 bHasAlreadyBeenRecorded : 1; uint8 m_ped_flagI10 : 1; uint8 m_ped_flagI20 : 1; uint8 m_ped_flagI40 : 1; @@ -299,10 +292,10 @@ public: int32 m_nPrevActionState; eWaitState m_nWaitState; uint32 m_nWaitTimer; - void *m_pPathNodesStates[8]; + void *m_pPathNodesStates[8]; // seems unused CVector2D m_stPathNodeStates[10]; uint16 m_nPathNodes; - uint8 m_nCurPathNode; + int16 m_nCurPathNode; int8 m_nPathState; private: int8 _pad2B5[3]; @@ -321,7 +314,7 @@ public: float m_fRotationCur; float m_fRotationDest; float m_headingRate; - eVehEnter m_vehEnterType; + uint16 m_vehEnterType; uint16 m_walkAroundType; CEntity *m_pCurrentPhysSurface; CVector m_vecOffsetFromPhysSurface; @@ -331,7 +324,7 @@ public: CVehicle *m_pMyVehicle; bool bInVehicle; uint8 pad_315[3]; - uint32 field_318; + float field_318; uint8 field_31C; uint8 field_31D; int16 m_phoneId; @@ -351,7 +344,7 @@ public: uint8 pad_351[3]; uint32 m_timerUnused; CEntity *m_targetUnused; - CWeapon m_weapons[NUM_PED_WEAPONTYPES]; + CWeapon m_weapons[WEAPONTYPE_TOTAL_INVENTORY_WEAPONS]; eWeaponType m_storedWeapon; uint8 m_currentWeapon; // eWeaponType uint8 m_maxWeaponTypeAllowed; // eWeaponType @@ -399,21 +392,19 @@ public: static void operator delete(void*, int); CPed(uint32 pedType); - virtual ~CPed(void); - - virtual void SetModelIndex(uint32 mi); - virtual void ProcessControl(void); - virtual void Teleport(CVector); - virtual void PreRender(void); - virtual void Render(void); - virtual bool SetupLighting(void); - virtual void RemoveLighting(bool); - virtual void FlagToDestroyWhenNextProcessed(void); - virtual int32 ProcessEntityCollision(CEntity*, CColPoint*); - virtual void SetMoveAnim(void); + ~CPed(void); + + void SetModelIndex(uint32 mi); + void ProcessControl(void); + void Teleport(CVector); + void PreRender(void); + void Render(void); + bool SetupLighting(void); + void RemoveLighting(bool); + void FlagToDestroyWhenNextProcessed(void); + int32 ProcessEntityCollision(CEntity*, CColPoint*); - CPed* ctor(uint32 pedType) { return ::new (this) CPed(pedType); } - void dtor(void) { this->CPed::~CPed(); } + virtual void SetMoveAnim(void); void AddWeaponModel(int id); void AimGun(void); @@ -423,6 +414,7 @@ public: void SetLookFlag(float direction, bool unknown); void SetLookTimer(int time); 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); @@ -465,6 +457,9 @@ public: void RegisterThreatWithGangPeds(CEntity*); bool TurnBody(void); void Chat(void); + void MakeChangesForNewWeapon(int8); + void CheckAroundForPossibleCollisions(void); + bool Seek(void); // Static methods static void GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float offset); @@ -526,30 +521,9 @@ public: CWeapon &GetWeapon(uint8 weaponType) { return m_weapons[weaponType]; } CWeapon *GetWeapon(void) { return &m_weapons[m_currentWeapon]; } RwFrame *GetNodeFrame(int nodeId) { return m_pFrames[nodeId]->frame; } - static uint8 GetVehEnterExitFlag(eVehEnter vehEnter) { - switch (vehEnter) { - case VEHICLE_ENTER_FRONT_RIGHT: - return 4; - case VEHICLE_ENTER_REAR_RIGHT: - return 8; - case VEHICLE_ENTER_FRONT_LEFT: - return 1; - case VEHICLE_ENTER_REAR_LEFT: - return 2; - default: - return 0; - } - } PedState GetPedState(void) { return m_nPedState; } void SetPedState(PedState state) { m_nPedState = state; } - // to make patching virtual functions possible - void SetModelIndex_(uint32 mi) { CPed::SetModelIndex(mi); } - void FlagToDestroyWhenNextProcessed_(void) { CPed::FlagToDestroyWhenNextProcessed(); } - bool SetupLighting_(void) { return CPed::SetupLighting(); } - void RemoveLighting_(bool reset) { CPed::RemoveLighting(reset); } - void Teleport_(CVector pos) { CPed::Teleport(pos); } - // set by 0482:set_threat_reaction_range_multiplier opcode static uint16 &distanceMultToCountPedNear; diff --git a/src/peds/PedIK.cpp b/src/peds/PedIK.cpp index b9baf49c..9b3f401f 100644 --- a/src/peds/PedIK.cpp +++ b/src/peds/PedIK.cpp @@ -34,8 +34,8 @@ CPedIK::RotateTorso(AnimBlendFrameData *animBlend, LimbOrientation *limb, bool c // rotation == 0 -> looking in y direction // left? vector - float c = cos(m_ped->m_fRotationCur); - float s = sin(m_ped->m_fRotationCur); + float c = Cos(m_ped->m_fRotationCur); + float s = Sin(m_ped->m_fRotationCur); rightVector.x = -(c*mat->right.x + s*mat->right.y); rightVector.y = -(c*mat->up.x + s*mat->up.y); rightVector.z = -(c*mat->at.x + s*mat->at.y); @@ -51,7 +51,7 @@ CPedIK::RotateTorso(AnimBlendFrameData *animBlend, LimbOrientation *limb, bool c float dotProduct = DotProduct(mat->at, inversedForward); if(dotProduct > 1.0f) dotProduct = 1.0f; if(dotProduct < -1.0f) dotProduct = -1.0f; - float alpha = acos(dotProduct); + float alpha = Acos(dotProduct); if(mat->at.z < 0.0f) alpha = -alpha; diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp index 2d67d5b2..4b484a7f 100644 --- a/src/peds/PlayerPed.cpp +++ b/src/peds/PlayerPed.cpp @@ -1,6 +1,8 @@ #include "common.h" #include "patcher.h" #include "PlayerPed.h" +#include "Camera.h" +#include "WeaponEffects.h" CPlayerPed::~CPlayerPed() { @@ -8,7 +10,40 @@ CPlayerPed::~CPlayerPed() } 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); } + +void CPlayerPed::ClearWeaponTarget() +{ + if (!m_nPedType) { + m_pPointGunAt = 0; + TheCamera.ClearPlayerWeaponMode(); + CWeaponEffects::ClearCrosshair(); + } + ClearPointGunAt(); +} + +void +CPlayerPed::SetWantedLevel(int32 level) +{ + m_pWanted->SetWantedLevel(level); +} + +void +CPlayerPed::SetWantedLevelNoDrop(int32 level) +{ + m_pWanted->SetWantedLevelNoDrop(level); +} + + +class CPlayerPed_ : public CPlayerPed +{ +public: + void dtor(void) { CPlayerPed::~CPlayerPed(); } +}; STARTPATCHES - InjectHook(0x4EFB30, &CPlayerPed::dtor, PATCH_JUMP); -ENDPATCHES
\ No newline at end of file + InjectHook(0x4EFB30, &CPlayerPed_::dtor, PATCH_JUMP); + InjectHook(0x4F28A0, &CPlayerPed::ClearWeaponTarget, PATCH_JUMP); +ENDPATCHES diff --git a/src/peds/PlayerPed.h b/src/peds/PlayerPed.h index 15ad74a6..51a45203 100644 --- a/src/peds/PlayerPed.h +++ b/src/peds/PlayerPed.h @@ -41,8 +41,14 @@ public: ~CPlayerPed(); - void dtor(void) { this->CPlayerPed::~CPlayerPed(); } void ReApplyMoveAnims(void); + void ClearWeaponTarget(); + void SetWantedLevel(int32 level); + void SetWantedLevelNoDrop(int32 level); + + static void SetupPlayerPed(int32); + static void DeactivatePlayerPed(int32); + static void ReactivatePlayerPed(int32); }; static_assert(sizeof(CPlayerPed) == 0x5F0, "CPlayerPed: error"); diff --git a/src/render/Clouds.cpp b/src/render/Clouds.cpp index d582bff8..2884894c 100644 --- a/src/render/Clouds.cpp +++ b/src/render/Clouds.cpp @@ -53,7 +53,7 @@ CClouds::Shutdown(void) void CClouds::Update(void) { - float s = sin(TheCamera.Orientation - 0.85f); + float s = Sin(TheCamera.Orientation - 0.85f); CloudRotation += CWeather::Wind*s*0.0025f; IndividualRotation += (CWeather::Wind*CTimer::GetTimeStep() + 0.3f) * 60.0f; } @@ -81,7 +81,7 @@ CClouds::Render(void) float coverage = CWeather::CloudCoverage <= CWeather::Foggyness ? CWeather::Foggyness : CWeather::CloudCoverage; // Moon - int moonfadeout = abs(minute - 180); // fully visible at 3AM + int moonfadeout = Abs(minute - 180); // fully visible at 3AM if(moonfadeout < 180){ // fade in/out 3 hours int brightness = (1.0f - coverage) * (180 - moonfadeout); RwV3d pos = { 0.0f, -100.0f, 15.0f }; @@ -169,8 +169,8 @@ CClouds::Render(void) } // Fluffy clouds - float rot_sin = sin(CloudRotation); - float rot_cos = cos(CloudRotation); + float rot_sin = Sin(CloudRotation); + float rot_cos = Cos(CloudRotation); int fluffyalpha = 160 * (1.0f - CWeather::Foggyness); if(fluffyalpha != 0){ static float CoorsOffsetX[37] = { @@ -210,7 +210,7 @@ CClouds::Render(void) worldpos.z = pos.z; if(CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false)){ - float sundist = sqrt(sq(screenpos.x-CCoronas::SunScreenX) + sq(screenpos.y-CCoronas::SunScreenY)); + float sundist = Sqrt(sq(screenpos.x-CCoronas::SunScreenX) + sq(screenpos.y-CCoronas::SunScreenY)); int tr = CTimeCycle::GetFluffyCloudsTopRed(); int tg = CTimeCycle::GetFluffyCloudsTopGreen(); int tb = CTimeCycle::GetFluffyCloudsTopBlue(); @@ -302,10 +302,10 @@ CClouds::RenderBackground(int16 topred, int16 topgreen, int16 topblue, int16 botred, int16 botgreen, int16 botblue, int16 alpha) { RwMatrix *mat = RwFrameGetLTM(RwCameraGetFrame(TheCamera.m_pRwCamera)); - float c = sqrt(mat->right.x * mat->right.x + mat->right.y * mat->right.y); + float c = Sqrt(mat->right.x * mat->right.x + mat->right.y * mat->right.y); if(c > 1.0f) c = 1.0f; - ms_cameraRoll = acos(c); + ms_cameraRoll = Acos(c); if(mat->right.z < 0.0f) ms_cameraRoll = -ms_cameraRoll; @@ -424,7 +424,7 @@ CClouds::RenderHorizon(void) SCREEN_HEIGHT/300.0f * max(TheCamera.GetPosition().z, 0.0f); float b = TheCamera.GetUp().z < 0.0f ? SCREEN_HEIGHT : - SCREEN_HEIGHT * fabs(TheCamera.GetRight().z); + SCREEN_HEIGHT * Abs(TheCamera.GetRight().z); float z2 = z1 + (a + b)*TheCamera.LODDistMultiplier; z2 = min(z2, SCREEN_HEIGHT); CSprite2d::DrawRect(CRect(0, z1, SCREEN_WIDTH, z2), diff --git a/src/render/Coronas.cpp b/src/render/Coronas.cpp index 61fa1a5a..5ac9b149 100644 --- a/src/render/Coronas.cpp +++ b/src/render/Coronas.cpp @@ -286,8 +286,8 @@ CCoronas::Render(void) // if distance too big, break streak if(aCoronas[i].hasValue[1]){ - if(fabs(aCoronas[i].prevX[0] - aCoronas[i].prevX[1]) > 50.0f || - fabs(aCoronas[i].prevY[0] - aCoronas[i].prevY[1]) > 50.0f) + if(Abs(aCoronas[i].prevX[0] - aCoronas[i].prevX[1]) > 50.0f || + Abs(aCoronas[i].prevY[0] - aCoronas[i].prevY[1]) > 50.0f) aCoronas[i].hasValue[0] = false; } } diff --git a/src/render/Draw.cpp b/src/render/Draw.cpp index f825ba42..beb3443d 100644 --- a/src/render/Draw.cpp +++ b/src/render/Draw.cpp @@ -29,6 +29,7 @@ CDraw::FindAspectRatio(void) switch (FrontEndMenuManager.m_PrefsUseWideScreen) { case AR_AUTO: return SCREEN_WIDTH / SCREEN_HEIGHT; + default: case AR_4_3: return 4.0f / 3.0f; case AR_16_9: @@ -49,8 +50,8 @@ CDraw::ConvertFOV(float hfov) float ar1 = DEFAULT_ASPECT_RATIO; float ar2 = GetAspectRatio(); hfov = DEGTORAD(hfov); - float vfov = atan(tan(hfov/2) / ar1) *2; - hfov = atan(tan(vfov/2) * ar2) *2; + float vfov = Atan(tan(hfov/2) / ar1) *2; + hfov = Atan(tan(vfov/2) * ar2) *2; return RADTODEG(hfov); } #endif diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp index 680720e0..81f27153 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -173,7 +173,7 @@ void CHud::Draw() RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); - float fStep = sin((CTimer::GetTimeInMilliseconds() & 1023) * 0.0061328127); + float fStep = Sin((CTimer::GetTimeInMilliseconds() & 1023) * 0.0061328127); float fMultBright = SpriteBrightness * 0.03f * (0.25f * fStep + 0.75f); CRect rect; #ifndef ASPECT_RATIO_SCALE @@ -814,8 +814,8 @@ void CHud::Draw() if (!CTimer::GetIsUserPaused()) { CTextLine* IntroText = CTheScripts::IntroTextLines; - for (int i = 0; i < 2; i++) { - if (CTheScripts::IntroTextLines[i].m_awText[0] && CTheScripts::IntroTextLines[i].field_29) { + for (int i = 0; i < MAX_NUM_INTRO_TEXT_LINES; i++) { + if (CTheScripts::IntroTextLines[i].m_Text[0] && CTheScripts::IntroTextLines[i].m_bTextBeforeFade) { CFont::SetScale(SCREEN_SCALE_X(CTheScripts::IntroTextLines[i].m_fScaleX), SCREEN_SCALE_Y(CTheScripts::IntroTextLines[i].m_fScaleY * 0.5f)); CFont::SetColor(CTheScripts::IntroTextLines[i].m_sColor); @@ -855,22 +855,22 @@ void CHud::Draw() CFont::SetPropOff(); CFont::SetFontStyle(CTheScripts::IntroTextLines[i].m_nFont); - CFont::PrintString(SCREEN_SCALE_X(640.0f - CTheScripts::IntroTextLines[i].field_36), SCREEN_SCALE_Y(448.0f - CTheScripts::IntroTextLines[i].field_40), IntroText->m_awText); + CFont::PrintString(SCREEN_SCALE_X(640.0f - CTheScripts::IntroTextLines[i].m_fAtX), SCREEN_SCALE_Y(448.0f - CTheScripts::IntroTextLines[i].m_fAtY), IntroText->m_Text); } } CScriptRectangle* IntroRect = CTheScripts::IntroRectangles; for (int i = 0; i < 16; i++) { - if (CTheScripts::IntroRectangles[i].m_bIsUsed && CTheScripts::IntroRectangles[i].m_bIsAntialiased) { - if (CTheScripts::IntroRectangles[i].m_wTextureId >= 0) { + if (CTheScripts::IntroRectangles[i].m_bIsUsed && CTheScripts::IntroRectangles[i].m_bBeforeFade) { + if (CTheScripts::IntroRectangles[i].m_nTextureId >= 0) { CRect rect = { CTheScripts::IntroRectangles[i].m_sRect.left, CTheScripts::IntroRectangles[i].m_sRect.bottom, CTheScripts::IntroRectangles[i].m_sRect.right, CTheScripts::IntroRectangles[i].m_sRect.bottom }; - CTheScripts::ScriptSprites[CTheScripts::IntroRectangles[i].m_wTextureId].Draw(rect, IntroRect->m_sColor); + CTheScripts::ScriptSprites[CTheScripts::IntroRectangles[i].m_nTextureId].Draw(rect, IntroRect->m_sColor); } else { CRect rect = { diff --git a/src/render/Particle.cpp b/src/render/Particle.cpp index 416e5af0..63545dff 100644 --- a/src/render/Particle.cpp +++ b/src/render/Particle.cpp @@ -299,8 +299,8 @@ void CParticle::Initialise() { float angle = DEGTORAD(float(i) * float(360.0f / SIN_COS_TABLE_SIZE)); - m_SinTable[i] = sin(angle); - m_CosTable[i] = cos(angle); + m_SinTable[i] = Sin(angle); + m_CosTable[i] = Cos(angle); } int32 slot = CTxdStore::FindTxdSlot("particle"); @@ -1599,7 +1599,7 @@ void CParticle::Render() fTrailLength = fDist; - //Float fRot = atan2( vecDist.x / fDist, sqrtf(1.0f - vecDist.x / fDist * (vecDist.x / fDist)) ); + //Float fRot = Atan2( vecDist.x / fDist, Sqrt(1.0f - vecDist.x / fDist * (vecDist.x / fDist)) ); float fRot = asinf(vecDist.x / fDist); fRotation = fRot; @@ -1651,7 +1651,7 @@ void CParticle::Render() fTrailLength = fDist; - //Float fRot = atan2(vecDist.x / fDist, sqrt(1.0f - vecDist.x / fDist * (vecDist.x / fDist))); + //Float fRot = Atan2(vecDist.x / fDist, Sqrt(1.0f - vecDist.x / fDist * (vecDist.x / fDist))); float fRot = asinf(vecDist.x / fDist); fRotation = fRot; diff --git a/src/render/PointLights.cpp b/src/render/PointLights.cpp index 9e98a327..a015ec54 100644 --- a/src/render/PointLights.cpp +++ b/src/render/PointLights.cpp @@ -33,7 +33,7 @@ CPointLights::AddLight(uint8 type, CVector coors, CVector dir, float radius, flo return; dist = coors - TheCamera.GetPosition(); - if(fabs(dist.x) < MAX_DIST && fabs(dist.y) < MAX_DIST){ + if(Abs(dist.x) < MAX_DIST && Abs(dist.y) < MAX_DIST){ distance = dist.Magnitude(); if(distance < MAX_DIST){ aLights[NumLights].type = type; @@ -73,9 +73,9 @@ CPointLights::GenerateLightsAffectingObject(CVector *objCoors) // same weird distance calculation. simplified here dist = aLights[i].coors - *objCoors; radius = aLights[i].radius; - if(fabs(dist.x) < radius && - fabs(dist.y) < radius && - fabs(dist.z) < radius){ + if(Abs(dist.x) < radius && + Abs(dist.y) < radius && + Abs(dist.z) < radius){ distance = dist.Magnitude(); if(distance < radius){ @@ -213,11 +213,11 @@ CPointLights::RenderFogEffect(void) if(dot > 0.0f && dot < FOG_AREA_LENGTH && linedistsq < sq(FOG_AREA_WIDTH)){ float intensity = 158.0f * fogginess; // more intensity the smaller the angle - intensity *= dot/sqrt(distsq); + intensity *= dot/Sqrt(distsq); // more intensity the closer to light source intensity *= 1.0f - sq(dot/FOG_AREA_LENGTH); // more intensity the closer to line - intensity *= 1.0f - sq(sqrt(linedistsq) / FOG_AREA_WIDTH); + intensity *= 1.0f - sq(Sqrt(linedistsq) / FOG_AREA_WIDTH); if(CSprite::CalcScreenCoors(fogcoors, spriteCoors, &spritew, &spriteh, true)){ float rotation = (CTimer::GetTimeInMilliseconds()&0x1FFF) * 2*3.14f / 0x1FFF; @@ -251,11 +251,11 @@ CPointLights::RenderFogEffect(void) float dx = xi - aLights[i].coors.x; float dy = yi - aLights[i].coors.y; - float lightdist = sqrt(sq(dx) + sq(dy)); + float lightdist = Sqrt(sq(dx) + sq(dy)); if(lightdist < FOG_AREA_RADIUS){ dx = xi - TheCamera.GetPosition().x; dy = yi - TheCamera.GetPosition().y; - float camdist = sqrt(sq(dx) + sq(dy)); + float camdist = Sqrt(sq(dx) + sq(dy)); if(camdist < MAX_DIST){ float intensity; // distance fade diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index a6f28443..69df63ba 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1160,7 +1160,7 @@ CRenderer::IsVehicleCullZoneVisible(CEntity *ent) case STATUS_PHYSICS: case STATUS_ABANDONED: case STATUS_WRECKED: - return !(v->m_pCurSurface && v->m_pCurSurface->bZoneCulled2); + return !(v->m_pCurGroundEntity && v->m_pCurGroundEntity->bZoneCulled2); return true; } diff --git a/src/render/Sprite.cpp b/src/render/Sprite.cpp index d917117a..24577f41 100644 --- a/src/render/Sprite.cpp +++ b/src/render/Sprite.cpp @@ -135,8 +135,8 @@ CSprite::RenderOneXLUSprite(float x, float y, float z, float w, float h, uint8 r void CSprite::RenderOneXLUSprite_Rotate_Aspect(float x, float y, float z, float w, float h, uint8 r, uint8 g, uint8 b, int16 intens, float recipz, float rotation, uint8 a) { - float c = cos(DEGTORAD(rotation)); - float s = sin(DEGTORAD(rotation)); + float c = Cos(DEGTORAD(rotation)); + float s = Sin(DEGTORAD(rotation)); float xs[4]; float ys[4]; @@ -261,8 +261,8 @@ CSprite::RenderBufferedOneXLUSprite_Rotate_Dimension(float x, float y, float z, { m_bFlushSpriteBufferSwitchZTest = 0; // TODO: replace with lookup - float c = cos(DEGTORAD(rotation)); - float s = sin(DEGTORAD(rotation)); + float c = Cos(DEGTORAD(rotation)); + float s = Sin(DEGTORAD(rotation)); float xs[4]; float ys[4]; @@ -313,8 +313,8 @@ void CSprite::RenderBufferedOneXLUSprite_Rotate_Aspect(float x, float y, float z, float w, float h, uint8 r, uint8 g, uint8 b, int16 intens, float recipz, float rotation, uint8 a) { m_bFlushSpriteBufferSwitchZTest = 0; - float c = cos(DEGTORAD(rotation)); - float s = sin(DEGTORAD(rotation)); + float c = Cos(DEGTORAD(rotation)); + float s = Sin(DEGTORAD(rotation)); float xs[4]; float ys[4]; @@ -365,8 +365,8 @@ void CSprite::RenderBufferedOneXLUSprite_Rotate_2Colours(float x, float y, float z, float w, float h, uint8 r1, uint8 g1, uint8 b1, uint8 r2, uint8 g2, uint8 b2, float cx, float cy, float recipz, float rotation, uint8 a) { m_bFlushSpriteBufferSwitchZTest = 0; - float c = cos(DEGTORAD(rotation)); - float s = sin(DEGTORAD(rotation)); + float c = Cos(DEGTORAD(rotation)); + float s = Sin(DEGTORAD(rotation)); float xs[4]; float ys[4]; @@ -572,8 +572,8 @@ CSprite::RenderBufferedOneXLUSprite2D_Rotate_Dimension(float x, float y, float w { m_bFlushSpriteBufferSwitchZTest = 1; CRGBA col(intens * colour.red >> 8, intens * colour.green >> 8, intens * colour.blue >> 8, alpha); - float c = cos(DEGTORAD(rotation)); - float s = sin(DEGTORAD(rotation)); + float c = Cos(DEGTORAD(rotation)); + float s = Sin(DEGTORAD(rotation)); Set6Vertices2D(&SpriteBufferVerts[6 * nSpriteBufferIndex], x + c*w - s*h, diff --git a/src/render/Timecycle.cpp b/src/render/Timecycle.cpp index af154716..7ab3e91e 100644 --- a/src/render/Timecycle.cpp +++ b/src/render/Timecycle.cpp @@ -299,9 +299,9 @@ CTimeCycle::Update(void) float sunAngle = 2*PI*(CClock::GetMinutes() + CClock::GetHours()*60)/(24*60); CVector &sunPos = GetSunPosition(); - sunPos.x = sinf(sunAngle); + sunPos.x = Sin(sunAngle); sunPos.y = 1.0f; - sunPos.z = 0.2f - cosf(sunAngle); + sunPos.z = 0.2f - Cos(sunAngle); sunPos.Normalise(); CShadows::CalcPedShadowValues(sunPos, diff --git a/src/render/WeaponEffects.cpp b/src/render/WeaponEffects.cpp index a1a6d25a..e062da07 100644 --- a/src/render/WeaponEffects.cpp +++ b/src/render/WeaponEffects.cpp @@ -3,3 +3,10 @@ #include "WeaponEffects.h" WRAPPER void CWeaponEffects::Render(void) { EAXJMP(0x564D70); } + +CWeaponEffects &gCrossHair = *(CWeaponEffects*)0x6503BC; + +void CWeaponEffects::ClearCrosshair() +{ + gCrossHair.m_bCrosshair = false; +} diff --git a/src/render/WeaponEffects.h b/src/render/WeaponEffects.h index 63c8fd7d..7176c26d 100644 --- a/src/render/WeaponEffects.h +++ b/src/render/WeaponEffects.h @@ -3,5 +3,19 @@ class CWeaponEffects { public: + bool m_bCrosshair; + int8 gap_1[3]; + CVector m_vecPos; + int8 field_16; + int8 field_17; + int8 field_18; + int8 field_19; + float field_20; + int32 field_24; + RwTexture *m_pTexture; + RwRaster *m_pRaster; + +public: static void Render(void); + static void ClearCrosshair(); }; diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp index 0481e104..ac0460f1 100644 --- a/src/skel/win/win.cpp +++ b/src/skel/win/win.cpp @@ -2340,8 +2340,8 @@ HRESULT CapturePad(RwInt32 padID) { float angle = DEGTORAD((float)js.rgdwPOV[0] / 100.0f); - leftStickPos.x = sin(angle); - leftStickPos.y = -cos(angle); + leftStickPos.x = Sin(angle); + leftStickPos.y = -Cos(angle); } if ( AllValidWinJoys.m_aJoys[bs.padID].m_bHasAxisR && AllValidWinJoys.m_aJoys[bs.padID].m_bHasAxisZ ) @@ -2365,16 +2365,16 @@ HRESULT CapturePad(RwInt32 padID) CPad *pad = CPad::GetPad(bs.padID); - if ( fabs(leftStickPos.x) > 0.3f ) + if ( Abs(leftStickPos.x) > 0.3f ) pad->PCTempJoyState.LeftStickX = (int32)(leftStickPos.x * 128.0f); - if ( fabs(leftStickPos.y) > 0.3f ) + if ( Abs(leftStickPos.y) > 0.3f ) pad->PCTempJoyState.LeftStickY = (int32)(leftStickPos.y * 128.0f); - if ( fabs(rightStickPos.x) > 0.3f ) + if ( Abs(rightStickPos.x) > 0.3f ) pad->PCTempJoyState.RightStickX = (int32)(rightStickPos.x * 128.0f); - if ( fabs(rightStickPos.y) > 0.3f ) + if ( Abs(rightStickPos.y) > 0.3f ) pad->PCTempJoyState.RightStickY = (int32)(rightStickPos.y * 128.0f); } diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 54eed17a..7d3f8ee3 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -1,18 +1,1152 @@ #include "common.h" #include "patcher.h" +#include "General.h" +#include "ModelIndices.h" +#include "VisibilityPlugins.h" +#include "DMAudio.h" +#include "Camera.h" +#include "Darkel.h" +#include "Fire.h" +#include "Explosion.h" +#include "World.h" +#include "SurfaceTable.h" +#include "HandlingMgr.h" +#include "CarCtrl.h" +#include "PathFind.h" +#include "Ped.h" +#include "PlayerPed.h" +#include "Object.h" #include "Automobile.h" -CAutomobile::CAutomobile(int mi, uint8 owner) +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) { - ctor(mi, owner); + ctor(mi, CreatedBy); } -WRAPPER CAutomobile* CAutomobile::ctor(int, uint8) { EAXJMP(0x52C6B0); } -WRAPPER void CAutomobile::SetDoorDamage(int32, uint32, bool) { EAXJMP(0x530200); } -WRAPPER void CAutomobile::SetPanelDamage(int32, uint32, bool) { EAXJMP(0x5301A0); } -WRAPPER void CAutomobile::SetBumperDamage(int32, uint32, bool) { EAXJMP(0x530120); } +void +CAutomobile::SetModelIndex(uint32 id) +{ + CVehicle::SetModelIndex(id); + SetupModelNodes(); +} + +WRAPPER void CAutomobile::ProcessControl(void) { EAXJMP(0x531470); } + +void +CAutomobile::Teleport(CVector pos) +{ + CWorld::Remove(this); + + GetPosition() = pos; + SetOrientation(0.0f, 0.0f, 0.0f); + SetMoveSpeed(0.0f, 0.0f, 0.0f); + SetTurnSpeed(0.0f, 0.0f, 0.0f); + + ResetSuspension(); + + CWorld::Add(this); +} + +WRAPPER void CAutomobile::PreRender(void) { EAXJMP(0x535B40); } +WRAPPER void CAutomobile::Render(void) { EAXJMP(0x539EA0); } + + +int32 +CAutomobile::ProcessEntityCollision(CEntity *ent, CColPoint *colpoints) +{ + int i; + CColModel *colModel; + + if(m_status != STATUS_SIMPLE) + bVehicleColProcessed = true; + + if(m_veh_flagC80) + colModel = &CWorld::Players[CWorld::PlayerInFocus].m_ColModel; + else + colModel = GetColModel(); + + int numWheelCollisions = 0; + float prevRatios[4] = { 0.0f, 0.0f, 0.0f, 0.0f}; + for(i = 0; i < 4; i++) + prevRatios[i] = m_aSuspensionSpringRatio[i]; + + int numCollisions = CCollision::ProcessColModels(GetMatrix(), *colModel, + ent->GetMatrix(), *ent->GetColModel(), + colpoints, + m_aWheelColPoints, m_aSuspensionSpringRatio); + + // m_aSuspensionSpringRatio are now set to the point where the tyre touches ground. + // In ProcessControl these will be re-normalized to ignore the tyre radius. + + if(field_EF || m_phy_flagA80 || + GetModelIndex() == MI_DODO && (ent->m_status == STATUS_PHYSICS || ent->m_status == STATUS_SIMPLE)){ + // don't do line collision + for(i = 0; i < 4; i++) + m_aSuspensionSpringRatio[i] = prevRatios[i]; + }else{ + for(i = 0; i < 4; i++) + if(m_aSuspensionSpringRatio[i] < 1.0f && m_aSuspensionSpringRatio[i] < prevRatios[i]){ + numWheelCollisions++; + + // wheel is touching a physical + if(ent->IsVehicle() || ent->IsObject()){ + CPhysical *phys = (CPhysical*)ent; + + m_aGroundPhysical[i] = phys; + phys->RegisterReference((CEntity**)&m_aGroundPhysical[i]); + m_aGroundOffset[i] = m_aWheelColPoints[i].point - phys->GetPosition(); + + if(phys->GetModelIndex() == MI_BODYCAST && m_status == STATUS_PLAYER){ + // damage body cast + float speed = m_vecMoveSpeed.MagnitudeSqr(); + if(speed > 0.1f){ + CObject::nBodyCastHealth -= 0.1f*m_fMass*speed; + DMAudio.PlayOneShot(m_audioEntityId, SOUND_PED_BODYCAST_HIT, 0.0f); + } + + // move body cast + if(phys->bIsStatic){ + phys->bIsStatic = false; + phys->m_nStaticFrames = 0; + phys->ApplyMoveForce(m_vecMoveSpeed / speed); + phys->AddToMovingList(); + } + } + } + + m_nSurfaceTouched = m_aWheelColPoints[i].surfaceB; + if(ent->IsBuilding()) + m_pCurGroundEntity = ent; + } + } + + if(numCollisions > 0 || numWheelCollisions > 0){ + AddCollisionRecord(ent); + if(!ent->IsBuilding()) + ((CPhysical*)ent)->AddCollisionRecord(this); + + if(numCollisions > 0) + if(ent->IsBuilding() || + ent->IsObject() && ((CPhysical*)ent)->bInfiniteMass) + bHasHitWall = true; + } + + return numCollisions; +} + + +WRAPPER void CAutomobile::ProcessControlInputs(uint8) { EAXJMP(0x53B660); } + +void +CAutomobile::GetComponentWorldPosition(int32 component, CVector &pos) +{ + if(m_aCarNodes[component] == nil){ + printf("CarNode missing: %d %d\n", GetModelIndex(), component); + return; + } + RwMatrix *ltm = RwFrameGetLTM(m_aCarNodes[component]); + pos = *RwMatrixGetPos(ltm); +} + +bool +CAutomobile::IsComponentPresent(int32 comp) +{ + return m_aCarNodes[comp] != nil; +} + +void +CAutomobile::SetComponentRotation(int32 component, CVector rotation) +{ + CMatrix mat(RwFrameGetMatrix(m_aCarNodes[component])); + CVector pos = mat.GetPosition(); + // BUG: all these set the whole matrix + mat.SetRotateX(DEGTORAD(rotation.x)); + mat.SetRotateY(DEGTORAD(rotation.y)); + mat.SetRotateZ(DEGTORAD(rotation.z)); + mat.Translate(pos); + mat.UpdateRW(); +} + +void +CAutomobile::OpenDoor(int32 component, eDoors door, float openRatio) +{ + CMatrix mat(RwFrameGetMatrix(m_aCarNodes[component])); + CVector pos = mat.GetPosition(); + float axes[3] = { 0.0f, 0.0f, 0.0f }; + float wasClosed = false; + + if(Doors[door].IsClosed()){ + // enable angle cull for closed doors + RwFrameForAllObjects(m_aCarNodes[component], CVehicleModelInfo::ClearAtomicFlagCB, (void*)ATOMIC_FLAG_NOCULL); + wasClosed = true; + } + + Doors[door].Open(openRatio); + + if(wasClosed && Doors[door].RetAngleWhenClosed() != Doors[door].m_fAngle){ + // door opened + HideAllComps(); + // turn off angle cull for swinging door + RwFrameForAllObjects(m_aCarNodes[component], CVehicleModelInfo::SetAtomicFlagCB, (void*)ATOMIC_FLAG_NOCULL); + DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_DOOR_OPEN_BONNET + door, 0.0f); + } + + if(!wasClosed && openRatio == 0.0f){ + // door closed + if(Damage.GetDoorStatus(door) == DOOR_STATUS_SWINGING) + Damage.SetDoorStatus(door, DOOR_STATUS_OK); // huh? + ShowAllComps(); + DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_DOOR_CLOSE_BONNET + door, 0.0f); + } + + axes[Doors[door].m_nAxis] = Doors[door].m_fAngle; + mat.SetRotate(axes[0], axes[1], axes[2]); + mat.Translate(pos); + mat.UpdateRW(); +} + +inline void ProcessDoorOpenAnimation(CAutomobile *car, uint32 component, eDoors door, float time, float start, float end) +{ + if(time > start && time < end){ + float ratio = (time - start)/(end - start); + if(car->Doors[door].GetAngleOpenRatio() < ratio) + car->OpenDoor(component, door, ratio); + }else if(time > end){ + car->OpenDoor(component, door, 1.0f); + } +} + +inline void ProcessDoorCloseAnimation(CAutomobile *car, uint32 component, eDoors door, float time, float start, float end) +{ + if(time > start && time < end){ + float ratio = 1.0f - (time - start)/(end - start); + if(car->Doors[door].GetAngleOpenRatio() > ratio) + car->OpenDoor(component, door, ratio); + }else if(time > end){ + car->OpenDoor(component, door, 0.0f); + } +} + +inline void ProcessDoorOpenCloseAnimation(CAutomobile *car, uint32 component, eDoors door, float time, float start, float mid, float end) +{ + if(time > start && time < mid){ + // open + float ratio = (time - start)/(mid - start); + if(car->Doors[door].GetAngleOpenRatio() < ratio) + car->OpenDoor(component, door, ratio); + }else if(time > mid && time < end){ + // close + float ratio = 1.0f - (time - mid)/(end - mid); + if(car->Doors[door].GetAngleOpenRatio() > ratio) + car->OpenDoor(component, door, ratio); + }else if(time > end){ + car->OpenDoor(component, door, 0.0f); + } +} +void +CAutomobile::ProcessOpenDoor(uint32 component, uint32 anim, float time) +{ + eDoors door; + + switch(component){ + case CAR_DOOR_RF: door = DOOR_FRONT_RIGHT; break; + case CAR_DOOR_RR: door = DOOR_REAR_RIGHT; break; + case CAR_DOOR_LF: door = DOOR_FRONT_LEFT; break; + case CAR_DOOR_LR: door = DOOR_REAR_LEFT; break; + default: assert(0); + } + + if(IsDoorMissing(door)) + return; + + switch(anim){ + case ANIM_CAR_QJACK: + case ANIM_CAR_OPEN_LHS: + case ANIM_CAR_OPEN_RHS: + ProcessDoorOpenAnimation(this, component, door, time, 0.66f, 0.8f); + break; + case ANIM_CAR_CLOSEDOOR_LHS: + case ANIM_CAR_CLOSEDOOR_LOW_LHS: + case ANIM_CAR_CLOSEDOOR_RHS: + case ANIM_CAR_CLOSEDOOR_LOW_RHS: + ProcessDoorCloseAnimation(this, component, door, time, 0.2f, 0.63f); + break; + case ANIM_CAR_ROLLDOOR: + case ANIM_CAR_ROLLDOOR_LOW: + ProcessDoorOpenCloseAnimation(this, component, door, time, 0.1f, 0.6f, 0.95f); + break; + break; + case ANIM_CAR_GETOUT_LHS: + case ANIM_CAR_GETOUT_LOW_LHS: + case ANIM_CAR_GETOUT_RHS: + case ANIM_CAR_GETOUT_LOW_RHS: + ProcessDoorOpenAnimation(this, component, door, time, 0.06f, 0.43f); + break; + case ANIM_CAR_CLOSE_LHS: + case ANIM_CAR_CLOSE_RHS: + ProcessDoorCloseAnimation(this, component, door, time, 0.1f, 0.23f); + break; + case ANIM_CAR_PULLOUT_RHS: + case ANIM_CAR_PULLOUT_LOW_RHS: + OpenDoor(component, door, 1.0f); + case ANIM_COACH_OPEN_L: + case ANIM_COACH_OPEN_R: + ProcessDoorOpenAnimation(this, component, door, time, 0.66f, 0.8f); + break; + case ANIM_COACH_OUT_L: + ProcessDoorOpenAnimation(this, component, door, time, 0.0f, 0.3f); + break; + case ANIM_VAN_OPEN_L: + case ANIM_VAN_OPEN: + ProcessDoorOpenAnimation(this, component, door, time, 0.37f, 0.55f); + break; + case ANIM_VAN_CLOSE_L: + case ANIM_VAN_CLOSE: + ProcessDoorCloseAnimation(this, component, door, time, 0.5f, 0.8f); + break; + case ANIM_VAN_GETOUT_L: + case ANIM_VAN_GETOUT: + ProcessDoorOpenAnimation(this, component, door, time, 0.5f, 0.6f); + break; + case NUM_ANIMS: + OpenDoor(component, door, time); + break; + } +} + +bool +CAutomobile::IsDoorReady(eDoors door) +{ + if(Doors[door].IsClosed() || IsDoorMissing(door)) + return true; + int doorflag = 0; + // TODO: enum? + switch(door){ + case DOOR_FRONT_LEFT: doorflag = 1; break; + case DOOR_FRONT_RIGHT: doorflag = 4; break; + case DOOR_REAR_LEFT: doorflag = 2; break; + case DOOR_REAR_RIGHT: doorflag = 8; break; + } + return (doorflag & m_nGettingInFlags) == 0; +} + +bool +CAutomobile::IsDoorFullyOpen(eDoors door) +{ + return Doors[door].IsFullyOpen() || IsDoorMissing(door); +} + +bool +CAutomobile::IsDoorClosed(eDoors door) +{ + return !!Doors[door].IsClosed(); +} + +bool +CAutomobile::IsDoorMissing(eDoors door) +{ + return Damage.GetDoorStatus(door) == DOOR_STATUS_MISSING; +} + +void +CAutomobile::RemoveRefsToVehicle(CEntity *ent) +{ + int i; + for(i = 0; i < 4; i++) + if(m_aGroundPhysical[i] == ent) + m_aGroundPhysical[i] = nil; +} + +void +CAutomobile::BlowUpCar(CEntity *culprit) +{ + int i; + RpAtomic *atomic; + + if(!bCanBeDamaged) + return; + + // explosion pushes vehicle up + m_vecMoveSpeed.z += 0.13f; + m_status = STATUS_WRECKED; + bRenderScorched = true; + m_nTimeOfDeath = CTimer::GetTimeInMilliseconds(); + Damage.FuckCarCompletely(); + + if(GetModelIndex() != MI_RCBANDIT){ + SetBumperDamage(CAR_BUMP_FRONT, VEHBUMPER_FRONT); + SetBumperDamage(CAR_BUMP_REAR, VEHBUMPER_REAR); + SetDoorDamage(CAR_BONNET, DOOR_BONNET); + SetDoorDamage(CAR_BOOT, DOOR_BOOT); + SetDoorDamage(CAR_DOOR_LF, DOOR_FRONT_LEFT); + SetDoorDamage(CAR_DOOR_RF, DOOR_FRONT_RIGHT); + SetDoorDamage(CAR_DOOR_LR, DOOR_REAR_LEFT); + SetDoorDamage(CAR_DOOR_RR, DOOR_REAR_RIGHT); + SpawnFlyingComponent(CAR_WHEEL_LF, COMPGROUP_WHEEL); + RwFrameForAllObjects(m_aCarNodes[CAR_WHEEL_LF], GetCurrentAtomicObjectCB, &atomic); + if(atomic) + RpAtomicSetFlags(atomic, 0); + } + + m_fHealth = 0.0f; + m_nBombTimer = 0; + m_auto_flagA7 = 0; + + TheCamera.CamShake(0.7f, GetPosition().x, GetPosition().y, GetPosition().z); + + // kill driver and passengers + if(pDriver){ + CDarkel::RegisterKillByPlayer(pDriver, WEAPONTYPE_EXPLOSION); + if(pDriver->GetPedState() == PED_DRIVING){ + pDriver->SetDead(); + if(!pDriver->IsPlayer()) + pDriver->FlagToDestroyWhenNextProcessed(); + }else + pDriver->SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); + } + for(i = 0; i < m_nNumMaxPassengers; i++){ + if(pPassengers[i]){ + CDarkel::RegisterKillByPlayer(pPassengers[i], WEAPONTYPE_EXPLOSION); + if(pPassengers[i]->GetPedState() == PED_DRIVING){ + pPassengers[i]->SetDead(); + if(!pPassengers[i]->IsPlayer()) + pPassengers[i]->FlagToDestroyWhenNextProcessed(); + }else + pPassengers[i]->SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); + } + } + + bEngineOn = false; + bLightsOn = false; + m_bSirenOrAlarm = false; + bTaxiLight = false; + if(bIsAmbulanceOnDuty){ + bIsAmbulanceOnDuty = false; + CCarCtrl::NumAmbulancesOnDuty--; + } + if(bIsFireTruckOnDuty){ + bIsFireTruckOnDuty = false; + CCarCtrl::NumFiretrucksOnDuty--; + } + ChangeLawEnforcerState(false); + + gFireManager.StartFire(this, culprit, 0.8f, 1); // TODO + CDarkel::RegisterCarBlownUpByPlayer(this); + if(GetModelIndex() == MI_RCBANDIT) + CExplosion::AddExplosion(this, culprit, EXPLOSION_4, GetPosition(), 0); // TODO + else + CExplosion::AddExplosion(this, culprit, EXPLOSION_3, GetPosition(), 0); // TODO +} + +bool +CAutomobile::SetUpWheelColModel(CColModel *colModel) +{ + CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()); + CColModel *vehColModel = mi->GetColModel(); + + colModel->boundingSphere = vehColModel->boundingSphere; + colModel->boundingBox = vehColModel->boundingBox; + + CMatrix mat; + mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LF])); + colModel->spheres[0].Set(mi->m_wheelScale, mat.GetPosition(), SURFACE_TIRE, CAR_PIECE_WHEEL_LF); + mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LB])); + colModel->spheres[1].Set(mi->m_wheelScale, mat.GetPosition(), SURFACE_TIRE, CAR_PIECE_WHEEL_LR); + mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF])); + colModel->spheres[2].Set(mi->m_wheelScale, mat.GetPosition(), SURFACE_TIRE, CAR_PIECE_WHEEL_RF); + mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RB])); + colModel->spheres[3].Set(mi->m_wheelScale, mat.GetPosition(), SURFACE_TIRE, CAR_PIECE_WHEEL_RR); + + if(m_aCarNodes[CAR_WHEEL_LM] != nil && m_aCarNodes[CAR_WHEEL_RM] != nil){ + mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LM])); + colModel->spheres[4].Set(mi->m_wheelScale, mat.GetPosition(), SURFACE_TIRE, CAR_PIECE_WHEEL_RF); + mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RM])); + colModel->spheres[5].Set(mi->m_wheelScale, mat.GetPosition(), SURFACE_TIRE, CAR_PIECE_WHEEL_RR); + colModel->numSpheres = 6; + }else + colModel->numSpheres = 4; + + return true; +} + +// this probably isn't used in III yet +void +CAutomobile::BurstTyre(uint8 wheel) +{ + switch(wheel){ + case CAR_PIECE_WHEEL_LF: wheel = VEHWHEEL_FRONT_LEFT; break; + case CAR_PIECE_WHEEL_LR: wheel = VEHWHEEL_REAR_LEFT; break; + case CAR_PIECE_WHEEL_RF: wheel = VEHWHEEL_FRONT_RIGHT; break; + case CAR_PIECE_WHEEL_RR: wheel = VEHWHEEL_REAR_RIGHT; break; + } + + int status = Damage.GetWheelStatus(wheel); + if(status == WHEEL_STATUS_OK){ + Damage.SetWheelStatus(wheel, WHEEL_STATUS_BURST); + + if(m_status == STATUS_SIMPLE){ + m_status = STATUS_PHYSICS; + CCarCtrl::SwitchVehicleToRealPhysics(this); + } + + ApplyMoveForce(GetRight() * CGeneral::GetRandomNumberInRange(-0.3f, 0.3f)); + ApplyTurnForce(GetRight() * CGeneral::GetRandomNumberInRange(-0.3f, 0.3f), GetForward()); + } +} + +WRAPPER bool CAutomobile::IsRoomForPedToLeaveCar(uint32, CVector *) { EAXJMP(0x53C5B0); } + +float +CAutomobile::GetHeightAboveRoad(void) +{ + return m_fHeightAboveRoad; +} + +void +CAutomobile::PlayCarHorn(void) +{ + int r; + + if(m_nCarHornTimer != 0) + return; + + r = CGeneral::GetRandomNumber() & 7; + if(r < 2){ + m_nCarHornTimer = 45; + }else if(r < 4){ + if(pDriver) + pDriver->Say(SOUND_PED_CAR_COLLISION); + m_nCarHornTimer = 45; + }else{ + if(pDriver) + pDriver->Say(SOUND_PED_CAR_COLLISION); + } +} + +void +CAutomobile::PlayHornIfNecessary(void) +{ + if(m_autoPilot.m_flag2 || + m_autoPilot.m_flag1) + if(!HasCarStoppedBecauseOfLight()) + PlayCarHorn(); +} + + +void +CAutomobile::ResetSuspension(void) +{ + int i; + for(i = 0; i < 4; i++){ + m_aSuspensionSpringRatio[i] = 1.0f; + m_aWheelSkidThing[i] = 0.0f; + m_aWheelRotation[i] = 0.0f; + m_aWheelState[i] = 0; // TODO: enum? + } +} + +void +CAutomobile::SetupSuspensionLines(void) +{ + int i; + CVector posn; + CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()); + CColModel *colModel = mi->GetColModel(); + + // Each suspension line starts at the uppermost wheel position + // and extends down to the lowermost point on the tyre + for(i = 0; i < 4; i++){ + mi->GetWheelPosn(i, posn); + m_aWheelPosition[i] = posn.z; + + // uppermost wheel position + posn.z += m_handling->fSuspensionUpperLimit; + colModel->lines[i].p0 = posn; + + // lowermost wheel position + posn.z += m_handling->fSuspensionLowerLimit - m_handling->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_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))); + for(i = 0; i < 4; i++) + m_aWheelPosition[i] = mi->m_wheelScale*0.5f - m_fHeightAboveRoad; + + // adjust col model to include suspension lines + if(colModel->boundingBox.min.z > colModel->lines[0].p1.z) + colModel->boundingBox.min.z = colModel->lines[0].p1.z; + float radius = max(colModel->boundingBox.min.Magnitude(), colModel->boundingBox.max.Magnitude()); + if(colModel->boundingSphere.radius < radius) + colModel->boundingSphere.radius = radius; + + if(GetModelIndex() == MI_RCBANDIT){ + colModel->boundingSphere.radius = 2.0f; + for(i = 0; i < colModel->numSpheres; i++) + colModel->spheres[i].radius = 0.3f; + } +} + +// called on police cars +void +CAutomobile::ScanForCrimes(void) +{ + if(FindPlayerVehicle() && FindPlayerVehicle()->IsCar()) + if(FindPlayerVehicle()->m_nAlarmState != -1) + // if player's alarm is on, increase wanted level + if((FindPlayerVehicle()->GetPosition() - GetPosition()).MagnitudeSqr() < sq(20.0f)) + CWorld::Players[CWorld::PlayerInFocus].m_pPed->SetWantedLevelNoDrop(1); +} + +void +CAutomobile::BlowUpCarsInPath(void) +{ + int i; + + if(m_vecMoveSpeed.Magnitude() > 0.1f) + for(i = 0; i < m_nCollisionRecords; i++) + if(m_aCollisionRecords[i] && + m_aCollisionRecords[i]->IsVehicle() && + m_aCollisionRecords[i]->GetModelIndex() != MI_RHINO && + !m_aCollisionRecords[i]->bRenderScorched) + ((CVehicle*)m_aCollisionRecords[i])->BlowUpCar(this); +} + +bool +CAutomobile::HasCarStoppedBecauseOfLight(void) +{ + int i; + + if(m_status != STATUS_SIMPLE && m_status != STATUS_PHYSICS) + return false; + + if(m_autoPilot.m_nCurrentRouteNode && m_autoPilot.m_nNextRouteNode){ + CPathNode *curnode = &ThePaths.m_pathNodes[m_autoPilot.m_nCurrentRouteNode]; + for(i = 0; i < curnode->numLinks; i++) + if(ThePaths.m_connections[curnode->firstLink + i] == m_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]; + for(i = 0; i < curnode->numLinks; i++) + if(ThePaths.m_connections[curnode->firstLink + i] == m_autoPilot.m_nPrevRouteNode) + break; + if(i < curnode->numLinks && + ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[curnode->firstLink + i]].trafficLightType & 3) // TODO + return true; + } + + return false; +} + +void +CAutomobile::SetBusDoorTimer(uint32 timer, uint8 type) +{ + if(timer < 1000) + timer = 1000; + if(type == 0) + // open and close + m_nBusDoorTimerStart = CTimer::GetTimeInMilliseconds(); + else + // only close + m_nBusDoorTimerStart = CTimer::GetTimeInMilliseconds() - 500; + m_nBusDoorTimerEnd = m_nBusDoorTimerStart + timer; +} + +void +CAutomobile::ProcessAutoBusDoors(void) +{ + if(CTimer::GetTimeInMilliseconds() < m_nBusDoorTimerEnd){ + if(m_nBusDoorTimerEnd != 0 && CTimer::GetTimeInMilliseconds() > m_nBusDoorTimerEnd-500){ + // close door + if(!IsDoorMissing(DOOR_FRONT_LEFT) && (m_nGettingInFlags & 1) == 0){ + if(IsDoorClosed(DOOR_FRONT_LEFT)){ + m_nBusDoorTimerEnd = CTimer::GetTimeInMilliseconds(); + OpenDoor(CAR_DOOR_LF, DOOR_FRONT_LEFT, 0.0f); + }else{ + OpenDoor(CAR_DOOR_LF, DOOR_FRONT_LEFT, + 1.0f - (CTimer::GetTimeInMilliseconds() - (m_nBusDoorTimerEnd-500))/500.0f); + } + } + + if(!IsDoorMissing(DOOR_FRONT_RIGHT) && (m_nGettingInFlags & 4) == 0){ + if(IsDoorClosed(DOOR_FRONT_RIGHT)){ + m_nBusDoorTimerEnd = CTimer::GetTimeInMilliseconds(); + OpenDoor(CAR_DOOR_RF, DOOR_FRONT_RIGHT, 0.0f); + }else{ + OpenDoor(CAR_DOOR_RF, DOOR_FRONT_RIGHT, + 1.0f - (CTimer::GetTimeInMilliseconds() - (m_nBusDoorTimerEnd-500))/500.0f); + } + } + } + }else{ + // ended + if(m_nBusDoorTimerStart){ + if(!IsDoorMissing(DOOR_FRONT_LEFT) && (m_nGettingInFlags & 1) == 0) + OpenDoor(CAR_DOOR_LF, DOOR_FRONT_LEFT, 0.0f); + if(!IsDoorMissing(DOOR_FRONT_RIGHT) && (m_nGettingInFlags & 4) == 0) + OpenDoor(CAR_DOOR_RF, DOOR_FRONT_RIGHT, 0.0f); + m_nBusDoorTimerStart = 0; + m_nBusDoorTimerEnd = 0; + } + } +} + +void +CAutomobile::ProcessSwingingDoor(int32 component, eDoors door) +{ + if(Damage.GetDoorStatus(door) != DOOR_STATUS_SWINGING) + return; + + CMatrix mat(RwFrameGetMatrix(m_aCarNodes[component])); + CVector pos = mat.GetPosition(); + float axes[3] = { 0.0f, 0.0f, 0.0f }; + + Doors[door].Process(this); + axes[Doors[door].m_nAxis] = Doors[door].m_fAngle; + mat.SetRotate(axes[0], axes[1], axes[2]); + mat.Translate(pos); + mat.UpdateRW(); +} + +void +CAutomobile::Fix(void) +{ + int component; + + Damage.ResetDamageStatus(); + + if(m_handling->Flags & HANDLING_NO_DOORS){ + Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_MISSING); + Damage.SetDoorStatus(DOOR_FRONT_RIGHT, DOOR_STATUS_MISSING); + Damage.SetDoorStatus(DOOR_REAR_LEFT, DOOR_STATUS_MISSING); + Damage.SetDoorStatus(DOOR_REAR_RIGHT, DOOR_STATUS_MISSING); + } + + bIsDamaged = false; + RpClumpForAllAtomics((RpClump*)m_rwObject, CVehicleModelInfo::HideAllComponentsAtomicCB, (void*)ATOMIC_FLAG_DAM); + + for(component = CAR_BUMP_FRONT; component < NUM_CAR_NODES; component++){ + if(m_aCarNodes[component]){ + CMatrix mat(RwFrameGetMatrix(m_aCarNodes[component])); + mat.SetTranslate(mat.GetPosition()); + mat.UpdateRW(); + } + } +} + +void +CAutomobile::SetupDamageAfterLoad(void) +{ + if(m_aCarNodes[CAR_BUMP_FRONT]) + SetBumperDamage(CAR_BUMP_FRONT, VEHBUMPER_FRONT); + if(m_aCarNodes[CAR_BONNET]) + SetDoorDamage(CAR_BONNET, DOOR_BONNET); + if(m_aCarNodes[CAR_BUMP_REAR]) + SetBumperDamage(CAR_BUMP_REAR, VEHBUMPER_REAR); + if(m_aCarNodes[CAR_BOOT]) + SetDoorDamage(CAR_BOOT, DOOR_BOOT); + if(m_aCarNodes[CAR_DOOR_LF]) + SetDoorDamage(CAR_DOOR_LF, DOOR_FRONT_LEFT); + if(m_aCarNodes[CAR_DOOR_RF]) + SetDoorDamage(CAR_DOOR_RF, DOOR_FRONT_RIGHT); + if(m_aCarNodes[CAR_DOOR_LR]) + SetDoorDamage(CAR_DOOR_LR, DOOR_REAR_LEFT); + if(m_aCarNodes[CAR_DOOR_RR]) + SetDoorDamage(CAR_DOOR_RR, DOOR_REAR_RIGHT); + if(m_aCarNodes[CAR_WING_LF]) + SetPanelDamage(CAR_WING_LF, VEHPANEL_FRONT_LEFT); + if(m_aCarNodes[CAR_WING_RF]) + SetPanelDamage(CAR_WING_RF, VEHPANEL_FRONT_RIGHT); + if(m_aCarNodes[CAR_WING_LR]) + SetPanelDamage(CAR_WING_LR, VEHPANEL_REAR_LEFT); + if(m_aCarNodes[CAR_WING_RR]) + SetPanelDamage(CAR_WING_RR, VEHPANEL_REAR_RIGHT); +} + +RwObject* +GetCurrentAtomicObjectCB(RwObject *object, void *data) +{ + RpAtomic *atomic = (RpAtomic*)object; + assert(RwObjectGetType(object) == rpATOMIC); + if(RpAtomicGetFlags(atomic) & rpATOMICRENDER) + *(RpAtomic**)data = atomic; + return object; +} + +CColPoint aTempPedColPts[32]; // this name doesn't make any sense + +CObject* +CAutomobile::SpawnFlyingComponent(int32 component, uint32 type) +{ + RpAtomic *atomic; + RwFrame *frame; + RwMatrix *matrix; + CObject *obj; + + if(CObject::nNoTempObjects >= NUMTEMPOBJECTS) + return nil; + + atomic = nil; + RwFrameForAllObjects(m_aCarNodes[component], GetCurrentAtomicObjectCB, &atomic); + if(atomic == nil) + return nil; + + obj = new CObject; + if(obj == nil) + return nil; + + if(component == CAR_WINDSCREEN){ + obj->SetModelIndexNoCreate(MI_CAR_BONNET); + }else switch(type){ + case COMPGROUP_BUMPER: + obj->SetModelIndexNoCreate(MI_CAR_BUMPER); + break; + case COMPGROUP_WHEEL: + obj->SetModelIndexNoCreate(MI_CAR_WHEEL); + break; + case COMPGROUP_DOOR: + obj->SetModelIndexNoCreate(MI_CAR_DOOR); + obj->SetCenterOfMass(0.0f, -0.5f, 0.0f); + break; + case COMPGROUP_BONNET: + obj->SetModelIndexNoCreate(MI_CAR_BONNET); + obj->SetCenterOfMass(0.0f, 0.4f, 0.0f); + break; + case COMPGROUP_BOOT: + obj->SetModelIndexNoCreate(MI_CAR_BOOT); + obj->SetCenterOfMass(0.0f, -0.3f, 0.0f); + break; + case COMPGROUP_PANEL: + default: + obj->SetModelIndexNoCreate(MI_CAR_PANEL); + break; + } + + // object needs base model + obj->RefModelInfo(GetModelIndex()); + + // create new atomic + matrix = RwFrameGetLTM(m_aCarNodes[component]); + frame = RwFrameCreate(); + atomic = RpAtomicClone(atomic); + *RwFrameGetMatrix(frame) = *matrix; + RpAtomicSetFrame(atomic, frame); + CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil); + obj->AttachToRwObject((RwObject*)atomic); + + // init object + obj->m_fMass = 10.0f; + obj->m_fTurnMass = 25.0f; + obj->m_fAirResistance = 0.97f; + obj->m_fElasticity = 0.1f; + obj->m_fBuoyancy = obj->m_fMass*GRAVITY/0.75f; + obj->ObjectCreatedBy = TEMP_OBJECT; + obj->bIsStatic = true; + obj->bIsPickup = false; + obj->bUseVehicleColours = true; + obj->m_colour1 = m_currentColour1; + obj->m_colour2 = m_currentColour2; + + // life time - the more objects the are, the shorter this one will live + CObject::nNoTempObjects++; + if(CObject::nNoTempObjects > 20) + obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 20000/5.0f; + else if(CObject::nNoTempObjects > 10) + obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 20000/2.0f; + else + obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 20000; + + obj->m_vecMoveSpeed = m_vecMoveSpeed; + if(obj->m_vecMoveSpeed.z > 0.0f){ + obj->m_vecMoveSpeed.z *= 1.5f; + }else if(GetUp().z > 0.0f && + (component == COMPGROUP_BONNET || component == COMPGROUP_BOOT || component == CAR_WINDSCREEN)){ + obj->m_vecMoveSpeed.z *= -1.5f; + obj->m_vecMoveSpeed.z += 0.04f; + }else{ + obj->m_vecMoveSpeed.z *= 0.25f; + } + obj->m_vecMoveSpeed.x *= 0.75f; + obj->m_vecMoveSpeed.y *= 0.75f; + + obj->m_vecTurnSpeed = m_vecTurnSpeed*2.0f; + + // push component away from car + CVector dist = obj->GetPosition() - GetPosition(); + dist.Normalise(); + if(component == COMPGROUP_BONNET || component == COMPGROUP_BOOT || component == CAR_WINDSCREEN){ + // push these up some + dist += GetUp(); + if(GetUp().z > 0.0f){ + // simulate fast upward movement if going fast + float speed = CVector2D(m_vecMoveSpeed).MagnitudeSqr(); + obj->GetPosition() += GetUp()*speed; + } + } + obj->ApplyMoveForce(dist); + + if(type == COMPGROUP_WHEEL){ + obj->m_fTurnMass = 5.0f; + obj->m_vecTurnSpeed.x = 0.5f; + obj->m_fAirResistance = 0.99f; + } + + if(CCollision::ProcessColModels(obj->GetMatrix(), *obj->GetColModel(), + this->GetMatrix(), *this->GetColModel(), + aTempPedColPts, nil, nil) > 0) + obj->m_pCollidingEntity = this; + + if(bRenderScorched) + obj->bRenderScorched = true; + + CWorld::Add(obj); + + return obj; +} + +CObject* +CAutomobile::RemoveBonnetInPedCollision(void) +{ + CObject *obj; + + if(Damage.GetDoorStatus(DOOR_BONNET) != DOOR_STATUS_SWINGING && + Doors[DOOR_BONNET].RetAngleWhenOpen()*0.4f < Doors[DOOR_BONNET].m_fAngle){ + // BUG? why not COMPGROUP_BONNET? + obj = SpawnFlyingComponent(CAR_BONNET, COMPGROUP_DOOR); + // make both doors invisible on car + SetComponentVisibility(m_aCarNodes[CAR_BONNET], ATOMIC_FLAG_NONE); + Damage.SetDoorStatus(DOOR_BONNET, DOOR_STATUS_MISSING); + return obj; + } + return nil; +} + +void +CAutomobile::SetPanelDamage(int32 component, ePanels panel, bool noFlyingComponents) +{ + int status = Damage.GetPanelStatus(panel); + if(m_aCarNodes[component] == nil) + return; + if(status == PANEL_STATUS_SMASHED1){ + // show damaged part + SetComponentVisibility(m_aCarNodes[component], ATOMIC_FLAG_DAM); + }else if(status == PANEL_STATUS_MISSING){ + if(!noFlyingComponents) + SpawnFlyingComponent(component, COMPGROUP_PANEL); + // hide both + SetComponentVisibility(m_aCarNodes[component], ATOMIC_FLAG_NONE); + } +} + +void +CAutomobile::SetBumperDamage(int32 component, ePanels panel, bool noFlyingComponents) +{ + int status = Damage.GetPanelStatus(panel); + if(m_aCarNodes[component] == nil){ + printf("Trying to damage component %d of %s\n", + component, CModelInfo::GetModelInfo(GetModelIndex())->GetName()); + return; + } + if(status == PANEL_STATUS_SMASHED1){ + // show damaged part + SetComponentVisibility(m_aCarNodes[component], ATOMIC_FLAG_DAM); + }else if(status == PANEL_STATUS_MISSING){ + if(!noFlyingComponents) + SpawnFlyingComponent(component, COMPGROUP_BUMPER); + // hide both + SetComponentVisibility(m_aCarNodes[component], ATOMIC_FLAG_NONE); + } +} + +void +CAutomobile::SetDoorDamage(int32 component, eDoors door, bool noFlyingComponents) +{ + int status = Damage.GetDoorStatus(door); + if(m_aCarNodes[component] == nil){ + printf("Trying to damage component %d of %s\n", + component, CModelInfo::GetModelInfo(GetModelIndex())->GetName()); + return; + } + + if(door == DOOR_BOOT && status == DOOR_STATUS_SWINGING && m_handling->Flags & HANDLING_NOSWING_BOOT){ + Damage.SetDoorStatus(DOOR_BOOT, DOOR_STATUS_MISSING); + status = DOOR_STATUS_MISSING; + } + + if(status == DOOR_STATUS_SMASHED){ + // show damaged part + SetComponentVisibility(m_aCarNodes[component], ATOMIC_FLAG_DAM); + }else if(status == DOOR_STATUS_SWINGING){ + // turn off angle cull for swinging doors + RwFrameForAllObjects(m_aCarNodes[component], CVehicleModelInfo::SetAtomicFlagCB, (void*)ATOMIC_FLAG_NOCULL); + }else if(status == DOOR_STATUS_MISSING){ + if(!noFlyingComponents){ + if(door == DOOR_BONNET) + SpawnFlyingComponent(component, COMPGROUP_BONNET); + else if(door == DOOR_BOOT) + SpawnFlyingComponent(component, COMPGROUP_BOOT); + else + SpawnFlyingComponent(component, COMPGROUP_DOOR); + } + // hide both + SetComponentVisibility(m_aCarNodes[component], ATOMIC_FLAG_NONE); + } +} + + +static RwObject* +SetVehicleAtomicVisibilityCB(RwObject *object, void *data) +{ + uint32 flags = (uint32)(uintptr)data; + RpAtomic *atomic = (RpAtomic*)object; + if((CVisibilityPlugins::GetAtomicId(atomic) & (ATOMIC_FLAG_OK|ATOMIC_FLAG_DAM)) == flags) + RpAtomicSetFlags(atomic, rpATOMICRENDER); + else + RpAtomicSetFlags(atomic, 0); + return object; +} + +void +CAutomobile::SetComponentVisibility(RwFrame *frame, uint32 flags) +{ + HideAllComps(); + bIsDamaged = true; + RwFrameForAllObjects(frame, SetVehicleAtomicVisibilityCB, (void*)flags); +} + +void +CAutomobile::SetupModelNodes(void) +{ + int i; + for(i = 0; i < NUM_CAR_NODES; i++) + m_aCarNodes[i] = nil; + CClumpModelInfo::FillFrameArray((RpClump*)m_rwObject, m_aCarNodes); +} + +void +CAutomobile::SetTaxiLight(bool light) +{ + bTaxiLight = light; +} + +bool +CAutomobile::GetAllWheelsOffGround(void) +{ + return m_nWheelsOnGround == 0; +} + +void +CAutomobile::HideAllComps(void) +{ + // empty +} + +void +CAutomobile::ShowAllComps(void) +{ + // empty +} + +void +CAutomobile::ReduceHornCounter(void) +{ + if(m_nCarHornTimer != 0) + m_nCarHornTimer--; +} + +void +CAutomobile::SetAllTaxiLights(bool set) +{ + m_sAllTaxiLights = set; +} + +class CAutomobile_ : public CAutomobile +{ +public: + void dtor() { CAutomobile::~CAutomobile(); } + void SetModelIndex_(uint32 id) { CAutomobile::SetModelIndex(id); } + void ProcessControl_(void) { CAutomobile::ProcessControl(); } + void Teleport_(CVector v) { CAutomobile::Teleport(v); } + void PreRender_(void) { CAutomobile::PreRender(); } + void Render_(void) { CAutomobile::Render(); } + + int32 ProcessEntityCollision_(CEntity *ent, CColPoint *colpoints){ return CAutomobile::ProcessEntityCollision(ent, colpoints); } + + void ProcessControlInputs_(uint8 x) { CAutomobile::ProcessControlInputs(x); } + void GetComponentWorldPosition_(int32 component, CVector &pos) { CAutomobile::GetComponentWorldPosition(component, pos); } + bool IsComponentPresent_(int32 component) { return CAutomobile::IsComponentPresent(component); } + void SetComponentRotation_(int32 component, CVector rotation) { CAutomobile::SetComponentRotation(component, rotation); } + void OpenDoor_(int32 component, eDoors door, float ratio) { CAutomobile::OpenDoor(component, door, ratio); } + void ProcessOpenDoor_(uint32 component, uint32 anim, float time) { CAutomobile::ProcessOpenDoor(component, anim, time); } + bool IsDoorReady_(eDoors door) { return CAutomobile::IsDoorReady(door); } + bool IsDoorFullyOpen_(eDoors door) { return CAutomobile::IsDoorFullyOpen(door); } + bool IsDoorClosed_(eDoors door) { return CAutomobile::IsDoorClosed(door); } + bool IsDoorMissing_(eDoors door) { return CAutomobile::IsDoorMissing(door); } + void RemoveRefsToVehicle_(CEntity *ent) { CAutomobile::RemoveRefsToVehicle(ent); } + void BlowUpCar_(CEntity *ent) { CAutomobile::BlowUpCar(ent); } + bool SetUpWheelColModel_(CColModel *colModel) { return CAutomobile::SetUpWheelColModel(colModel); } + void BurstTyre_(uint8 tyre) { CAutomobile::BurstTyre(tyre); } + bool IsRoomForPedToLeaveCar_(uint32 door, CVector *pos) { return CAutomobile::IsRoomForPedToLeaveCar(door, pos); } + float GetHeightAboveRoad_(void) { return CAutomobile::GetHeightAboveRoad(); } + void PlayCarHorn_(void) { CAutomobile::PlayCarHorn(); } +}; STARTPATCHES -InjectHook(0x52D170, &CAutomobile::dtor, PATCH_JUMP); -ENDPATCHES
\ No newline at end of file + InjectHook(0x52D170, &CAutomobile_::dtor, PATCH_JUMP); + InjectHook(0x52D190, &CAutomobile_::SetModelIndex_, PATCH_JUMP); + InjectHook(0x535180, &CAutomobile_::Teleport_, PATCH_JUMP); + InjectHook(0x53B270, &CAutomobile_::ProcessEntityCollision_, PATCH_JUMP); + InjectHook(0x52E5F0, &CAutomobile_::GetComponentWorldPosition_, PATCH_JUMP); + InjectHook(0x52E660, &CAutomobile_::IsComponentPresent_, PATCH_JUMP); + InjectHook(0x52E680, &CAutomobile_::SetComponentRotation_, PATCH_JUMP); + InjectHook(0x52E750, &CAutomobile_::OpenDoor_, PATCH_JUMP); + InjectHook(0x52EF10, &CAutomobile_::IsDoorReady_, PATCH_JUMP); + InjectHook(0x52EF90, &CAutomobile_::IsDoorFullyOpen_, PATCH_JUMP); + InjectHook(0x52EFD0, &CAutomobile_::IsDoorClosed_, PATCH_JUMP); + InjectHook(0x52F000, &CAutomobile_::IsDoorMissing_, PATCH_JUMP); + InjectHook(0x53BF40, &CAutomobile_::RemoveRefsToVehicle_, PATCH_JUMP); + InjectHook(0x53BC60, &CAutomobile_::BlowUpCar_, PATCH_JUMP); + InjectHook(0x53BF70, &CAutomobile_::SetUpWheelColModel_, PATCH_JUMP); + InjectHook(0x53C0E0, &CAutomobile_::BurstTyre_, PATCH_JUMP); + InjectHook(0x437690, &CAutomobile_::GetHeightAboveRoad_, PATCH_JUMP); + InjectHook(0x53C450, &CAutomobile_::PlayCarHorn_, PATCH_JUMP); + InjectHook(0x5353A0, &CAutomobile::ResetSuspension, PATCH_JUMP); + InjectHook(0x52D210, &CAutomobile::SetupSuspensionLines, PATCH_JUMP); + InjectHook(0x53E000, &CAutomobile::BlowUpCarsInPath, PATCH_JUMP); + InjectHook(0x42E220, &CAutomobile::HasCarStoppedBecauseOfLight, PATCH_JUMP); + InjectHook(0x53D320, &CAutomobile::SetBusDoorTimer, PATCH_JUMP); + InjectHook(0x53D370, &CAutomobile::ProcessAutoBusDoors, PATCH_JUMP); + InjectHook(0x535250, &CAutomobile::ProcessSwingingDoor, PATCH_JUMP); + InjectHook(0x53C240, &CAutomobile::Fix, PATCH_JUMP); + InjectHook(0x53C310, &CAutomobile::SetupDamageAfterLoad, PATCH_JUMP); + InjectHook(0x530300, &CAutomobile::SpawnFlyingComponent, PATCH_JUMP); + InjectHook(0x535320, &CAutomobile::RemoveBonnetInPedCollision, PATCH_JUMP); + InjectHook(0x5301A0, &CAutomobile::SetPanelDamage, PATCH_JUMP); + InjectHook(0x530120, &CAutomobile::SetBumperDamage, PATCH_JUMP); + InjectHook(0x530200, &CAutomobile::SetDoorDamage, PATCH_JUMP); + InjectHook(0x5300E0, &CAutomobile::SetComponentVisibility, PATCH_JUMP); + InjectHook(0x52D1B0, &CAutomobile::SetupModelNodes, PATCH_JUMP); + InjectHook(0x53C420, &CAutomobile::SetTaxiLight, PATCH_JUMP); + InjectHook(0x53BC40, &CAutomobile::GetAllWheelsOffGround, PATCH_JUMP); + InjectHook(0x5308C0, &CAutomobile::ReduceHornCounter, PATCH_JUMP); + InjectHook(0x53C440, &CAutomobile::SetAllTaxiLights, PATCH_JUMP); +ENDPATCHES diff --git a/src/vehicles/Automobile.h b/src/vehicles/Automobile.h index 630635c7..60e08d0a 100644 --- a/src/vehicles/Automobile.h +++ b/src/vehicles/Automobile.h @@ -1,21 +1,10 @@ #pragma once -#include "DamageManager.h" #include "Vehicle.h" +#include "DamageManager.h" +#include "Door.h" -struct CDoor -{ - float m_fAngleWhenOpened; - float m_fAngleWhenClosed; - char field_8; - char field_9; - char field_10; - char field_11; - float m_fAngle; - float m_fPreviousAngle; - float m_fAngularVelocity; - CVector m_vecVelocity; -}; +class CObject; class CAutomobile : public CVehicle { @@ -28,20 +17,28 @@ public: float m_aSuspensionSpringRatio[4]; float m_aSuspensionSpringRatioPrev[4]; float m_aWheelSkidThing[4]; - int field_49C; + float field_49C; bool m_aWheelSkidmarkMuddy[4]; bool m_aWheelSkidmarkBloody[4]; float m_aWheelRotation[4]; float m_aWheelPosition[4]; float m_aWheelSpeed[4]; - uint8 stuff3[12]; + uint8 field_4D8; + uint8 m_auto_flagA7 : 1; + uint8 bTaxiLight : 1; + uint8 m_auto_flagA10 : 1; + uint8 m_auto_flagA20 : 1; + uint8 m_auto_flagA40 : 1; + uint8 m_auto_flagA80 : 1; + uint8 field_4DA[10]; uint32 m_nBusDoorTimerEnd; uint32 m_nBusDoorTimerStart; float m_aSuspensionSpringLength[4]; float m_aSuspensionLineLength[4]; float m_fHeightAboveRoad; float m_fImprovedHandling; - uint8 stuff6[32]; + uint8 stuff6[28]; + float field_530; CPhysical *m_aGroundPhysical[4]; // physicals touching wheels CVector m_aGroundOffset[4]; // from ground object to colpoint CEntity *m_pBlowUpEntity; @@ -57,11 +54,66 @@ public: uint8 stuff5[5]; int32 m_aWheelState[4]; + static bool &m_sAllTaxiLights; + CAutomobile(int, uint8); + + // from CEntity + void SetModelIndex(uint32 id); + void ProcessControl(void); + void Teleport(CVector v); + void PreRender(void); + void Render(void); + + // from CPhysical + int32 ProcessEntityCollision(CEntity *ent, CColPoint *colpoints); + + // from CVehicle + void ProcessControlInputs(uint8); + void GetComponentWorldPosition(int32 component, CVector &pos); + bool IsComponentPresent(int32 component); + void SetComponentRotation(int32 component, CVector rotation); + void OpenDoor(int32 component, eDoors door, float openRatio); + void ProcessOpenDoor(uint32, uint32, float); + bool IsDoorReady(eDoors door); + bool IsDoorFullyOpen(eDoors door); + bool IsDoorClosed(eDoors door); + bool IsDoorMissing(eDoors door); + void RemoveRefsToVehicle(CEntity *ent); + void BlowUpCar(CEntity *ent); + bool SetUpWheelColModel(CColModel *colModel); + void BurstTyre(uint8 tyre); + bool IsRoomForPedToLeaveCar(uint32, CVector *); + float GetHeightAboveRoad(void); + void PlayCarHorn(void); + + void PlayHornIfNecessary(void); + void ResetSuspension(void); + void SetupSuspensionLines(void); + void ScanForCrimes(void); + void BlowUpCarsInPath(void); + bool HasCarStoppedBecauseOfLight(void); + void SetBusDoorTimer(uint32 timer, uint8 type); + void ProcessAutoBusDoors(void); + void ProcessSwingingDoor(int32 component, eDoors door); + void SetupDamageAfterLoad(void); + CObject *SpawnFlyingComponent(int32 component, uint32 type); + CObject *RemoveBonnetInPedCollision(void); + void SetPanelDamage(int32 component, ePanels panel, bool noFlyingComponents = false); + void SetBumperDamage(int32 component, ePanels panel, bool noFlyingComponents = false); + void SetDoorDamage(int32 component, eDoors door, bool noFlyingComponents = false); + + void Fix(void); + void SetComponentVisibility(RwFrame *frame, uint32 flags); + void SetupModelNodes(void); + void SetTaxiLight(bool light); + bool GetAllWheelsOffGround(void); + void HideAllComps(void); + void ShowAllComps(void); + void ReduceHornCounter(void); + + static void SetAllTaxiLights(bool set); + CAutomobile* ctor(int, uint8); - void SetDoorDamage(int32, uint32, bool); /* TODO: eDoors */ - void SetPanelDamage(int32, uint32, bool); /* TODO: ePanels */ - void SetBumperDamage(int32, uint32, bool); /* TODO: ePanels */ - void dtor() { this->CAutomobile::~CAutomobile(); } }; static_assert(sizeof(CAutomobile) == 0x5A8, "CAutomobile: error"); diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp index 9b462971..53a912b3 100644 --- a/src/vehicles/Boat.cpp +++ b/src/vehicles/Boat.cpp @@ -20,7 +20,6 @@ CBoat::CBoat(int mi, uint8 owner) WRAPPER CBoat* CBoat::ctor(int, uint8) { EAXJMP(0x53E3E0); } - bool CBoat::IsSectorAffectedByWake(CVector2D sector, float fSize, CBoat **apBoats) { uint8 numVerts = 0; @@ -71,7 +70,12 @@ float CBoat::IsVertexAffectedByWake(CVector vecVertex, CBoat *pBoat) WRAPPER void CBoat::FillBoatList(void) { EAXJMP(0x542250); } +class CBoat_ : public CBoat +{ +public: + void dtor() { CBoat::~CBoat(); }; +}; STARTPATCHES -InjectHook(0x53E790, &CBoat::dtor, PATCH_JUMP); -ENDPATCHES
\ No newline at end of file + InjectHook(0x53E790, &CBoat_::dtor, PATCH_JUMP); +ENDPATCHES diff --git a/src/vehicles/Boat.h b/src/vehicles/Boat.h index 41fed2ff..52f3530c 100644 --- a/src/vehicles/Boat.h +++ b/src/vehicles/Boat.h @@ -49,6 +49,7 @@ public: static bool IsSectorAffectedByWake(CVector2D sector, float fSize, CBoat **apBoats); static float IsVertexAffectedByWake(CVector vecVertex, CBoat *pBoat); static void FillBoatList(void); + }; static_assert(sizeof(CBoat) == 0x484, "CBoat: error"); diff --git a/src/vehicles/DamageManager.cpp b/src/vehicles/DamageManager.cpp index 1a7f25ed..380537f2 100644 --- a/src/vehicles/DamageManager.cpp +++ b/src/vehicles/DamageManager.cpp @@ -1,6 +1,7 @@ #include "common.h" #include "patcher.h" #include "General.h" +#include "Vehicle.h" #include "DamageManager.h" diff --git a/src/vehicles/DamageManager.h b/src/vehicles/DamageManager.h index 1fdbc6b1..b815f724 100644 --- a/src/vehicles/DamageManager.h +++ b/src/vehicles/DamageManager.h @@ -4,6 +4,28 @@ // TODO: move some of this into Vehicle.h +enum eDoorStatus +{ + DOOR_STATUS_OK, + DOOR_STATUS_SMASHED, + DOOR_STATUS_SWINGING, + DOOR_STATUS_MISSING +}; + +enum ePanelStatus +{ + PANEL_STATUS_OK, + PANEL_STATUS_SMASHED1, + PANEL_STATUS_SMASHED2, + PANEL_STATUS_MISSING, +}; + +enum eWheelStatus +{ + WHEEL_STATUS_OK, + WHEEL_STATUS_BURST +}; + enum tComponent { COMPONENT_DEFAULT, @@ -37,23 +59,7 @@ enum tComponentGroup COMPGROUP_DEFAULT, }; -enum eLights -{ - VEHLIGHT_FRONT_LEFT, - VEHLIGHT_FRONT_RIGHT, - VEHLIGHT_REAR_LEFT, - VEHLIGHT_REAR_RIGHT, -}; - -enum { - VEHPANEL_FRONT_LEFT, - VEHPANEL_FRONT_RIGHT, - VEHPANEL_REAR_LEFT, - VEHPANEL_REAR_RIGHT, - VEHPANEL_WINDSCREEN, - VEHBUMPER_FRONT, - VEHBUMPER_REAR, -}; +enum eLights; class CDamageManager { diff --git a/src/vehicles/Door.cpp b/src/vehicles/Door.cpp new file mode 100644 index 00000000..25e87504 --- /dev/null +++ b/src/vehicles/Door.cpp @@ -0,0 +1,126 @@ +#include "common.h" +#include "patcher.h" +#include "Vehicle.h" +#include "Door.h" + +CDoor::CDoor(void) +{ + memset(this, 0, sizeof(*this)); +} + +void +CDoor::Open(float ratio) +{ + float open; + + m_fPrevAngle = m_fAngle; + open = RetAngleWhenOpen(); + if(ratio < 1.0f){ + m_fAngle = open*ratio; + if(m_fAngle == 0.0f) + m_fAngVel = 0.0f; + }else{ + m_nDoorState = DOORST_OPEN; + m_fAngle = open; + } +} + +void +CDoor::Process(CVehicle *vehicle) +{ + static CVector vecOffset(1.0f, 0.0f, 0.0f); + CVector speed = vehicle->GetSpeed(vecOffset); + CVector vecSpeedDiff = speed - m_vecSpeed; + vecSpeedDiff = Multiply3x3(vecSpeedDiff, vehicle->GetMatrix()); + + // air resistance + float fSpeedDiff = 0.0f; // uninitialized in game + switch(m_nAxis){ + case 0: // x-axis + if(m_nDirn) + fSpeedDiff = vecSpeedDiff.y + vecSpeedDiff.z; + else + fSpeedDiff = -(vecSpeedDiff.y + vecSpeedDiff.z); + break; + + // we don't support y axis apparently? + + case 2: // z-axis + if(m_nDirn) + fSpeedDiff = -(vecSpeedDiff.x + vecSpeedDiff.y); + else + fSpeedDiff = vecSpeedDiff.x + vecSpeedDiff.y; + break; + } + fSpeedDiff = clamp(fSpeedDiff, -0.2f, 0.2f); + if(Abs(fSpeedDiff) > 0.002f) + m_fAngVel += fSpeedDiff; + m_fAngVel *= 0.945f; + m_fAngVel = clamp(m_fAngVel, -0.3f, 0.3f); + + m_fAngle += m_fAngVel; + m_nDoorState = DOORST_SWINGING; + if(m_fAngle > m_fMaxAngle){ + m_fAngle = m_fMaxAngle; + m_fAngVel *= -0.8f; + m_nDoorState = DOORST_OPEN; + } + if(m_fAngle < m_fMinAngle){ + m_fAngle = m_fMinAngle; + m_fAngVel *= -0.8f; + m_nDoorState = DOORST_CLOSED; + } + m_vecSpeed = speed; +} + +float +CDoor::RetAngleWhenClosed(void) +{ + if(Abs(m_fMaxAngle) < Abs(m_fMinAngle)) + return m_fMaxAngle; + else + return m_fMinAngle; +} + +float +CDoor::RetAngleWhenOpen(void) +{ + if(Abs(m_fMaxAngle) < Abs(m_fMinAngle)) + return m_fMinAngle; + else + return m_fMaxAngle; +} + +float +CDoor::GetAngleOpenRatio(void) +{ + float open = RetAngleWhenOpen(); + if(open == 0.0f) + return 0.0f; + return m_fAngle/open; +} + +bool +CDoor::IsFullyOpen(void) +{ + // why -0.5? that's around 28 deg less than fully open + if(Abs(m_fAngle) < Abs(RetAngleWhenOpen()) - 0.5f) + return false; + return true; +} + +bool +CDoor::IsClosed(void) +{ + return m_fAngle == RetAngleWhenClosed(); +} + +STARTPATCHES + InjectHook(0x545EF0, &CDoor::Open, PATCH_JUMP); + InjectHook(0x545BD0, &CDoor::Process, PATCH_JUMP); + InjectHook(0x545FE0, &CDoor::RetAngleWhenClosed, PATCH_JUMP); + InjectHook(0x546020, &CDoor::RetAngleWhenOpen, PATCH_JUMP); + InjectHook(0x545F80, &CDoor::GetAngleOpenRatio, PATCH_JUMP); + InjectHook(0x546090, &CDoor::IsFullyOpen, PATCH_JUMP); + InjectHook(0x546060, &CDoor::IsClosed, PATCH_JUMP); +ENDPATCHES diff --git a/src/vehicles/Door.h b/src/vehicles/Door.h new file mode 100644 index 00000000..fc771a40 --- /dev/null +++ b/src/vehicles/Door.h @@ -0,0 +1,36 @@ +#pragma once + +class CVehicle; + +enum eDoorState +{ + DOORST_SWINGING, + // actually wrong though, + // OPEN is really MAX_ANGLE and CLOSED is MIN_ANGLE + DOORST_OPEN, + DOORST_CLOSED +}; + +struct CDoor +{ + float m_fMaxAngle; + float m_fMinAngle; + // direction of rotation for air resistance + int8 m_nDirn; + // axis in which this door rotates + int8 m_nAxis; + int8 m_nDoorState; + float m_fAngle; + float m_fPrevAngle; + float m_fAngVel; + CVector m_vecSpeed; + + CDoor(void); + void Open(float ratio); + void Process(CVehicle *veh); + float RetAngleWhenClosed(void); + float RetAngleWhenOpen(void); + float GetAngleOpenRatio(void); + bool IsFullyOpen(void); + bool IsClosed(void); +}; diff --git a/src/vehicles/HandlingMgr.h b/src/vehicles/HandlingMgr.h index 958e2351..2627fbae 100644 --- a/src/vehicles/HandlingMgr.h +++ b/src/vehicles/HandlingMgr.h @@ -119,7 +119,9 @@ VALIDATE_SIZE(tHandlingData, 0xD8); class cHandlingDataMgr { float field_0; // unused it seems +public: float field_4; // wheel related +private: float field_8; // float field_C; // unused it seems float field_10; // diff --git a/src/vehicles/Heli.cpp b/src/vehicles/Heli.cpp index 01ee5375..d43e8c19 100644 --- a/src/vehicles/Heli.cpp +++ b/src/vehicles/Heli.cpp @@ -10,6 +10,12 @@ CHeli::CHeli(int mi, uint8 owner) WRAPPER CHeli* CHeli::ctor(int, uint8) { EAXJMP(0x547220); } WRAPPER void CHeli::SpecialHeliPreRender(void) { EAXJMP(0x54AE10); } +class CHeli_ : public CHeli +{ +public: + void dtor(void) { CHeli::~CHeli(); } +}; + STARTPATCHES -InjectHook(0x5474A0, &CHeli::dtor, PATCH_JUMP); + InjectHook(0x5474A0, &CHeli_::dtor, PATCH_JUMP); ENDPATCHES diff --git a/src/vehicles/Heli.h b/src/vehicles/Heli.h index da7bb171..db873ae2 100644 --- a/src/vehicles/Heli.h +++ b/src/vehicles/Heli.h @@ -10,7 +10,6 @@ public: CHeli(int, uint8); CHeli* ctor(int, uint8); - void dtor(void) { this->CHeli::~CHeli(); } static void SpecialHeliPreRender(void); }; diff --git a/src/vehicles/Plane.cpp b/src/vehicles/Plane.cpp index 6e30bced..3bad1e07 100644 --- a/src/vehicles/Plane.cpp +++ b/src/vehicles/Plane.cpp @@ -14,6 +14,12 @@ CPlane::~CPlane() DeleteRwObject(); } +class CPlane_ : public CPlane +{ +public: + void dtor(void) { CPlane::~CPlane(); } +}; + STARTPATCHES -InjectHook(0x54B270, &CPlane::dtor, PATCH_JUMP); -ENDPATCHES
\ No newline at end of file + InjectHook(0x54B270, &CPlane_::dtor, PATCH_JUMP); +ENDPATCHES diff --git a/src/vehicles/Plane.h b/src/vehicles/Plane.h index e26008f6..1f54e529 100644 --- a/src/vehicles/Plane.h +++ b/src/vehicles/Plane.h @@ -12,7 +12,6 @@ public: CPlane(int, uint8); ~CPlane(void); CPlane* ctor(int, uint8); - void dtor(void) { this->CPlane::~CPlane(); } void FlagToDestroyWhenNextProcessed() { bRemoveFromWorld = true; } }; static_assert(sizeof(CPlane) == 0x29C, "CPlane: error"); diff --git a/src/vehicles/Train.cpp b/src/vehicles/Train.cpp index 62fd53ec..b7fd6ca1 100644 --- a/src/vehicles/Train.cpp +++ b/src/vehicles/Train.cpp @@ -9,6 +9,12 @@ CTrain::CTrain(int mi, uint8 owner) WRAPPER CTrain* CTrain::ctor(int, uint8) { EAXJMP(0x54E2A0); } +class CTrain_ : public CTrain +{ +public: + void dtor(void) { CTrain::~CTrain(); } +}; + STARTPATCHES -InjectHook(0x54E450, &CTrain::dtor, PATCH_JUMP); -ENDPATCHES
\ No newline at end of file + InjectHook(0x54E450, &CTrain_::dtor, PATCH_JUMP); +ENDPATCHES diff --git a/src/vehicles/Train.h b/src/vehicles/Train.h index 84b6faf5..5e1e2e35 100644 --- a/src/vehicles/Train.h +++ b/src/vehicles/Train.h @@ -21,6 +21,5 @@ public: CTrain(int, uint8); CTrain* ctor(int, uint8); - void dtor(void) { this->CTrain::~CTrain(); } }; static_assert(sizeof(CTrain) == 0x2E4, "CTrain: error"); diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index dccd9195..d8ed1a15 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -1,7 +1,9 @@ #include "common.h" #include "main.h" #include "patcher.h" +#include "General.h" #include "Timer.h" +#include "Pad.h" #include "Vehicle.h" #include "Pools.h" #include "HandlingMgr.h" @@ -13,6 +15,7 @@ #include "PointLights.h" #include "Renderer.h" #include "DMAudio.h" +#include "MusicManager.h" #include "Radar.h" bool &CVehicle::bWheelsOnlyCheat = *(bool *)0x95CD78; @@ -27,6 +30,79 @@ void *CVehicle::operator new(size_t sz, int handle) { return CPools::GetVehicleP void CVehicle::operator delete(void *p, size_t sz) { CPools::GetVehiclePool()->Delete((CVehicle*)p); } void CVehicle::operator delete(void *p, int handle) { CPools::GetVehiclePool()->Delete((CVehicle*)p); } +CVehicle::CVehicle(uint8 CreatedBy) +{ + int i; + + m_nCurrentGear = 0; + field_208 = 0; + m_fSteerRatio = 0.0f; + m_type = ENTITY_TYPE_VEHICLE; + VehicleCreatedBy = CreatedBy; + bIsLocked = false; + bIsLawEnforcer = false; + bIsAmbulanceOnDuty = false; + bIsFireTruckOnDuty = false; + CCarCtrl::UpdateCarCount(this, false); + m_fHealth = 1000.0f; + bEngineOn = true; + bFreebies = true; + pDriver = nil; + m_nNumPassengers = 0; + m_nNumGettingIn = 0; + m_nGettingInFlags = 0; + m_nGettingOutFlags = 0; + m_nNumMaxPassengers = 8; + for(i = 0; i < m_nNumMaxPassengers; i++) + pPassengers[i] = nil; + m_nBombTimer = 0; + m_pWhoSetMeOnFire = nil; + field_1FB = 0; + m_veh_flagB10 = false; + m_veh_flagB40 = false; + m_veh_flagB80 = false; + m_veh_flagC1 = false; + bIsDamaged = false; + m_veh_flagC8 = false; + m_veh_flagC10 = false; + m_veh_flagC4 = false; + m_veh_flagC20 = false; + bCanBeDamaged = true; + m_veh_flagC80 = false; + m_veh_flagD1 = false; + m_veh_flagD2 = false; + m_nGunFiringTime = 0; + field_214 = 0; + bLightsOn = false; + bVehicleColProcessed = false; + field_1F9 = 0; + bIsCarParkVehicle = false; + bHasAlreadyBeenRecorded = false; + m_bSirenOrAlarm = 0; + m_nCarHornTimer = 0; + field_22D = 0; + m_nAlarmState = 0; + m_nDoorLock = CARLOCK_UNLOCKED; + m_nLastWeaponDamage = -1; + field_220 = 0.0; + field_21C = field_220; + m_audioEntityId = DMAudio.CreateEntity(0, this); + if(m_audioEntityId) + DMAudio.SetEntityStatus(m_audioEntityId, true); + m_nRadioStation = CGeneral::GetRandomNumber() % USERTRACK; + m_pCurGroundEntity = nil; + field_22A = 0; + field_22B = 0; + field_22F = 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; +} + CVehicle::~CVehicle() { m_nAlarmState = 0; @@ -92,9 +168,227 @@ CVehicle::RemoveLighting(bool reset) float CVehicle::GetHeightAboveRoad(void) { - return -1.0f * CModelInfo::GetModelInfo(GetModelIndex())->GetColModel()->boundingBox.min.z; + return -1.0f * GetColModel()->boundingBox.min.z; +} + +void +CVehicle::FlyingControl(eFlightModel flightModel) +{ + switch(flightModel){ + case FLIGHT_MODEL_DODO: + { + // This seems pretty magic + + // Move Left/Right + float moveSpeed = m_vecMoveSpeed.Magnitude(); + float sideSpeed = DotProduct(m_vecMoveSpeed, GetRight()); + float sideImpulse = -1.0f * sideSpeed / moveSpeed; + float fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward()); + float magic = m_vecMoveSpeed.MagnitudeSqr() * sq(fwdSpeed); + float turnImpulse = (sideImpulse*0.003f + m_fSteerAngle*0.001f) * + magic*m_fTurnMass*CTimer::GetTimeStep(); + ApplyTurnForce(turnImpulse*GetRight(), -4.0f*GetForward()); + + float impulse = sideImpulse*0.2f * + magic*m_fMass*CTimer::GetTimeStep(); + ApplyMoveForce(impulse*GetRight()); + ApplyTurnForce(impulse*GetRight(), 2.0f*GetUp()); + + + // Move Up/Down + moveSpeed = m_vecMoveSpeed.Magnitude(); + float upSpeed = DotProduct(m_vecMoveSpeed, GetUp()); + float upImpulse = -1.0f * upSpeed / moveSpeed; + turnImpulse = (upImpulse*0.002f + -CPad::GetPad(0)->GetSteeringUpDown()/128.0f*0.001f) * + magic*m_fTurnMass*CTimer::GetTimeStep(); + ApplyTurnForce(turnImpulse*GetUp(), -4.0f*GetForward()); + + impulse = (upImpulse*3.5f + 0.5f)*0.05f * + magic*m_fMass*CTimer::GetTimeStep(); + if(GRAVITY*m_fMass*CTimer::GetTimeStep() < impulse && + GetPosition().z > 100.0f) + impulse = 0.9f*GRAVITY*m_fMass*CTimer::GetTimeStep(); + CVector com = Multiply3x3(GetMatrix(), m_vecCentreOfMass); + ApplyMoveForce(impulse*GetUp()); + ApplyTurnForce(impulse*GetUp(), 2.0f*GetUp() + com); + + + m_vecTurnSpeed.y *= Pow(0.9f, CTimer::GetTimeStep()); + moveSpeed = m_vecMoveSpeed.MagnitudeSqr(); + if(moveSpeed > 2.25f) + m_vecMoveSpeed *= 1.5f/Sqrt(moveSpeed); + + float turnSpeed = m_vecTurnSpeed.MagnitudeSqr(); + if(turnSpeed > 0.04f) + m_vecTurnSpeed *= 0.2f/Sqrt(turnSpeed); + } + break; + + case FLIGHT_MODEL_RCPLANE: + case FLIGHT_MODEL_SEAPLANE: + assert(0 && "Plane flight model not implemented"); + case FLIGHT_MODEL_HELI: + assert(0 && "Heli flight model not implemented"); + } +} + +void +CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelContactSpeed, CVector &wheelContactPoint, + int32 wheelsOnGround, float thrust, float brake, float adhesion, int8 wheelId, float *wheelSpeed, tWheelState *wheelState, uint16 wheelStatus) +{ + // BUG: using statics here is probably a bad idea + static bool bAlreadySkidding = false; // this is never reset + static bool bBraking; + static bool bDriving; + + // how much force we want to apply in these axes + float fwd = 0.0f; + float right = 0.0f; + + bBraking = brake != 0.0f; + if(bBraking) + thrust = 0.0f; + bDriving = thrust != 0.0f; + + float contactSpeedFwd = DotProduct(wheelContactSpeed, wheelFwd); + float contactSpeedRight = DotProduct(wheelContactSpeed, wheelRight); + + if(*wheelState != WHEEL_STATE_0) + bAlreadySkidding = true; + *wheelState = WHEEL_STATE_0; + + adhesion *= CTimer::GetTimeStep(); + if(bAlreadySkidding) + adhesion *= m_handling->fTractionLoss; + + // moving sideways + if(contactSpeedRight != 0.0f){ + // exert opposing force + right = -contactSpeedRight/wheelsOnGround; + + if(wheelStatus == WHEEL_STATUS_BURST){ + float fwdspeed = min(contactSpeedFwd, 0.3f); + right += fwdspeed * CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); + } + } + + if(bDriving){ + fwd = thrust; + + // limit sideways force (why?) + if(right > 0.0f){ + if(right > adhesion) + right = adhesion; + }else{ + if(right < -adhesion) + right = -adhesion; + } + }else if(contactSpeedFwd != 0.0f){ + fwd = -contactSpeedFwd/wheelsOnGround; + + if(!bBraking){ + if(m_fGasPedal < 0.01f){ + if(GetModelIndex() == MI_RCBANDIT) + brake = 0.2f * mod_HandlingManager.field_4 / m_fMass; + else + brake = mod_HandlingManager.field_4 / m_fMass; + } + } + + if(brake > adhesion){ + if(Abs(contactSpeedFwd) > 0.005f) + *wheelState = WHEEL_STATE_STATIC; + }else { + if(fwd > 0.0f){ + if(fwd > brake) + fwd = brake; + }else{ + if(fwd < -brake) + fwd = -brake; + } + } + } + + if(sq(adhesion) < sq(right) + sq(fwd)){ + if(*wheelState != WHEEL_STATE_STATIC){ + if(bDriving && contactSpeedFwd < 0.2f) + *wheelState = WHEEL_STATE_1; + else + *wheelState = WHEEL_STATE_2; + } + + float l = Sqrt(sq(right) + sq(fwd)); + float tractionLoss = bAlreadySkidding ? 1.0f : m_handling->fTractionLoss; + right *= adhesion * tractionLoss / l; + fwd *= adhesion * tractionLoss / l; + } + + if(fwd != 0.0f || right != 0.0f){ + CVector direction = fwd*wheelFwd + right*wheelRight; + float speed = direction.Magnitude(); + direction.Normalise(); + + float impulse = speed*m_fMass; + float turnImpulse = speed*GetMass(wheelContactPoint, direction); + + ApplyMoveForce(impulse * direction); + ApplyTurnForce(turnImpulse * direction, wheelContactPoint); + } +} + +float +CVehicle::ProcessWheelRotation(tWheelState state, const CVector &fwd, const CVector &speed, float radius) +{ + float angularVelocity; + switch(state){ + case WHEEL_STATE_1: + angularVelocity = -1.1f; // constant speed forward + break; + case WHEEL_STATE_STATIC: + angularVelocity = 0.0f; // not moving + break; + default: + angularVelocity = -DotProduct(fwd, speed) / radius; // forward speed + break; + } + return angularVelocity * CTimer::GetTimeStep(); } +void +CVehicle::ExtinguishCarFire(void) +{ + m_fHealth = max(m_fHealth, 300.0f); + if(m_pCarFire) + m_pCarFire->Extinguish(); + if(IsCar()){ + CAutomobile *car = (CAutomobile*)this; + if(car->Damage.GetEngineStatus() >= 225) + car->Damage.SetEngineStatus(215); + car->field_530 = 0.0f; + } +} + +void +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; + + if(IsCar() && ((CAutomobile*)this)->m_auto_flagA7 == 4 && (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); + } +} bool CVehicle::IsLawEnforcementVehicle(void) @@ -258,9 +552,9 @@ CVehicle::CanPedExitCar(void) if(m_vecMoveSpeed.MagnitudeSqr() > 0.005f) return false; // if car is slow enough, check turn speed - if(fabs(m_vecTurnSpeed.x) > 0.01f || - fabs(m_vecTurnSpeed.y) > 0.01f || - fabs(m_vecTurnSpeed.z) > 0.01f) + if(Abs(m_vecTurnSpeed.x) > 0.01f || + Abs(m_vecTurnSpeed.y) > 0.01f || + Abs(m_vecTurnSpeed.z) > 0.01f) return false; return true; }else{ @@ -270,9 +564,9 @@ CVehicle::CanPedExitCar(void) if(m_vecMoveSpeed.MagnitudeSqr() >= 0.005f) return false; // if car is slow enough, check turn speed - if(fabs(m_vecTurnSpeed.x) >= 0.01f || - fabs(m_vecTurnSpeed.y) >= 0.01f || - fabs(m_vecTurnSpeed.z) >= 0.01f) + if(Abs(m_vecTurnSpeed.x) >= 0.01f || + Abs(m_vecTurnSpeed.y) >= 0.01f || + Abs(m_vecTurnSpeed.z) >= 0.01f) return false; return true; } @@ -442,7 +736,7 @@ CVehicle::IsSphereTouchingVehicle(float sx, float sy, float sz, float radius) float x, y, z; // sphere relative to vehicle CVector sph = CVector(sx, sy, sz) - GetPosition(); - CColModel *colmodel = CModelInfo::GetModelInfo(GetModelIndex())->GetColModel(); + CColModel *colmodel = GetColModel(); x = DotProduct(sph, GetRight()); if(colmodel->boundingBox.min.x - radius > x || @@ -460,12 +754,28 @@ CVehicle::IsSphereTouchingVehicle(float sx, float sy, float sz, float radius) return true; } -STARTPATCHES - InjectHook(0x551170, &CVehicle::SetModelIndex_, PATCH_JUMP); - InjectHook(0x4A7DD0, &CVehicle::SetupLighting_, PATCH_JUMP); - InjectHook(0x4A7E60, &CVehicle::RemoveLighting_, PATCH_JUMP); - InjectHook(0x417E60, &CVehicle::GetHeightAboveRoad_, PATCH_JUMP); +class CVehicle_ : public CVehicle +{ +public: + void dtor(void) { CVehicle::~CVehicle(); } + void SetModelIndex_(uint32 id) { CVehicle::SetModelIndex(id); } + bool SetupLighting_(void) { return CVehicle::SetupLighting(); } + void RemoveLighting_(bool reset) { CVehicle::RemoveLighting(reset); } + float GetHeightAboveRoad_(void) { return CVehicle::GetHeightAboveRoad(); } +}; + +STARTPATCHES + InjectHook(0x551170, &CVehicle_::SetModelIndex_, PATCH_JUMP); + InjectHook(0x4A7DD0, &CVehicle_::SetupLighting_, PATCH_JUMP); + InjectHook(0x4A7E60, &CVehicle_::RemoveLighting_, PATCH_JUMP); + InjectHook(0x417E60, &CVehicle_::GetHeightAboveRoad_, PATCH_JUMP); + + InjectHook(0x552BB0, &CVehicle::FlyingControl, PATCH_JUMP); + InjectHook(0x5512E0, &CVehicle::ProcessWheel, PATCH_JUMP); + InjectHook(0x551280, &CVehicle::ProcessWheelRotation, PATCH_JUMP); + InjectHook(0x552AF0, &CVehicle::ExtinguishCarFire, PATCH_JUMP); + InjectHook(0x551C90, &CVehicle::ProcessDelayedExplosion, PATCH_JUMP); InjectHook(0x552880, &CVehicle::IsLawEnforcementVehicle, PATCH_JUMP); InjectHook(0x552820, &CVehicle::ChangeLawEnforcerState, PATCH_JUMP); InjectHook(0x552200, &CVehicle::UsesSiren, PATCH_JUMP); diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h index 39a56fe0..c293b8a6 100644 --- a/src/vehicles/Vehicle.h +++ b/src/vehicles/Vehicle.h @@ -69,6 +69,58 @@ enum eDoors DOOR_REAR_RIGHT }; +enum ePanels +{ + VEHPANEL_FRONT_LEFT, + VEHPANEL_FRONT_RIGHT, + VEHPANEL_REAR_LEFT, + VEHPANEL_REAR_RIGHT, + VEHPANEL_WINDSCREEN, + VEHBUMPER_FRONT, + VEHBUMPER_REAR, +}; + +enum eLights +{ + VEHLIGHT_FRONT_LEFT, + VEHLIGHT_FRONT_RIGHT, + VEHLIGHT_REAR_LEFT, + VEHLIGHT_REAR_RIGHT, +}; + +enum eWheels +{ + VEHWHEEL_FRONT_LEFT, + VEHWHEEL_FRONT_RIGHT, + VEHWHEEL_REAR_LEFT, + VEHWHEEL_REAR_RIGHT, +}; + +enum +{ + CAR_PIECE_WHEEL_LF = 13, + CAR_PIECE_WHEEL_LR, + CAR_PIECE_WHEEL_RF, + CAR_PIECE_WHEEL_RR, +}; + +enum tWheelState +{ + WHEEL_STATE_0 = 0, + WHEEL_STATE_1 = 1, // constant velocity + WHEEL_STATE_2 = 2, // normal + WHEEL_STATE_STATIC = 3, // not moving +}; + +enum eFlightModel +{ + FLIGHT_MODEL_DODO, + // not used in III + FLIGHT_MODEL_RCPLANE, + FLIGHT_MODEL_HELI, + FLIGHT_MODEL_SEAPLANE +}; + class CVehicle : public CPhysical { public: @@ -88,7 +140,7 @@ public: int8 m_nGettingOutFlags; uint8 m_nNumMaxPassengers; char field_1CD[19]; - CEntity *m_pCurSurface; + CEntity *m_pCurGroundEntity; CFire *m_pCarFire; float m_fSteerAngle; float m_fGasPedal; @@ -115,19 +167,19 @@ public: uint8 m_veh_flagB80 : 1; uint8 m_veh_flagC1 : 1; - uint8 m_veh_flagC2 : 1; + 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 m_veh_flagC10 : 1; uint8 m_veh_flagC20 : 1; - uint8 m_veh_flagC40 : 1; + uint8 bCanBeDamaged : 1; // Set to FALSE during cut scenes to avoid explosions uint8 m_veh_flagC80 : 1; uint8 m_veh_flagD1 : 1; uint8 m_veh_flagD2 : 1; - uint8 m_veh_flagD4 : 1; - uint8 m_veh_flagD8 : 1; - uint8 bRecordedForReplay : 1; + uint8 bVehicleColProcessed : 1;// Has ProcessEntityCollision been processed for this car? + uint8 bIsCarParkVehicle : 1; // Car has been created using the special CAR_PARK script command + uint8 bHasAlreadyBeenRecorded : 1; // Used for replays uint8 m_veh_flagD20 : 1; uint8 m_veh_flagD40 : 1; uint8 m_veh_flagD80 : 1; @@ -144,7 +196,7 @@ public: uint32 m_nTimeOfDeath; int16 field_214; int16 m_nBombTimer; // goes down with each frame - CPed *m_pWhoDetonatedMe; + CPed *m_pWhoSetMeOnFire; float field_21C; float field_220; eCarLock m_nDoorLock; @@ -154,11 +206,9 @@ public: int8 field_22B; uint8 m_nCarHornTimer; int8 field_22D; - uint8 m_nSirenOrAlarm; + bool m_bSirenOrAlarm; int8 field_22F; - // TODO: this is an array - CStoredCollPoly m_frontCollPoly; // poly which is under front part of car - CStoredCollPoly m_rearCollPoly; // poly which is under rear part of car + CStoredCollPoly m_aCollPolys[2]; // poly which is under front/rear part of car float m_fSteerRatio; eVehicleType m_vehType; @@ -167,9 +217,11 @@ public: static void operator delete(void*, size_t); static void operator delete(void*, int); + CVehicle(void) {} // FAKE + CVehicle(uint8 CreatedBy); ~CVehicle(void); // from CEntity - void SetModelIndex(uint32 i); + void SetModelIndex(uint32 id); bool SetupLighting(void); void RemoveLighting(bool); void FlagToDestroyWhenNextProcessed(void) {} @@ -197,6 +249,13 @@ public: bool IsTrain(void) { return m_vehType == VEHICLE_TYPE_TRAIN; } bool IsHeli(void) { return m_vehType == VEHICLE_TYPE_HELI; } bool IsPlane(void) { return m_vehType == VEHICLE_TYPE_PLANE; } + + void FlyingControl(eFlightModel flightModel); + void ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelContactSpeed, CVector &wheelContactPoint, + int32 wheelsOnGround, float thrust, float brake, float adhesion, int8 wheelId, float *wheelSpeed, tWheelState *wheelState, uint16 wheelStatus); + void ExtinguishCarFire(void); + void ProcessDelayedExplosion(void); + float ProcessWheelRotation(tWheelState state, const CVector &fwd, const CVector &speed, float radius); bool IsLawEnforcementVehicle(void); void ChangeLawEnforcerState(uint8 enable); bool UsesSiren(uint32 id); @@ -225,16 +284,24 @@ public: static bool &bCheat4; static bool &bCheat5; static bool &m_bDisableMouseSteering; - - - void dtor(void) { CVehicle::~CVehicle(); } - void SetModelIndex_(uint32 id) { CVehicle::SetModelIndex(id); } - bool SetupLighting_(void) { return CVehicle::SetupLighting(); } - void RemoveLighting_(bool reset) { CVehicle::RemoveLighting(reset); } - float GetHeightAboveRoad_(void) { return CVehicle::GetHeightAboveRoad(); } }; static_assert(sizeof(CVehicle) == 0x288, "CVehicle: error"); -static_assert(offsetof(CVehicle, m_pCurSurface) == 0x1E0, "CVehicle: error"); +static_assert(offsetof(CVehicle, m_pCurGroundEntity) == 0x1E0, "CVehicle: error"); static_assert(offsetof(CVehicle, m_nAlarmState) == 0x1A0, "CVehicle: error"); static_assert(offsetof(CVehicle, m_nLastWeaponDamage) == 0x228, "CVehicle: error"); + +inline uint8 GetVehDoorFlag(int32 carnode) { + switch (carnode) { + case CAR_DOOR_LF: + return 1; + case CAR_DOOR_LR: + return 2; + case CAR_DOOR_RF: + return 4; + case CAR_DOOR_RR: + return 8; + default: + return 0; + } +} diff --git a/src/weapons/Weapon.h b/src/weapons/Weapon.h index ba552035..81516c4e 100644 --- a/src/weapons/Weapon.h +++ b/src/weapons/Weapon.h @@ -1,9 +1,9 @@ #pragma once #include "Entity.h" -enum eWeaponType : uint32 +enum eWeaponType { - WEAPONTYPE_UNARMED = 0, + WEAPONTYPE_UNARMED, WEAPONTYPE_BASEBALLBAT, WEAPONTYPE_COLT45, WEAPONTYPE_UZI, @@ -16,10 +16,16 @@ enum eWeaponType : uint32 WEAPONTYPE_MOLOTOV, WEAPONTYPE_GRENADE, WEAPONTYPE_DETONATOR, - NUM_PED_WEAPONTYPES = 13, - WEAPONTYPE_HELICANNON = 13, - NUM_WEAPONTYPES, - NO_STORED_WEAPON = 22 + WEAPONTYPE_TOTAL_INVENTORY_WEAPONS, + WEAPONTYPE_TOTALWEAPONS, + WEAPONTYPE_ARMOUR, + WEAPONTYPE_RAMMEDBYCAR, + WEAPONTYPE_RUNOVERBYCAR, + WEAPONTYPE_EXPLOSION, + WEAPONTYPE_UZI_DRIVEBY, + WEAPONTYPE_WATER, + WEAPONTYPE_FALL_DAMAGE, + WEAPONTYPE_UNIDENTIFIED, }; enum eWeaponFire { diff --git a/src/weapons/WeaponInfo.cpp b/src/weapons/WeaponInfo.cpp index 5be18c3c..6884d347 100644 --- a/src/weapons/WeaponInfo.cpp +++ b/src/weapons/WeaponInfo.cpp @@ -6,7 +6,7 @@ #include "AnimBlendAssociation.h" //CWeaponInfo (&CWeaponInfo::ms_apWeaponInfos)[14] = * (CWeaponInfo(*)[14]) * (uintptr*)0x6503EC; -CWeaponInfo CWeaponInfo::ms_apWeaponInfos[NUM_WEAPONTYPES]; +CWeaponInfo CWeaponInfo::ms_apWeaponInfos[WEAPONTYPE_TOTALWEAPONS]; static char ms_aWeaponNames[][32] = { "Unarmed", @@ -34,7 +34,7 @@ void CWeaponInfo::Initialise(void) { debug("Initialising CWeaponInfo...\n"); - for (int i = 0; i < NUM_WEAPONTYPES; i++) { + for (int i = 0; i < WEAPONTYPE_TOTALWEAPONS; i++) { ms_apWeaponInfos[i].m_eWeaponFire = WEAPON_FIRE_INSTANT_HIT; ms_apWeaponInfos[i].m_AnimToPlay = ANIM_PUNCH_R; ms_apWeaponInfos[i].m_Anim2ToPlay = NUM_ANIMS; @@ -176,7 +176,7 @@ CWeaponInfo::LoadWeaponData(void) eWeaponType CWeaponInfo::FindWeaponType(char *name) { - for (int i = 0; i < NUM_WEAPONTYPES; i++) { + for (int i = 0; i < WEAPONTYPE_TOTALWEAPONS; i++) { if (strcmp(ms_aWeaponNames[i], name) == 0) { return static_cast<eWeaponType>(i); } |