diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/audio/AudioManager.cpp | 275 | ||||
-rw-r--r-- | src/audio/AudioManager.h | 24 | ||||
-rw-r--r-- | src/audio/MusicManager.cpp | 14 | ||||
-rw-r--r-- | src/audio/MusicManager.h | 3 | ||||
-rw-r--r-- | src/audio/SampleManager.cpp | 28 | ||||
-rw-r--r-- | src/audio/SampleManager.h | 7 | ||||
-rw-r--r-- | src/control/Replay.cpp | 4 | ||||
-rw-r--r-- | src/control/Script.cpp | 305 | ||||
-rw-r--r-- | src/control/Script.h | 182 | ||||
-rw-r--r-- | src/core/config.h | 1 | ||||
-rw-r--r-- | src/core/re3.cpp | 23 | ||||
-rw-r--r-- | src/math/Matrix.h | 9 | ||||
-rw-r--r-- | src/render/Hud.cpp | 10 | ||||
-rw-r--r-- | src/vehicles/Automobile.cpp | 4 | ||||
-rw-r--r-- | src/vehicles/Automobile.h | 17 | ||||
-rw-r--r-- | src/vehicles/Door.cpp | 126 | ||||
-rw-r--r-- | src/vehicles/Door.h | 36 |
17 files changed, 974 insertions, 94 deletions
diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp index 76ef8244..9e86aef0 100644 --- a/src/audio/AudioManager.cpp +++ b/src/audio/AudioManager.cpp @@ -91,9 +91,249 @@ enum eVehicleModel cAudioManager &AudioManager = *(cAudioManager *)0x880FC0; constexpr int totalAudioEntitiesSlots = 200; +constexpr int maxVolume = 127; char &g_nMissionAudioPlayingStatus = *(char *)0x60ED88; +void +cAudioManager::AddSampleToRequestedQueue() +{ + int32 calculatedVolume; + tActiveSample *sample; + int32 unknown1; + uint8 unknown2; + bool bReflections; + + if(m_sQueueSample.m_nSampleIndex < TOTAL_AUDIO_SAMPLES) { + calculatedVolume = m_sQueueSample.field_16 * (maxVolume - m_sQueueSample.m_bVolume); + unknown2 = m_bSampleRequestQueuesStatus[m_bActiveSampleQueue]; + if(unknown2 >= m_bActiveSamples) { + unknown1 = 27 * m_bActiveSampleQueue; + unknown2 = *(&m_asSamples[53].field_91 + m_bActiveSamples + unknown1); + if(m_asSamples[unknown1 + unknown2].calculatedVolume <= calculatedVolume) + return; + } else { + ++m_bSampleRequestQueuesStatus[m_bActiveSampleQueue]; + } + m_sQueueSample.calculatedVolume = calculatedVolume; + m_sQueueSample.m_bLoopEnded = 0; + if(m_sQueueSample.m_bIsDistant) { + m_sQueueSample.m_bRequireReflection = 0; + m_sQueueSample.m_bLoopsRemaining = 0; + } + if(m_bDynamicAcousticModelingStatus && m_sQueueSample.m_nLoopCount) { + bReflections = m_sQueueSample.m_bRequireReflection; + } else { + bReflections = false; + m_sQueueSample.m_bLoopsRemaining = 0; + } + m_sQueueSample.m_bRequireReflection = 0; + + if(!m_bDynamicAcousticModelingStatus) m_sQueueSample.m_bReverbFlag = 0; + + sample = &m_asSamples[27 * m_bActiveSampleQueue + unknown2]; + sample->m_nEntityIndex = m_sQueueSample.m_nEntityIndex; + sample->field_4 = m_sQueueSample.field_4; + sample->m_nSampleIndex = m_sQueueSample.m_nSampleIndex; + sample->m_bBankIndex = m_sQueueSample.m_bBankIndex; + sample->m_bIsDistant = m_sQueueSample.m_bIsDistant; + sample->field_16 = m_sQueueSample.field_16; + sample->m_nFrequency = m_sQueueSample.m_nFrequency; + sample->m_bVolume = m_sQueueSample.m_bVolume; + sample->m_fDistance = m_sQueueSample.m_fDistance; + sample->m_nLoopCount = m_sQueueSample.m_nLoopCount; + sample->m_nLoopStart = m_sQueueSample.m_nLoopStart; + sample->m_nLoopEnd = m_sQueueSample.m_nLoopEnd; + sample->m_bEmittingVolume = m_sQueueSample.m_bEmittingVolume; + sample->field_48 = m_sQueueSample.field_48; + sample->m_fSoundIntensity = m_sQueueSample.m_fSoundIntensity; + sample->field_56 = m_sQueueSample.field_56; + sample->m_vecPos = m_sQueueSample.m_vecPos; + sample->m_bReverbFlag = m_sQueueSample.m_bReverbFlag; + sample->m_bLoopsRemaining = m_sQueueSample.m_bLoopsRemaining; + sample->m_bRequireReflection = m_sQueueSample.m_bRequireReflection; + sample->m_bOffset = m_sQueueSample.m_bOffset; + sample->field_76 = m_sQueueSample.field_76; + sample->m_bIsProcessed = m_sQueueSample.m_bIsProcessed; + sample->m_bLoopEnded = m_sQueueSample.m_bLoopEnded; + sample->calculatedVolume = m_sQueueSample.calculatedVolume; + sample->field_88 = m_sQueueSample.field_88; + + AddDetailsToRequestedOrderList(unknown2); + if(bReflections) AddReflectionsToRequestedQueue(); + } +} + +void +cAudioManager::AddDetailsToRequestedOrderList(uint8 sample) +{ + int32 offset; + uint32 i = 0; + if(sample != 0) { + for(; i < sample; i++) { + offset = 27 * m_bActiveSampleQueue; + if(m_asSamples[offset + m_abSampleQueueIndexTable[i + offset]] + .calculatedVolume > m_asSamples[offset + sample].calculatedVolume) + break; + } + if(i < sample) { + memmove(&m_abSampleQueueIndexTable[offset + 1 + i], + &m_abSampleQueueIndexTable[offset + i], m_bActiveSamples - i - 1); + } + } + m_abSampleQueueIndexTable[27 * m_bActiveSampleQueue + i] = sample; +} + +void +cAudioManager::AddReflectionsToRequestedQueue() +{ + float reflectionDistance; + int32 noise; + uint8 emittingVolume = emittingVolume = + (m_sQueueSample.m_bVolume >> 1) + (m_sQueueSample.m_bVolume >> 3); + + for(uint32 i = 0; i < 5u; i++) { + reflectionDistance = m_afReflectionsDistances[i]; + if(reflectionDistance > 0.0f && reflectionDistance < 100.f && + reflectionDistance < m_sQueueSample.m_fSoundIntensity) { + m_sQueueSample.m_bLoopsRemaining = (reflectionDistance * 0.38873f); // @todo assert value + if(m_sQueueSample.m_bLoopsRemaining > 5u) { + m_sQueueSample.m_fDistance = m_afReflectionsDistances[i]; + m_sQueueSample.m_bEmittingVolume = emittingVolume; + m_sQueueSample.m_bVolume = + ComputeVolume(emittingVolume, m_sQueueSample.m_fSoundIntensity, + m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume > emittingVolume >> 4) { + m_sQueueSample.field_4 += ((i + 1) << 8); + if(m_sQueueSample.m_nLoopCount) { + noise = RandomDisplacement( + m_sQueueSample.m_nFrequency >> 5); + if(noise <= 0) + m_sQueueSample.m_nFrequency += noise; + else + m_sQueueSample.m_nFrequency -= noise; + } + m_sQueueSample.field_16 += 20; + m_sQueueSample.m_vecPos.x = m_avecReflectionsPos[i].x; + m_sQueueSample.m_vecPos.y = m_avecReflectionsPos[i].y; + m_sQueueSample.m_vecPos.z = m_avecReflectionsPos[i].z; + AddSampleToRequestedQueue(); + } + } + } + } +} + +uint32 +cAudioManager::ComputeVolume(int emittingVolume, float soundIntensity, float distance) +{ + float newSoundIntensity; + if(soundIntensity <= 0.0f) return 0; + if((soundIntensity * 0.2f) <= distance) { + newSoundIntensity = soundIntensity * 0.2f; + emittingVolume = + sq((soundIntensity - distance) / (soundIntensity - newSoundIntensity)) * + emittingVolume; + } + return emittingVolume; +} + +void +cAudioManager::Initialise() +{ + if(!m_bIsInitialised) { + PreInitialiseGameSpecificSetup(); + m_bIsInitialised = cSampleManager.Initialise(); + if(m_bIsInitialised) { + m_bActiveSamples = cSampleManager.GetActiveSamples(); + if(m_bActiveSamples <= 1u) { + Terminate(); + } else { + --m_bActiveSamples; + PostInitialiseGameSpecificSetup(); + InitialisePoliceRadioZones(); + InitialisePoliceRadio(); + MusicManager.Initialise(); + } + } + } +} + +void +cAudioManager::PostInitialiseGameSpecificSetup() +{ + m_nFireAudioEntity = CreateEntity( + AUDIOTYPE_FIRE, (CPhysical *)0x8F31D0); // last is addr of firemanager @todo change + if(m_nFireAudioEntity >= 0) cAudioManager::SetEntityStatus(m_nFireAudioEntity, 1); + + m_nCollisionEntity = CreateEntity(AUDIOTYPE_COLLISION, (CPhysical *)1); + if(m_nCollisionEntity >= 0) cAudioManager::SetEntityStatus(m_nCollisionEntity, 1); + + m_nFrontEndEntity = CreateEntity(AUDIOTYPE_FRONTEND, (CPhysical *)1); + if(m_nFrontEndEntity >= 0) cAudioManager::SetEntityStatus(m_nFrontEndEntity, 1); + + m_nProjectileEntity = CreateEntity(AUDIOTYPE_PROJECTILE, (CPhysical *)1); + if(m_nProjectileEntity >= 0) cAudioManager::SetEntityStatus(m_nProjectileEntity, 1); + + m_nWaterCannonEntity = CreateEntity(AUDIOTYPE_WATER_CANNON, (CPhysical *)1); + if(m_nWaterCannonEntity >= 0) cAudioManager::SetEntityStatus(m_nWaterCannonEntity, 1); + + m_nPoliceChannelEntity = CreateEntity(AUDIOTYPE_D, (CPhysical *)1); + if(m_nPoliceChannelEntity >= 0) cAudioManager::SetEntityStatus(m_nPoliceChannelEntity, 1); + + m_nBridgeEntity = CreateEntity(AUDIOTYPE_BRIDGE, (CPhysical *)1); + if(m_nBridgeEntity >= 0) cAudioManager::SetEntityStatus(m_nBridgeEntity, 1); + + m_sMissionAudio.m_nSampleIndex = NO_SAMPLE; + m_sMissionAudio.m_bLoadingStatus = 0; + m_sMissionAudio.m_bPlayStatus = 0; + m_sMissionAudio.field_22 = 0; + m_sMissionAudio.m_bIsPlayed = 0; + m_sMissionAudio.field_12 = 1; + m_sMissionAudio.field_24 = 0; + ResetAudioLogicTimers((int32)CTimer::GetTimeInMilliseconds); +} + +WRAPPER +void +cAudioManager::InitialisePoliceRadioZones() +{ + EAXJMP(0x57EAC0); +} + +WRAPPER +void +cAudioManager::ResetAudioLogicTimers(int32 timer) +{ + EAXJMP(0x569650); +} + +void +cAudioManager::Terminate() +{ + if(m_bIsInitialised) { + MusicManager.Terminate(); + + for(uint32 i = 0; i < totalAudioEntitiesSlots; i++) { + m_asAudioEntities[i].m_bIsUsed = 0; + m_anAudioEntityIndices[i] = 200; + } + + m_nAudioEntitiesTotal = 0; + m_nScriptObjectEntityTotal = 0; + PreTerminateGameSpecificShutdown(); + + for(uint32 i = 0; i < 2; i++) { + if(cSampleManager.IsSampleBankLoaded(i)) cSampleManager.UnloadSampleBank(i); + } + + cSampleManager.Terminate(); + + m_bIsInitialised = 0; + PostTerminateGameSpecificShutdown(); + } +} + char cAudioManager::GetMissionScriptPoliceAudioPlayingStatus() { @@ -313,20 +553,16 @@ cAudioManager::ResetPoliceRadio() void cAudioManager::InterrogateAudioEntities() { - int32 i = 0; - int32 next; - - while(i < m_nAudioEntitiesTotal) { + for(int32 i = 0; i < m_nAudioEntitiesTotal; i++) { ProcessEntity(m_anAudioEntityIndices[i]); - next = m_anAudioEntityIndices[i++]; - m_asAudioEntities[next].field_24 = 0; + m_asAudioEntities[m_anAudioEntityIndices[i]].field_24 = 0; } } void cAudioManager::ClearRequestedQueue() { - for(uint32 i = 0; i < m_bActiveSamples; i++) { + for(int32 i = 0; i < m_bActiveSamples; i++) { m_abSampleQueueIndexTable[i + 27 * m_bActiveSampleQueue] = m_bActiveSamples; } m_bSampleRequestQueuesStatus[m_bActiveSampleQueue] = 0; @@ -340,14 +576,14 @@ cAudioManager::ClearRequestedQueue() bool cAudioManager::UsesReverseWarning(int32 model) { - return model == LINERUN || fabs(model - FIRETRUK) <= 1 || model == BUS || + return model == LINERUN || model == FIRETRUK || model == TRASH || model == BUS || model == COACH; // fix } bool cAudioManager::HasAirBrakes(int32 model) { - return model == LINERUN || fabs(model - FIRETRUK) <= 1 || model == BUS || + return model == LINERUN || model == FIRETRUK || model == TRASH || model == BUS || model == COACH; // fix } @@ -436,7 +672,7 @@ cAudioManager::RandomDisplacement(uint32 seed) int32 value; static bool bIsEven = true; - static uint8 base = 0; + static uint32 base = 0; if(!seed) return 0; @@ -473,17 +709,17 @@ cAudioManager::IsAudioInitialised() const } int32 -cAudioManager::CreateEntity(int32 type, CPhysical *memory) +cAudioManager::CreateEntity(int32 type, CPhysical *entity) { if(!m_bIsInitialised) return -4; - if(!memory) return -2; + if(!entity) return -2; if(type >= TOTAL_AUDIO_TYPES) return -1; for(uint32 i = 0; i < 200; i++) { if(!m_asAudioEntities[i].m_bIsUsed) { m_asAudioEntities[i].m_bIsUsed = true; m_asAudioEntities[i].m_bStatus = 0; m_asAudioEntities[i].m_nType = (eAudioType)type; - m_asAudioEntities[i].m_pEntity = memory; + m_asAudioEntities[i].m_pEntity = entity; m_asAudioEntities[i].m_awAudioEvent[0] = SOUND_TOTAL_PED_SOUNDS; m_asAudioEntities[i].m_awAudioEvent[1] = SOUND_TOTAL_PED_SOUNDS; m_asAudioEntities[i].m_awAudioEvent[2] = SOUND_TOTAL_PED_SOUNDS; @@ -502,7 +738,7 @@ cAudioManager::DestroyEntity(int32 id) if(m_bIsInitialised && id >= 0 && id < totalAudioEntitiesSlots && m_asAudioEntities[id].m_bIsUsed) { m_asAudioEntities[id].m_bIsUsed = 0; - for(uint32 i = 0; i < m_nAudioEntitiesTotal; ++i) { + for(int32 i = 0; i < m_nAudioEntitiesTotal; ++i) { if(id == m_anAudioEntityIndices[i]) { if(i < totalAudioEntitiesSlots - 1) memmove(&m_anAudioEntityIndices[i], @@ -2724,6 +2960,17 @@ cAudioManager::Service() } STARTPATCHES +InjectHook(0x57B070, &cAudioManager::AddSampleToRequestedQueue, PATCH_JUMP); +InjectHook(0x57B210, &cAudioManager::AddDetailsToRequestedOrderList, PATCH_JUMP); +InjectHook(0x57B300, &cAudioManager::AddReflectionsToRequestedQueue, PATCH_JUMP); +InjectHook(0x57ABB0, &cAudioManager::ComputeVolume, PATCH_JUMP); + +InjectHook(0x57A0E0, &cAudioManager::Initialise, PATCH_JUMP); +InjectHook(0x569420, &cAudioManager::PostInitialiseGameSpecificSetup, PATCH_JUMP); +//InjectHook(0x57EAC0, &cAudioManager::InitialisePoliceRadioZones, PATCH_JUMP); +//InjectHook(0x569650, &cAudioManager::ResetAudioLogicTimers, PATCH_JUMP); +InjectHook(0x57A150, &cAudioManager::Terminate, PATCH_JUMP); + InjectHook(0x57F050, &cAudioManager::GetMissionScriptPoliceAudioPlayingStatus, PATCH_JUMP); InjectHook(0x5795D0, &cAudioManager::GetMissionAudioLoadingStatus, PATCH_JUMP); diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h index 24dae2ce..7a2dc9c5 100644 --- a/src/audio/AudioManager.h +++ b/src/audio/AudioManager.h @@ -44,7 +44,7 @@ public: char m_bLoopEnded; char field_82; char field_83; - int field_84; + int calculatedVolume; char field_88; char field_89; char field_90; @@ -218,6 +218,20 @@ public: char field_19195; int m_nTimeOfRecentCrime; + void AddSampleToRequestedQueue(); + + void AddDetailsToRequestedOrderList(uint8 sample); + void AddReflectionsToRequestedQueue(); + + uint32 ComputeVolume(int emittingVolume, float soundIntensity, float distance); + + void Initialise(); + void PostInitialiseGameSpecificSetup(); + void InitialisePoliceRadioZones(); // @todo + void ResetAudioLogicTimers(int32 timer); // @todo + + void Terminate(); + char GetMissionScriptPoliceAudioPlayingStatus(); bool GetMissionAudioLoadingStatus(); @@ -261,7 +275,7 @@ public: void InterrogateAudioEntities(); void ClearRequestedQueue(); -// void AgeCrimes(); + // void AgeCrimes(); //todo bool UsesReverseWarning(int32 model); bool HasAirBrakes(int32 model); @@ -274,7 +288,7 @@ public: void ProcessPlane(void *); // todo void ClearMissionAudio(); -// void ProcessReverb(); + // void ProcessReverb(); // todo bool IsMissionAudioSampleFinished(); @@ -282,8 +296,6 @@ public: void InitialisePoliceRadio(); - // done - int32 RandomDisplacement(uint32 seed); void ReleaseDigitalHandle(); @@ -292,7 +304,7 @@ public: bool IsAudioInitialised() const; - int32 CreateEntity(int32 type, CPhysical *memory); + int32 CreateEntity(int32 type, CPhysical *entity); void DestroyEntity(int32 id); void SetEntityStatus(int32 id, bool status); diff --git a/src/audio/MusicManager.cpp b/src/audio/MusicManager.cpp index 7b7c1182..dcd4ae93 100644 --- a/src/audio/MusicManager.cpp +++ b/src/audio/MusicManager.cpp @@ -174,3 +174,17 @@ void cMusicManager::DisplayRadioStationName() } } #endif + +WRAPPER +void +cMusicManager::Initialise() +{ + EAXJMP(0x57CF70); +} + +WRAPPER +void +cMusicManager::Terminate() +{ + EAXJMP(0x57D140); +} diff --git a/src/audio/MusicManager.h b/src/audio/MusicManager.h index dcb34daf..944fd16e 100644 --- a/src/audio/MusicManager.h +++ b/src/audio/MusicManager.h @@ -264,6 +264,9 @@ public: uint8 field_2395; public: + void Initialise(); + void Terminate(); + char *Get3DProviderName(char); bool PlayerInCar(); void DisplayRadioStationName(); diff --git a/src/audio/SampleManager.cpp b/src/audio/SampleManager.cpp index 7af3446b..fbeb49ed 100644 --- a/src/audio/SampleManager.cpp +++ b/src/audio/SampleManager.cpp @@ -12,6 +12,33 @@ bool CSampleManager::IsMP3RadioChannelAvailable() { return nNumOfMp3Files != 0; } +WRAPPER +bool CSampleManager::IsSampleBankLoaded(uint8) { EAXJMP(0x567130); } + +WRAPPER +void CSampleManager::UnloadSampleBank(uint8) { EAXJMP(0x567110); } + +WRAPPER +void +CSampleManager::Terminate() +{ + EAXJMP(0x566DC0); +} + +WRAPPER +bool +CSampleManager::Initialise() +{ + EAXJMP(0x566530); +} + +WRAPPER +int32 +CSampleManager::GetActiveSamples() +{ + EAXJMP(0x565970); +} + WRAPPER void CSampleManager::ReleaseDigitalHandle() { @@ -87,6 +114,7 @@ CSampleManager::StopChannel(int32 id) { EAXJMP(0x567BE0); } + STARTPATCHES InjectHook(0x566490, CSampleManager::IsMP3RadioChannelAvailable, PATCH_JUMP); ENDPATCHES
\ No newline at end of file diff --git a/src/audio/SampleManager.h b/src/audio/SampleManager.h index 1bee1775..f0245d4e 100644 --- a/src/audio/SampleManager.h +++ b/src/audio/SampleManager.h @@ -11,6 +11,13 @@ struct tSample { class CSampleManager { public: + bool IsSampleBankLoaded(uint8); + void UnloadSampleBank(uint8); + void Terminate(); + + bool Initialise(); + int32 GetActiveSamples(); + void ReleaseDigitalHandle(); void RequireDigitalHandle(); diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp index 06995663..d0264415 100644 --- a/src/control/Replay.cpp +++ b/src/control/Replay.cpp @@ -686,8 +686,8 @@ void CReplay::ProcessCarUpdate(CVehicle *vehicle, float interpolation, CAddressI car->m_aSuspensionSpringRatio[i] = vp->wheel_susp_dist[i] / 50.0f; car->m_aWheelRotation[i] = vp->wheel_rotation[i] * M_PI / 128.0f; } - car->Doors[2].m_fAngle = car->Doors[2].m_fPreviousAngle = vp->door_angles[0] * M_PI / 127.0f; - car->Doors[3].m_fAngle = car->Doors[3].m_fPreviousAngle = vp->door_angles[1] * M_PI / 127.0f; + car->Doors[2].m_fAngle = car->Doors[2].m_fPrevAngle = vp->door_angles[0] * M_PI / 127.0f; + car->Doors[3].m_fAngle = car->Doors[3].m_fPrevAngle = vp->door_angles[1] * M_PI / 127.0f; if (vp->door_angles[0]) car->Damage.SetDoorStatus(2, 2); if (vp->door_angles[1]) diff --git a/src/control/Script.cpp b/src/control/Script.cpp index 5e7f4936..d2e27487 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -6,6 +6,7 @@ #include "Camera.h" #include "CarCtrl.h" #include "DMAudio.h" +#include "FileMgr.h" #include "Hud.h" #include "ModelIndices.h" #include "PlayerInfo.h" @@ -17,18 +18,44 @@ #include "Weather.h" #include "World.h" -uint8 (&CTheScripts::ScriptSpace)[160 * 1024] = *(uint8(*)[160 * 1024])*(uintptr*)0x74B248; -CTextLine (&CTheScripts::IntroTextLines)[2] = *(CTextLine (*)[2])*(uintptr*)0x70EA74; -CScriptRectangle (&CTheScripts::IntroRectangles)[16] = *(CScriptRectangle (*)[16])*(uintptr*)0x72D108; -CSprite2d (&CTheScripts::ScriptSprites)[16] = *(CSprite2d(*)[16])*(uintptr*)0x72B090; +uint8 (&CTheScripts::ScriptSpace)[SIZE_SCRIPT_SPACE] = *(uint8(*)[SIZE_SCRIPT_SPACE])*(uintptr*)0x74B248; +CRunningScript(&CTheScripts::ScriptsArray)[MAX_NUM_SCRIPTS] = *(CRunningScript(*)[MAX_NUM_SCRIPTS])*(uintptr*)0x6F5C08; +int32(&CTheScripts::BaseBriefIdForContact)[MAX_NUM_CONTACTS] = *(int32(*)[MAX_NUM_CONTACTS])*(uintptr*)0x880200; +int32(&CTheScripts::OnAMissionForContactFlag)[MAX_NUM_CONTACTS] = *(int32(*)[MAX_NUM_CONTACTS])*(uintptr*)0x8622F0; +CTextLine (&CTheScripts::IntroTextLines)[MAX_NUM_INTRO_TEXT_LINES] = *(CTextLine (*)[MAX_NUM_INTRO_TEXT_LINES])*(uintptr*)0x70EA68; +CScriptRectangle (&CTheScripts::IntroRectangles)[MAX_NUM_INTRO_RECTANGLES] = *(CScriptRectangle (*)[MAX_NUM_INTRO_RECTANGLES])*(uintptr*)0x72D108; +CSprite2d (&CTheScripts::ScriptSprites)[MAX_NUM_SCRIPT_SRPITES] = *(CSprite2d(*)[MAX_NUM_SCRIPT_SRPITES])*(uintptr*)0x72B090; +CScriptSphere(&CTheScripts::ScriptSphereArray)[MAX_NUM_SCRIPT_SPHERES] = *(CScriptSphere(*)[MAX_NUM_SCRIPT_SPHERES])*(uintptr*)0x727D60; +tCollectiveData(&CTheScripts::CollectiveArray)[MAX_NUM_COLLECTIVES] = *(tCollectiveData(*)[MAX_NUM_COLLECTIVES])*(uintptr*)0x6FA008; +tUsedObject(&CTheScripts::UsedObjectArray)[MAX_NUM_USED_OBJECTS] = *(tUsedObject(*)[MAX_NUM_USED_OBJECTS])*(uintptr*)0x6E69C8; +int32(&CTheScripts::MultiScriptArray)[MAX_NUM_MISSION_SCRIPTS] = *(int32(*)[MAX_NUM_MISSION_SCRIPTS])*(uintptr*)0x6F0558; +tBuildingSwap(&CTheScripts::BuildingSwapArray)[MAX_NUM_BUILDING_SWAPS] = *(tBuildingSwap(*)[MAX_NUM_BUILDING_SWAPS])*(uintptr*)0x880E30; +CEntity*(&CTheScripts::InvisibilitySettingArray)[MAX_NUM_INVISIBILITY_SETTINGS] = *(CEntity*(*)[MAX_NUM_INVISIBILITY_SETTINGS])*(uintptr*)0x8620F0; bool &CTheScripts::DbgFlag = *(bool*)0x95CD87; uint32 &CTheScripts::OnAMissionFlag = *(uint32*)0x8F2A24; int32 &CTheScripts::StoreVehicleIndex = *(int32*)0x8F5F3C; bool &CTheScripts::StoreVehicleWasRandom = *(bool*)0x95CDBC; - -CMissionCleanup(&CTheScripts::MissionCleanup) = *(CMissionCleanup*)0x8F2AD8; -CUpsideDownCarCheck(&CTheScripts::UpsideDownCars) = *(CUpsideDownCarCheck*)0x6EE450; -CStuckCarCheck(&CTheScripts::StuckCars) = *(CStuckCarCheck*)0x87C588; +CRunningScript *&CTheScripts::pIdleScripts = *(CRunningScript**)0x9430D4; +CRunningScript *&CTheScripts::pActiveScripts = *(CRunningScript**)0x8E2BF4; +uint32 &CTheScripts::NextFreeCollectiveIndex = *(uint32*)0x942F98; +int32 &CTheScripts::LastRandomPedId = *(int32*)0x8F251C; +uint16 &CTheScripts::NumberOfUsedObjects = *(uint16*)0x95CC72; +bool &CTheScripts::bAlreadyRunningAMissionScript = *(bool*)0x95CDB3; +bool &CTheScripts::bUsingAMultiScriptFile = *(bool*)0x95CD55; +uint16 &CTheScripts::NumberOfMissionScripts = *(uint16*)0x95CC9A; +uint32 &CTheScripts::LargestMissionScriptSize = *(uint32*)0x9414C8; +uint32 &CTheScripts::MainScriptSize = *(uint32*)0x9405A4; +uint8 &CTheScripts::FailCurrentMission = *(uint8*)0x95CD41; +uint8 &CTheScripts::CountdownToMakePlayerUnsafe = *(uint8*)0x95CD51; +uint8 &CTheScripts::DelayMakingPlayerUnsafeThisTime = *(uint8*)0x95CD88; +uint16 &CTheScripts::NumScriptDebugLines = *(uint16*)0x95CC42; +uint16 &CTheScripts::NumberOfIntroRectanglesThisFrame = *(uint16*)0x95CC88; +uint16 &CTheScripts::NumberOfIntroTextLinesThisFrame = *(uint16*)0x95CC32; +bool &CTheScripts::UseTextCommands = *(bool*)0x95CD57; +CMissionCleanup (&CTheScripts::MissionCleanup) = *(CMissionCleanup*)0x8F2A24; +CUpsideDownCarCheck (&CTheScripts::UpsideDownCars) = *(CUpsideDownCarCheck*)0x6EE450; +CStuckCarCheck (&CTheScripts::StuckCars) = *(CStuckCarCheck*)0x87C588; +int32(&ScriptParams)[32] = *(int32(*)[32])*(uintptr*)0x6ED460; CMissionCleanup::CMissionCleanup() { @@ -277,11 +304,263 @@ bool CStuckCarCheck::HasCarBeenStuckForAWhile(int32 id) return false; } +void CRunningScript::CollectParameters(uint32* pIp, int16 total) +{ + for (int16 i = 0; i < total; i++){ + float tmp; + switch (CTheScripts::Read1ByteFromScript(pIp)) + { + case ARGUMENT_INT32: + ScriptParams[i] = CTheScripts::Read4BytesFromScript(pIp); + break; + case ARGUMENT_GLOBALVAR: + ScriptParams[i] = *((int32*)&CTheScripts::ScriptSpace[CTheScripts::Read2BytesFromScript(pIp)]); + break; + case ARGUMENT_LOCALVAR: + ScriptParams[i] = m_anLocalVariables[CTheScripts::Read2BytesFromScript(pIp)]; + break; + case ARGUMENT_INT8: + ScriptParams[i] = CTheScripts::Read1ByteFromScript(pIp); + break; + case ARGUMENT_INT16: + ScriptParams[i] = CTheScripts::Read2BytesFromScript(pIp); + break; + case ARGUMENT_FLOAT: + tmp = CTheScripts::ReadFloatFromScript(pIp); + ScriptParams[i] = *(int32*)&tmp; + break; + default: + assert(0); + break; + } + } +} + +int32 CRunningScript::CollectNextParameterWithoutIncreasingPC(uint32 ip) +{ + uint32* pIp = &ip; + float tmp; + switch (CTheScripts::Read1ByteFromScript(pIp)) + { + case ARGUMENT_INT32: + return CTheScripts::Read4BytesFromScript(pIp); + case ARGUMENT_GLOBALVAR: + return *((int32*)&CTheScripts::ScriptSpace[CTheScripts::Read2BytesFromScript(pIp)]); + case ARGUMENT_LOCALVAR: + return m_anLocalVariables[CTheScripts::Read2BytesFromScript(pIp)]; + case ARGUMENT_INT8: + return CTheScripts::Read1ByteFromScript(pIp); + case ARGUMENT_INT16: + return CTheScripts::Read2BytesFromScript(pIp); + case ARGUMENT_FLOAT: + tmp = CTheScripts::ReadFloatFromScript(pIp); + return *(int32*)&tmp; + default: + assert(0); + } + return -1; +} + +void CRunningScript::StoreParameters(uint32* pIp, int16 number) +{ + for (int16 i = 0; i < number; i++){ + switch (CTheScripts::Read1ByteFromScript(pIp)) { + case ARGUMENT_GLOBALVAR: + *(int32*)&CTheScripts::ScriptSpace[CTheScripts::Read2BytesFromScript(pIp)] = ScriptParams[i]; + break; + case ARGUMENT_LOCALVAR: + m_anLocalVariables[CTheScripts::Read2BytesFromScript(pIp)] = ScriptParams[i]; + break; + default: + assert(0); + } + } +} + +int32 *CRunningScript::GetPointerToScriptVariable(uint32* pIp, int16 type) +{ + switch (CTheScripts::Read1ByteFromScript(pIp)) + { + case ARGUMENT_GLOBALVAR: + assert(type == VAR_GLOBAL); + return (int32*)&CTheScripts::ScriptSpace[CTheScripts::Read2BytesFromScript(pIp)]; + case ARGUMENT_LOCALVAR: + assert(type == VAR_LOCAL); + return &m_anLocalVariables[CTheScripts::Read2BytesFromScript(pIp)]; + default: + assert(0); + } + return nil; +} + +void CRunningScript::Init() +{ + strcpy(m_abScriptName, "noname"); + next = prev = nil; + m_nIp = 0; + for (int i = 0; i < MAX_STACK_DEPTH; i++) + m_anStack[i] = 0; + m_nStackPointer = 0; + m_nWakeTime = 0; + m_bCondResult = false; + m_bIsMissionThread = false; + m_bSkipWakeTime = false; + for (int i = 0; i < NUM_LOCAL_VARS + NUM_TIMERS; i++) + m_anLocalVariables[i] = 0; + m_nAndOrState = 0; + m_bNotFlag = false; + m_bWBCheckEnabled = true; + m_bWBChecked = false; + m_bMissionFlag = false; +} + +#ifdef USE_DEBUG_SCRIPT_LOADER +int open_script() +{ + static int scriptToLoad = 1; + + if (GetAsyncKeyState('G') & 0x8000) + scriptToLoad = 0; + if (GetAsyncKeyState('R') & 0x8000) + scriptToLoad = 1; + if (GetAsyncKeyState('D') & 0x8000) + scriptToLoad = 2; + + switch (scriptToLoad) { + case 0: return CFileMgr::OpenFile("main.scm", "rb"); + case 1: return CFileMgr::OpenFile("main_freeroam.scm", "rb"); + case 2: return CFileMgr::OpenFile("main_d.scm", "rb"); + } + return CFileMgr::OpenFile("main.scm", "rb"); +} +#endif + +void CTheScripts::Init() +{ + for (int i = 0; i < SIZE_SCRIPT_SPACE; i++) + ScriptSpace[i] = 0; + pActiveScripts = pIdleScripts = nil; + for (int i = 0; i < MAX_NUM_SCRIPTS; i++){ + ScriptsArray[i].Init(); + ScriptsArray[i].AddScriptToList(&pIdleScripts); + } + MissionCleanup.Init(); + UpsideDownCars.Init(); + StuckCars.Init(); + CFileMgr::SetDir("data"); +#ifdef USE_DEBUG_SCRIPT_LOADER + int mainf = open_script(); +#else + int mainf = CFileMgr::OpenFile("main.scm", "rb"); +#endif + CFileMgr::Read(mainf, (char*)ScriptSpace, SIZE_MAIN_SCRIPT); + CFileMgr::CloseFile(mainf); + CFileMgr::SetDir(""); + StoreVehicleIndex = -1; + StoreVehicleWasRandom = true; + OnAMissionFlag = 0; + for (int i = 0; i < MAX_NUM_CONTACTS; i++){ + BaseBriefIdForContact[i] = 0; + OnAMissionForContactFlag[i] = 0; + } + for (int i = 0; i < MAX_NUM_COLLECTIVES; i++){ + CollectiveArray[i].index = -1; + CollectiveArray[i].unk_data = 0; + } + NextFreeCollectiveIndex = 0; + LastRandomPedId = -1; + for (int i = 0; i < MAX_NUM_USED_OBJECTS; i++){ + memset(&UsedObjectArray[i].name, 0, sizeof(UsedObjectArray[i].name)); + UsedObjectArray[i].index = 0; + } + NumberOfUsedObjects = 0; + ReadObjectNamesFromScript(); + UpdateObjectIndices(); + bAlreadyRunningAMissionScript = false; + bUsingAMultiScriptFile = true; + for (int i = 0; i < MAX_NUM_MISSION_SCRIPTS; i++) + MultiScriptArray[i] = 0; + NumberOfMissionScripts = 0; + LargestMissionScriptSize = 0; + MainScriptSize = 0; + ReadMultiScriptFileOffsetsFromScript(); + FailCurrentMission = 0; + CountdownToMakePlayerUnsafe = 0; + DbgFlag = 0; + DelayMakingPlayerUnsafeThisTime = 0; + NumScriptDebugLines = 0; + for (int i = 0; i < MAX_NUM_SCRIPT_SPHERES; i++){ + ScriptSphereArray[i].m_bInUse = false; + ScriptSphereArray[i].m_Index = 1; + ScriptSphereArray[i].m_Id = 0; + ScriptSphereArray[i].m_vecCenter = CVector(0.0f, 0.0f, 0.0f); + ScriptSphereArray[i].m_fRadius = 0.0f; + } + for (int i = 0; i < MAX_NUM_INTRO_TEXT_LINES; i++){ + IntroTextLines[i].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)); + } + 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_nTextureId = -1; + IntroRectangles[i].m_sRect = CRect(0.0f, 0.0f, 0.0f, 0.0f); + IntroRectangles[i].m_sColor = CRGBA(255, 255, 255, 255); + } + NumberOfIntroRectanglesThisFrame = 0; + for (int i = 0; i < MAX_NUM_BUILDING_SWAPS; i++){ + BuildingSwapArray[i].m_pBuilding = nil; + BuildingSwapArray[i].m_nNewModel = -1; + BuildingSwapArray[i].m_nOldModel = -1; + } + for (int i = 0; i < MAX_NUM_INVISIBILITY_SETTINGS; i++) + InvisibilitySettingArray[i] = nil; +} + +void CRunningScript::RemoveScriptFromList(CRunningScript** ppScript) +{ + if (prev) + prev->next = next; + else + *ppScript = next; + if (next) + next->prev = prev; +} + +void CRunningScript::AddScriptToList(CRunningScript** ppScript) +{ + next = *ppScript; + prev = nil; + if (*ppScript) + (*ppScript)->prev = this; + *ppScript = this; +} + +WRAPPER bool CTheScripts::IsPlayerOnAMission() { EAXJMP(0x439410); } +WRAPPER void CTheScripts::ScriptDebugLine3D(float x1, float y1, float z1, float x2, float y2, float z2, int col, int col2) { EAXJMP(0x4534E0); } WRAPPER void CTheScripts::CleanUpThisVehicle(CVehicle*) { EAXJMP(0x4548D0); } WRAPPER void CTheScripts::CleanUpThisPed(CPed*) { EAXJMP(0x4547A0); } WRAPPER void CTheScripts::CleanUpThisObject(CObject*) { EAXJMP(0x454910); } -WRAPPER bool CTheScripts::IsPlayerOnAMission() { EAXJMP(0x439410); } -WRAPPER void CTheScripts::ScriptDebugLine3D(float x1, float y1, float z1, float x2, float y2, float z2, int col, int col2) { EAXJMP(0x4534E0); } +WRAPPER void CTheScripts::ReadObjectNamesFromScript() { EAXJMP(0x454960); } +WRAPPER void CTheScripts::UpdateObjectIndices() { EAXJMP(0x454AD0); } +WRAPPER void CTheScripts::ReadMultiScriptFileOffsetsFromScript() { EAXJMP(0x454BC0); } STARTPATCHES InjectHook(0x437AE0, &CMissionCleanup::Init, PATCH_JUMP); @@ -299,4 +578,10 @@ InjectHook(0x4380A0, &CStuckCarCheck::Process, PATCH_JUMP); InjectHook(0x4381C0, &CStuckCarCheck::AddCarToCheck, PATCH_JUMP); InjectHook(0x438240, &CStuckCarCheck::RemoveCarFromCheck, PATCH_JUMP); InjectHook(0x4382A0, &CStuckCarCheck::HasCarBeenStuckForAWhile, PATCH_JUMP); +InjectHook(0x4382E0, &CRunningScript::CollectParameters, PATCH_JUMP); +InjectHook(0x438460, &CRunningScript::CollectNextParameterWithoutIncreasingPC, PATCH_JUMP); +InjectHook(0x4385A0, &CRunningScript::StoreParameters, PATCH_JUMP); +InjectHook(0x438640, &CRunningScript::GetPointerToScriptVariable, PATCH_JUMP); +InjectHook(0x4386C0, &CRunningScript::Init, PATCH_JUMP); +InjectHook(0x438790, &CTheScripts::Init, PATCH_JUMP); ENDPATCHES
\ No newline at end of file diff --git a/src/control/Script.h b/src/control/Script.h index 42e41c70..5759cf82 100644 --- a/src/control/Script.h +++ b/src/control/Script.h @@ -1,4 +1,6 @@ #pragma once +#include "common.h" +#include "Collision.h" #include "Ped.h" #include "Object.h" #include "Sprite2d.h" @@ -8,11 +10,17 @@ struct CScriptRectangle { bool m_bIsUsed; bool m_bIsAntialiased; - uint16 m_wTextureId; + int16 m_nTextureId; CRect m_sRect; CRGBA m_sColor; }; +static_assert(sizeof(CScriptRectangle) == 0x18, "Script.h: error"); + +enum { + SCRIPT_TEXT_MAX_LENGTH = 500 +}; + struct CTextLine { float m_fScaleX; @@ -26,33 +34,58 @@ struct CTextLine float m_fCenterSize; CRGBA m_sBackgroundColor; bool m_bTextProportional; - int32 field_29; + bool m_bTextBeforeFade; bool m_bRightJustify; - int32 field_31; int32 m_nFont; - float field_36; - float field_40; - wchar m_awText[500]; + float m_fAtX; + float m_fAtY; + wchar m_Text[SCRIPT_TEXT_MAX_LENGTH]; +}; + +static_assert(sizeof(CTextLine) == 0x414, "Script.h: error"); + +struct CScriptSphere +{ + bool m_bInUse; + uint16 m_Index; + uint32 m_Id; + CVector m_vecCenter; + float m_fRadius; +}; + +enum { + MAX_STACK_DEPTH = 6, + NUM_LOCAL_VARS = 16, + NUM_TIMERS = 2 }; -struct CRunningScript +class CRunningScript { CRunningScript *next; CRunningScript *prev; - uint8 m_abScriptName[8]; + char m_abScriptName[8]; uint32 m_nIp; - uint32 m_anStack[6]; + uint32 m_anStack[MAX_STACK_DEPTH]; uint16 m_nStackPointer; - void* m_anLocalVariables[18]; + int32 m_anLocalVariables[NUM_LOCAL_VARS + NUM_TIMERS]; bool m_bCondResult; bool m_bIsMissionThread; bool m_bSkipWakeTime; uint32 m_nWakeTime; - uint16 m_wIfOp; + uint16 m_nAndOrState; bool m_bNotFlag; - bool m_bWBCheck; - bool m_bWastedOrBusted; + bool m_bWBCheckEnabled; + bool m_bWBChecked; bool m_bMissionFlag; + +public: + void CollectParameters(uint32*, int16); + int32 CollectNextParameterWithoutIncreasingPC(uint32); + int32* GetPointerToScriptVariable(uint32*, int16); + void StoreParameters(uint32*, int16); + void Init(); + void RemoveScriptFromList(CRunningScript**); + void AddScriptToList(CRunningScript**); }; enum { @@ -133,13 +166,80 @@ public: bool HasCarBeenStuckForAWhile(int32); }; +enum { + ARGUMENT_INT32 = 1, + ARGUMENT_GLOBALVAR, + ARGUMENT_LOCALVAR, + ARGUMENT_INT8, + ARGUMENT_INT16, + ARGUMENT_FLOAT +}; + +struct tCollectiveData +{ + int32 index; + uint32 unk_data; +}; + +enum { + USED_OBJECT_NAME_LENGTH = 24 +}; + +struct tUsedObject +{ + char name[USED_OBJECT_NAME_LENGTH]; + int32 index; +}; + +struct tBuildingSwap +{ + CBuilding* m_pBuilding; + int32 m_nNewModel; + int32 m_nOldModel; +}; + + +enum { + VAR_LOCAL = 1, + VAR_GLOBAL = 2, +}; + +enum { + SIZE_MAIN_SCRIPT = 128 * 1024, + SIZE_MISSION_SCRIPT = 32 * 1024, + SIZE_SCRIPT_SPACE = SIZE_MAIN_SCRIPT + SIZE_MISSION_SCRIPT +}; + +enum { + MAX_NUM_SCRIPTS = 128, + MAX_NUM_CONTACTS = 16, + MAX_NUM_INTRO_TEXT_LINES = 2, + MAX_NUM_INTRO_RECTANGLES = 16, + MAX_NUM_SCRIPT_SRPITES = 16, + MAX_NUM_SCRIPT_SPHERES = 16, + MAX_NUM_COLLECTIVES = 32, + MAX_NUM_USED_OBJECTS = 200, + MAX_NUM_MISSION_SCRIPTS = 120, + MAX_NUM_BUILDING_SWAPS = 25, + MAX_NUM_INVISIBILITY_SETTINGS = 20 +}; + class CTheScripts { public: - static uint8(&ScriptSpace)[160 * 1024]; - static CTextLine(&IntroTextLines)[2]; - static CScriptRectangle(&IntroRectangles)[16]; - static CSprite2d(&ScriptSprites)[16]; + static uint8(&ScriptSpace)[SIZE_SCRIPT_SPACE]; + static CRunningScript(&ScriptsArray)[MAX_NUM_SCRIPTS]; + static int32(&BaseBriefIdForContact)[MAX_NUM_CONTACTS]; + static int32(&OnAMissionForContactFlag)[MAX_NUM_CONTACTS]; + static CTextLine(&IntroTextLines)[MAX_NUM_INTRO_TEXT_LINES]; + static CScriptRectangle(&IntroRectangles)[MAX_NUM_INTRO_RECTANGLES]; + static CSprite2d(&ScriptSprites)[MAX_NUM_SCRIPT_SRPITES]; + static CScriptSphere(&ScriptSphereArray)[MAX_NUM_SCRIPT_SPHERES]; + static tCollectiveData(&CollectiveArray)[MAX_NUM_COLLECTIVES]; + static tUsedObject(&UsedObjectArray)[MAX_NUM_USED_OBJECTS]; + static int32(&MultiScriptArray)[MAX_NUM_MISSION_SCRIPTS]; + static tBuildingSwap(&BuildingSwapArray)[MAX_NUM_BUILDING_SWAPS]; + static CEntity*(&InvisibilitySettingArray)[MAX_NUM_INVISIBILITY_SETTINGS]; static bool &DbgFlag; static uint32 &OnAMissionFlag; static CMissionCleanup &MissionCleanup; @@ -147,11 +247,57 @@ public: static CUpsideDownCarCheck &UpsideDownCars; static int32 &StoreVehicleIndex; static bool &StoreVehicleWasRandom; - + static CRunningScript *&pIdleScripts; + static CRunningScript *&pActiveScripts; + static uint32 &NextFreeCollectiveIndex; + static int32 &LastRandomPedId; + static uint16 &NumberOfUsedObjects; + static bool &bAlreadyRunningAMissionScript; + static bool &bUsingAMultiScriptFile; + static uint16 &NumberOfMissionScripts; + static uint32 &LargestMissionScriptSize; + static uint32 &MainScriptSize; + static uint8 &FailCurrentMission; + static uint8 &CountdownToMakePlayerUnsafe; + static uint8 &DelayMakingPlayerUnsafeThisTime; + static uint16 &NumScriptDebugLines; + static uint16 &NumberOfIntroRectanglesThisFrame; + static uint16 &NumberOfIntroTextLinesThisFrame; + static bool &UseTextCommands; 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 void ReadObjectNamesFromScript(); + static void UpdateObjectIndices(); + static void ReadMultiScriptFileOffsetsFromScript(); + + static int32 Read4BytesFromScript(uint32* pIp){ + int32 retval = 0; + for (int i = 0; i < 4; i++){ + retval |= ScriptSpace[(*pIp)++] << (8 * i); + } + return retval; + } + static int16 Read2BytesFromScript(uint32* pIp){ + int16 retval = 0; + for (int i = 0; i < 2; i++){ + retval |= ScriptSpace[(*pIp)++] << (8 * i); + } + return retval; + } + static int8 Read1ByteFromScript(uint32* pIp){ + int8 retval = 0; + for (int i = 0; i < 1; i++){ + retval |= ScriptSpace[(*pIp)++] << (8 * i); + } + return retval; + } + static float ReadFloatFromScript(uint32* pIp){ + return Read2BytesFromScript(pIp) / 16.0f; + } }; diff --git a/src/core/config.h b/src/core/config.h index 8cb02190..c3b66ff7 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -114,3 +114,4 @@ enum Config { #define FIX_BUGS // fix bugs in the game, TODO: use this more #define KANGAROO_CHEAT #define ASPECT_RATIO_SCALE +#define USE_DEBUG_SCRIPT_LOADER
\ No newline at end of file diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 9dc39d46..d6e81214 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -57,27 +57,6 @@ mysrand(unsigned int seed) myrand_seed = seed; } -int (*open_script_orig)(const char *path, const char *mode); -int -open_script(const char *path, const char *mode) -{ - static int scriptToLoad = 1; - - if(GetAsyncKeyState('G') & 0x8000) - scriptToLoad = 0; - if(GetAsyncKeyState('R') & 0x8000) - scriptToLoad = 1; - if(GetAsyncKeyState('D') & 0x8000) - scriptToLoad = 2; - - switch(scriptToLoad){ - case 0: return open_script_orig(path, mode); - case 1: return open_script_orig("main_freeroam.scm", mode); - case 2: return open_script_orig("main_d.scm", mode); - } - return open_script_orig(path, mode); -} - int gDbgSurf; void (*DebugMenuProcess)(void); @@ -356,7 +335,7 @@ patch() Patch<WORD>(0x5382BF, 0x0EEB); InjectHook(0x5382EC, HeadlightsFix, PATCH_JUMP); - InterceptCall(&open_script_orig, open_script, 0x438869); +// InterceptCall(&open_script_orig, open_script, 0x438869); // InterceptCall(&RsEventHandler_orig, delayedPatches10, 0x58275E); } diff --git a/src/math/Matrix.h b/src/math/Matrix.h index 6e1001cb..5cc7d12f 100644 --- a/src/math/Matrix.h +++ b/src/math/Matrix.h @@ -306,6 +306,15 @@ Multiply3x3(const CMatrix &mat, const CVector &vec) mat.m_matrix.right.z * vec.x + mat.m_matrix.up.z * vec.y + mat.m_matrix.at.z * vec.z); } +inline CVector +Multiply3x3(const CVector &vec, const CMatrix &mat) +{ + return CVector( + mat.m_matrix.right.x * vec.x + mat.m_matrix.right.y * vec.y + mat.m_matrix.right.z * vec.z, + mat.m_matrix.up.x * vec.x + mat.m_matrix.up.y * vec.y + mat.m_matrix.up.z * vec.z, + mat.m_matrix.at.x * vec.x + mat.m_matrix.at.y * vec.y + mat.m_matrix.at.z * vec.z); +} + class CCompressedMatrixNotAligned { CVector m_vecPos; diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp index 680720e0..754f4b85 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -814,8 +814,8 @@ void CHud::Draw() if (!CTimer::GetIsUserPaused()) { CTextLine* IntroText = CTheScripts::IntroTextLines; - for (int i = 0; i < 2; i++) { - if (CTheScripts::IntroTextLines[i].m_awText[0] && CTheScripts::IntroTextLines[i].field_29) { + for (int i = 0; i < MAX_NUM_INTRO_TEXT_LINES; i++) { + if (CTheScripts::IntroTextLines[i].m_Text[0] && CTheScripts::IntroTextLines[i].m_bTextBeforeFade) { CFont::SetScale(SCREEN_SCALE_X(CTheScripts::IntroTextLines[i].m_fScaleX), SCREEN_SCALE_Y(CTheScripts::IntroTextLines[i].m_fScaleY * 0.5f)); CFont::SetColor(CTheScripts::IntroTextLines[i].m_sColor); @@ -855,7 +855,7 @@ void CHud::Draw() CFont::SetPropOff(); CFont::SetFontStyle(CTheScripts::IntroTextLines[i].m_nFont); - CFont::PrintString(SCREEN_SCALE_X(640.0f - CTheScripts::IntroTextLines[i].field_36), SCREEN_SCALE_Y(448.0f - CTheScripts::IntroTextLines[i].field_40), IntroText->m_awText); + CFont::PrintString(SCREEN_SCALE_X(640.0f - CTheScripts::IntroTextLines[i].m_fAtX), SCREEN_SCALE_Y(448.0f - CTheScripts::IntroTextLines[i].m_fAtY), IntroText->m_Text); } } @@ -863,14 +863,14 @@ void CHud::Draw() for (int i = 0; i < 16; i++) { if (CTheScripts::IntroRectangles[i].m_bIsUsed && CTheScripts::IntroRectangles[i].m_bIsAntialiased) { - if (CTheScripts::IntroRectangles[i].m_wTextureId >= 0) { + if (CTheScripts::IntroRectangles[i].m_nTextureId >= 0) { CRect rect = { CTheScripts::IntroRectangles[i].m_sRect.left, CTheScripts::IntroRectangles[i].m_sRect.bottom, CTheScripts::IntroRectangles[i].m_sRect.right, CTheScripts::IntroRectangles[i].m_sRect.bottom }; - CTheScripts::ScriptSprites[CTheScripts::IntroRectangles[i].m_wTextureId].Draw(rect, IntroRect->m_sColor); + CTheScripts::ScriptSprites[CTheScripts::IntroRectangles[i].m_nTextureId].Draw(rect, IntroRect->m_sColor); } else { CRect rect = { diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 54eed17a..80131179 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -14,5 +14,5 @@ WRAPPER void CAutomobile::SetPanelDamage(int32, uint32, bool) { EAXJMP(0x5301A0) WRAPPER void CAutomobile::SetBumperDamage(int32, uint32, bool) { EAXJMP(0x530120); } STARTPATCHES -InjectHook(0x52D170, &CAutomobile::dtor, PATCH_JUMP); -ENDPATCHES
\ No newline at end of file + InjectHook(0x52D170, &CAutomobile::dtor, PATCH_JUMP); +ENDPATCHES diff --git a/src/vehicles/Automobile.h b/src/vehicles/Automobile.h index 630635c7..c20d078b 100644 --- a/src/vehicles/Automobile.h +++ b/src/vehicles/Automobile.h @@ -1,21 +1,8 @@ #pragma once -#include "DamageManager.h" #include "Vehicle.h" - -struct CDoor -{ - float m_fAngleWhenOpened; - float m_fAngleWhenClosed; - char field_8; - char field_9; - char field_10; - char field_11; - float m_fAngle; - float m_fPreviousAngle; - float m_fAngularVelocity; - CVector m_vecVelocity; -}; +#include "DamageManager.h" +#include "Door.h" class CAutomobile : public CVehicle { diff --git a/src/vehicles/Door.cpp b/src/vehicles/Door.cpp new file mode 100644 index 00000000..ec5eb223 --- /dev/null +++ b/src/vehicles/Door.cpp @@ -0,0 +1,126 @@ +#include "common.h" +#include "patcher.h" +#include "Vehicle.h" +#include "Door.h" + +CDoor::CDoor(void) +{ + memset(this, 0, sizeof(*this)); +} + +void +CDoor::Open(float ratio) +{ + float open; + + m_fPrevAngle = m_fAngle; + open = RetAngleWhenOpen(); + if(ratio < 1.0f){ + m_fAngle = open*ratio; + if(m_fAngle == 0.0f) + m_fAngVel = 0.0f; + }else{ + m_nDoorState = DOORST_OPEN; + m_fAngle = open; + } +} + +void +CDoor::Process(CVehicle *vehicle) +{ + static CVector vecOffset(1.0f, 0.0f, 0.0f); + CVector speed = vehicle->GetSpeed(vecOffset); + CVector vecSpeedDiff = speed - m_vecSpeed; + vecSpeedDiff = Multiply3x3(vecSpeedDiff, vehicle->GetMatrix()); + + // air resistance + float fSpeedDiff = 0.0f; // uninitialized in game + switch(m_nAxis){ + case 0: // x-axis + if(m_nDirn) + fSpeedDiff = vecSpeedDiff.y + vecSpeedDiff.z; + else + fSpeedDiff = -(vecSpeedDiff.y + vecSpeedDiff.z); + break; + + // we don't support y axis apparently? + + case 2: // z-axis + if(m_nDirn) + fSpeedDiff = -(vecSpeedDiff.x + vecSpeedDiff.y); + else + fSpeedDiff = vecSpeedDiff.x + vecSpeedDiff.y; + break; + } + fSpeedDiff = clamp(fSpeedDiff, -0.2f, 0.2f); + if(fabs(fSpeedDiff) > 0.002f) + m_fAngVel += fSpeedDiff; + m_fAngVel *= 0.945f; + m_fAngVel = clamp(m_fAngVel, -0.3f, 0.3f); + + m_fAngle += m_fAngVel; + m_nDoorState = DOORST_SWINGING; + if(m_fAngle > m_fMaxAngle){ + m_fAngle = m_fMaxAngle; + m_fAngVel *= -0.8f; + m_nDoorState = DOORST_OPEN; + } + if(m_fAngle < m_fMinAngle){ + m_fAngle = m_fMinAngle; + m_fAngVel *= -0.8f; + m_nDoorState = DOORST_CLOSED; + } + m_vecSpeed = speed; +} + +float +CDoor::RetAngleWhenClosed(void) +{ + if(fabs(m_fMaxAngle) < fabs(m_fMinAngle)) + return m_fMaxAngle; + else + return m_fMinAngle; +} + +float +CDoor::RetAngleWhenOpen(void) +{ + if(fabs(m_fMaxAngle) < fabs(m_fMinAngle)) + return m_fMinAngle; + else + return m_fMaxAngle; +} + +float +CDoor::GetAngleOpenRatio(void) +{ + float open = RetAngleWhenOpen(); + if(open == 0.0f) + return 0.0f; + return m_fAngle/open; +} + +bool +CDoor::IsFullyOpen(void) +{ + // why -0.5? that's around 28 deg less than fully open + if(fabs(m_fAngle) < fabs(RetAngleWhenOpen()) - 0.5f) + return false; + return true; +} + +bool +CDoor::IsClosed(void) +{ + return m_fAngle == RetAngleWhenClosed(); +} + +STARTPATCHES + InjectHook(0x545EF0, &CDoor::Open, PATCH_JUMP); + InjectHook(0x545BD0, &CDoor::Process, PATCH_JUMP); + InjectHook(0x545FE0, &CDoor::RetAngleWhenClosed, PATCH_JUMP); + InjectHook(0x546020, &CDoor::RetAngleWhenOpen, PATCH_JUMP); + InjectHook(0x545F80, &CDoor::GetAngleOpenRatio, PATCH_JUMP); + InjectHook(0x546090, &CDoor::IsFullyOpen, PATCH_JUMP); + InjectHook(0x546060, &CDoor::IsClosed, PATCH_JUMP); +ENDPATCHES diff --git a/src/vehicles/Door.h b/src/vehicles/Door.h new file mode 100644 index 00000000..fc771a40 --- /dev/null +++ b/src/vehicles/Door.h @@ -0,0 +1,36 @@ +#pragma once + +class CVehicle; + +enum eDoorState +{ + DOORST_SWINGING, + // actually wrong though, + // OPEN is really MAX_ANGLE and CLOSED is MIN_ANGLE + DOORST_OPEN, + DOORST_CLOSED +}; + +struct CDoor +{ + float m_fMaxAngle; + float m_fMinAngle; + // direction of rotation for air resistance + int8 m_nDirn; + // axis in which this door rotates + int8 m_nAxis; + int8 m_nDoorState; + float m_fAngle; + float m_fPrevAngle; + float m_fAngVel; + CVector m_vecSpeed; + + CDoor(void); + void Open(float ratio); + void Process(CVehicle *veh); + float RetAngleWhenClosed(void); + float RetAngleWhenOpen(void); + float GetAngleOpenRatio(void); + bool IsFullyOpen(void); + bool IsClosed(void); +}; |