diff options
author | eray orçunus <erayorcunus@gmail.com> | 2019-07-10 14:56:56 +0200 |
---|---|---|
committer | eray orçunus <erayorcunus@gmail.com> | 2019-07-10 14:56:56 +0200 |
commit | 2ef5e4cd662d642b839a9e65b3176335c6b50448 (patch) | |
tree | 5e0a6dcdbf8f1566974c0514986ab7b61e5c067a | |
parent | Phone start, ped spinning and cop car fix, and some love to CPed (diff) | |
parent | fixed COMMAND_IS_PLAYER_IN_AREA_3D (diff) | |
download | re3-2ef5e4cd662d642b839a9e65b3176335c6b50448.tar re3-2ef5e4cd662d642b839a9e65b3176335c6b50448.tar.gz re3-2ef5e4cd662d642b839a9e65b3176335c6b50448.tar.bz2 re3-2ef5e4cd662d642b839a9e65b3176335c6b50448.tar.lz re3-2ef5e4cd662d642b839a9e65b3176335c6b50448.tar.xz re3-2ef5e4cd662d642b839a9e65b3176335c6b50448.tar.zst re3-2ef5e4cd662d642b839a9e65b3176335c6b50448.zip |
54 files changed, 3963 insertions, 249 deletions
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/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 f050a540..ab28f96e 100644 --- a/src/control/Darkel.cpp +++ b/src/control/Darkel.cpp @@ -123,18 +123,18 @@ eKillFrenzyStatus CDarkel::ReadStatus() } #if 1 -WRAPPER int32 CDarkel::RegisterCarBlownUpByPlayer(eKillFrenzyStatus status) { EAXJMP(0x421070); } +WRAPPER void CDarkel::RegisterCarBlownUpByPlayer(CVehicle *vehicle) { EAXJMP(0x421070); } #else -int32 CDarkel::RegisterCarBlownUpByPlayer(eKillFrenzyStatus status) +int32 CDarkel::RegisterCarBlownUpByPlayer(CVehicle *vehicle) { return 0; } #endif #if 1 -WRAPPER void CDarkel::RegisterKillByPlayer(int32 modelid, eWeaponType weapontype, bool flag) { EAXJMP(0x420F60); } +WRAPPER void CDarkel::RegisterKillByPlayer(CPed *victim, eWeaponType weapontype, bool headshot) { EAXJMP(0x420F60); } #else -void CDarkel::RegisterKillByPlayer(int32 modelid, eWeaponType weapontype, bool flag) +void CDarkel::RegisterKillByPlayer(CPed *victim, eWeaponType weapontype, bool headshot) { diff --git a/src/control/Darkel.h b/src/control/Darkel.h index da1df24a..35d849d2 100644 --- a/src/control/Darkel.h +++ b/src/control/Darkel.h @@ -1,6 +1,9 @@ #pragma once #include "Weapon.h" +class CVehicle; +class CPed; + enum eKillFrenzyStatus { KILLFRENZY_NONE, @@ -37,8 +40,8 @@ public: static void Init(); static int16 QueryModelsKilledByPlayer(int32 modelId); static eKillFrenzyStatus ReadStatus(); - static int32 RegisterCarBlownUpByPlayer(eKillFrenzyStatus status); - static void RegisterKillByPlayer(int32 modelid, eWeaponType weapontype, bool flag); + static void RegisterCarBlownUpByPlayer(CVehicle *vehicle); + static void RegisterKillByPlayer(CPed *victim, eWeaponType weapontype, bool headshot = false); static void RegisterKillNotByPlayer(); static void ResetModelsKilledByPlayer(); static void ResetOnPlayerDeath(); diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp index 9041a003..2bdb9dfe 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); } @@ -1012,7 +1012,7 @@ void CReplay::ProcessReplayCamera(void) 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)); @@ -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 diff --git a/src/control/Script.cpp b/src/control/Script.cpp index d2e27487..b50c101e 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -2,17 +2,21 @@ #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" @@ -32,7 +36,7 @@ int32(&CTheScripts::MultiScriptArray)[MAX_NUM_MISSION_SCRIPTS] = *(int32(*)[MAX_ 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; CRunningScript *&CTheScripts::pIdleScripts = *(CRunningScript**)0x9430D4; @@ -55,6 +59,8 @@ 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() @@ -93,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; } @@ -403,7 +409,7 @@ void CRunningScript::Init() m_nStackPointer = 0; m_nWakeTime = 0; m_bCondResult = false; - m_bIsMissionThread = false; + m_bIsMissionScript = false; m_bSkipWakeTime = false; for (int i = 0; i < NUM_LOCAL_VARS + NUM_TIMERS; i++) m_anLocalVariables[i] = 0; @@ -435,6 +441,27 @@ int open_script() } #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++) @@ -497,29 +524,13 @@ void CTheScripts::Init() ScriptSphereArray[i].m_fRadius = 0.0f; } for (int i = 0; i < MAX_NUM_INTRO_TEXT_LINES; i++){ - IntroTextLines[i].m_fScaleX = 0.48f; - IntroTextLines[i].m_fScaleY = 1.12f; - IntroTextLines[i].m_sColor = CRGBA(225, 225, 225, 255); - IntroTextLines[i].m_bJustify = false; - IntroTextLines[i].m_bRightJustify = false; - IntroTextLines[i].m_bCentered = false; - IntroTextLines[i].m_bBackground = false; - IntroTextLines[i].m_bBackgroundOnly = false; - IntroTextLines[i].m_fWrapX = 182.0f; /* TODO: scaling as bugfix */ - IntroTextLines[i].m_fCenterSize = 640.0f; /* --||-- */ - IntroTextLines[i].m_sBackgroundColor = CRGBA(128, 128, 128, 128); - IntroTextLines[i].m_bTextProportional = true; - IntroTextLines[i].m_bTextBeforeFade = false; - IntroTextLines[i].m_nFont = 2; /* enum? */ - IntroTextLines[i].m_fAtX = 0.0f; - IntroTextLines[i].m_fAtY = 0.0f; - memset(&IntroTextLines[i].m_Text, 0, sizeof(IntroTextLines[i].m_Text)); + 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_bIsAntialiased = 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); @@ -553,8 +564,835 @@ void CRunningScript::AddScriptToList(CRunningScript** ppScript) *ppScript = this; } -WRAPPER bool CTheScripts::IsPlayerOnAMission() { EAXJMP(0x439410); } +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); } @@ -582,6 +1420,9 @@ 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(0x4386C0, &CRunningScript::Init, 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 96e1aed5..0cbd40c0 100644 --- a/src/control/Script.h +++ b/src/control/Script.h @@ -10,8 +10,8 @@ class CObject; struct CScriptRectangle { - bool m_bIsUsed; - bool m_bIsAntialiased; + int8 m_bIsUsed; + bool m_bBeforeFade; int16 m_nTextureId; CRect m_sRect; CRGBA m_sColor; @@ -42,6 +42,8 @@ struct CTextLine float m_fAtX; float m_fAtY; wchar m_Text[SCRIPT_TEXT_MAX_LENGTH]; + + void Reset(); }; static_assert(sizeof(CTextLine) == 0x414, "Script.h: error"); @@ -71,7 +73,7 @@ class CRunningScript uint16 m_nStackPointer; 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_nAndOrState; @@ -81,6 +83,13 @@ class CRunningScript 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); @@ -88,6 +97,22 @@ public: 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 { @@ -169,7 +194,8 @@ public: }; enum { - ARGUMENT_INT32 = 1, + ARGUMENT_END = 0, + ARGUMENT_INT32, ARGUMENT_GLOBALVAR, ARGUMENT_LOCALVAR, ARGUMENT_INT8, @@ -266,17 +292,27 @@ public: 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; 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 58e65d24..4f565897 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) @@ -678,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); diff --git a/src/core/Camera.h b/src/core/Camera.h index db5fff46..c0309b5f 100644 --- a/src/core/Camera.h +++ b/src/core/Camera.h @@ -454,6 +454,8 @@ 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); @@ -463,6 +465,7 @@ int m_iModeObbeCamIsInForCar; 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..94da1338 100644 --- a/src/core/Collision.cpp +++ b/src/core/Collision.cpp @@ -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, 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/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..a846efc6 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,18 @@ CMenuManager &FrontEndMenuManager = *(CMenuManager*)0x8F59D8; float lodMultiplier = *(float*)0x5F726C; // Stuff not in CMenuManager: -int VibrationTime; -char* pEditString; -int32 pControlEdit; +uint32 VibrationTime; +char* pEditString = (char*)0x628D00; +int32 *&pControlEdit = *(int32**)0x628D08; int8 DisplayComboButtonErrMsg; -bool MouseButtonJustClicked; -bool JoyButtonJustClicked; +int8 MouseButtonJustClicked; +int8 JoyButtonJustClicked; +int32 &nTimeForSomething = *(int32*)0x628D54; +int32 TypeOfControl = 0; +int32 *pControlTemp = 0; // Frontend inputs. + bool GetPadBack(); bool GetPadExitEnter(); bool GetPadForward(); @@ -73,6 +83,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 +150,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 (stat2) { + 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 +198,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 +285,7 @@ void CMenuManager::CheckSliderMovement(int value) TheCamera.m_fMouseAccelVertical = fMouseSens; SaveSettings(); break; - }; + } } #if 1 @@ -263,7 +297,7 @@ int CMenuManager::CostructStatLine(int) } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::DisplayHelperText() { EAXJMP(0x48B490); } #else void CMenuManager::DisplayHelperText() @@ -303,7 +337,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 +350,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 +376,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 +400,7 @@ void CMenuManager::DoSettingsBeforeStartingAGame() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::Draw() { EAXJMP(0x47AE00); } #else void CMenuManager::Draw() @@ -427,7 +461,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 +514,7 @@ void CMenuManager::Draw() case 3: textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEC_CF4"); break; - }; + } break; case MENUACTION_CTRLDISPLAY: break; @@ -510,7 +544,7 @@ void CMenuManager::Draw() case AR_16_9: textToPrint[MENUCOLUMN_RIGHT] = (wchar*)L"16:9"; break; - }; + } #endif break; case MENUACTION_RADIO: @@ -560,7 +594,7 @@ void CMenuManager::Draw() case 2: textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEA_4SP"); break; - }; + } } break; case MENUACTION_CTRLMETHOD: @@ -571,7 +605,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 +613,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 +701,7 @@ void CMenuManager::Draw() default: vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_MID_Y); break; - }; + } } if (i > 0) @@ -719,9 +753,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 +778,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 +827,9 @@ void CMenuManager::Draw() case MENUPAGE_MOUSE_CONTROLS: DisplayHelperText(); break; - }; + } } - }; + } } #endif @@ -826,7 +860,7 @@ void CMenuManager::DrawControllerSetupScreen() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::DrawFrontEnd(void) { EAXJMP(0x47A540); } #else void CMenuManager::DrawFrontEnd() @@ -850,7 +884,7 @@ void CMenuManager::DrawFrontEnd() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::DrawFrontEndNormal(void) { EAXJMP(0x47A5B0); } #else void CMenuManager::DrawFrontEndNormal() @@ -904,7 +938,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 +983,7 @@ void CMenuManager::DrawFrontEndNormal() case MENUPAGE_OPTIONS: currentSprite = MENUSPRITE_PLAYERSET; break; - }; + } uint32 savedShade; uint32 savedAlpha; @@ -993,7 +1027,7 @@ void CMenuManager::DrawFrontEndNormal() default: CMenuManager::Draw(); break; - }; + } CFont::DrawFonts(); @@ -1012,7 +1046,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 +1081,7 @@ int CMenuManager::GetStartOptionsCntrlConfigScreens() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::InitialiseChangedLanguageSettings() { EAXJMP(0x47A4D0); } #else void CMenuManager::InitialiseChangedLanguageSettings() @@ -1069,12 +1103,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 +1144,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 +1157,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 +1166,7 @@ void CMenuManager::LoadAllTextures() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::LoadSettings() { EAXJMP(0x488EE0); } #else void CMenuManager::LoadSettings() @@ -1151,13 +1185,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 +1287,7 @@ void CMenuManager::PrintBriefs() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::PrintErrorMessage() { EAXJMP(0x484F70); } #else void CMenuManager::PrintErrorMessage() @@ -1286,22 +1320,32 @@ 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_bLanguageLoaded = false; //XXX + m_bStartGameLoading = false; InitialiseChangedLanguageSettings(); + if (GetPadExitEnter()) //XXX only escape + 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 +1394,107 @@ 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 && !field_456) { + 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(); + + 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; + // 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 +1516,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 +1626,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 +1709,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 +1774,7 @@ void CMenuManager::ProcessOnOffMenuOptions() case AR_16_9: m_PrefsUseWideScreen = AR_AUTO; break; - }; + } } else { switch (m_PrefsUseWideScreen) { @@ -1580,7 +1787,7 @@ void CMenuManager::ProcessOnOffMenuOptions() case AR_16_9: m_PrefsUseWideScreen = AR_4_3; break; - }; + } } #endif SaveSettings(); @@ -1683,6 +1890,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 +2033,7 @@ void CMenuManager::ProcessOnOffMenuOptions() case 2: m_PrefsSpeakers = 0; break; - }; + } } else { switch (m_PrefsSpeakers) { @@ -1836,7 +2046,7 @@ void CMenuManager::ProcessOnOffMenuOptions() case 2: m_PrefsSpeakers = 1; break; - }; + } } DMAudio.SetSpeakerConfig(m_PrefsSpeakers); @@ -1864,11 +2074,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 +2088,7 @@ void CMenuManager::RequestFrontEndShutdown() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::RequestFrontEndStartUp() { EAXJMP(0x488770); } #else void CMenuManager::RequestFrontEndStartUp() @@ -1887,7 +2097,7 @@ void CMenuManager::RequestFrontEndStartUp() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::ResetHelperText() { EAXJMP(0x48B470); } #else void CMenuManager::ResetHelperText() @@ -1897,7 +2107,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 +2150,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 +2160,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 +2207,7 @@ void CMenuManager::SaveSettings() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::ShutdownJustMenu() { EAXJMP(0x488920); } #else void CMenuManager::ShutdownJustMenu() @@ -2008,7 +2218,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 +2230,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 +2242,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 +2264,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 +2288,7 @@ void CMenuManager::SwitchMenuOnAndOff() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::UnloadTextures() { EAXJMP(0x47A440); } #else void CMenuManager::UnloadTextures() @@ -2103,7 +2313,7 @@ void CMenuManager::UnloadTextures() } #endif -#if 0 +#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::WaitForUserCD(void) { EAXJMP(0x48ADD0); } #else void CMenuManager::WaitForUserCD() @@ -2131,7 +2341,7 @@ uint8 CMenuManager::GetNumberOfMenuOptions() break; ++Rows; - }; + } return Rows; } @@ -2204,7 +2414,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 +2440,7 @@ void CMenuManager::SetDefaultPreferences(int8 screen) CVehicle::m_bDisableMouseSteering = true; TheCamera.m_bHeadBob = false; break; - }; + } } // Frontend inputs. @@ -2261,7 +2471,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 +2479,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 +2487,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 +2495,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 +2547,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 +2577,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 +2588,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/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/Placeable.h b/src/core/Placeable.h index 1dfece69..648b315c 100644 --- a/src/core/Placeable.h +++ b/src/core/Placeable.h @@ -17,6 +17,11 @@ public: 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); }; 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/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 21853308..4608bfef 100644 --- a/src/core/Wanted.cpp +++ b/src/core/Wanted.cpp @@ -34,7 +34,7 @@ int CWanted::NumOfHelisRequired() return 2; default: return 0; - }; + } } void CWanted::SetWantedLevel(int32 level) @@ -70,11 +70,17 @@ void CWanted::SetWantedLevel(int32 level) 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() diff --git a/src/core/Wanted.h b/src/core/Wanted.h index d14bb905..d3f6638b 100644 --- a/src/core/Wanted.h +++ b/src/core/Wanted.h @@ -42,6 +42,7 @@ public: bool AreArmyRequired(); int NumOfHelisRequired(); void SetWantedLevel(int32); + void SetWantedLevelNoDrop(int32 level); void ClearQdCrimes(); void UpdateWantedLevel(); }; diff --git a/src/core/config.h b/src/core/config.h index c3b66ff7..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, diff --git a/src/core/main.cpp b/src/core/main.cpp index e7f42780..9ac271f9 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -54,8 +54,14 @@ 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 d6e81214..8bb9caee 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -155,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()){ @@ -198,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); diff --git a/src/entities/Entity.h b/src/entities/Entity.h index d055d25f..12a631d2 100644 --- a/src/entities/Entity.h +++ b/src/entities/Entity.h @@ -94,6 +94,8 @@ public: uint16 m_level; // int16 CReference *m_pFirstReference; + CColModel *GetColModel(void) { return CModelInfo::GetModelInfo(m_modelIndex)->GetColModel(); } + CEntity(void); ~CEntity(void); diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp index c9e0da90..9cabb28b 100644 --- a/src/entities/Physical.cpp +++ b/src/entities/Physical.cpp @@ -62,7 +62,7 @@ CPhysical::CPhysical(void) m_phy_flagA10 = false; m_phy_flagA20 = false; - m_nLastCollType = 0; + m_nSurfaceTouched = SURFACE_DEFAULT; } CPhysical::~CPhysical(void) @@ -457,7 +457,7 @@ CPhysical::ApplySpringCollision(float springConst, CVector &springDir, CVector & float compression = 1.0f - springRatio; if(compression > 0.0f){ float step = min(CTimer::GetTimeStep(), 3.0f); - float 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); } @@ -489,7 +489,7 @@ void CPhysical::ApplyGravity(void) { if(bAffectedByGravity) - m_vecMoveSpeed.z -= 0.008f * CTimer::GetTimeStep(); + m_vecMoveSpeed.z -= GRAVITY * CTimer::GetTimeStep(); } void @@ -1783,7 +1783,7 @@ CPhysical::ProcessShift(void) } bIsStuck = false; bIsInSafePosition = true; - m_fDistanceTravelled = (GetPosition() - *matrix.GetPosition()).Magnitude(); + m_fDistanceTravelled = (GetPosition() - matrix.GetPosition()).Magnitude(); RemoveAndAdd(); } } @@ -1918,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; diff --git a/src/entities/Physical.h b/src/entities/Physical.h index c1f9f1d9..5bd98815 100644 --- a/src/entities/Physical.h +++ b/src/entities/Physical.h @@ -8,6 +8,8 @@ enum { PHYSICAL_MAX_COLLISIONRECORDS = 6 }; +#define GRAVITY (0.008f) + class CTreadable; class CPhysical : public CEntity @@ -59,7 +61,7 @@ public: uint8 bHitByTrain : 1; // from nick uint8 m_phy_flagA80 : 1; - uint8 m_nLastCollType; + uint8 m_nSurfaceTouched; uint8 m_nZoneLevel; CPhysical(void); @@ -73,7 +75,7 @@ public: void ProcessShift(void); void ProcessCollision(void); - virtual int32 ProcessEntityCollision(CEntity *ent, CColPoint *point); + virtual int32 ProcessEntityCollision(CEntity *ent, CColPoint *colpoints); void RemoveAndAdd(void); void AddToMovingList(void); @@ -108,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); diff --git a/src/math/Matrix.h b/src/math/Matrix.h index eda75e4a..b7d6c207 100644 --- a/src/math/Matrix.h +++ b/src/math/Matrix.h @@ -82,6 +82,32 @@ public: 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,6 +125,7 @@ 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); 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/VehicleModelInfo.cpp b/src/modelinfo/VehicleModelInfo.cpp index 810ed042..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* diff --git a/src/modelinfo/VehicleModelInfo.h b/src/modelinfo/VehicleModelInfo.h index f66bc21f..37f47489 100644 --- a/src/modelinfo/VehicleModelInfo.h +++ b/src/modelinfo/VehicleModelInfo.h @@ -107,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); diff --git a/src/objects/Object.cpp b/src/objects/Object.cpp index e13a2ad0..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,7 +87,13 @@ 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 { diff --git a/src/objects/Object.h b/src/objects/Object.h index 8afc4d0a..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,6 +73,7 @@ public: void RemoveLighting(bool reset); void ObjectDamage(float amount); + void RefModelInfo(int32 modelId); static void DeleteAllTempObjectInArea(CVector, float); }; diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index cce5d6a9..8ebe456f 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" @@ -28,6 +29,7 @@ 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); } @@ -432,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; @@ -671,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); @@ -1542,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 @@ -1661,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); } @@ -1774,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); @@ -1881,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; @@ -2090,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); diff --git a/src/peds/Ped.h b/src/peds/Ped.h index 4909a583..cd7d88af 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -251,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; @@ -414,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); diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp index 07cb5541..4b484a7f 100644 --- a/src/peds/PlayerPed.cpp +++ b/src/peds/PlayerPed.cpp @@ -10,6 +10,9 @@ 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() { @@ -21,6 +24,19 @@ void CPlayerPed::ClearWeaponTarget() ClearPointGunAt(); } +void +CPlayerPed::SetWantedLevel(int32 level) +{ + m_pWanted->SetWantedLevel(level); +} + +void +CPlayerPed::SetWantedLevelNoDrop(int32 level) +{ + m_pWanted->SetWantedLevelNoDrop(level); +} + + class CPlayerPed_ : public CPlayerPed { public: diff --git a/src/peds/PlayerPed.h b/src/peds/PlayerPed.h index 1a106b38..51a45203 100644 --- a/src/peds/PlayerPed.h +++ b/src/peds/PlayerPed.h @@ -43,6 +43,12 @@ public: 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/Hud.cpp b/src/render/Hud.cpp index 754f4b85..b3264dc7 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -862,7 +862,7 @@ void CHud::Draw() 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_bIsUsed && CTheScripts::IntroRectangles[i].m_bBeforeFade) { if (CTheScripts::IntroRectangles[i].m_nTextureId >= 0) { CRect rect = { CTheScripts::IntroRectangles[i].m_sRect.left, 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/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index c06c958c..7d3f8ee3 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -1,17 +1,32 @@ #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" +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 owner) +CAutomobile::CAutomobile(int mi, uint8 CreatedBy) { - ctor(mi, owner); + ctor(mi, CreatedBy); } @@ -23,11 +38,110 @@ CAutomobile::SetModelIndex(uint32 id) } WRAPPER void CAutomobile::ProcessControl(void) { EAXJMP(0x531470); } -WRAPPER void CAutomobile::Teleport(CVector v) { EAXJMP(0x535180); } + +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 @@ -51,17 +165,161 @@ void CAutomobile::SetComponentRotation(int32 component, CVector rotation) { CMatrix mat(RwFrameGetMatrix(m_aCarNodes[component])); - CVector pos = *mat.GetPosition(); + 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.GetPosition() += pos; + 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(); } -WRAPPER void CAutomobile::OpenDoor(int32, eDoors door, float) { EAXJMP(0x52E750); } -WRAPPER void CAutomobile::ProcessOpenDoor(uint32, uint32, float) { EAXJMP(0x52E910); } +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) @@ -106,7 +364,86 @@ CAutomobile::RemoveRefsToVehicle(CEntity *ent) m_aGroundPhysical[i] = nil; } -WRAPPER void CAutomobile::BlowUpCar(CEntity *ent) { EAXJMP(0x53BC60); } +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) @@ -139,7 +476,31 @@ CAutomobile::SetUpWheelColModel(CColModel *colModel) return true; } -WRAPPER void CAutomobile::BurstTyre(uint8 tyre) { EAXJMP(0x53C0E0); } +// 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 @@ -148,13 +509,436 @@ CAutomobile::GetHeightAboveRoad(void) return m_fHeightAboveRoad; } -WRAPPER void CAutomobile::PlayCarHorn(void) { EAXJMP(0x53C450); } +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); + } + } -WRAPPER void CAutomobile::SpawnFlyingComponent(int32 component, uint32 type) { EAXJMP(0x530300); } + 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) @@ -245,7 +1029,7 @@ void CAutomobile::SetComponentVisibility(RwFrame *frame, uint32 flags) { HideAllComps(); - m_veh_flagC2 = true; + bIsDamaged = true; RwFrameForAllObjects(frame, SetVehicleAtomicVisibilityCB, (void*)flags); } @@ -305,6 +1089,8 @@ public: 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); } @@ -327,16 +1113,33 @@ public: STARTPATCHES 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); diff --git a/src/vehicles/Automobile.h b/src/vehicles/Automobile.h index a9def14f..60e08d0a 100644 --- a/src/vehicles/Automobile.h +++ b/src/vehicles/Automobile.h @@ -4,6 +4,8 @@ #include "DamageManager.h" #include "Door.h" +class CObject; + class CAutomobile : public CVehicle { public: @@ -22,9 +24,7 @@ public: float m_aWheelPosition[4]; float m_aWheelSpeed[4]; uint8 field_4D8; - uint8 m_auto_flagA1 : 1; - uint8 m_auto_flagA2 : 1; - uint8 m_auto_flagA4 : 1; + uint8 m_auto_flagA7 : 1; uint8 bTaxiLight : 1; uint8 m_auto_flagA10 : 1; uint8 m_auto_flagA20 : 1; @@ -37,7 +37,8 @@ public: 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; @@ -64,12 +65,15 @@ public: 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, eDoors door, float); + void OpenDoor(int32 component, eDoors door, float openRatio); void ProcessOpenDoor(uint32, uint32, float); bool IsDoorReady(eDoors door); bool IsDoorFullyOpen(eDoors door); @@ -83,12 +87,23 @@ public: float GetHeightAboveRoad(void); void PlayCarHorn(void); - void SpawnFlyingComponent(int32 component, uint32 type); - - void SetPanelDamage(int32 component, ePanels panel, bool noFlyingComponents); - void SetBumperDamage(int32 component, ePanels panel, bool noFlyingComponents); - void SetDoorDamage(int32 component, eDoors door, bool noFlyingComponents); + 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); diff --git a/src/vehicles/DamageManager.h b/src/vehicles/DamageManager.h index 0914ded3..b815f724 100644 --- a/src/vehicles/DamageManager.h +++ b/src/vehicles/DamageManager.h @@ -20,6 +20,12 @@ enum ePanelStatus PANEL_STATUS_MISSING, }; +enum eWheelStatus +{ + WHEEL_STATUS_OK, + WHEEL_STATUS_BURST +}; + enum tComponent { COMPONENT_DEFAULT, 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/Vehicle.cpp b/src/vehicles/Vehicle.cpp index 1a22e98a..13e02566 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 *= powf(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(fabs(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) @@ -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 || @@ -477,6 +771,11 @@ STARTPATCHES 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 1e70d171..c293b8a6 100644 --- a/src/vehicles/Vehicle.h +++ b/src/vehicles/Vehicle.h @@ -88,6 +88,14 @@ enum eLights VEHLIGHT_REAR_RIGHT, }; +enum eWheels +{ + VEHWHEEL_FRONT_LEFT, + VEHWHEEL_FRONT_RIGHT, + VEHWHEEL_REAR_LEFT, + VEHWHEEL_REAR_RIGHT, +}; + enum { CAR_PIECE_WHEEL_LF = 13, @@ -96,6 +104,23 @@ enum 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: @@ -115,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; @@ -142,19 +167,19 @@ public: uint8 m_veh_flagB80 : 1; uint8 m_veh_flagC1 : 1; - uint8 m_veh_flagC2 : 1; // bIsDamaged + 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; @@ -171,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; @@ -181,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; @@ -194,6 +217,8 @@ 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 id); @@ -224,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); @@ -255,7 +287,7 @@ public: }; 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"); |