diff options
Diffstat (limited to '')
119 files changed, 11359 insertions, 1522 deletions
diff --git a/src/animation/AnimBlendAssocGroup.cpp b/src/animation/AnimBlendAssocGroup.cpp index fbca92b7..05f9a06a 100644 --- a/src/animation/AnimBlendAssocGroup.cpp +++ b/src/animation/AnimBlendAssocGroup.cpp @@ -116,14 +116,13 @@ CAnimBlendAssocGroup::CreateAssociations(const char *name) for(i = 0; i < animBlock->numAnims; i++){ CAnimBlendHierarchy *anim = CAnimManager::GetAnimation(animBlock->firstIndex + i); CBaseModelInfo *model = GetModelFromName(anim->name); + assert(model); printf("Associated anim %s with model %s\n", anim->name, model->GetName()); - if(model){ - RpClump *clump = (RpClump*)model->CreateInstance(); - RpAnimBlendClumpInit(clump); - assocList[i].Init(clump, anim); - RpClumpDestroy(clump); - assocList[i].animId = i; - } + RpClump *clump = (RpClump*)model->CreateInstance(); + RpAnimBlendClumpInit(clump); + assocList[i].Init(clump, anim); + RpClumpDestroy(clump); + assocList[i].animId = i; } numAssociations = animBlock->numAnims; } diff --git a/src/animation/AnimBlendAssociation.h b/src/animation/AnimBlendAssociation.h index a7e127f7..cd61636f 100644 --- a/src/animation/AnimBlendAssociation.h +++ b/src/animation/AnimBlendAssociation.h @@ -77,6 +77,8 @@ public: void UpdateTime(float timeDelta, float relSpeed); bool UpdateBlend(float timeDelta); + void SetRun(void) { flags |= ASSOC_RUNNING; } + inline float GetTimeLeft() { return hierarchy->totalLength - currentTime; } static CAnimBlendAssociation *FromLink(CAnimBlendLink *l) { diff --git a/src/animation/AnimBlendSequence.h b/src/animation/AnimBlendSequence.h index 7538cf56..1246d7b4 100644 --- a/src/animation/AnimBlendSequence.h +++ b/src/animation/AnimBlendSequence.h @@ -1,6 +1,6 @@ #pragma once -#include "math/Quaternion.h" +#include "Quaternion.h" // TODO: put them somewhere else? struct KeyFrame { diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp index 51f45e16..c0479002 100644 --- a/src/audio/AudioManager.cpp +++ b/src/audio/AudioManager.cpp @@ -3,19 +3,26 @@ #include "AudioManager.h" +#include "Automobile.h" +#include "Camera.h" #include "DMAudio.h" +#include "Garages.h" #include "ModelIndices.h" #include "MusicManager.h" #include "Ped.h" #include "Physical.h" +#include "Plane.h" #include "PlayerPed.h" +#include "Pools.h" #include "SampleManager.h" +#include "Stats.h" #include "Vehicle.h" #include "World.h" +uint32 *audioLogicTimers = (uint32 *)0x6508A0; + // TODO: where is this used? Is this the right file? -enum eVehicleModel -{ +enum eVehicleModel { LANDSTAL, IDAHO, STINGER, @@ -88,6 +95,11 @@ enum eVehicleModel CAR159, }; +void *cAudioScriptObject::operator new(size_t sz) { return CPools::GetAudioScriptObjectPool()->New(); } +void *cAudioScriptObject::operator new(size_t sz, int handle) { return CPools::GetAudioScriptObjectPool()->New(handle); } +void cAudioScriptObject::operator delete(void *p, size_t sz) { CPools::GetAudioScriptObjectPool()->Delete((cAudioScriptObject*)p); } +void cAudioScriptObject::operator delete(void *p, int handle) { CPools::GetAudioScriptObjectPool()->Delete((cAudioScriptObject*)p); } + cAudioManager &AudioManager = *(cAudioManager *)0x880FC0; constexpr int totalAudioEntitiesSlots = 200; @@ -96,21 +108,187 @@ constexpr int maxVolume = 127; char &g_nMissionAudioPlayingStatus = *(char *)0x60ED88; void +cAudioManager::AddDetailsToRequestedOrderList(uint8 sample) +{ + uint32 i = 0; + if(sample != 0) { + for(; i < sample; i++) { + if(m_asSamples[m_bActiveSampleQueue] + [m_abSampleQueueIndexTable[m_bActiveSampleQueue][i]] + .calculatedVolume > + m_asSamples[m_bActiveSampleQueue][sample].calculatedVolume) + break; + } + if(i < sample) { + memmove(&m_abSampleQueueIndexTable[m_bActiveSampleQueue][i + 1], + &m_abSampleQueueIndexTable[m_bActiveSampleQueue][i], + m_bActiveSamples - i - 1); + } + } + m_abSampleQueueIndexTable[m_bActiveSampleQueue][i] = sample; +} + +void +cAudioManager::AddPlayerCarSample(uint8 emittingVolume, int32 freq, uint32 sample, uint8 unk1, + uint8 unk2, bool notLooping) +{ + m_sQueueSample.m_bVolume = ComputeVolume(emittingVolume, 50.f, m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.field_4 = unk2; + m_sQueueSample.m_nSampleIndex = sample; + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.field_16 = 0; + m_sQueueSample.m_nFrequency = freq; + if(notLooping) { + m_sQueueSample.m_nLoopCount = 0; + m_sQueueSample.field_76 = 8; + } else { + m_sQueueSample.m_nLoopCount = 1; + } + m_sQueueSample.m_bEmittingVolume = emittingVolume; + m_sQueueSample.m_nLoopStart = + cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_nLoopEnd = + cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.field_48 = 6.0f; + m_sQueueSample.m_fSoundIntensity = 50.0f; + m_sQueueSample.field_56 = 0; + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); + } +} + +void +cAudioManager::AddReflectionsToRequestedQueue() +{ + float reflectionDistance; + int32 noise; + uint8 emittingVolume = emittingVolume = + (m_sQueueSample.m_bVolume >> 1) + (m_sQueueSample.m_bVolume >> 3); + + for(uint32 i = 0; i < 5u; i++) { + reflectionDistance = m_afReflectionsDistances[i]; + if(reflectionDistance > 0.0f && reflectionDistance < 100.f && + reflectionDistance < m_sQueueSample.m_fSoundIntensity) { + m_sQueueSample.m_bLoopsRemaining = (reflectionDistance * 500.f / 1029.f); + if(m_sQueueSample.m_bLoopsRemaining > 5u) { + m_sQueueSample.m_fDistance = m_afReflectionsDistances[i]; + m_sQueueSample.m_bEmittingVolume = emittingVolume; + m_sQueueSample.m_bVolume = + ComputeVolume(emittingVolume, m_sQueueSample.m_fSoundIntensity, + m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume > emittingVolume >> 4) { + m_sQueueSample.field_4 += ((i + 1) << 8); + if(m_sQueueSample.m_nLoopCount) { + noise = RandomDisplacement( + m_sQueueSample.m_nFrequency >> 5); + if(noise <= 0) + m_sQueueSample.m_nFrequency += noise; + else + m_sQueueSample.m_nFrequency -= noise; + } + m_sQueueSample.field_16 += 20; + m_sQueueSample.m_vecPos.x = m_avecReflectionsPos[i].x; + m_sQueueSample.m_vecPos.y = m_avecReflectionsPos[i].y; + m_sQueueSample.m_vecPos.z = m_avecReflectionsPos[i].z; + AddSampleToRequestedQueue(); + } + } + } + } +} + +#if 1 +WRAPPER void +cAudioManager::AddReleasingSounds() +{ + EAXJMP(0x57B8D0); +} +#else +void +cAudioManager::AddReleasingSounds() +{ + bool isFirstSampleQueue; + int32 calculatedIndex; + tActiveSample *sample; + uint8 field_76; + uint8 field_88; + int sampleQueue; + bool toProcess[44]; + isFirstSampleQueue = m_bActiveSampleQueue == 0; + + cAudioManager *s = (this + 2484 * isFirstSampleQueue); // wtf + + for(uint32 i = 0; i < m_bSampleRequestQueuesStatus[isFirstSampleQueue]; i++) { + calculatedIndex = i + 27 * isFirstSampleQueue; + sample = &s->m_asSamples[m_abSampleQueueIndexTable[calculatedIndex]]; + if(!s->m_asSamples[m_abSampleQueueIndexTable[calculatedIndex]].m_bLoopEnded) { + toProcess[i] = 0; + sampleQueue = m_bActiveSampleQueue; + for(uint8 j = 0; j < m_bSampleRequestQueuesStatus[m_bActiveSampleQueue]; + j++) { + if(sample->m_nEntityIndex == + m_asSamples[27 * sampleQueue + + m_abSampleQueueIndexTable[27 * sampleQueue + j]] + .m_nEntityIndex && + sample->field_4 == + m_asSamples[27 * sampleQueue + + m_abSampleQueueIndexTable[27 * sampleQueue + j]] + .field_4) { + toProcess[i] = 1; + break; + } + } + if(!toProcess[i]) { + if(sample->field_4 <= 255u || !sample->m_bLoopsRemaining) { + field_76 = sample->field_76; + if(!field_76) continue; + if(!sample->m_nLoopCount) { + uint8 &vol = sample->m_bVolume; + if(sample->field_88 == -1) { + sample->field_88 = vol / field_76; + if(sample->field_88 <= 0) + sample->field_88 = 1; + } + field_88 = sample->field_88; + if(vol <= field_88) { + sample->field_76 = 0; + continue; + } + vol -= field_88; + } + --sample->field_76; + if(field_2) { + if(sample->field_16 < 20u) ++sample->field_16; + } + sample->field_56 = 0; + } + memcpy(&m_sQueueSample, sample, 92); + AddSampleToRequestedQueue(); + } + } + } +} +#endif + +void cAudioManager::AddSampleToRequestedQueue() { int32 calculatedVolume; tActiveSample *sample; - int32 unknown1; - uint8 unknown2; + uint8 sampleIndex; bool bReflections; if(m_sQueueSample.m_nSampleIndex < TOTAL_AUDIO_SAMPLES) { calculatedVolume = m_sQueueSample.field_16 * (maxVolume - m_sQueueSample.m_bVolume); - unknown2 = m_bSampleRequestQueuesStatus[m_bActiveSampleQueue]; - if(unknown2 >= m_bActiveSamples) { - unknown1 = 27 * m_bActiveSampleQueue; - unknown2 = *(&m_asSamples[53].field_91 + m_bActiveSamples + unknown1); - if(m_asSamples[unknown1 + unknown2].calculatedVolume <= calculatedVolume) + sampleIndex = m_bSampleRequestQueuesStatus[m_bActiveSampleQueue]; + if(sampleIndex >= m_bActiveSamples) { + sampleIndex = + m_abSampleQueueIndexTable[m_bActiveSampleQueue][m_bActiveSamples - 1]; + if(m_asSamples[m_bActiveSampleQueue][sampleIndex].calculatedVolume <= + calculatedVolume) return; } else { ++m_bSampleRequestQueuesStatus[m_bActiveSampleQueue]; @@ -131,7 +309,7 @@ cAudioManager::AddSampleToRequestedQueue() if(!m_bDynamicAcousticModelingStatus) m_sQueueSample.m_bReverbFlag = 0; - sample = &m_asSamples[27 * m_bActiveSampleQueue + unknown2]; + sample = &m_asSamples[m_bActiveSampleQueue][sampleIndex]; sample->m_nEntityIndex = m_sQueueSample.m_nEntityIndex; sample->field_4 = m_sQueueSample.field_4; sample->m_nSampleIndex = m_sQueueSample.m_nSampleIndex; @@ -159,69 +337,91 @@ cAudioManager::AddSampleToRequestedQueue() sample->calculatedVolume = m_sQueueSample.calculatedVolume; sample->field_88 = m_sQueueSample.field_88; - AddDetailsToRequestedOrderList(unknown2); + AddDetailsToRequestedOrderList(sampleIndex); if(bReflections) AddReflectionsToRequestedQueue(); } } +WRAPPER void -cAudioManager::AddDetailsToRequestedOrderList(uint8 sample) +cAudioManager::AgeCrimes() { - int32 offset; - uint32 i = 0; - if(sample != 0) { - for(; i < sample; i++) { - offset = 27 * m_bActiveSampleQueue; - if(m_asSamples[offset + m_abSampleQueueIndexTable[i + offset]] - .calculatedVolume > m_asSamples[offset + sample].calculatedVolume) - break; - } - if(i < sample) { - memmove(&m_abSampleQueueIndexTable[offset + 1 + i], - &m_abSampleQueueIndexTable[offset + i], m_bActiveSamples - i - 1); - } + EAXJMP(0x580AF0); +} + +int8 +cAudioManager::AutoDetect3DProviders() +{ + if(m_bIsInitialised) return cSampleManager.AutoDetect3DProviders(); + + return -1; +} + +void +cAudioManager::CalculateDistance(bool *ptr, float dist) +{ + if(*ptr == false) { + m_sQueueSample.m_fDistance = sqrt(dist); + *ptr = true; } - m_abSampleQueueIndexTable[27 * m_bActiveSampleQueue + i] = sample; +} + +bool +cAudioManager::CheckForAnAudioFileOnCD() +{ + return cSampleManager.CheckForAnAudioFileOnCD(); } void -cAudioManager::AddReflectionsToRequestedQueue() +cAudioManager::ClearMissionAudio() { - float reflectionDistance; - int32 noise; - uint8 emittingVolume = emittingVolume = - (m_sQueueSample.m_bVolume >> 1) + (m_sQueueSample.m_bVolume >> 3); + if(m_bIsInitialised) { + m_sMissionAudio.m_nSampleIndex = NO_SAMPLE; + m_sMissionAudio.m_bLoadingStatus = 0; + m_sMissionAudio.m_bPlayStatus = 0; + m_sMissionAudio.field_22 = 0; + m_sMissionAudio.m_bIsPlayed = false; + m_sMissionAudio.field_12 = 1; + m_sMissionAudio.field_24 = 0; + } +} - for(uint32 i = 0; i < 5u; i++) { - reflectionDistance = m_afReflectionsDistances[i]; - if(reflectionDistance > 0.0f && reflectionDistance < 100.f && - reflectionDistance < m_sQueueSample.m_fSoundIntensity) { - m_sQueueSample.m_bLoopsRemaining = (reflectionDistance * 0.38873f); // @todo assert value - if(m_sQueueSample.m_bLoopsRemaining > 5u) { - m_sQueueSample.m_fDistance = m_afReflectionsDistances[i]; - m_sQueueSample.m_bEmittingVolume = emittingVolume; - m_sQueueSample.m_bVolume = - ComputeVolume(emittingVolume, m_sQueueSample.m_fSoundIntensity, - m_sQueueSample.m_fDistance); - if(m_sQueueSample.m_bVolume > emittingVolume >> 4) { - m_sQueueSample.field_4 += ((i + 1) << 8); - if(m_sQueueSample.m_nLoopCount) { - noise = RandomDisplacement( - m_sQueueSample.m_nFrequency >> 5); - if(noise <= 0) - m_sQueueSample.m_nFrequency += noise; - else - m_sQueueSample.m_nFrequency -= noise; - } - m_sQueueSample.field_16 += 20; - m_sQueueSample.m_vecPos.x = m_avecReflectionsPos[i].x; - m_sQueueSample.m_vecPos.y = m_avecReflectionsPos[i].y; - m_sQueueSample.m_vecPos.z = m_avecReflectionsPos[i].z; - AddSampleToRequestedQueue(); +void +cAudioManager::ClearRequestedQueue() +{ + for(int32 i = 0; i < m_bActiveSamples; i++) { + m_abSampleQueueIndexTable[m_bActiveSampleQueue][i] = m_bActiveSamples; + } + m_bSampleRequestQueuesStatus[m_bActiveSampleQueue] = 0; +} + +int32 +cAudioManager::ComputeDopplerEffectedFrequency(uint32 oldFreq, float position1, float position2, + float speedMultiplier) +{ + uint32 newFreq = oldFreq; + if(!TheCamera.Get_Just_Switched_Status() && speedMultiplier != 0.0f) { + float dist = position2 - position1; + if(dist != 0.0f) { + float speedOfSource = (dist / field_19195) * speedMultiplier; + if(speedOfSound > fabsf(speedOfSource)) { + if(speedOfSource < 0.0f) { + speedOfSource = max(speedOfSource, -1.5f); + } else { + speedOfSource = min(speedOfSource, 1.5f); } + newFreq = (oldFreq * speedOfSound) / (speedOfSource + speedOfSound); } } } + return newFreq; +} + +WRAPPER +int32 +cAudioManager::ComputePan(float, CVector *) +{ + EAXJMP(0x57AD20); } uint32 @@ -238,6 +438,131 @@ cAudioManager::ComputeVolume(int emittingVolume, float soundIntensity, float dis return emittingVolume; } +int32 +cAudioManager::CreateEntity(int32 type, CPhysical *entity) +{ + if(!m_bIsInitialised) return -4; + if(!entity) return -2; + if(type >= TOTAL_AUDIO_TYPES) return -1; + for(uint32 i = 0; i < 200; i++) { + if(!m_asAudioEntities[i].m_bIsUsed) { + m_asAudioEntities[i].m_bIsUsed = true; + m_asAudioEntities[i].m_bStatus = 0; + m_asAudioEntities[i].m_nType = (eAudioType)type; + m_asAudioEntities[i].m_pEntity = entity; + m_asAudioEntities[i].m_awAudioEvent[0] = SOUND_TOTAL_PED_SOUNDS; + m_asAudioEntities[i].m_awAudioEvent[1] = SOUND_TOTAL_PED_SOUNDS; + m_asAudioEntities[i].m_awAudioEvent[2] = SOUND_TOTAL_PED_SOUNDS; + m_asAudioEntities[i].m_awAudioEvent[3] = SOUND_TOTAL_PED_SOUNDS; + m_asAudioEntities[i].field_24 = 0; + m_anAudioEntityIndices[m_nAudioEntitiesTotal++] = i; + return i; + } + } + return -3; +} + +void +cAudioManager::DestroyAllGameCreatedEntities() +{ + cAudioScriptObject *entity; + + if(m_bIsInitialised) { + for(uint32 i = 0; i < 200; i++) { + if(m_asAudioEntities[i].m_bIsUsed) { + switch(m_asAudioEntities[i].m_nType) { + case AUDIOTYPE_PHYSICAL: + case AUDIOTYPE_EXPLOSION: + case AUDIOTYPE_WEATHER: + case AUDIOTYPE_CRANE: + case AUDIOTYPE_GARAGE: + case AUDIOTYPE_HYDRANT: cAudioManager::DestroyEntity(i); break; + case AUDIOTYPE_ONE_SHOT: + entity = + (cAudioScriptObject *)m_asAudioEntities[i].m_pEntity; + if(entity) { delete entity; } + DestroyEntity(i); + break; + default: break; + } + } + } + m_nScriptObjectEntityTotal = 0; + } +} + +void +cAudioManager::DestroyEntity(int32 id) +{ + if(m_bIsInitialised && id >= 0 && id < totalAudioEntitiesSlots && + m_asAudioEntities[id].m_bIsUsed) { + m_asAudioEntities[id].m_bIsUsed = 0; + for(int32 i = 0; i < m_nAudioEntitiesTotal; ++i) { + if(id == m_anAudioEntityIndices[i]) { + if(i < totalAudioEntitiesSlots - 1) + memmove(&m_anAudioEntityIndices[i], + &m_anAudioEntityIndices[i + 1], + 4 * (m_nAudioEntitiesTotal - (i + 1))); + m_anAudioEntityIndices[--m_nAudioEntitiesTotal] = + totalAudioEntitiesSlots; + return; + } + } + } +} + +void +cAudioManager::DoPoliceRadioCrackle() +{ + m_sQueueSample.m_nEntityIndex = m_nPoliceChannelEntity; + m_sQueueSample.field_4 = 0; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_POLICE_SCANNER_CRACKLE; + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_bIsDistant = 1; + m_sQueueSample.field_16 = 10; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_POLICE_SCANNER_CRACKLE); + m_sQueueSample.m_bVolume = m_anRandomTable[2] % 20u + 15; + m_sQueueSample.m_nLoopCount = 0; + m_sQueueSample.m_bEmittingVolume = m_sQueueSample.m_bVolume; + m_sQueueSample.m_nLoopStart = cSampleManager.GetSampleLoopStartOffset(188); + m_sQueueSample.m_nLoopEnd = cSampleManager.GetSampleLoopEndOffset(188); + m_sQueueSample.field_56 = 0; + m_sQueueSample.m_bReverbFlag = 0; + m_sQueueSample.m_bOffset = 63; + m_sQueueSample.field_76 = 3; + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); +} + +void +cAudioManager::GenerateIntegerRandomNumberTable() +{ + for(int32 i = 0; i < 5; i++) { m_anRandomTable[i] = rand(); } +} + +float +cAudioManager::GetDistanceSquared(CVector *v) +{ + const CVector &c = TheCamera.GetPosition(); + return sq(v->x - c.x) + sq(v->y - c.y) + sq((v->z - c.z) * 0.2f); +} + +void +cAudioManager::TranslateEntity(CVector *v1, CVector *v2) +{ + const RwMatrix &cM = TheCamera.GetMatrix().m_matrix; + const CVector &cV = TheCamera.GetPosition(); + + float a = v1->z - cV.z; + float b = v1->y - cV.y; + float c = v1->x - cV.x; + + v2->x = cM.right.y * b + cM.right.x * c + cM.right.z * a; + v2->y = cM.up.y * b + cM.up.x * c + cM.up.z * a; + v2->z = cM.at.y * b + cM.at.x * c + cM.at.z * a; +} + void cAudioManager::Initialise() { @@ -262,27 +587,28 @@ cAudioManager::Initialise() void cAudioManager::PostInitialiseGameSpecificSetup() { - m_nFireAudioEntity = CreateEntity( - AUDIOTYPE_FIRE, (CPhysical *)0x8F31D0); // last is addr of firemanager @todo change - if(m_nFireAudioEntity >= 0) cAudioManager::SetEntityStatus(m_nFireAudioEntity, 1); + m_nFireAudioEntity = + CreateEntity(AUDIOTYPE_FIRE, + (CPhysical *)0x8F31D0); // last is addr of firemanager @todo change + if(m_nFireAudioEntity >= 0) SetEntityStatus(m_nFireAudioEntity, 1); m_nCollisionEntity = CreateEntity(AUDIOTYPE_COLLISION, (CPhysical *)1); - if(m_nCollisionEntity >= 0) cAudioManager::SetEntityStatus(m_nCollisionEntity, 1); + if(m_nCollisionEntity >= 0) SetEntityStatus(m_nCollisionEntity, 1); m_nFrontEndEntity = CreateEntity(AUDIOTYPE_FRONTEND, (CPhysical *)1); - if(m_nFrontEndEntity >= 0) cAudioManager::SetEntityStatus(m_nFrontEndEntity, 1); + if(m_nFrontEndEntity >= 0) SetEntityStatus(m_nFrontEndEntity, 1); m_nProjectileEntity = CreateEntity(AUDIOTYPE_PROJECTILE, (CPhysical *)1); - if(m_nProjectileEntity >= 0) cAudioManager::SetEntityStatus(m_nProjectileEntity, 1); + if(m_nProjectileEntity >= 0) SetEntityStatus(m_nProjectileEntity, 1); m_nWaterCannonEntity = CreateEntity(AUDIOTYPE_WATER_CANNON, (CPhysical *)1); - if(m_nWaterCannonEntity >= 0) cAudioManager::SetEntityStatus(m_nWaterCannonEntity, 1); + if(m_nWaterCannonEntity >= 0) SetEntityStatus(m_nWaterCannonEntity, 1); m_nPoliceChannelEntity = CreateEntity(AUDIOTYPE_D, (CPhysical *)1); - if(m_nPoliceChannelEntity >= 0) cAudioManager::SetEntityStatus(m_nPoliceChannelEntity, 1); + if(m_nPoliceChannelEntity >= 0) SetEntityStatus(m_nPoliceChannelEntity, 1); m_nBridgeEntity = CreateEntity(AUDIOTYPE_BRIDGE, (CPhysical *)1); - if(m_nBridgeEntity >= 0) cAudioManager::SetEntityStatus(m_nBridgeEntity, 1); + if(m_nBridgeEntity >= 0) SetEntityStatus(m_nBridgeEntity, 1); m_sMissionAudio.m_nSampleIndex = NO_SAMPLE; m_sMissionAudio.m_bLoadingStatus = 0; @@ -348,7 +674,6 @@ cAudioManager::GetMissionAudioLoadingStatus() return true; } - uint8 cAudioManager::GetNum3DProvidersAvailable() { @@ -356,14 +681,6 @@ cAudioManager::GetNum3DProvidersAvailable() return 0; } -int8 -cAudioManager::AutoDetect3DProviders() -{ - if(m_bIsInitialised) return cSampleManager.AutoDetect3DProviders(); - - return -1; -} - bool cAudioManager::IsMP3RadioChannelAvailable() { @@ -410,12 +727,6 @@ cAudioManager::SetSpeakerConfig(int32 conf) cSampleManager.SetSpeakerConfig(conf); } -void -cAudioManager::ProcessJumboFlying() -{ - if(SetupJumboFlySound(127u)) SetupJumboEngineSound(63u, 22050); -} - WRAPPER bool cAudioManager::SetupJumboEngineSound(uint8, int32) { EAXJMP(0x56F140); } @@ -441,15 +752,6 @@ cAudioManager::SetMissionScriptPoliceAudio(int32 sfx) } } -void -cAudioManager::CalculateDistance(bool *ptr, float dist) -{ - if(*ptr == false) { - m_sQueueSample.m_fDistance = Sqrt(dist); - *ptr = true; - } -} - bool cAudioManager::UsesSiren(int32 model) { @@ -496,30 +798,154 @@ cAudioManager::MissionScriptAudioUsesPoliceChannel(int32 soundMission) } } -uint8 +char * cAudioManager::Get3DProviderName(uint8 id) { - if(m_bIsInitialised) return 0; + if(!m_bIsInitialised) return 0; if(id >= num3DProvidersAvailable) return 0; return asName3DProviders[id]; } -void -cAudioManager::ProcessJumboTaxi() -{ - if(SetupJumboFlySound(20u)) { - if(SetupJumboTaxiSound(75u)) SetupJumboWhineSound(18u, 29500); +bool +cAudioManager::SetupJumboFlySound(uint8 emittingVol) +{ + int32 vol; + + if(m_sQueueSample.m_fDistance >= 440.0) return 0; + + vol = ComputeVolume(emittingVol, 440.0f, m_sQueueSample.m_fDistance); + m_sQueueSample.m_bVolume = vol; + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_JUMBO_FLY_SOUND; + m_sQueueSample.field_4 = 0; + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.field_16 = 1; + m_sQueueSample.m_bEmittingVolume = emittingVol; + m_sQueueSample.m_nLoopCount = 0; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_JUMBO_FLY_SOUND); + m_sQueueSample.m_nLoopStart = + cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_fSoundIntensity = 440.0f; + m_sQueueSample.field_56 = 0; + m_sQueueSample.field_48 = 4.0; + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.field_76 = 5; + m_sQueueSample.m_nLoopEnd = + cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex); + AddSampleToRequestedQueue(); } + return 1; } -WRAPPER -bool cAudioManager::SetupJumboFlySound(uint8) { EAXJMP(0x56F230); } +bool +cAudioManager::SetupJumboRumbleSound(uint8 emittingVol) +{ + if(m_sQueueSample.m_fDistance >= 240.f) return 0; + + m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 240.f, m_sQueueSample.m_fDistance); + + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.field_4 = 5; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_JUMBO_RUMBLE_SOUND; + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_bIsDistant = 1; + m_sQueueSample.field_16 = 1; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_JUMBO_RUMBLE_SOUND); + m_sQueueSample.m_nLoopCount = 0; + m_sQueueSample.m_bEmittingVolume = emittingVol; + m_sQueueSample.m_nLoopStart = + cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_nLoopEnd = + cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.field_48 = 4.0; + m_sQueueSample.m_fSoundIntensity = 240.0; + m_sQueueSample.field_56 = 0; + m_sQueueSample.field_76 = 12; + m_sQueueSample.m_bOffset = 0; + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); + m_sQueueSample.field_4 = 6; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_JUMBO_RUMBLE_SOUND; + m_sQueueSample.m_nFrequency += 200; + m_sQueueSample.m_bOffset = 127; + AddSampleToRequestedQueue(); + } + return 1; +} -WRAPPER -bool cAudioManager::SetupJumboTaxiSound(uint8) { EAXJMP(0x56EF20); } +uint8 &gJumboVolOffsetPercentage = *(uint8 *)0x6508ED; -WRAPPER -bool cAudioManager::SetupJumboWhineSound(uint8, int32) { EAXJMP(0x56F070); } +bool +cAudioManager::SetupJumboTaxiSound(uint8 vol) +{ + uint8 emittingVol; + + if(m_sQueueSample.m_fDistance >= 180.f) return 0; + + emittingVol = (vol >> 1) + ((vol >> 1) * m_sQueueSample.m_fDistance * 0.0055556f); + + if(m_sQueueSample.m_fDistance * 0.0055556f < 0.7f) + emittingVol -= emittingVol * gJumboVolOffsetPercentage / 100; + m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 180.f, m_sQueueSample.m_fDistance); + + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.field_4 = 1; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_JUMBO_TAXI_SOUND; + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.field_16 = 1; + m_sQueueSample.m_nFrequency = GetJumboTaxiFreq(); + m_sQueueSample.m_nLoopCount = 0; + m_sQueueSample.m_bEmittingVolume = emittingVol; + m_sQueueSample.m_nLoopStart = + cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_nLoopEnd = + cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.field_48 = 4.0f; + m_sQueueSample.m_fSoundIntensity = 180.0f; + m_sQueueSample.field_56 = 0; + m_sQueueSample.field_76 = 4; + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); + } + return 1; +} + +bool +cAudioManager::SetupJumboWhineSound(uint8 emittingVol, int32 freq) +{ + if(m_sQueueSample.m_fDistance >= 170.f) return 0; + + m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 170.f, m_sQueueSample.m_fDistance); + + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.field_4 = 2; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_JUMBO_WHINE_SOUND; + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.field_16 = 1; + m_sQueueSample.m_nFrequency = freq; + m_sQueueSample.m_nLoopCount = 0; + m_sQueueSample.m_bEmittingVolume = emittingVol; + m_sQueueSample.m_nLoopStart = + cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_nLoopEnd = + cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.field_48 = 4.0f; + m_sQueueSample.m_fSoundIntensity = 170.0f; + m_sQueueSample.field_56 = 0; + m_sQueueSample.field_76 = 4; + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); + } + return 1; +} void cAudioManager::PlayLoadedMissionAudio() @@ -559,20 +985,6 @@ cAudioManager::InterrogateAudioEntities() } } -void -cAudioManager::ClearRequestedQueue() -{ - for(int32 i = 0; i < m_bActiveSamples; i++) { - m_abSampleQueueIndexTable[i + 27 * m_bActiveSampleQueue] = m_bActiveSamples; - } - m_bSampleRequestQueuesStatus[m_bActiveSampleQueue] = 0; -} - -// void cAudioManager::AgeCrimes() -//{ - -//} - bool cAudioManager::UsesReverseWarning(int32 model) { @@ -593,59 +1005,6 @@ cAudioManager::GetJumboTaxiFreq() return (60.833f * m_sQueueSample.m_fDistance) + 22050; } -void -cAudioManager::ProcessPhysical(int32 id) -{ - CPhysical *entity = m_asAudioEntities[id].m_pEntity; - if(entity) { - switch(entity->m_type & 7) { - case ENTITY_TYPE_VEHICLE: ProcessVehicle(m_asAudioEntities[id].m_pEntity); break; - case ENTITY_TYPE_PED: ProcessPed(m_asAudioEntities[id].m_pEntity); break; - default: return; - } - } -} - -WRAPPER -void -cAudioManager::ProcessVehicle(CPhysical *) -{ - EAXJMP(0x569A00); -} - -WRAPPER -void -cAudioManager::ProcessPed(CPhysical *) -{ - EAXJMP(0x56F450); -} - -WRAPPER -void -cAudioManager::ProcessPlane(void *ptr) -{ - EAXJMP(0x56E860); -} - -void -cAudioManager::ClearMissionAudio() -{ - if(m_bIsInitialised) { - m_sMissionAudio.m_nSampleIndex = NO_SAMPLE; - m_sMissionAudio.m_bLoadingStatus = 0; - m_sMissionAudio.m_bPlayStatus = 0; - m_sMissionAudio.field_22 = 0; - m_sMissionAudio.m_bIsPlayed = false; - m_sMissionAudio.field_12 = 1; - m_sMissionAudio.field_24 = 0; - } -} - -// void -// cAudioManager::ProcessReverb() -//{ -//} - bool cAudioManager::IsMissionAudioSampleFinished() { @@ -657,9 +1016,6 @@ cAudioManager::IsMissionAudioSampleFinished() } WRAPPER -void cAudioManager::ProcessEntity(int32) { EAXJMP(0x569870); } - -WRAPPER void cAudioManager::InitialisePoliceRadio() { @@ -708,50 +1064,6 @@ cAudioManager::IsAudioInitialised() const return m_bIsInitialised; } -int32 -cAudioManager::CreateEntity(int32 type, CPhysical *entity) -{ - if(!m_bIsInitialised) return -4; - if(!entity) return -2; - if(type >= TOTAL_AUDIO_TYPES) return -1; - for(uint32 i = 0; i < 200; i++) { - if(!m_asAudioEntities[i].m_bIsUsed) { - m_asAudioEntities[i].m_bIsUsed = true; - m_asAudioEntities[i].m_bStatus = 0; - m_asAudioEntities[i].m_nType = (eAudioType)type; - m_asAudioEntities[i].m_pEntity = entity; - m_asAudioEntities[i].m_awAudioEvent[0] = SOUND_TOTAL_PED_SOUNDS; - m_asAudioEntities[i].m_awAudioEvent[1] = SOUND_TOTAL_PED_SOUNDS; - m_asAudioEntities[i].m_awAudioEvent[2] = SOUND_TOTAL_PED_SOUNDS; - m_asAudioEntities[i].m_awAudioEvent[3] = SOUND_TOTAL_PED_SOUNDS; - m_asAudioEntities[i].field_24 = 0; - m_anAudioEntityIndices[m_nAudioEntitiesTotal++] = i; - return i; - } - } - return -3; -} - -void -cAudioManager::DestroyEntity(int32 id) -{ - if(m_bIsInitialised && id >= 0 && id < totalAudioEntitiesSlots && - m_asAudioEntities[id].m_bIsUsed) { - m_asAudioEntities[id].m_bIsUsed = 0; - for(int32 i = 0; i < m_nAudioEntitiesTotal; ++i) { - if(id == m_anAudioEntityIndices[i]) { - if(i < totalAudioEntitiesSlots - 1) - memmove(&m_anAudioEntityIndices[i], - &m_anAudioEntityIndices[i + 1], - 4 * (m_nAudioEntitiesTotal - (i + 1))); - m_anAudioEntityIndices[--m_nAudioEntitiesTotal] = - totalAudioEntitiesSlots; - return; - } - } - } -} - void cAudioManager::SetEntityStatus(int32 id, bool status) { @@ -799,12 +1111,6 @@ cAudioManager::PostTerminateGameSpecificShutdown() ; } -void -cAudioManager::GenerateIntegerRandomNumberTable() -{ - for(int32 i = 0; i < 5; i++) { m_anRandomTable[i] = rand(); } -} - bool &bPlayerJustEnteredCar = *(bool *)0x6508C4; void @@ -830,6 +1136,107 @@ cAudioManager::GetPhrase(uint32 *phrase, uint32 *prevPhrase, uint32 sample, uint *prevPhrase = *phrase; } +uint8 &jumboVolOffset = *(uint8 *)0x6508ED; + +void +cAudioManager::DoJumboVolOffset() +{ + if(!(m_nTimeOfRecentCrime % (m_anRandomTable[0] % 6u + 3))) + jumboVolOffset = m_anRandomTable[1] % 60u; +} + +int32 +cAudioManager::GetPedCommentSfx(CPed *ped, int32 sound) +{ + if(ped->IsPlayer()) return GetPlayerTalkSfx(sound); + + switch(ped->m_modelIndex) { + case MI_COP: return GetCopTalkSfx(sound); + case MI_SWAT: return GetSwatTalkSfx(sound); + case MI_FBI: return GetFBITalkSfx(sound); + case MI_ARMY: return GetArmyTalkSfx(sound); + case MI_MEDIC: return GetMedicTalkSfx(sound); + case MI_FIREMAN: return GetFiremanTalkSfx(sound); + case MI_MALE01: return GetNormalMaleTalkSfx(sound); + case MI_TAXI_D: return GetTaxiDriverTalkSfx(sound); + case MI_PIMP: return GetPimpTalkSfx(sound); + case MI_GANG01: + case MI_GANG02: return GetMafiaTalkSfx(sound); + case MI_GANG03: + case MI_GANG04: return GetTriadTalkSfx(sound); + case MI_GANG05: + case MI_GANG06: return GetDiabloTalkSfx(sound); + case MI_GANG07: + case MI_GANG08: return GetYakuzaTalkSfx(sound); + case MI_GANG09: + case MI_GANG10: return GetYardieTalkSfx(sound); + case MI_GANG11: + case MI_GANG12: return GetColumbianTalkSfx(sound); + case MI_GANG13: + case MI_GANG14: return GetHoodTalkSfx(sound); + case MI_CRIMINAL01: return GetBlackCriminalTalkSfx(sound); + case MI_CRIMINAL02: return GetWhiteCriminalTalkSfx(sound); + case MI_SPECIAL01: + case MI_SPECIAL02: + case MI_SPECIAL03: + case MI_SPECIAL04: return GetSpecialCharacterTalkSfx(ped->m_modelIndex, sound); + case MI_MALE02: return GetMaleNo2TalkSfx(sound); + case MI_MALE03: + case MI_P_MAN1: + case MI_P_MAN2: return GetBlackProjectMaleTalkSfx(sound, ped->m_modelIndex); + case MI_FATMALE01: return GetWhiteFatMaleTalkSfx(sound); + case MI_FATMALE02: return GetBlackFatMaleTalkSfx(sound); + case MI_FEMALE01: return GetBlackCasualFemaleTalkSfx(sound); + case MI_FEMALE02: + case MI_CAS_WOM: return GetWhiteCasualFemaleTalkSfx(sound); + case MI_FEMALE03: return GetFemaleNo3TalkSfx(sound); + case MI_FATFEMALE01: return GetBlackFatFemaleTalkSfx(sound); + case MI_FATFEMALE02: return GetWhiteFatFemaleTalkSfx(sound); + case MI_PROSTITUTE: return GetBlackFemaleProstituteTalkSfx(sound); + case MI_PROSTITUTE2: return GetWhiteFemaleProstituteTalkSfx(sound); + case MI_P_WOM1: return GetBlackProjectFemaleOldTalkSfx(sound); + case MI_P_WOM2: return GetBlackProjectFemaleYoungTalkSfx(sound); + case MI_CT_MAN1: return GetChinatownMaleOldTalkSfx(sound); + case MI_CT_MAN2: return GetChinatownMaleYoungTalkSfx(sound); + case MI_CT_WOM1: return GetChinatownFemaleOldTalkSfx(sound); + case MI_CT_WOM2: return GetChinatownFemaleYoungTalkSfx(sound); + case MI_LI_MAN1: + case MI_LI_MAN2: return GetLittleItalyMaleTalkSfx(sound); + case MI_LI_WOM1: return GetLittleItalyFemaleOldTalkSfx(sound); + case MI_LI_WOM2: return GetLittleItalyFemaleYoungTalkSfx(sound); + case MI_DOCKER1: return GetWhiteDockerMaleTalkSfx(sound); + case MI_DOCKER2: return GetBlackDockerMaleTalkSfx(sound); + case MI_SCUM_MAN: return GetScumMaleTalkSfx(sound); + case MI_SCUM_WOM: return GetScumFemaleTalkSfx(sound); + case MI_WORKER1: return GetWhiteWorkerMaleTalkSfx(sound); + case MI_WORKER2: return GetBlackWorkerMaleTalkSfx(sound); + case MI_B_MAN1: + case MI_B_MAN3: return GetBusinessMaleYoungTalkSfx(sound, ped->m_modelIndex); + case MI_B_MAN2: return GetBusinessMaleOldTalkSfx(sound); + case MI_B_WOM1: + case MI_B_WOM2: return GetWhiteBusinessFemaleTalkSfx(sound, ped->m_modelIndex); + case MI_B_WOM3: return GetBlackBusinessFemaleTalkSfx(sound); + case MI_MOD_MAN: return GetSupermodelMaleTalkSfx(sound); + case MI_MOD_WOM: return GetSupermodelFemaleTalkSfx(sound); + case MI_ST_MAN: return GetStewardMaleTalkSfx(sound); + case MI_ST_WOM: return GetStewardFemaleTalkSfx(sound); + case MI_FAN_MAN1: + case MI_FAN_MAN2: return GetFanMaleTalkSfx(sound, ped->m_modelIndex); + case MI_FAN_WOM: return GetFanFemaleTalkSfx(sound); + case MI_HOS_MAN: return GetHospitalMaleTalkSfx(sound); + case MI_HOS_WOM: return GetHospitalFemaleTalkSfx(sound); + case MI_CONST1: return GetWhiteConstructionWorkerTalkSfx(sound); + case MI_CONST2: return GetBlackConstructionWorkerTalkSfx(sound); + case MI_SHOPPER1: + case MI_SHOPPER2: + case MI_SHOPPER3: return GetShopperFemaleTalkSfx(sound, ped->m_modelIndex); + case MI_STUD_MAN: return GetStudentMaleTalkSfx(sound); + case MI_STUD_WOM: return GetStudentFemaleTalkSfx(sound); + case MI_CAS_MAN: return GetCasualMaleOldTalkSfx(sound); + default: return GetGenericMaleTalkSfx(sound); + } +} + uint32 cAudioManager::GetPlayerTalkSfx(int16 sound) { @@ -2953,6 +3360,2260 @@ cAudioManager::GetGenericFemaleTalkSfx(int16 sound) return sfx; } +#if 1 + +WRAPPER +void +cAudioManager::ProcessActiveQueues() +{ + EAXJMP(0x57BA60); +} + +#else +void +cAudioManager::ProcessActiveQueues() +{ + int v3; // ecx + cAudioManager *v4; // edx + tActiveSample *v5; // ebx + cAudioManager *v6; // edi + tActiveSample *v7; // esi + char v8; // al + unsigned __int8 v9; // dl + double v10; // st7 + double v11; // st6 + float a4; // ST08_4 + float a3; // ST04_4 + int activeSampleFreq; // ecx + int freq; // edi + int newFreq; // ecx + int v17; // eax + char v18; // al + unsigned __int8 v19; // al + float v20; // ST0C_4 + int v21; // edx + unsigned __int8 v22; // bl + cAudioManager *v23; // ebp + int v24; // ecx + cAudioManager *v25; // edx + tActiveSample *v26; // ebx + cAudioManager *v27; // ebp + unsigned int v28; // edi + unsigned int v29; // eax + unsigned __int8 v30; // cl + double v31; // st4 + double v32; // st7 + double v33; // st6 + double v34; // st5 + float v35; // ST0C_4 + float v36; // ST08_4 + float v37; // ST04_4 + float v38; // ST0C_4 + int v39; // edx + int v40; // [esp+Ch] [ebp-58h] + int v41; // [esp+Ch] [ebp-58h] + unsigned int v42; // [esp+10h] [ebp-54h] + int v43; // [esp+10h] [ebp-54h] + char v44; // [esp+14h] [ebp-50h] + unsigned __int8 v45; // [esp+14h] [ebp-50h] + unsigned __int8 l; // [esp+24h] [ebp-40h] + unsigned __int8 j; // [esp+28h] [ebp-3Ch] + unsigned __int8 k; // [esp+34h] [ebp-30h] + unsigned __int8 i; // [esp+38h] [ebp-2Ch] + CVector a2; // [esp+48h] [ebp-1Ch] + + for(uint32 i = 0; i < m_bActiveSamples; i++) { + m_asSamples[m_bActiveSampleQueue][i].m_bIsProcessed = 0; + m_asActiveSamples[i].m_bIsProcessed = 0; + } + + for(i = 0;; ++i) { + v21 = m_bActiveSampleQueue; + if(i >= m_bSampleRequestQueuesStatus[v21]) break; + v3 = i + 27 * v21; + v4 = (this + 2484 * v21); + v5 = &v4->m_asSamples[m_abSampleQueueIndexTable[v3]]; + if(v4->m_asSamples[m_abSampleQueueIndexTable[v3]].m_nSampleIndex != NO_SAMPLE) { + v6 = this; + for(j = 0;; ++j) { + if(j >= m_bActiveSamples) goto LABEL_58; + v7 = m_asActiveSamples; + if(v5->m_nEntityIndex == m_asActiveSamples[0].m_nEntityIndex && + v5->field_4 == m_asActiveSamples[0].field_4 && + v5->m_nSampleIndex == m_asActiveSamples[0].m_nSampleIndex) { + break; + } + LABEL_56: + v6 = (v6 + 92); + } + if(v5->m_nLoopCount) { + if(m_nTimeOfRecentCrime & 1) { + if(!(j & 1)) { + v8 = 0; + goto LABEL_17; + } + LABEL_16: + v8 = 1; + } else { + if(!(j & 1)) goto LABEL_16; + v8 = 0; + } + LABEL_17: + if(v8 && !cSampleManager.GetChannelUsedFlag(j)) { + v5->m_bLoopEnded = 1; + m_asActiveSamples[0].m_bLoopEnded = 1; + m_asActiveSamples[0].m_nSampleIndex = NO_SAMPLE; + v7->m_nEntityIndex = -5; + goto LABEL_56; + } + } + v5->m_bIsProcessed = 1; + m_asActiveSamples[0].m_bIsProcessed = 1; + v5->field_88 = -1; + if(!v5->field_56) { + if(v5->m_bIsDistant) { + if(field_4) { + v9 = v5->m_bEmittingVolume; + if(v9 >= 63u) + v42 = 63; + else + v42 = v9; + v43 = 2 * v42; + } else { + v43 = v5->m_bEmittingVolume; + } + cSampleManager.SetChannelFrequency(j, v5->m_nFrequency); + cSampleManager.SetChannelEmittingVolume(j, v43); + } else { + v10 = m_asActiveSamples[0].m_fDistance; + v11 = v5->m_fDistance; + m_asActiveSamples[0].m_fDistance = v5->m_fDistance; + a4 = v11; + a3 = v10; + v5->m_nFrequency = ComputeDopplerEffectedFrequency( + v5->m_nFrequency, a3, a4, v5->field_48); + activeSampleFreq = m_asActiveSamples[0].m_nFrequency; + freq = v5->m_nFrequency; + if(freq != activeSampleFreq) { + if(freq <= activeSampleFreq) { + if(activeSampleFreq - 6000 > freq) + freq = activeSampleFreq - 6000; + newFreq = freq; + } else if(activeSampleFreq + 6000 >= freq) { + newFreq = v5->m_nFrequency; + } else { + newFreq = activeSampleFreq + 6000; + } + v7->m_nFrequency = newFreq; + cSampleManager.SetChannelFrequency(j, newFreq); + } + v40 = v7->m_bEmittingVolume; + v17 = v5->m_bEmittingVolume; + if(v17 != v40) { + if(v17 <= v40) { + if(v40 - 10 > v17) v17 = v40 - 10; + v41 = v17; + } else if(v40 + 10 >= v17) { + v41 = v5->m_bEmittingVolume; + } else { + v41 = v40 + 10; + } + if(field_4) { + if(v41 >= 63) + v18 = 63; + else + v18 = v41; + v19 = 2 * v18; + } else { + v19 = v41; + } + cSampleManager.SetChannelEmittingVolume(j, v19); + v7->m_bEmittingVolume = v41; + } + TranslateEntity(&v5->m_vecPos, &a2); + cSampleManager.SetChannel3DPosition(j, a2.x, a2.y, a2.z); + v20 = 0.25f * v5->m_fSoundIntensity; + cSampleManager.SetChannel3DDistances( + j, v5->m_fSoundIntensity, v20); + } + cSampleManager.SetChannelReverbFlag(j, v5->m_bReverbFlag); + continue; + } + v5->m_bIsProcessed = 0; + m_asActiveSamples[0].m_bIsProcessed = 0; + goto LABEL_56; + } + LABEL_58:; + } + v22 = 0; + v23 = this; + for(uint32 i = 0; v22 < m_bActiveSamples; i++) { + if(v23->m_asActiveSamples[0].m_nSampleIndex != NO_SAMPLE && + !v23->m_asActiveSamples[0].m_bIsProcessed) { + cSampleManager.StopChannel(i); + v23->m_asActiveSamples[0].m_nSampleIndex = NO_SAMPLE; + v23->m_asActiveSamples[0].m_nEntityIndex = -5; + } + v23 = (v23 + 92); + } + for(k = 0; k < m_bSampleRequestQueuesStatus[m_bActiveSampleQueue]; ++k) { + v24 = k + 27 * v39; + v25 = (this + 2484 * v39); + v26 = &v25->m_asSamples[m_abSampleQueueIndexTable[v24]]; + if(!v25->m_asSamples[m_abSampleQueueIndexTable[v24]].m_bIsProcessed && + !v25->m_asSamples[m_abSampleQueueIndexTable[v24]].m_bLoopEnded && + m_asAudioEntities[v26->m_nEntityIndex].m_bIsUsed && + v25->m_asSamples[m_abSampleQueueIndexTable[v24]].m_nSampleIndex < NO_SAMPLE) { + if(v25->m_asSamples[m_abSampleQueueIndexTable[v24]].field_4 > 255u && + v25->m_asSamples[m_abSampleQueueIndexTable[v24]].m_nLoopCount && + v25->m_asSamples[m_abSampleQueueIndexTable[v24]].m_bLoopsRemaining) { + --v25->m_asSamples[m_abSampleQueueIndexTable[v24]] + .m_bLoopsRemaining; + v26->field_76 = 1; + } else { + v27 = this; + for(l = 0; l < m_bActiveSamples; ++l) { + if(!v27->m_asActiveSamples[0].m_bIsProcessed) { + if(!v26->m_nLoopCount) goto LABEL_80; + v28 = v26->m_nFrequency / field_19192; + v29 = v26->m_nLoopCount * + cSampleManager.GetSampleLength( + v26->m_nSampleIndex); + if(v28) { + v26->field_76 = v29 / v28 + 1; + LABEL_80: + memcpy(v27->m_asActiveSamples, v26, 92); + if(!v27->m_asActiveSamples[0].m_bIsDistant) + TranslateEntity( + &v27->m_asActiveSamples[0] + .m_vecPos, + &a2); + if(field_4) { + if(v27->m_asActiveSamples[0] + .m_bEmittingVolume >= 63u) + v44 = 63; + else + v44 = + v27 + ->m_asActiveSamples + [0] + .m_bEmittingVolume; + v45 = 2 * v44; + } else { + v45 = v27->m_asActiveSamples[0] + .m_bEmittingVolume; + } + if(cSampleManager.InitialiseChannel( + l, + v27->m_asActiveSamples[0] + .m_nSampleIndex, + v27->m_asActiveSamples[0] + .m_bBankIndex)) { + cSampleManager.SetChannelFrequency( + l, v27->m_asActiveSamples[0] + .m_nFrequency); + cSampleManager + .SetChannelEmittingVolume(l, + v45); + cSampleManager.SetChannelLoopPoints( + l, + v27->m_asActiveSamples[0] + .m_nLoopStart, + v27->m_asActiveSamples[0] + .m_nLoopEnd); + cSampleManager.SetChannelLoopCount( + l, v27->m_asActiveSamples[0] + .m_nLoopCount); + cSampleManager.SetChannelReverbFlag( + l, v27->m_asActiveSamples[0] + .m_bReverbFlag); + if(v27->m_asActiveSamples[0] + .m_bIsDistant) { + v30 = v27->m_asActiveSamples + [0] + .m_bOffset; + if(v30 == 63) { + v31 = 0.0f; + } else if(v30 >= 63u) { + v31 = (v30 - 63) * + 15.873f; + } else { + v31 = -((63 - v30) * + 15.873f); + } + v32 = v31; + v33 = 0.0f; + v34 = 0.0f; + v27->m_asActiveSamples[0] + .m_fSoundIntensity = + 100000.0f; + } else { + v32 = a2.x; + v33 = a2.y; + v34 = a2.z; + } + v35 = v34; + v36 = v33; + v37 = v32; + cSampleManager.SetChannel3DPosition( + l, v37, v36, v35); + v38 = 0.25f * + v27->m_asActiveSamples[0] + .m_fSoundIntensity; + cSampleManager + .SetChannel3DDistances( + l, + v27->m_asActiveSamples[0] + .m_fSoundIntensity, + v38); + cSampleManager.StartChannel(l); + } + v27->m_asActiveSamples[0].m_bIsProcessed = + 1; + v26->m_bIsProcessed = 1; + v26->field_88 = -1; + break; + } + } + v27 = (v27 + 92); + } + } + } + } +} +#endif + +bool +cAudioManager::ProcessAirBrakes(cVehicleParams *params) +{ + CAutomobile *automobile; + uint8 rand; + + if(params->m_fDistance > 900.0f) return 0; + automobile = (CAutomobile *)params->m_pVehicle; + if(!automobile->bEngineOn) return 1; + + if((automobile->m_fVelocityChangeForAudio < 0.025f || + params->m_fVelocityChange >= 0.025f) && + (automobile->m_fVelocityChangeForAudio > -0.025f || params->m_fVelocityChange <= 0.025f)) + return 1; + + CalculateDistance((bool *)params, params->m_fDistance); + rand = m_anRandomTable[0] % 10u + 70; + m_sQueueSample.m_bVolume = ComputeVolume(rand, 30.0f, m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.field_4 = 13; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_VEHICLE_AIR_BRAKES; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_VEHICLE_AIR_BRAKES); + m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency >> 4); + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.field_16 = 10; + m_sQueueSample.m_nLoopCount = 1; + m_sQueueSample.m_bEmittingVolume = rand; + m_sQueueSample.m_nLoopStart = 0; + m_sQueueSample.m_nLoopEnd = -1; + m_sQueueSample.field_48 = 0.0f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.field_56 = 1; + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); + } + + return 1; +} + +void +cAudioManager::ProcessAirportScriptObject(uint8 sound) +{ + + float dist; + float distSquared; + float maxDist; + + static uint8 counter = 0; + + uint32 time = CTimer::GetTimeInMilliseconds(); + if(time > audioLogicTimers[3]) { + switch(sound) { + case SCRIPT_SOUND_AIRPORT_LOOP_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + break; + case SCRIPT_SOUND_AIRPORT_LOOP_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + break; + default: break; + } + distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos); + if(distSquared < maxDist) { + dist = sqrt(distSquared); + m_sQueueSample.m_fDistance = dist; + m_sQueueSample.m_bVolume = ComputeVolume( + 110u, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.m_nSampleIndex = + (m_anRandomTable[1] & 3) + AUDIO_SAMPLE_AIRPORT_1; + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency( + m_sQueueSample.m_nSampleIndex); + m_sQueueSample.field_4 = counter++; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.m_nLoopCount = 1; + m_sQueueSample.field_56 = 1; + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_48 = 2.0f; + m_sQueueSample.m_bEmittingVolume = 110; + m_sQueueSample.m_nLoopStart = 0; + m_sQueueSample.m_nLoopEnd = -1; + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); + audioLogicTimers[3] = time + 10000 + m_anRandomTable[3] % 20000u; + } + } + } +} + +WRAPPER +bool +cAudioManager::ProcessBoatEngine(cVehicleParams *params) +{ + EAXJMP(0x56DE80); +} + +WRAPPER +bool +cAudioManager::ProcessBoatMovingOverWater(cVehicleParams *params) +{ + EAXJMP(0x56E500); +} + +WRAPPER +void +cAudioManager::ProcessBridge() +{ + EAXJMP(0x5790D0); +} + +void +cAudioManager::ProcessBridgeMotor() +{ + if(m_sQueueSample.m_fDistance < 400.f) { + m_sQueueSample.m_bVolume = ComputeVolume(127, 400.f, m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.field_4 = 1; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_MOTOR; + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.field_16 = 1; + m_sQueueSample.m_nFrequency = 5500; + m_sQueueSample.m_nLoopCount = 0; + m_sQueueSample.m_bEmittingVolume = 127; + m_sQueueSample.m_nLoopStart = + cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_nLoopEnd = + cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.field_48 = 2.0f; + m_sQueueSample.m_fSoundIntensity = 400.0f; + m_sQueueSample.field_56 = 0; + m_sQueueSample.field_76 = 3; + m_sQueueSample.m_bReverbFlag = 0; + AddSampleToRequestedQueue(); + } + } +} + +WRAPPER +void +cAudioManager::ProcessBridgeOneShots() +{ + EAXJMP(0x579310); +} + +void +cAudioManager::ProcessBridgeWarning() +{ + if(CStats::CommercialPassed && m_sQueueSample.m_fDistance < 450.f) { + m_sQueueSample.m_bVolume = ComputeVolume(100u, 450.f, m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.field_4 = 0; + m_sQueueSample.m_nSampleIndex = 457; + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.field_16 = 1; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_BRIDGE_WARNING); + m_sQueueSample.m_nLoopCount = 0; + m_sQueueSample.m_bEmittingVolume = 100; + m_sQueueSample.m_nLoopStart = + cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_nLoopEnd = + cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.field_48 = 2.0f; + m_sQueueSample.m_fSoundIntensity = 450.0f; + m_sQueueSample.field_56 = 0; + m_sQueueSample.field_76 = 8; + m_sQueueSample.m_bReverbFlag = 0; + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); + } + } +} + +WRAPPER +bool +cAudioManager::ProcessCarBombTick(void *) +{ + EAXJMP(0x56CC20); +} + +WRAPPER +void +cAudioManager::ProcessCesna(void *) +{ + EAXJMP(0x56ADF0); +} + +void +cAudioManager::ProcessCinemaScriptObject(uint8 sound) +{ + uint8 rand; + float distSquared; + float maxDist; + + static uint8 counter = 0; + + uint32 time = CTimer::GetTimeInMilliseconds(); + if(time > audioLogicTimers[4]) { + switch(sound) { + case SCRIPT_SOUND_CINEMA_LOOP_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + break; + case SCRIPT_SOUND_CINEMA_LOOP_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + break; + default: break; + } + distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos); + if(distSquared < maxDist) { + m_sQueueSample.m_fDistance = sqrt(distSquared); + rand = m_anRandomTable[0] % 90u + 30; + m_sQueueSample.m_bVolume = ComputeVolume( + rand, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.m_nSampleIndex = counter % 3 + AUDIO_SAMPLE_CINEMA_1; + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency( + m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_nFrequency += + RandomDisplacement(m_sQueueSample.m_nFrequency >> 2); + m_sQueueSample.field_4 = counter++; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.m_nLoopCount = 1; + m_sQueueSample.field_56 = 1; + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_48 = 2.0f; + m_sQueueSample.m_bEmittingVolume = rand; + m_sQueueSample.m_nLoopStart = 0; + m_sQueueSample.m_nLoopEnd = -1; + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); + audioLogicTimers[4] = time + 1000 + m_anRandomTable[3] % 4000u; + } + } + } +} + +WRAPPER +void +cAudioManager::ProcessCrane() +{ + EAXJMP(0x578910); +} + +void +cAudioManager::ProcessDocksScriptObject(uint8 sound) +{ + uint32 time; + uint8 rand; + float distSquared; + float maxDist; + + static uint32 counter = 0; + + time = CTimer::GetTimeInMilliseconds(); + if(time > audioLogicTimers[5]) { + switch(sound) { + case SCRIPT_SOUND_DOCKS_LOOP_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + break; + case SCRIPT_SOUND_DOCKS_LOOP_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + break; + default: break; + } + distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos); + if(distSquared < maxDist) { + m_sQueueSample.m_fDistance = sqrt(distSquared); + rand = m_anRandomTable[0] % 60u + 40; + m_sQueueSample.m_bVolume = ComputeVolume( + rand, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_DOCKS; + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_DOCKS); + m_sQueueSample.m_nFrequency += + RandomDisplacement(m_sQueueSample.m_nFrequency >> 3); + m_sQueueSample.field_4 = counter++; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.m_nLoopCount = 1; + m_sQueueSample.field_56 = 1; + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_48 = 2.0f; + m_sQueueSample.m_bEmittingVolume = rand; + m_sQueueSample.m_nLoopStart = 0; + m_sQueueSample.m_nLoopEnd = -1; + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); + audioLogicTimers[5] = time + 10000 + m_anRandomTable[3] % 40000u; + } + } + } +} + +void +cAudioManager::ProcessEntity(int32 id) +{ + if(m_asAudioEntities[id].m_bStatus) { + m_sQueueSample.m_nEntityIndex = id; + switch(m_asAudioEntities[id].m_nType) { + case AUDIOTYPE_PHYSICAL: + if(!m_bUserPause) { + m_sQueueSample.m_bReverbFlag = 1; + cAudioManager::ProcessPhysical(id); + } + break; + case AUDIOTYPE_EXPLOSION: + if(!m_bUserPause) { + m_sQueueSample.m_bReverbFlag = 1; + cAudioManager::ProcessExplosions(id); + } + break; + case AUDIOTYPE_FIRE: + if(!m_bUserPause) { + m_sQueueSample.m_bReverbFlag = 1; + cAudioManager::ProcessFires(id); + } + break; + case AUDIOTYPE_WEATHER: + if(!m_bUserPause) { + m_sQueueSample.m_bReverbFlag = 1; + cAudioManager::ProcessWeather(id); + } + break; + case AUDIOTYPE_CRANE: + if(!m_bUserPause) { + m_sQueueSample.m_bReverbFlag = 1; + cAudioManager::ProcessCrane(); + } + break; + case AUDIOTYPE_ONE_SHOT: + if(!m_bUserPause) { + m_sQueueSample.m_bReverbFlag = 1; + cAudioManager::ProcessScriptObject(id); + } + break; + case AUDIOTYPE_BRIDGE: + if(!m_bUserPause) { + m_sQueueSample.m_bReverbFlag = 1; + cAudioManager::ProcessBridgeOneShots(); + } + break; + case AUDIOTYPE_FRONTEND: + m_sQueueSample.m_bReverbFlag = 0; + cAudioManager::ProcessFrontEnd(); + break; + case AUDIOTYPE_PROJECTILE: + if(!m_bUserPause) { + m_sQueueSample.m_bReverbFlag = 1; + cAudioManager::ProcessProjectiles(); + } + break; + case AUDIOTYPE_GARAGE: + if(!m_bUserPause) cAudioManager::ProcessGarages(); + break; + case AUDIOTYPE_HYDRANT: + if(!m_bUserPause) { + m_sQueueSample.m_bReverbFlag = 1; + cAudioManager::ProcessFireHydrant(); + } + break; + case AUDIOTYPE_WATER_CANNON: + if(!m_bUserPause) { + m_sQueueSample.m_bReverbFlag = 1; + cAudioManager::ProcessWaterCannon(id); + } + break; + default: return; + } + } +} + +WRAPPER +void +cAudioManager::ProcessExplosions(int32 explosion) +{ + EAXJMP(0x575AC0); +} + +void +cAudioManager::ProcessFireHydrant() +{ + float distSquared; + bool something = false; + + m_sQueueSample.m_vecPos = + *(CVector *)((size_t)m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_pEntity + 52); + distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos); + if(distSquared < 1225.f) { + CalculateDistance(&something, distSquared); + m_sQueueSample.m_bVolume = ComputeVolume(40u, 35.f, m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.field_4 = 0; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_JUMBO_TAXI_SOUND; + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.field_16 = 4; + m_sQueueSample.m_nFrequency = 15591; + m_sQueueSample.m_nLoopCount = 0; + m_sQueueSample.m_bEmittingVolume = 40; + m_sQueueSample.m_nLoopStart = + cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_nLoopEnd = + cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.field_48 = 2.0f; + m_sQueueSample.m_fSoundIntensity = 35.0f; + m_sQueueSample.field_56 = 0; + m_sQueueSample.field_76 = 3; + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); + } + } +} + +WRAPPER +void +cAudioManager::ProcessFires(int32 entity) +{ + EAXJMP(0x575CD0); +} + +void +cAudioManager::ProcessFrontEnd() +{ + bool processed; + int16 sample; + + static uint32 counter = 0; + + for(uint32 i = 0; i < m_asAudioEntities[m_sQueueSample.m_nEntityIndex].field_24; i++) { + processed = 0; + switch( + m_asAudioEntities[0].m_awAudioEvent[i + 20 * m_sQueueSample.m_nEntityIndex]) { + case SOUND_WEAPON_SNIPER_SHOT_NO_ZOOM: + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_SNIPER_NO_ZOOM; + break; + case SOUND_WEAPON_ROCKET_SHOT_NO_ZOOM: + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_ROCKET_NO_ZOOM; + break; + case SOUND_GARAGE_NO_MONEY: + case SOUND_GARAGE_BAD_VEHICLE: + case SOUND_3C: + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PICKUP_FAIL_1; + processed = 1; + break; + case SOUND_GARAGE_OPENING: + case SOUND_GARAGE_BOMB1_SET: + case SOUND_GARAGE_BOMB2_SET: + case SOUND_GARAGE_BOMB3_SET: + case SOUND_41: + case SOUND_GARAGE_VEHICLE_DECLINED: + case SOUND_GARAGE_VEHICLE_ACCEPTED: + case SOUND_PICKUP_HEALTH: + case SOUND_4B: + case SOUND_PICKUP_ADRENALINE: + case SOUND_PICKUP_ARMOUR: + case SOUND_EVIDENCE_PICKUP: + case SOUND_UNLOAD_GOLD: + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PICKUP_SUCCESS_1; + processed = 1; + break; + case SOUND_PICKUP_WEAPON_BOUGHT: + case SOUND_PICKUP_WEAPON: + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PICKUP_NEUTRAL_1; + processed = 1; + break; + case SOUND_4A: + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PICKUP_FAIL_1; + processed = 1; + break; + case SOUND_PICKUP_BONUS: + case SOUND_PICKUP_MONEY: + case SOUND_PICKUP_HIDDEN_PACKAGE: + case SOUND_PICKUP_PACMAN_PILL: + case SOUND_PICKUP_PACMAN_PACKAGE: + case SOUND_PICKUP_FLOAT_PACKAGE: + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PICKUP_SUCCESS_3; + processed = 1; + break; + case SOUND_PAGER: m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PAGER; break; + case SOUND_RACE_START_3: + case SOUND_RACE_START_2: + case SOUND_RACE_START_1: + case SOUND_CLOCK_TICK: + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FRONTEND_CLOCK_TICK; + break; + case SOUND_RACE_START_GO: + m_sQueueSample.m_nSampleIndex = + AUDIO_SAMPLE_FRONTEND_PART_MISSION_COMPLETED; + break; + case SOUND_PART_MISSION_COMPLETE: + m_sQueueSample.m_nSampleIndex = + AUDIO_SAMPLE_FRONTEND_PART_MISSION_COMPLETED; + break; + case SOUND_FRONTEND_MENU_STARTING: + processed = 1; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FRONTEND_MENU_STARTING_1; + break; + case SOUND_FRONTEND_MENU_COMPLETED: + processed = 1; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FRONTEND_MENU_COMPLETED_1; + break; + case SOUND_FRONTEND_MENU_DENIED: + processed = 1; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FRONTEND_MENU_DENIED_1; + break; + case SOUND_FRONTEND_MENU_SUCCESS: + processed = 1; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FRONTEND_MENU_SUCCESS_1; + break; + case SOUND_FRONTEND_EXIT: + processed = 1; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FRONTEND_MENU_EXIT_1; + break; + case SOUND_9A: + processed = 1; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_380; + break; + case SOUND_9B: m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_382; break; + case SOUND_FRONTEND_AUDIO_TEST: + m_sQueueSample.m_nSampleIndex = + m_anRandomTable[0] % 3u + AUDIO_SAMPLE_FRONTEND_MENU_AUDIO_TEST_1; + break; + case SOUND_FRONTEND_FAIL: + processed = 1; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FRONTEND_MENU_FAIL_1; + break; + case SOUND_FRONTEND_NO_RADIO: + case SOUND_FRONTEND_RADIO_CHANGE: + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FRONTEND_GAMEPLAY_FAIL; + break; + case SOUND_A0: + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FRONTEND_GAMEPLAY_SUCCESS; + break; + default: continue; + } + + sample = + m_asAudioEntities[0].m_awAudioEvent[i + 20 * m_sQueueSample.m_nEntityIndex]; + if(sample == AUDIO_SAMPLE_COLLISION_LOOPING_GRASS) { + m_sQueueSample.m_nFrequency = 28509; + } else if(sample == AUDIO_SAMPLE_PICKUP_NEUTRAL_1) { + if(1.f == + m_asAudioEntities[0].m_afVolume[i + 10 * m_sQueueSample.m_nEntityIndex]) + m_sQueueSample.m_nFrequency = 32000; + else + m_sQueueSample.m_nFrequency = 48000; + } else { + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex); + } + m_sQueueSample.m_bVolume = 110; + m_sQueueSample.field_4 = counter++; + m_sQueueSample.m_nLoopCount = 1; + m_sQueueSample.field_56 = 1; + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.field_16 = 0; + m_sQueueSample.m_bIsDistant = 1; + m_sQueueSample.m_bEmittingVolume = m_sQueueSample.m_bVolume; + m_sQueueSample.m_nLoopStart = 0; + m_sQueueSample.m_nLoopEnd = -1; + if(processed) + m_sQueueSample.m_bOffset = m_anRandomTable[0] & 0x1F; + else + m_sQueueSample.m_bOffset = 63; + m_sQueueSample.m_bReverbFlag = 0; + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); + if(processed) { + ++m_sQueueSample.m_nSampleIndex; + m_sQueueSample.field_4 = counter++; + m_sQueueSample.m_bOffset = 127 - m_sQueueSample.m_bOffset; + AddSampleToRequestedQueue(); + } + } +} + +WRAPPER +void +cAudioManager::ProcessGarages() +{ + EAXJMP(0x578C20); +} + +void +cAudioManager::ProcessHomeScriptObject(uint8 sound) +{ + uint32 time; + uint8 rand; + float dist; + float maxDist; + + static uint8 counter = 0; + + time = CTimer::GetTimeInMilliseconds(); + if(time > audioLogicTimers[6]) { + switch(sound) { + case SCRIPT_SOUND_HOME_LOOP_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + break; + case SCRIPT_SOUND_HOME_LOOP_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + break; + default: break; + } + dist = GetDistanceSquared(&m_sQueueSample.m_vecPos); + if(dist < maxDist) { + m_sQueueSample.m_fDistance = sqrt(dist); + rand = m_anRandomTable[0] % 30u + 40; + m_sQueueSample.m_bVolume = ComputeVolume( + rand, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.m_nSampleIndex = + m_anRandomTable[0] % 5u + AUDIO_SAMPLE_HOME_1; + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency( + m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_nFrequency += + RandomDisplacement(m_sQueueSample.m_nFrequency >> 4); + m_sQueueSample.field_4 = counter++; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.m_nLoopCount = 1; + m_sQueueSample.field_56 = 1; + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_48 = 0.0f; + m_sQueueSample.m_bEmittingVolume = rand; + m_sQueueSample.m_nLoopStart = 0; + m_sQueueSample.m_nLoopEnd = -1; + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.m_bRequireReflection = 1; + AddSampleToRequestedQueue(); + audioLogicTimers[6] = time + 1000 + m_anRandomTable[3] % 4000u; + } + } + } +} + +float *PlanePathPosition = (float *)0x8F5FC8; +float &LandingPoint = *(float *)0x8F2C7C; +float &TakeOffPoint = *(float *)0x8E28A4; + +void +cAudioManager::ProcessJumbo(cVehicleParams *params) +{ + CPlane *plane; + float position; + + if(params->m_fDistance < 193600.0f) { + CalculateDistance((bool *)params, params->m_fDistance); + plane = (CPlane *)params->m_pVehicle; + DoJumboVolOffset(); + position = PlanePathPosition[plane->m_wIndex]; + if(position <= TakeOffPoint) { + if(plane->field_656 <= 0.10334f) { + ProcessJumboTaxi(); + return; + } + + ProcessJumboAccel(plane); + } else if(300.0f + TakeOffPoint >= position) { + ProcessJumboTakeOff(plane); + } else if(LandingPoint - 350.0f >= position) { + ProcessJumboFlying(); + } else { + if(position > LandingPoint) { + if(plane->field_656 > 0.10334f) { + ProcessJumboDecel(plane); + return; + } + ProcessJumboTaxi(); + return; + } + ProcessJumboLanding(plane); + } + } +} + +void +cAudioManager::ProcessJumboAccel(CPlane *plane) +{ + int32 engineFreq; + int32 vol; + float whineSoundFreq; + float modificator; + + if(SetupJumboFlySound(20u)) { + modificator = (plane->field_656 - 0.10334f) * 1.676f; + if(modificator > 1.0f) modificator = 1.0f; + if(cAudioManager::SetupJumboRumbleSound(maxVolume * modificator) && + SetupJumboTaxiSound((1.0f - modificator) * 75.f)) { + if(modificator < 0.2f) { + whineSoundFreq = modificator * 5.f * 14600.0f + 29500; + vol = modificator * 5.f * maxVolume; + engineFreq = modificator * 5.f * 6050.f + 16000; + } else { + whineSoundFreq = 44100; + engineFreq = 22050; + vol = maxVolume; + } + SetupJumboEngineSound(vol, engineFreq); + SetupJumboWhineSound(18u, whineSoundFreq); + } + } +} + +void +cAudioManager::ProcessJumboDecel(CPlane *plane) +{ + float modificator; + + if(SetupJumboFlySound(20u) && SetupJumboTaxiSound(75u)) { + modificator = (plane->field_656 - 0.10334f) * 1.676f; + if(modificator > 1.0f) modificator = 1.0f; + SetupJumboEngineSound(maxVolume * modificator, 6050.f * modificator + 16000); + SetupJumboWhineSound(18u, 29500); + } +} + +void +cAudioManager::ProcessJumboFlying() +{ + if(SetupJumboFlySound(127u)) SetupJumboEngineSound(63u, 22050); +} + +void +cAudioManager::ProcessJumboLanding(CPlane *plane) +{ + float modificator = (LandingPoint - PlanePathPosition[plane->m_wIndex]) * 0.0028571f; + if(SetupJumboFlySound(107.f * modificator + 20)) { + if(SetupJumboTaxiSound(75.f * (1.f - modificator))) { + SetupJumboEngineSound(maxVolume, 22050); + SetupJumboWhineSound(18.f * (1.f - modificator), + 14600.f * modificator + 29500); + } + } +} + +void +cAudioManager::ProcessJumboTakeOff(CPlane *plane) +{ + double modificator = (PlanePathPosition[plane->m_wIndex] - TakeOffPoint) * 0.0033333f; + + if(cAudioManager::SetupJumboFlySound((107.f * modificator) + 20) && + cAudioManager::SetupJumboRumbleSound(maxVolume * (1.f - modificator))) { + if(cAudioManager::SetupJumboEngineSound(127u, 22050)) + cAudioManager::SetupJumboWhineSound(18.f * (1.f - modificator), 44100); + } +} + +void +cAudioManager::ProcessJumboTaxi() +{ + if(SetupJumboFlySound(20u)) { + if(SetupJumboTaxiSound(75u)) SetupJumboWhineSound(18u, 29500); + } +} + +void +cAudioManager::ProcessLaunderetteScriptObject(uint8 sound) +{ + float maxDist; + float distSquared; + + switch(sound) { + case SCRIPT_SOUND_LAUNDERETTE_LOOP_S: + case SCRIPT_SOUND_LAUNDERETTE_LOOP_L: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + break; + default: break; + } + distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos); + if(distSquared < maxDist) { + m_sQueueSample.m_fDistance = sqrt(distSquared); + m_sQueueSample.m_bVolume = ComputeVolume(45u, m_sQueueSample.m_fSoundIntensity, + m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_LAUNDERETTE_1; + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_LAUNDERETTE_1); + m_sQueueSample.field_4 = 0; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.m_nLoopCount = 0; + m_sQueueSample.field_56 = 0; + m_sQueueSample.field_16 = 5; + m_sQueueSample.field_48 = 2.0f; + m_sQueueSample.m_bEmittingVolume = 45; + m_sQueueSample.m_nLoopStart = + cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_nLoopEnd = + cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); + } + m_sQueueSample.m_bVolume = ComputeVolume(110u, m_sQueueSample.m_fSoundIntensity, + m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_LAUNDERETTE_2; + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_LAUNDERETTE_2); + m_sQueueSample.field_4 = 1; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.m_nLoopCount = 0; + m_sQueueSample.field_56 = 0; + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_48 = 2.0f; + m_sQueueSample.m_bEmittingVolume = 110; + m_sQueueSample.m_nLoopStart = + cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_nLoopEnd = + cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); + } + } +} + +void +cAudioManager::ProcessLoopingScriptObject(uint8 sound) +{ + uint8 emittingVolume; + float maxDist; + float distSquared; + + switch(sound) { + case SCRIPT_SOUND_PARTY_1_LOOP_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_1; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_1); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_1_LOOP_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_1; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_1); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_2_LOOP_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_2; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_2); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_2_LOOP_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_2; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_2); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_3_LOOP_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_3; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_3); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_3_LOOP_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_3; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_3); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_4_LOOP_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_4; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_4); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_4_LOOP_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_4; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_4); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_5_LOOP_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_5; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_5); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_5_LOOP_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_5; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_5); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_6_LOOP_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_6; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_6); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_6_LOOP_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_6; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_6); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_7_LOOP_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_7; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_7); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_7_LOOP_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_7; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_7); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_8_LOOP_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_8; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_8); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_8_LOOP_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_8; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_8); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_9_LOOP_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_9; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_9); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_9_LOOP_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_9; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_9); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_10_LOOP_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_10; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_10); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_10_LOOP_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_10; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_10); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_11_LOOP_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_11; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_11); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_11_LOOP_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_11; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_11); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_12_LOOP_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_12; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_12); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_12_LOOP_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_12; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_12); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_13_LOOP_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_13; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_13); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_13_LOOP_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_13; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_13); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_STRIP_CLUB_LOOP_1_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_STRIP_CLUB_1; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_STRIP_CLUB_1); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_STRIP_CLUB_LOOP_1_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_STRIP_CLUB_1; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_STRIP_CLUB_1); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_STRIP_CLUB_LOOP_2_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_STRIP_CLUB_2; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_STRIP_CLUB_2); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_STRIP_CLUB_LOOP_2_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_STRIP_CLUB_2; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_STRIP_CLUB_2); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_WORK_SHOP_LOOP_S: + case SCRIPT_SOUND_WORK_SHOP_LOOP_L: + cAudioManager::ProcessWorkShopScriptObject(sound); + return; + case SCRIPT_SOUND_SAWMILL_LOOP_S: + case SCRIPT_SOUND_SAWMILL_LOOP_L: cAudioManager::ProcessSawMillScriptObject(sound); return; + case SCRIPT_SOUND_38: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_409; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 110; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_409); + m_sQueueSample.field_16 = 6; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_39: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_409; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 110; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_409); + m_sQueueSample.field_16 = 6; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_LAUNDERETTE_LOOP_S: + case SCRIPT_SOUND_LAUNDERETTE_LOOP_L: ProcessLaunderetteScriptObject(sound); return; + case SCRIPT_SOUND_CHINATOWN_RESTAURANT_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_CHINATOWN_RESTAURANT; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 110; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_CHINATOWN_RESTAURANT); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_CHINATOWN_RESTAURANT_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_CHINATOWN_RESTAURANT; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 110; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_CHINATOWN_RESTAURANT); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_CIPRIANI_RESAURANT_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_CIPRIANI_RESTAURANT; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 110; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_CIPRIANI_RESTAURANT); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_CIPRIANI_RESAURANT_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_CIPRIANI_RESTAURANT; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 110; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_CIPRIANI_RESTAURANT); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_46: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_414; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 110; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_414); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_47: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_414; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 110; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_414); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_MARCO_BISTRO_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_MARCO_BISTRO; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 110; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_MARCO_BISTRO); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_MARCO_BISTRO_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_MARCO_BISTRO; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 110; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_MARCO_BISTRO); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_AIRPORT_LOOP_S: + case SCRIPT_SOUND_AIRPORT_LOOP_L: ProcessAirportScriptObject(sound); return; + case SCRIPT_SOUND_SHOP_LOOP_S: + case SCRIPT_SOUND_SHOP_LOOP_L: ProcessShopScriptObject(sound); return; + case SCRIPT_SOUND_CINEMA_LOOP_S: + case SCRIPT_SOUND_CINEMA_LOOP_L: ProcessCinemaScriptObject(sound); return; + case SCRIPT_SOUND_DOCKS_LOOP_S: + case SCRIPT_SOUND_DOCKS_LOOP_L: cAudioManager::ProcessDocksScriptObject(sound); return; + case SCRIPT_SOUND_HOME_LOOP_S: + case SCRIPT_SOUND_HOME_LOOP_L: cAudioManager::ProcessHomeScriptObject(sound); return; + case SCRIPT_SOUND_FRANKIE_PIANO: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FRANKIE_PIANO; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_FRANKIE_PIANO); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PARTY_1_LOOP: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PARTY_1; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_PARTY_1); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PORN_CINEMA_1_S: + case SCRIPT_SOUND_PORN_CINEMA_1_L: + case SCRIPT_SOUND_PORN_CINEMA_2_S: + case SCRIPT_SOUND_PORN_CINEMA_2_L: + case SCRIPT_SOUND_PORN_CINEMA_3_S: + case SCRIPT_SOUND_PORN_CINEMA_3_L: + case SCRIPT_SOUND_MISTY_SEX_S: + case SCRIPT_SOUND_MISTY_SEX_L: ProcessPornCinema(sound); return; + case SCRIPT_SOUND_BANK_ALARM_LOOP_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_BANK_ALARM; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 90; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_BANK_ALARM); + m_sQueueSample.field_16 = 2; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_BANK_ALARM_LOOP_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_BANK_ALARM; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 90; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_BANK_ALARM); + m_sQueueSample.field_16 = 2; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_POLICE_BALL_LOOP_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_POLICE_BALL; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_POLICE_BALL); + m_sQueueSample.field_16 = 2; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_POLICE_BALL_LOOP_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_POLICE_BALL; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_POLICE_BALL); + m_sQueueSample.field_16 = 2; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_RAVE_LOOP_INDUSTRIAL_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_RAVE_INDUSTRIAL; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_RAVE_INDUSTRIAL); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_RAVE_LOOP_INDUSTRIAL_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_RAVE_INDUSTRIAL; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_RAVE_INDUSTRIAL); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_POLICE_CELL_BEATING_LOOP_S: + case SCRIPT_SOUND_POLICE_CELL_BEATING_LOOP_L: + cAudioManager::ProcessPoliceCellBeatingScriptObject(sound); + return; + case SCRIPT_SOUND_RAVE_1_LOOP_S: + case SCRIPT_SOUND_RAVE_2_LOOP_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_RAVE_1; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_RAVE_1_LOOP_L: + case SCRIPT_SOUND_RAVE_2_LOOP_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_RAVE_1; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_RAVE_3_LOOP_S: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_RAVE_2; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_RAVE_2); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_RAVE_3_LOOP_L: + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_RAVE_2; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 127; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_RAVE_2); + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_76 = 3; + m_sQueueSample.field_48 = 2.0f; + break; + case SCRIPT_SOUND_PRETEND_FIRE_LOOP: + maxDist = 2500.f; + m_sQueueSample.m_fSoundIntensity = 50.0f; + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_FIRE_ENTITY; + m_sQueueSample.m_bBankIndex = 0; + emittingVolume = 80; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_FIRE_ENTITY); + m_sQueueSample.field_16 = 8; + m_sQueueSample.field_76 = 10; + m_sQueueSample.field_48 = 2.0f; + break; + default: return; + } + + distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos); + if(distSquared < maxDist) { + m_sQueueSample.m_fDistance = Sqrt(distSquared); + m_sQueueSample.m_bVolume = ComputeVolume( + emittingVolume, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.field_4 = 0; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.m_nLoopCount = 0; + m_sQueueSample.field_56 = 0; + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.m_bEmittingVolume = emittingVolume; + m_sQueueSample.m_nLoopStart = + cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_nLoopEnd = + cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); + } + } +} + +WRAPPER +void +cAudioManager::ProcessPed(CPhysical *) +{ + EAXJMP(0x56F450); +} + +void +cAudioManager::ProcessPhysical(int32 id) +{ + CPhysical *entity = (CPhysical *)m_asAudioEntities[id].m_pEntity; + if(entity) { + switch(entity->m_type & 7) { + case ENTITY_TYPE_VEHICLE: + ProcessVehicle((CVehicle *)m_asAudioEntities[id].m_pEntity); + break; + case ENTITY_TYPE_PED: + ProcessPed((CPhysical *)m_asAudioEntities[id].m_pEntity); + break; + default: return; + } + } +} + +WRAPPER +void +cAudioManager::ProcessPlane(void *ptr) +{ + EAXJMP(0x56E860); +} + +WRAPPER +void +cAudioManager::ProcessPoliceCellBeatingScriptObject(uint8 sound) +{ + EAXJMP(0x578190); +} + +void +cAudioManager::ProcessPornCinema(uint8 sound) +{ + + eAudioSamples sample; + uint32 time; + int32 rand; + float distSquared; + float maxDist; + + switch(sound) { + case SCRIPT_SOUND_PORN_CINEMA_1_S: + case SCRIPT_SOUND_MISTY_SEX_S: + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PORN_CINEMA_1_BACKGROUND_1; + m_sQueueSample.m_bBankIndex = 0; + maxDist = 400.f; + sample = AUDIO_SAMPLE_PORN_CINEMA_1_SEX_1; + m_sQueueSample.m_fSoundIntensity = 20.0f; + break; + case SCRIPT_SOUND_PORN_CINEMA_1_L: + case SCRIPT_SOUND_MISTY_SEX_L: + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PORN_CINEMA_1_BACKGROUND_1; + m_sQueueSample.m_bBankIndex = 0; + maxDist = 6400.f; + sample = AUDIO_SAMPLE_PORN_CINEMA_1_SEX_1; + m_sQueueSample.m_fSoundIntensity = 80.0f; + break; + case SCRIPT_SOUND_PORN_CINEMA_2_S: + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PORN_CINEMA_2_BACKGROUND_2; + m_sQueueSample.m_bBankIndex = 0; + maxDist = 400.f; + sample = AUDIO_SAMPLE_PORN_CINEMA_2_SEX_1; + m_sQueueSample.m_fSoundIntensity = 20.0f; + break; + case SCRIPT_SOUND_PORN_CINEMA_2_L: + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PORN_CINEMA_2_BACKGROUND_2; + m_sQueueSample.m_bBankIndex = 0; + maxDist = 6400.f; + sample = AUDIO_SAMPLE_PORN_CINEMA_2_SEX_1; + m_sQueueSample.m_fSoundIntensity = 80.0f; + break; + case SCRIPT_SOUND_PORN_CINEMA_3_S: + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PORN_CINEMA_3_BACKGROUND_3; + m_sQueueSample.m_bBankIndex = 0; + maxDist = 400.f; + m_sQueueSample.m_fSoundIntensity = 20.0f; + sample = AUDIO_SAMPLE_PORN_CINEMA_3_SEX_1; + break; + case SCRIPT_SOUND_PORN_CINEMA_3_L: + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_PORN_CINEMA_3_BACKGROUND_3; + m_sQueueSample.m_bBankIndex = 0; + maxDist = 6400.f; + m_sQueueSample.m_fSoundIntensity = 80.0f; + sample = AUDIO_SAMPLE_PORN_CINEMA_3_SEX_1; + break; + default: break; + } + distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos); + if(distSquared < maxDist) { + m_sQueueSample.m_fDistance = sqrt(distSquared); + if(sound != SCRIPT_SOUND_MISTY_SEX_S && sound != SCRIPT_SOUND_MISTY_SEX_L) { + m_sQueueSample.m_bVolume = + ComputeVolume(maxVolume, m_sQueueSample.m_fSoundIntensity, + m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency( + m_sQueueSample.m_nSampleIndex); + m_sQueueSample.field_4 = 0; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.m_nLoopCount = 0; + m_sQueueSample.field_56 = 0; + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_48 = 2.0f; + m_sQueueSample.m_bEmittingVolume = maxVolume; + m_sQueueSample.m_nLoopStart = + cSampleManager.GetSampleLoopStartOffset( + m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_nLoopEnd = cSampleManager.GetSampleLoopEndOffset( + m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); + } + } + + time = CTimer::GetTimeInMilliseconds(); + if(time > audioLogicTimers[0]) { + m_sQueueSample.m_bVolume = ComputeVolume( + 90u, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume) { + rand = m_anRandomTable[1] & 1; + m_sQueueSample.m_nSampleIndex = rand + sample; + m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency( + m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_nFrequency += + RandomDisplacement(m_sQueueSample.m_nFrequency >> 4); + m_sQueueSample.field_4 = rand + 1; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.m_nLoopCount = 1; + m_sQueueSample.field_56 = 1; + m_sQueueSample.field_16 = 6; + m_sQueueSample.field_48 = 0.0f; + m_sQueueSample.m_nLoopStart = 0; + m_sQueueSample.m_nLoopEnd = -1; + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); + audioLogicTimers[0] = time + 2000 + m_anRandomTable[3] % 6000u; + } + } + } +} + +WRAPPER +void +cAudioManager::ProcessProjectiles() +{ + EAXJMP(0x578A80); +} + +void +cAudioManager::ProcessSawMillScriptObject(uint8 sound) +{ + uint32 time; + float distSquared; + float maxDist; + + switch(sound) { + case SCRIPT_SOUND_SAWMILL_LOOP_S: + case SCRIPT_SOUND_SAWMILL_LOOP_L: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + break; + default: break; + } + distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos); + if(distSquared < maxDist) { + m_sQueueSample.m_fDistance = sqrt(distSquared); + m_sQueueSample.m_bVolume = cAudioManager::ComputeVolume( + 30u, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_SAWMILL_1; + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_SAWMILL_1); + m_sQueueSample.field_4 = 0; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.m_nLoopCount = 0; + m_sQueueSample.field_56 = 0; + m_sQueueSample.field_16 = 5; + m_sQueueSample.field_48 = 2.0f; + m_sQueueSample.m_bEmittingVolume = 30; + m_sQueueSample.m_nLoopStart = + cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_nLoopEnd = + cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); + } + time = CTimer::GetTimeInMilliseconds(); + if(time > audioLogicTimers[1]) { + m_sQueueSample.m_bVolume = cAudioManager::ComputeVolume( + 70u, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_SAWMILL_2; + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency( + m_sQueueSample.m_nSampleIndex); + m_sQueueSample.field_4 = 1; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.m_nLoopCount = 1; + m_sQueueSample.field_56 = 1; + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_48 = 2.0f; + m_sQueueSample.m_nLoopStart = 0; + m_sQueueSample.m_nLoopEnd = -1; + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); + audioLogicTimers[1] = time + 2000 + m_anRandomTable[3] % 4000u; + } + } + } +} + +WRAPPER +void +cAudioManager::ProcessScriptObject(int32 id) +{ + EAXJMP(0x576070); +} + +void +cAudioManager::ProcessShopScriptObject(uint8 sound) +{ + uint32 time; + int32 rand; + float distSquared; + float maxDist; + + switch(sound) { + case SCRIPT_SOUND_SHOP_LOOP_S: + case SCRIPT_SOUND_SHOP_LOOP_L: + maxDist = 900.f; + m_sQueueSample.m_fSoundIntensity = 30.0f; + break; + default: break; + } + distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos); + if(distSquared < maxDist) { + m_sQueueSample.m_fDistance = sqrt(distSquared); + m_sQueueSample.m_bVolume = ComputeVolume(30u, m_sQueueSample.m_fSoundIntensity, + m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_SHOP_1; + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_SHOP_1); + m_sQueueSample.field_4 = 0; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.m_nLoopCount = 0; + m_sQueueSample.field_56 = 0; + m_sQueueSample.field_16 = 5; + m_sQueueSample.field_48 = 2.0f; + m_sQueueSample.m_bEmittingVolume = 30; + m_sQueueSample.m_nLoopStart = + cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_nLoopEnd = + cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.m_bRequireReflection = 0; + cAudioManager::AddSampleToRequestedQueue(); + } + time = CTimer::GetTimeInMilliseconds(); + if(time > audioLogicTimers[2]) { + m_sQueueSample.m_bVolume = ComputeVolume( + 70u, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume) { + rand = m_anRandomTable[1] & 1; + m_sQueueSample.m_nSampleIndex = rand + AUDIO_SAMPLE_SHOP_2; + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_nFrequency = cSampleManager.GetSampleBaseFrequency( + m_sQueueSample.m_nSampleIndex); + m_sQueueSample.field_4 = rand + 1; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.m_nLoopCount = 1; + m_sQueueSample.field_56 = 1; + m_sQueueSample.field_16 = 3; + m_sQueueSample.field_48 = 2.0f; + m_sQueueSample.m_bEmittingVolume = 70; + m_sQueueSample.m_nLoopStart = 0; + m_sQueueSample.m_nLoopEnd = -1; + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); + audioLogicTimers[2] = time + 3000 + m_anRandomTable[3] % 7000u; + } + } + } +} + +void +cAudioManager::ProcessSpecial() +{ + if(m_bUserPause) { + if(!m_bPreviousUserPause) { + MusicManager.ChangeMusicMode(0); + cSampleManager.SetEffectsFadeVol(maxVolume); + cSampleManager.SetMusicFadeVol(maxVolume); + } + } else { + if(m_bPreviousUserPause) { + MusicManager.StopFrontEndTrack(); + MusicManager.ChangeMusicMode(1u); + } + CPlayerPed *playerPed = FindPlayerPed(); + if(playerPed) { + const PedState &state = playerPed->m_nPedState; + if(state != PED_ENTER_CAR && state != PED_STEAL_CAR && + !playerPed->bInVehicle) + cSampleManager.StopChannel(m_bActiveSamples); + } + } +} + +#if 1 +WRAPPER +void +cAudioManager::ProcessVehicle(CVehicle *) +{ + EAXJMP(0x569A00); +} +#else +void +cAudioManager::ProcessVehicle(CVehicle *) +{ + EAXJMP(0x569A00); +} +#endif + +WRAPPER +void cAudioManager::ProcessWaterCannon(int32) { EAXJMP(0x575F30); } + +WRAPPER +void +cAudioManager::ProcessWeather(int32 id) +{ + EAXJMP(0x578370); +} + +void +cAudioManager::ProcessWorkShopScriptObject(uint8 sound) +{ + float distSquared; + float maxDist; + + switch(sound) { + case SCRIPT_SOUND_WORK_SHOP_LOOP_S: + case SCRIPT_SOUND_WORK_SHOP_LOOP_L: + maxDist = 400.f; + m_sQueueSample.m_fSoundIntensity = 20.0; + break; + default: break; + } + distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos); + if(distSquared < maxDist) { + m_sQueueSample.m_fDistance = sqrt(distSquared); + m_sQueueSample.m_bVolume = ComputeVolume(30u, m_sQueueSample.m_fSoundIntensity, + m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.m_nSampleIndex = AUDIO_SAMPLE_WORK_SHOP; + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_nFrequency = + cSampleManager.GetSampleBaseFrequency(AUDIO_SAMPLE_WORK_SHOP); + m_sQueueSample.field_4 = 0; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.m_nLoopCount = 0; + m_sQueueSample.field_56 = 0; + m_sQueueSample.field_16 = 5; + m_sQueueSample.field_48 = 2.0; + m_sQueueSample.m_bEmittingVolume = 30; + m_sQueueSample.m_nLoopStart = + cSampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_nLoopEnd = + cSampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); + } + } +} + WRAPPER void cAudioManager::Service() { @@ -2960,22 +5621,40 @@ cAudioManager::Service() } STARTPATCHES -InjectHook(0x57B070, &cAudioManager::AddSampleToRequestedQueue, PATCH_JUMP); InjectHook(0x57B210, &cAudioManager::AddDetailsToRequestedOrderList, PATCH_JUMP); +InjectHook(0x56AD30, &cAudioManager::AddPlayerCarSample, PATCH_JUMP); InjectHook(0x57B300, &cAudioManager::AddReflectionsToRequestedQueue, PATCH_JUMP); +// InjectHook(0x57B8D0, &cAudioManager::AddReleasingSounds, PATCH_JUMP); +InjectHook(0x57B070, &cAudioManager::AddSampleToRequestedQueue, PATCH_JUMP); +InjectHook(0x57A8F0, &cAudioManager::AutoDetect3DProviders, PATCH_JUMP); +// InjectHook(0x580AF0, &cAudioManager::AgeCrimes, PATCH_JUMP); + +InjectHook(0x5697A0, &cAudioManager::CalculateDistance, PATCH_JUMP); +InjectHook(0x57AA10, &cAudioManager::CheckForAnAudioFileOnCD, PATCH_JUMP); +InjectHook(0x5796A0, &cAudioManager::ClearMissionAudio, PATCH_JUMP); +InjectHook(0x57C120, &cAudioManager::ClearRequestedQueue, PATCH_JUMP); +InjectHook(0x57AE00, &cAudioManager::ComputeDopplerEffectedFrequency, PATCH_JUMP); InjectHook(0x57ABB0, &cAudioManager::ComputeVolume, PATCH_JUMP); +InjectHook(0x57A310, &cAudioManager::CreateEntity, PATCH_JUMP); + +InjectHook(0x57A830, &cAudioManager::DestroyAllGameCreatedEntities, PATCH_JUMP); +InjectHook(0x57A400, &cAudioManager::DestroyEntity, PATCH_JUMP); +InjectHook(0x57F060, &cAudioManager::DoPoliceRadioCrackle, PATCH_JUMP); + +InjectHook(0x57C290, &cAudioManager::GenerateIntegerRandomNumberTable, PATCH_JUMP); +InjectHook(0x569750, &cAudioManager::GetDistanceSquared, PATCH_JUMP); +InjectHook(0x57AC60, &cAudioManager::TranslateEntity, PATCH_JUMP); InjectHook(0x57A0E0, &cAudioManager::Initialise, PATCH_JUMP); InjectHook(0x569420, &cAudioManager::PostInitialiseGameSpecificSetup, PATCH_JUMP); -//InjectHook(0x57EAC0, &cAudioManager::InitialisePoliceRadioZones, PATCH_JUMP); -//InjectHook(0x569650, &cAudioManager::ResetAudioLogicTimers, PATCH_JUMP); +// InjectHook(0x57EAC0, &cAudioManager::InitialisePoliceRadioZones, PATCH_JUMP); +// InjectHook(0x569650, &cAudioManager::ResetAudioLogicTimers, PATCH_JUMP); InjectHook(0x57A150, &cAudioManager::Terminate, PATCH_JUMP); InjectHook(0x57F050, &cAudioManager::GetMissionScriptPoliceAudioPlayingStatus, PATCH_JUMP); InjectHook(0x5795D0, &cAudioManager::GetMissionAudioLoadingStatus, PATCH_JUMP); InjectHook(0x57A8A0, &cAudioManager::GetNum3DProvidersAvailable, PATCH_JUMP); -InjectHook(0x57A8F0, &cAudioManager::AutoDetect3DProviders, PATCH_JUMP); InjectHook(0x57A9C0, &cAudioManager::IsMP3RadioChannelAvailable, PATCH_JUMP); InjectHook(0x57AA30, &cAudioManager::GetCDAudioDriveLetter, PATCH_JUMP); @@ -2986,20 +5665,20 @@ InjectHook(0x57A790, &cAudioManager::SetMusicFadeVol, PATCH_JUMP); InjectHook(0x57A9A0, &cAudioManager::SetSpeakerConfig, PATCH_JUMP); -InjectHook(0x56ECF0, &cAudioManager::ProcessJumboFlying, PATCH_JUMP); InjectHook(0x569400, &cAudioManager::PreInitialiseGameSpecificSetup, PATCH_JUMP); InjectHook(0x57F020, &cAudioManager::SetMissionScriptPoliceAudio, PATCH_JUMP); -InjectHook(0x5697A0, &cAudioManager::CalculateDistance, PATCH_JUMP); - InjectHook(0x56C3C0, &cAudioManager::UsesSiren, PATCH_JUMP); InjectHook(0x56C3F0, &cAudioManager::UsesSirenSwitching, PATCH_JUMP); InjectHook(0x579520, &cAudioManager::MissionScriptAudioUsesPoliceChannel, PATCH_JUMP); InjectHook(0x57A8C0, &cAudioManager::Get3DProviderName, PATCH_JUMP); -InjectHook(0x56EA10, &cAudioManager::ProcessJumboTaxi, PATCH_JUMP); +InjectHook(0x56F230, &cAudioManager::SetupJumboFlySound, PATCH_JUMP); +InjectHook(0x56F310, &cAudioManager::SetupJumboRumbleSound, PATCH_JUMP); +InjectHook(0x56EF20, &cAudioManager::SetupJumboTaxiSound, PATCH_JUMP); +InjectHook(0x56F070, &cAudioManager::SetupJumboWhineSound, PATCH_JUMP); InjectHook(0x579620, &cAudioManager::PlayLoadedMissionAudio, PATCH_JUMP); @@ -3009,22 +5688,12 @@ InjectHook(0x57EFF0, &cAudioManager::ResetPoliceRadio, PATCH_JUMP); InjectHook(0x57B030, &cAudioManager::InterrogateAudioEntities, PATCH_JUMP); -InjectHook(0x57C120, &cAudioManager::ClearRequestedQueue, PATCH_JUMP); -// InjectHook(0x580AF0, &cAudioManager::AgeCrimes, PATCH_JUMP); - InjectHook(0x56C600, &cAudioManager::UsesReverseWarning, PATCH_JUMP); InjectHook(0x56CAB0, &cAudioManager::HasAirBrakes, PATCH_JUMP); InjectHook(0x56F410, &cAudioManager::GetJumboTaxiFreq, PATCH_JUMP); -InjectHook(0x5699C0, &cAudioManager::ProcessPhysical, PATCH_JUMP); -// InjectHook(0x56E860, &cAudioManager::ProcessPlane, PATCH_JUMP); - -InjectHook(0x5796A0, &cAudioManager::ClearMissionAudio, PATCH_JUMP); -// InjectHook(0x569700, &cAudioManager::ProcessReverb, PATCH_JUMP); - InjectHook(0x579650, &cAudioManager::IsMissionAudioSampleFinished, PATCH_JUMP); -// done InjectHook(0x57AF90, &cAudioManager::RandomDisplacement, PATCH_JUMP); InjectHook(0x57A9E0, &cAudioManager::ReleaseDigitalHandle, PATCH_JUMP); @@ -3033,19 +5702,18 @@ InjectHook(0x57AA00, &cAudioManager::SetDynamicAcousticModelingStatus, PATCH_JUM InjectHook(0x57AA50, &cAudioManager::IsAudioInitialised, PATCH_JUMP); -InjectHook(0x57A310, &cAudioManager::CreateEntity, PATCH_JUMP); -InjectHook(0x57A400, &cAudioManager::DestroyEntity, PATCH_JUMP); InjectHook(0x57A4C0, &cAudioManager::SetEntityStatus, PATCH_JUMP); InjectHook(0x569570, &cAudioManager::PreTerminateGameSpecificShutdown, PATCH_JUMP); InjectHook(0x569640, &cAudioManager::PostTerminateGameSpecificShutdown, PATCH_JUMP); -InjectHook(0x57C290, &cAudioManager::GenerateIntegerRandomNumberTable, PATCH_JUMP); - InjectHook(0x56AD10, &cAudioManager::PlayerJustGotInCar, PATCH_JUMP); InjectHook(0x56AD20, &cAudioManager::PlayerJustLeftCar, PATCH_JUMP); InjectHook(0x570DB0, &cAudioManager::GetPhrase, PATCH_JUMP); +// Get ped sfx stuff +InjectHook(0x570960, &cAudioManager::GetPedCommentSfx, PATCH_JUMP); + InjectHook(0x570E00, &cAudioManager::GetPlayerTalkSfx, PATCH_JUMP); InjectHook(0x570EA0, &cAudioManager::GetCopTalkSfx, PATCH_JUMP); InjectHook(0x570F80, &cAudioManager::GetSwatTalkSfx, PATCH_JUMP); @@ -3122,4 +5790,32 @@ InjectHook(0x575120, &cAudioManager::GetChunkyTalkSfx, PATCH_JUMP); InjectHook(0x575460, &cAudioManager::GetGenericMaleTalkSfx, PATCH_JUMP); InjectHook(0x575510, &cAudioManager::GetGenericFemaleTalkSfx, PATCH_JUMP); + +// Process stuff +// InjectHook(0x57BA60, &cAudioManager::ProcessActiveQueues, PATCH_JUMP); +InjectHook(0x56C940, &cAudioManager::ProcessAirBrakes, PATCH_JUMP); +InjectHook(0x577B30, &cAudioManager::ProcessAirportScriptObject, PATCH_JUMP); +InjectHook(0x579250, &cAudioManager::ProcessBridgeMotor, PATCH_JUMP); +InjectHook(0x579170, &cAudioManager::ProcessBridgeWarning, PATCH_JUMP); +InjectHook(0x577CA0, &cAudioManager::ProcessCinemaScriptObject, PATCH_JUMP); +InjectHook(0x577E50, &cAudioManager::ProcessDocksScriptObject, PATCH_JUMP); +InjectHook(0x569870, &cAudioManager::ProcessEntity, PATCH_JUMP); +InjectHook(0x578FD0, &cAudioManager::ProcessFireHydrant, PATCH_JUMP); +InjectHook(0x5785E0, &cAudioManager::ProcessFrontEnd, PATCH_JUMP); +InjectHook(0x577FE0, &cAudioManager::ProcessHomeScriptObject, PATCH_JUMP); +InjectHook(0x56E8F0, &cAudioManager::ProcessJumbo, PATCH_JUMP); +InjectHook(0x56EA40, &cAudioManager::ProcessJumboAccel, PATCH_JUMP); +InjectHook(0x56EE40, &cAudioManager::ProcessJumboDecel, PATCH_JUMP); +InjectHook(0x56ECF0, &cAudioManager::ProcessJumboFlying, PATCH_JUMP); +InjectHook(0x56ED10, &cAudioManager::ProcessJumboLanding, PATCH_JUMP); +InjectHook(0x56EC00, &cAudioManager::ProcessJumboTakeOff, PATCH_JUMP); +InjectHook(0x56EA10, &cAudioManager::ProcessJumboTaxi, PATCH_JUMP); +InjectHook(0x5777E0, &cAudioManager::ProcessLaunderetteScriptObject, PATCH_JUMP); +InjectHook(0x576770, &cAudioManager::ProcessLoopingScriptObject, PATCH_JUMP); +InjectHook(0x5699C0, &cAudioManager::ProcessPhysical, PATCH_JUMP); +InjectHook(0x577280, &cAudioManager::ProcessPornCinema, PATCH_JUMP); +InjectHook(0x577630, &cAudioManager::ProcessSawMillScriptObject, PATCH_JUMP); +InjectHook(0x577970, &cAudioManager::ProcessShopScriptObject, PATCH_JUMP); +InjectHook(0x5697D0, &cAudioManager::ProcessSpecial, PATCH_JUMP); +InjectHook(0x577530, &cAudioManager::ProcessWorkShopScriptObject, PATCH_JUMP); ENDPATCHES diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h index 7a2dc9c5..1ae50b2f 100644 --- a/src/audio/AudioManager.h +++ b/src/audio/AudioManager.h @@ -7,48 +7,48 @@ class tActiveSample { public: - int m_nEntityIndex; - int field_4; - int m_nSampleIndex; - char m_bBankIndex; - char m_bIsDistant; - char field_14; - char field_15; - int field_16; - int m_nFrequency; + int32 m_nEntityIndex; + int32 field_4; + int32 m_nSampleIndex; + uint8 m_bBankIndex; + uint8 m_bIsDistant; + uint8 field_14; + uint8 field_15; + int32 field_16; + int32 m_nFrequency; uint8 m_bVolume; - char field_25; - char field_26; - char field_27; + uint8 field_25; + uint8 field_26; + uint8 field_27; float m_fDistance; - int m_nLoopCount; - int m_nLoopStart; - int m_nLoopEnd; + int32 m_nLoopCount; + int32 m_nLoopStart; + int32 m_nLoopEnd; uint8 m_bEmittingVolume; - char field_45; - char field_46; - char field_47; + uint8 field_45; + uint8 field_46; + uint8 field_47; float field_48; float m_fSoundIntensity; - char field_56; - char field_57; - char field_58; - char field_59; + uint8 field_56; + uint8 field_57; + uint8 field_58; + uint8 field_59; CVector m_vecPos; - char m_bReverbFlag; - char m_bLoopsRemaining; - char m_bRequireReflection; + uint8 m_bReverbFlag; + uint8 m_bLoopsRemaining; + uint8 m_bRequireReflection; uint8 m_bOffset; - int field_76; - char m_bIsProcessed; - char m_bLoopEnded; - char field_82; - char field_83; - int calculatedVolume; - char field_88; - char field_89; - char field_90; - char field_91; + int32 field_76; + uint8 m_bIsProcessed; + uint8 m_bLoopEnded; + uint8 field_82; + uint8 field_83; + int32 calculatedVolume; + uint8 field_88; + uint8 field_89; + uint8 field_90; + uint8 field_91; }; static_assert(sizeof(tActiveSample) == 0x5c, "tActiveSample: error"); @@ -77,14 +77,14 @@ class tAudioEntity { public: eAudioType m_nType; - CPhysical *m_pEntity; + void *m_pEntity; bool m_bIsUsed; - char m_bStatus; + uint8 m_bStatus; int16 m_awAudioEvent[4]; - char gap_18[2]; + uint8 gap_18[2]; float m_afVolume[4]; - char field_24; - char field_25[3]; + uint8 field_24; + uint8 field_25[3]; }; static_assert(sizeof(tAudioEntity) == 0x28, "tAudioEntity: error"); @@ -96,9 +96,9 @@ public: int field_4; CVector m_vecPos; float m_fDistance; - char m_bVolume; - char field_25; - char gap_26[2]; + uint8 m_bVolume; + uint8 field_25; + uint8 gap_26[2]; }; static_assert(sizeof(tPedComment) == 0x1c, "tPedComment: error"); @@ -107,10 +107,10 @@ class cPedComments { public: tPedComment m_asPedComments[40]; - char field_1120[40]; - char field_1160[2]; - char field_1162; - char gap_1163[1]; + uint8 field_1120[40]; + uint8 field_1160[2]; + uint8 field_1162; + uint8 gap_1163[1]; }; static_assert(sizeof(cPedComments) == 0x48c, "cPedComments: error"); @@ -122,15 +122,15 @@ class cAudioCollision public: CEntity *m_pEntity1; CEntity *m_pEntity2; - char m_bSurface1; - char m_bSurface2; - char field_10; - char field_11; + uint8 m_bSurface1; + uint8 m_bSurface2; + uint8 field_10; + uint8 field_11; float m_fIntensity1; float m_fIntensity2; CVector m_vecPosition; float m_fDistance; - int m_nBaseVolume; + int32 m_nBaseVolume; }; static_assert(sizeof(cAudioCollision) == 0x28, "cAudioCollision: error"); @@ -140,95 +140,137 @@ class cAudioCollisionManager public: cAudioCollision m_asCollisions1[10]; cAudioCollision m_asCollisions2[10]; - char m_bIndicesTable[10]; - char m_bCollisionsInQueue; - char gap_811; + uint8 m_bIndicesTable[10]; + uint8 m_bCollisionsInQueue; + uint8 gap_811; cAudioCollision m_sQueue; }; -static_assert(sizeof(cAudioCollisionManager) == 0x354, - "cAudioCollisionManager: error"); +static_assert(sizeof(cAudioCollisionManager) == 0x354, "cAudioCollisionManager: error"); class cMissionAudio { public: CVector m_vecPos; - char field_12; - char gap_13[3]; + uint8 field_12; + uint8 gap_13[3]; int m_nSampleIndex; - char m_bLoadingStatus; - char m_bPlayStatus; - char field_22; - char field_23; + uint8 m_bLoadingStatus; + uint8 m_bPlayStatus; + uint8 field_22; + uint8 field_23; int field_24; bool m_bIsPlayed; - char field_29; - char field_30; - char field_31; + uint8 field_29; + uint8 field_30; + uint8 field_31; }; static_assert(sizeof(cMissionAudio) == 0x20, "cMissionAudio: error"); +class cVehicleParams; +class CPlane; +class CVehicle; +class CPed; + +struct cAudioScriptObject { + int16 m_wSound; + char gap_2[2]; + CVector m_vecPos; + int m_nAudioEntityId; + + static void *operator new(size_t); + static void *operator new(size_t, int); + static void operator delete(void*, size_t); + static void operator delete(void*, int); +}; + +static_assert(sizeof(cAudioScriptObject) == 0x14, "cAudioScriptObject: error"); + class cAudioManager { public: bool m_bIsInitialised; - char field_1; - char field_2; - char m_bActiveSamples; - char field_4; + uint8 field_1; + uint8 field_2; + uint8 m_bActiveSamples; + uint8 field_4; bool m_bDynamicAcousticModelingStatus; - char field_6; - char field_7; - float field_8; + uint8 field_6; + uint8 field_7; + float speedOfSound; bool m_bTimerJustReset; - char field_13; - char field_14; - char field_15; - int m_nTimer; + uint8 field_13; + uint8 field_14; + uint8 field_15; + int32 m_nTimer; tActiveSample m_sQueueSample; uint8 m_bActiveSampleQueue; - char gap_109[3]; - tActiveSample m_asSamples[54]; - char m_abSampleQueueIndexTable[54]; - char m_bSampleRequestQueuesStatus[2]; + uint8 gap_109[3]; + tActiveSample m_asSamples[2][27]; + uint8 m_abSampleQueueIndexTable[2][27]; + uint8 m_bSampleRequestQueuesStatus[2]; tActiveSample m_asActiveSamples[27]; tAudioEntity m_asAudioEntities[200]; - int m_anAudioEntityIndices[200]; - int m_nAudioEntitiesTotal; + int32 m_anAudioEntityIndices[200]; + int32 m_nAudioEntitiesTotal; CVector m_avecReflectionsPos[5]; float m_afReflectionsDistances[5]; - int m_anScriptObjectEntityIndices[40]; - int m_nScriptObjectEntityTotal; + int32 m_anScriptObjectEntityIndices[40]; + int32 m_nScriptObjectEntityTotal; cPedComments m_sPedComments; - int m_nFireAudioEntity; - int m_nWaterCannonEntity; - int m_nPoliceChannelEntity; - char gap45B8[444]; - int m_nFrontEndEntity; - int m_nCollisionEntity; + int32 m_nFireAudioEntity; + int32 m_nWaterCannonEntity; + int32 m_nPoliceChannelEntity; + uint8 gap45B8[444]; + int32 m_nFrontEndEntity; + int32 m_nCollisionEntity; cAudioCollisionManager m_sCollisionManager; - int m_nProjectileEntity; - int m_nBridgeEntity; + int32 m_nProjectileEntity; + int32 m_nBridgeEntity; cMissionAudio m_sMissionAudio; - int m_anRandomTable[5]; - char field_19192; - char m_bUserPause; - char m_bPreviousUserPause; - char field_19195; - int m_nTimeOfRecentCrime; - - void AddSampleToRequestedQueue(); - - void AddDetailsToRequestedOrderList(uint8 sample); - void AddReflectionsToRequestedQueue(); - - uint32 ComputeVolume(int emittingVolume, float soundIntensity, float distance); + int32 m_anRandomTable[5]; + uint8 field_19192; + uint8 m_bUserPause; + uint8 m_bPreviousUserPause; + uint8 field_19195; + int32 m_nTimeOfRecentCrime; + + void AddDetailsToRequestedOrderList(uint8 sample); /// ok + void AddPlayerCarSample(uint8 emittingVolume, int32 freq, uint32 sample, uint8 unk1, + uint8 unk2, bool notLooping); /// ok + void AddReflectionsToRequestedQueue(); /// ok (check value) + void AddReleasingSounds(); // todo (difficult) + void AddSampleToRequestedQueue(); /// ok + void AgeCrimes(); // todo + int8 AutoDetect3DProviders(); /// ok + + void CalculateDistance(bool *ptr, float dist); /// ok + bool CheckForAnAudioFileOnCD(); /// ok + void ClearMissionAudio(); /// ok + void ClearRequestedQueue(); /// ok + int32 ComputeDopplerEffectedFrequency(uint32 oldFreq, float position1, float position2, + float speedMultiplier); /// ok + int32 ComputePan(float, CVector *); // todo + uint32 ComputeVolume(int emittingVolume, float soundIntensity, float distance); /// ok + int32 CreateEntity(int32 type, CPhysical *entity); /// ok + + void DestroyAllGameCreatedEntities(); /// ok + void DestroyEntity(int32 id); /// ok + void DoPoliceRadioCrackle(); /// ok + + void GenerateIntegerRandomNumberTable(); /// ok + + float GetDistanceSquared(CVector *v); /// ok + + void TranslateEntity(CVector *v1, CVector *v2); /// ok + + // done void Initialise(); void PostInitialiseGameSpecificSetup(); - void InitialisePoliceRadioZones(); // @todo - void ResetAudioLogicTimers(int32 timer); // @todo + void InitialisePoliceRadioZones(); // todo + void ResetAudioLogicTimers(int32 timer); // todo void Terminate(); @@ -236,7 +278,6 @@ public: bool GetMissionAudioLoadingStatus(); uint8 GetNum3DProvidersAvailable(); - int8 AutoDetect3DProviders(); bool IsMP3RadioChannelAvailable(); uint8 GetCDAudioDriveLetter(); @@ -247,24 +288,21 @@ public: void SetSpeakerConfig(int32 conf); - void ProcessJumboFlying(); bool SetupJumboEngineSound(uint8, int32); // todo void PreInitialiseGameSpecificSetup(); void SetMissionScriptPoliceAudio(int32 sfx); - void CalculateDistance(bool *ptr, float dist); - bool UsesSiren(int32 model); bool UsesSirenSwitching(int32 model); bool MissionScriptAudioUsesPoliceChannel(int32 soundMission); - uint8 Get3DProviderName(uint8 id); + char* Get3DProviderName(uint8 id); - void ProcessJumboTaxi(); - bool SetupJumboFlySound(uint8); // todo - bool SetupJumboTaxiSound(uint8); // todo - bool SetupJumboWhineSound(uint8, int32); // todo + bool SetupJumboFlySound(uint8 emittingVol); /// ok + bool SetupJumboRumbleSound(uint8 emittingVol); /// ok + bool SetupJumboTaxiSound(uint8 vol); /// ok + bool SetupJumboWhineSound(uint8 emittingVol, int32 freq); /// ok void PlayLoadedMissionAudio(); @@ -274,27 +312,14 @@ public: void InterrogateAudioEntities(); - void ClearRequestedQueue(); - // void AgeCrimes(); //todo - bool UsesReverseWarning(int32 model); bool HasAirBrakes(int32 model); int32 GetJumboTaxiFreq(); - void ProcessPhysical(int32 id); - void ProcessVehicle(CPhysical *); // todo - void ProcessPed(CPhysical *); // todo - void ProcessPlane(void *); // todo - - void ClearMissionAudio(); - // void ProcessReverb(); // todo - bool IsMissionAudioSampleFinished(); - void ProcessEntity(int32); - - void InitialisePoliceRadio(); + void InitialisePoliceRadio(); // todo int32 RandomDisplacement(uint32 seed); @@ -304,21 +329,20 @@ public: bool IsAudioInitialised() const; - int32 CreateEntity(int32 type, CPhysical *entity); - void DestroyEntity(int32 id); void SetEntityStatus(int32 id, bool status); void PreTerminateGameSpecificShutdown(); void PostTerminateGameSpecificShutdown(); - void GenerateIntegerRandomNumberTable(); - void PlayerJustGotInCar(); void PlayerJustLeftCar(); void Service(); - void GetPhrase(uint32 *phrase, uint32 *prevPhrase, uint32 sample, - uint32 maxOffset); + void GetPhrase(uint32 *phrase, uint32 *prevPhrase, uint32 sample, uint32 maxOffset); + + void DoJumboVolOffset(); + + int32 GetPedCommentSfx(CPed *ped, int32 sound); uint32 GetPlayerTalkSfx(int16 sound); uint32 GetCopTalkSfx(int16 sound); @@ -396,9 +420,74 @@ public: uint32 GetGenericMaleTalkSfx(int16 sound); uint32 GetGenericFemaleTalkSfx(int16 sound); + + void ProcessActiveQueues(); // todo + bool ProcessAirBrakes(cVehicleParams *params); /// ok + void ProcessAirportScriptObject(uint8 sound); /// ok + bool ProcessBoatEngine(cVehicleParams *params); // todo requires CBoat + bool ProcessBoatMovingOverWater(cVehicleParams *params); // todo requires CBoat + void ProcessBridge(); // todo requires CBridge + void ProcessBridgeMotor(); /// ok + void ProcessBridgeOneShots(); // todo requires CBridge + void ProcessBridgeWarning(); /// ok + bool ProcessCarBombTick(void *); // todo requires CVehicle + void ProcessCesna(void *); // todo requires CPlane + void ProcessCinemaScriptObject(uint8 sound); /// ok + void ProcessCrane(); // todo requires CCrane + void ProcessDocksScriptObject(uint8 sound); /// ok + // bool ProcessEngineDamage(void *); //todo requires CVehicle + void ProcessEntity(int32 sound); /// ok + void ProcessExplosions(int32 explosion); // todo requires CExplosion + void ProcessFireHydrant(); /// ok + void ProcessFires(int32 entity); // todo requires gFireManager + void ProcessFrontEnd(); /// ok + void ProcessGarages(); // todo requires CGarages::aGarages + // bool ProcessHelicopter(void *); // todo requires CVehicle + void ProcessHomeScriptObject(uint8 sound); /// ok + void ProcessJumbo(cVehicleParams *); /// ok + void ProcessJumboAccel(CPlane *plane); /// ok + void ProcessJumboDecel(CPlane *plane); /// ok + void ProcessJumboFlying(); /// ok + void ProcessJumboLanding(CPlane *plane); /// ok + void ProcessJumboTakeOff(CPlane *plane); /// ok + void ProcessJumboTaxi(); /// ok + void ProcessLaunderetteScriptObject(uint8 sound); /// ok + void ProcessLoopingScriptObject(uint8 sound); /// ok + // void ProcessMissionAudio(); + // void ProcessModelVehicle(void *); + // void ProcessOneShotScriptObject(uint8 sound); + void ProcessPed(CPhysical *p); // todo + // void ProcessPedHeadphones(void *); + // void ProcessPedOneShots(void *); + void ProcessPhysical(int32 id); /// ok + void ProcessPlane(void *); // todo + // void ProcessPlayersVehicleEngine(void *, void *); + void ProcessPoliceCellBeatingScriptObject(uint8 sound); // todo + void ProcessPornCinema(uint8 sound); /// ok + void ProcessProjectiles(); // todo + // void ProcessRainOnVehicle(void *); + // void ProcessReverb(); + // bool ProcessReverseGear(void *); + void ProcessSawMillScriptObject(uint8 sound); /// ok + void ProcessScriptObject(int32 id); // todo + void ProcessShopScriptObject(uint8 sound); /// ok + void ProcessSpecial(); /// ok + // bool ProcessTrainNoise(void *); + void ProcessVehicle(CVehicle *); // todo + // bool ProcessVehicleDoors(void *); + // bool ProcessVehicleEngine(void *); + // void ProcessVehicleHorn(void *); + // void ProcessVehicleOneShots(void *); + // bool ProcessVehicleReverseWarning(void *); + // bool ProcessVehicleRoadNoise(void *); + // void ProcessVehicleSirenOrAlarm(void *); + // void ProcessVehicleSkidding(void *); + void ProcessWaterCannon(int32); // todo + void ProcessWeather(int32 id); // todo + // bool ProcessWetRoadNoise(void *); + void ProcessWorkShopScriptObject(uint8 sound); /// ok }; static_assert(sizeof(cAudioManager) == 0x4B14, "cAudioManager: error"); extern cAudioManager &AudioManager; -extern cAudioManager &Players; diff --git a/src/audio/AudioSamples.h b/src/audio/AudioSamples.h index 26fffe63..ba7bf7a8 100644 --- a/src/audio/AudioSamples.h +++ b/src/audio/AudioSamples.h @@ -3037,4 +3037,132 @@ enum eAudioSamples : uint32 { AUDIO_SAMPLE_AMMUNATION_WELCOME_3 = 3031, TOTAL_AUDIO_SAMPLES = 3032, NO_SAMPLE = 3033, -};
\ No newline at end of file +}; + +enum eScriptSounds : int16 +{ + SCRIPT_SOUND_0 = 0, + SCRIPT_SOUND_1 = 1, + SCRIPT_SOUND_2 = 2, + SCRIPT_SOUND_3 = 3, + SCRIPT_SOUND_PARTY_1_LOOP_S = 4, + SCRIPT_SOUND_PARTY_1_LOOP_L = 5, + SCRIPT_SOUND_PARTY_2_LOOP_S = 6, + SCRIPT_SOUND_PARTY_2_LOOP_L = 7, + SCRIPT_SOUND_PARTY_3_LOOP_S = 8, + SCRIPT_SOUND_PARTY_3_LOOP_L = 9, + SCRIPT_SOUND_PARTY_4_LOOP_S = 10, + SCRIPT_SOUND_PARTY_4_LOOP_L = 11, + SCRIPT_SOUND_PARTY_5_LOOP_S = 12, + SCRIPT_SOUND_PARTY_5_LOOP_L = 13, + SCRIPT_SOUND_PARTY_6_LOOP_S = 14, + SCRIPT_SOUND_PARTY_6_LOOP_L = 15, + SCRIPT_SOUND_PARTY_7_LOOP_S = 16, + SCRIPT_SOUND_PARTY_7_LOOP_L = 17, + SCRIPT_SOUND_PARTY_8_LOOP_S = 18, + SCRIPT_SOUND_PARTY_8_LOOP_L = 19, + SCRIPT_SOUND_PARTY_9_LOOP_S = 20, + SCRIPT_SOUND_PARTY_9_LOOP_L = 21, + SCRIPT_SOUND_PARTY_10_LOOP_S = 22, + SCRIPT_SOUND_PARTY_10_LOOP_L = 23, + SCRIPT_SOUND_PARTY_11_LOOP_S = 24, + SCRIPT_SOUND_PARTY_11_LOOP_L = 25, + SCRIPT_SOUND_PARTY_12_LOOP_S = 26, + SCRIPT_SOUND_PARTY_12_LOOP_L = 27, + SCRIPT_SOUND_PARTY_13_LOOP_S = 28, + SCRIPT_SOUND_PARTY_13_LOOP_L = 29, + SCRIPT_SOUND_STRIP_CLUB_LOOP_1_S = 30, + SCRIPT_SOUND_STRIP_CLUB_LOOP_1_L = 31, + SCRIPT_SOUND_STRIP_CLUB_LOOP_2_S = 32, + SCRIPT_SOUND_STRIP_CLUB_LOOP_2_L = 33, + SCRIPT_SOUND_WORK_SHOP_LOOP_S = 34, + SCRIPT_SOUND_WORK_SHOP_LOOP_L = 35, + SCRIPT_SOUND_SAWMILL_LOOP_S = 36, + SCRIPT_SOUND_SAWMILL_LOOP_L = 37, + SCRIPT_SOUND_38 = 38, + SCRIPT_SOUND_39 = 39, + SCRIPT_SOUND_LAUNDERETTE_LOOP_S = 40, + SCRIPT_SOUND_LAUNDERETTE_LOOP_L = 41, + SCRIPT_SOUND_CHINATOWN_RESTAURANT_S = 42, + SCRIPT_SOUND_CHINATOWN_RESTAURANT_L = 43, + SCRIPT_SOUND_CIPRIANI_RESAURANT_S = 44, + SCRIPT_SOUND_CIPRIANI_RESAURANT_L = 45, + SCRIPT_SOUND_46 = 46, + SCRIPT_SOUND_47 = 47, + SCRIPT_SOUND_MARCO_BISTRO_S = 48, + SCRIPT_SOUND_MARCO_BISTRO_L = 49, + SCRIPT_SOUND_AIRPORT_LOOP_S = 50, + SCRIPT_SOUND_AIRPORT_LOOP_L = 51, + SCRIPT_SOUND_SHOP_LOOP_S = 52, + SCRIPT_SOUND_SHOP_LOOP_L = 53, + SCRIPT_SOUND_CINEMA_LOOP_S = 54, + SCRIPT_SOUND_CINEMA_LOOP_L = 55, + SCRIPT_SOUND_DOCKS_LOOP_S = 56, + SCRIPT_SOUND_DOCKS_LOOP_L = 57, + SCRIPT_SOUND_HOME_LOOP_S = 58, + SCRIPT_SOUND_HOME_LOOP_L = 59, + SCRIPT_SOUND_FRANKIE_PIANO = 60, + SCRIPT_SOUND_PARTY_1_LOOP = 61, + SCRIPT_SOUND_PORN_CINEMA_1_S = 62, + SCRIPT_SOUND_PORN_CINEMA_1_L = 63, + SCRIPT_SOUND_PORN_CINEMA_2_S = 64, + SCRIPT_SOUND_PORN_CINEMA_2_L = 65, + SCRIPT_SOUND_PORN_CINEMA_3_S = 66, + SCRIPT_SOUND_PORN_CINEMA_3_L = 67, + SCRIPT_SOUND_BANK_ALARM_LOOP_S = 68, + SCRIPT_SOUND_BANK_ALARM_LOOP_L = 69, + SCRIPT_SOUND_POLICE_BALL_LOOP_S = 70, + SCRIPT_SOUND_POLICE_BALL_LOOP_L = 71, + SCRIPT_SOUND_RAVE_LOOP_INDUSTRIAL_S = 72, + SCRIPT_SOUND_RAVE_LOOP_INDUSTRIAL_L = 73, + SCRIPT_SOUND_74 = 74, + SCRIPT_SOUND_75 = 75, + SCRIPT_SOUND_POLICE_CELL_BEATING_LOOP_S = 76, + SCRIPT_SOUND_POLICE_CELL_BEATING_LOOP_L = 77, + SCRIPT_SOUND_INJURED_PED_MALE_OUCH_S = 78, + SCRIPT_SOUND_INJURED_PED_MALE_OUCH_L = 79, + SCRIPT_SOUND_INJURED_PED_FEMALE_OUCH_S = 80, + SCRIPT_SOUND_INJURED_PED_FEMALE_OUCH_L = 81, + SCRIPT_SOUND_EVIDENCE_PICKUP = 82, + SCRIPT_SOUND_UNLOAD_GOLD = 83, + SCRIPT_SOUND_RAVE_1_LOOP_S = 84, + SCRIPT_SOUND_RAVE_1_LOOP_L = 85, + SCRIPT_SOUND_RAVE_2_LOOP_S = 86, + SCRIPT_SOUND_RAVE_2_LOOP_L = 87, + SCRIPT_SOUND_RAVE_3_LOOP_S = 88, + SCRIPT_SOUND_RAVE_3_LOOP_L = 89, + SCRIPT_SOUND_MISTY_SEX_S = 90, + SCRIPT_SOUND_MISTY_SEX_L = 91, + SCRIPT_SOUND_GATE_START_CLUNK = 92, + SCRIPT_SOUND_GATE_STOP_CLUNK = 93, + SCRIPT_SOUND_PART_MISSION_COMPLETE = 94, + SCRIPT_SOUND_CHUNKY_RUN_SHOUT = 95, + SCRIPT_SOUND_SECURITY_GUARD_AWAY_SHOUT = 96, + SCRIPT_SOUND_RACE_START_3 = 97, + SCRIPT_SOUND_RACE_START_2 = 98, + SCRIPT_SOUND_RACE_START_1 = 99, + SCRIPT_SOUND_RACE_START_GO = 100, + SCRIPT_SOUND_SWAT_PED_SHOUT = 101, + SCRIPT_SOUND_PRETEND_FIRE_LOOP = 102, + SCRIPT_SOUND_AMMUNATION_CHAT_1 = 103, + SCRIPT_SOUND_AMMUNATION_CHAT_2 = 104, + SCRIPT_SOUND_AMMUNATION_CHAT_3 = 105, + SCRIPT_SOUND_BULLET_HIT_GROUND_1 = 106, + SCRIPT_SOUND_BULLET_HIT_GROUND_2 = 107, + SCRIPT_SOUND_BULLET_HIT_GROUND_3 = 108, + SCRIPT_SOUND_109 = 109, + SCRIPT_SOUND_110 = 110, + SCRIPT_SOUND_111 = 111, + SCRIPT_SOUND_PAYPHONE_RINGING = 112, + SCRIPT_SOUND_113 = 113, + SCRIPT_SOUND_GLASS_BREAK_L = 114, + SCRIPT_SOUND_GLASS_BREAK_S = 115, + SCRIPT_SOUND_GLASS_CRACK = 116, + SCRIPT_SOUND_GLASS_LIGHT_BREAK = 117, + SCRIPT_SOUND_BOX_DESTROYED_1 = 118, + SCRIPT_SOUND_BOX_DESTROYED_2 = 119, + SCRIPT_SOUND_METAL_COLLISION = 120, + SCRIPT_SOUND_TIRE_COLLISION = 121, + SCRIPT_SOUND_GUNSHELL_DROP = 122, + SCRIPT_SOUND_GUNSHELL_DROP_SOFT = 123, +}; diff --git a/src/audio/DMAudio.cpp b/src/audio/DMAudio.cpp index b4fee67f..2019c394 100644 --- a/src/audio/DMAudio.cpp +++ b/src/audio/DMAudio.cpp @@ -20,9 +20,9 @@ WRAPPER void cDMAudio::PlayFrontEndSound(uint32, uint32) { EAXJMP(0x57CC20); } WRAPPER void cDMAudio::PlayFrontEndTrack(uint32, uint32) { EAXJMP(0x57CC80); } WRAPPER void cDMAudio::StopFrontEndTrack() { EAXJMP(0x57CCB0); } WRAPPER void cDMAudio::PlayOneShot(int32 audioentity, uint16 sound/*eSound*/, float) { EAXJMP(0x57C840); } -WRAPPER void cDMAudio::SetMusicMasterVolume(int8) { EAXJMP(0x57C8C0); } -WRAPPER void cDMAudio::SetEffectsMasterVolume(int8) { EAXJMP(0x57C890); } -WRAPPER int8 cDMAudio::SetCurrent3DProvider(int8) { EAXJMP(0x57C9B0); } +WRAPPER void cDMAudio::SetMusicMasterVolume(uint8) { EAXJMP(0x57C8C0); } +WRAPPER void cDMAudio::SetEffectsMasterVolume(uint8) { EAXJMP(0x57C890); } +WRAPPER uint8 cDMAudio::SetCurrent3DProvider(uint8) { EAXJMP(0x57C9B0); } WRAPPER int32 cDMAudio::SetSpeakerConfig(int32) { EAXJMP(0x57C9D0); } WRAPPER int32 cDMAudio::GetRadioInCar() { EAXJMP(0x57CE40); } @@ -33,4 +33,5 @@ WRAPPER int32 cDMAudio::CreateEntity(int, void*) { EAXJMP(0x57C7C0); } WRAPPER void cDMAudio::SetEntityStatus(int32 id, uint8 enable) { EAXJMP(0x57C810); } WRAPPER void cDMAudio::SetRadioInCar(int32) { EAXJMP(0x57CE60); } WRAPPER void cDMAudio::DestroyEntity(int32) { EAXJMP(0x57C7F0); } -WRAPPER void cDMAudio::ClearMissionAudio(void) { EAXJMP(0x57CE20); }
\ No newline at end of file +WRAPPER void cDMAudio::ClearMissionAudio(void) { EAXJMP(0x57CE20); } +WRAPPER void cDMAudio::ReportCrime(eCrimeType crime, const CVector &pos) { EAXJMP(0x57CAD0); } diff --git a/src/audio/DMAudio.h b/src/audio/DMAudio.h index 8be09ac6..da20dc31 100644 --- a/src/audio/DMAudio.h +++ b/src/audio/DMAudio.h @@ -96,8 +96,8 @@ enum eSound : int16 SOUND_RAMPAGE_FAILED = 91, SOUND_RAMPAGE_KILL = 92, SOUND_RAMPAGE_CAR_BLOWN = 93, - _SOUND_EVIDENCE_PICKUP = 94, - _SOUND_UNLOAD_GOLD = 95, + SOUND_EVIDENCE_PICKUP = 94, + SOUND_UNLOAD_GOLD = 95, SOUND_PAGER = 96, SOUND_PED_DEATH = 97, SOUND_PED_DAMAGE = 98, @@ -141,16 +141,16 @@ enum eSound : int16 SOUND_INJURED_PED_MALE_OUCH = 136, SOUND_INJURED_PED_FEMALE = 137, SOUND_8A = 138, - _SOUND_RACE_START_3 = 139, - _SOUND_RACE_START_2 = 140, - _SOUND_RACE_START_1 = 141, - _SOUND_RACE_START_GO = 142, + SOUND_RACE_START_3 = 139, + SOUND_RACE_START_2 = 140, + SOUND_RACE_START_1 = 141, + SOUND_RACE_START_GO = 142, SOUND_SPLASH = 143, SOUND_WATER_FALL = 144, SOUND_SPLATTER = 145, SOUND_CAR_PED_COLLISION = 146, SOUND_CLOCK_TICK = 147, - _SOUND_PART_MISSION_COMPLETE = 148, + SOUND_PART_MISSION_COMPLETE = 148, SOUND_FRONTEND_MENU_STARTING = 149, SOUND_FRONTEND_MENU_COMPLETED = 150, SOUND_FRONTEND_MENU_DENIED = 151, @@ -173,6 +173,7 @@ enum eSound : int16 }; class CEntity; +enum eCrimeType; class cDMAudio { @@ -191,9 +192,9 @@ public: void PlayFrontEndTrack(uint32, uint32); void StopFrontEndTrack(); void PlayOneShot(int32 audioentity, uint16 sound/*eSound*/, float); - void SetMusicMasterVolume(int8); - void SetEffectsMasterVolume(int8); - int8 SetCurrent3DProvider(int8); + void SetMusicMasterVolume(uint8); + void SetEffectsMasterVolume(uint8); + uint8 SetCurrent3DProvider(uint8); int32 SetSpeakerConfig(int32); int32 GetRadioInCar(void); void SetEffectsFadeVol(uint8); @@ -204,5 +205,6 @@ public: uint8 IsMP3RadioChannelAvailable(); void DestroyEntity(int32); void ClearMissionAudio(void); + void ReportCrime(eCrimeType crime, const CVector &pos); }; extern cDMAudio &DMAudio; diff --git a/src/audio/MusicManager.cpp b/src/audio/MusicManager.cpp index dcd4ae93..71cc594b 100644 --- a/src/audio/MusicManager.cpp +++ b/src/audio/MusicManager.cpp @@ -188,3 +188,17 @@ cMusicManager::Terminate() { EAXJMP(0x57D140); } + +WRAPPER +void +cMusicManager::ChangeMusicMode(int32 mode) +{ + EAXJMP(0x57D310); +} + +WRAPPER +void +cMusicManager::StopFrontEndTrack() +{ + EAXJMP(0x57E3D0); +} diff --git a/src/audio/MusicManager.h b/src/audio/MusicManager.h index 944fd16e..6a08882f 100644 --- a/src/audio/MusicManager.h +++ b/src/audio/MusicManager.h @@ -267,6 +267,9 @@ public: void Initialise(); void Terminate(); + void ChangeMusicMode(int32 mode); + void StopFrontEndTrack(); + char *Get3DProviderName(char); bool PlayerInCar(); void DisplayRadioStationName(); diff --git a/src/audio/SampleManager.cpp b/src/audio/SampleManager.cpp index fbeb49ed..b2f0cf35 100644 --- a/src/audio/SampleManager.cpp +++ b/src/audio/SampleManager.cpp @@ -1,18 +1,67 @@ +#include "SampleManager.h" #include "common.h" #include "patcher.h" -#include "SampleManager.h" CSampleManager &cSampleManager = *(CSampleManager *)0x7341E0; uint32 &nNumOfMp3Files = *(uint32 *)0x95CC00; uint8 &num3DProvidersAvailable = *(uint8 *)0x734237; -uint32 *asName3DProviders = (uint32 *)0x734238; +char **asName3DProviders = (char **)0x734238; -bool CSampleManager::IsMP3RadioChannelAvailable() { +bool +CSampleManager::IsMP3RadioChannelAvailable() +{ return nNumOfMp3Files != 0; } WRAPPER +void CSampleManager::SetChannelFrequency(int32, int32) { EAXJMP(0x5679D0); } + +WRAPPER +void CSampleManager::SetChannelEmittingVolume(int32, uint32) { EAXJMP(0x567820); } + +WRAPPER +void +CSampleManager::SetChannel3DPosition(int32, float, float, float) +{ + EAXJMP(0x567890); +} + +WRAPPER +void CSampleManager::SetChannelLoopCount(int32, int32) { EAXJMP(0x567AA0); } + +WRAPPER +void CSampleManager::SetChannel3DDistances(int32, int32, int32) { EAXJMP(0x5678D0); } + +WRAPPER +void CSampleManager::SetChannelReverbFlag(int32, uint8) { EAXJMP(0x567630); } + +WRAPPER +int32 CSampleManager::GetSampleLength(int32) { EAXJMP(0x567300); } + +WRAPPER +bool CSampleManager::InitialiseChannel(int32, int32, uint32, uint32) { EAXJMP(0x5676A0); } + +WRAPPER +void CSampleManager::SetChannelLoopPoints(int32, int32, int32) { EAXJMP(0x567A30); } + +WRAPPER +bool +CSampleManager::CheckForAnAudioFileOnCD() +{ + EAXJMP(0x566EA0); +} + +WRAPPER +int32 CSampleManager::GetSampleBaseFrequency(int32) { EAXJMP(0x5672A0); } + +WRAPPER +int32 CSampleManager::GetSampleLoopStartOffset(int32) { EAXJMP(0x5672C0); } + +WRAPPER +int32 CSampleManager::GetSampleLoopEndOffset(int32) { EAXJMP(0x5672E0); } + +WRAPPER bool CSampleManager::IsSampleBankLoaded(uint8) { EAXJMP(0x567130); } WRAPPER @@ -110,6 +159,13 @@ CSampleManager::GetChannelUsedFlag(int32 id) WRAPPER void +CSampleManager::StartChannel(int32 id) +{ + EAXJMP(0x567B80); +} + +WRAPPER +void CSampleManager::StopChannel(int32 id) { EAXJMP(0x567BE0); diff --git a/src/audio/SampleManager.h b/src/audio/SampleManager.h index f0245d4e..dc46e7ec 100644 --- a/src/audio/SampleManager.h +++ b/src/audio/SampleManager.h @@ -1,5 +1,7 @@ #pragma once +#include "common.h" + struct tSample { int m_nOffset; unsigned int m_nSize; @@ -11,6 +13,26 @@ struct tSample { class CSampleManager { public: + void SetChannelFrequency(int32, int32); + void SetChannelEmittingVolume(int32, uint32); + void SetChannel3DPosition(int32, float, float, float); + void SetChannelLoopCount(int32, int32); + + void SetChannel3DDistances(int32, int32, int32); + void SetChannelReverbFlag(int32, uint8); + + int32 GetSampleLength(int32); + + bool InitialiseChannel(int32, int32, uint32, uint32 something = 0); + + void SetChannelLoopPoints(int32, int32, int32); + + bool CheckForAnAudioFileOnCD(); + + int32 GetSampleBaseFrequency(int32); + int32 GetSampleLoopStartOffset(int32); + int32 GetSampleLoopEndOffset(int32); + bool IsSampleBankLoaded(uint8); void UnloadSampleBank(uint8); void Terminate(); @@ -32,6 +54,8 @@ public: void SetSpeakerConfig(uint32 config); bool GetChannelUsedFlag(int32 id); + + void StartChannel(int32 id); void StopChannel(int32 id); static bool IsMP3RadioChannelAvailable(); @@ -39,6 +63,6 @@ public: extern uint32 &nNumOfMp3Files; extern uint8 &num3DProvidersAvailable; -extern uint32* asName3DProviders; +extern char **asName3DProviders; extern CSampleManager &cSampleManager;
\ No newline at end of file diff --git a/src/control/AutoPilot.h b/src/control/AutoPilot.h index 364cb633..b1c824d8 100644 --- a/src/control/AutoPilot.h +++ b/src/control/AutoPilot.h @@ -72,8 +72,8 @@ public: int8 m_nPreviousDirection; int8 m_nCurrentDirecton; int8 m_nNextDirection; - int8 m_nPreviousPathDirection; - int8 m_nCurrentPathDirection; + int8 m_nPreviousLane; + int8 m_nCurrentLane; eCarDrivingStyle m_nDrivingStyle; eCarMission m_nCarMission; eCarTempAction m_nAnimationId; @@ -101,8 +101,7 @@ public: m_nCurrentPathNodeInfo = m_nNextPathNodeInfo; m_nNextDirection = 1; m_nCurrentDirecton = m_nNextDirection; - m_nCurrentPathDirection = 0; - m_nPreviousPathDirection = m_nCurrentPathDirection; + m_nPreviousLane = m_nCurrentLane = 0; m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS; m_nCarMission = MISSION_NONE; m_nAnimationId = TEMPACT_NONE; diff --git a/src/control/Bridge.cpp b/src/control/Bridge.cpp index 3215ea2d..81f43f32 100644 --- a/src/control/Bridge.cpp +++ b/src/control/Bridge.cpp @@ -46,6 +46,7 @@ void CBridge::Update() float liftHeight; + // Set bridge height and state if (CStats::CommercialPassed) { if (TimeOfBridgeBecomingOperational == 0) @@ -81,30 +82,6 @@ void CBridge::Update() liftHeight = 25.0; State = STATE_LIFT_PART_IS_UP; } - - // Move bridge part - if (liftHeight != OldLift) - { - pLiftPart->GetPosition().z = DefaultZLiftPart + liftHeight; - pLiftPart->GetMatrix().UpdateRW(); - pLiftPart->UpdateRwFrame(); - if (pLiftRoad) - { - pLiftRoad->GetPosition().z = DefaultZLiftRoad + liftHeight; - pLiftRoad->GetMatrix().UpdateRW(); - pLiftRoad->UpdateRwFrame(); - } - pWeight->GetPosition().z = DefaultZLiftWeight - liftHeight; - pWeight->GetMatrix().UpdateRW(); - pWeight->UpdateRwFrame(); - - OldLift = liftHeight; - } - - if (State == STATE_LIFT_PART_ABOUT_TO_MOVE_UP && OldState == STATE_LIFT_PART_IS_DOWN) - ThePaths.SetLinksBridgeLights(-330.0, -230.0, -700.0, -588.0, true); - else if (State == STATE_LIFT_PART_IS_DOWN && OldState == STATE_LIFT_PART_MOVING_DOWN) - ThePaths.SetLinksBridgeLights(-330.0, -230.0, -700.0, -588.0, false); } else { @@ -112,6 +89,30 @@ void CBridge::Update() TimeOfBridgeBecomingOperational = 0; State = STATE_BRIDGE_LOCKED; } + + // Move bridge part + if (liftHeight != OldLift) + { + pLiftPart->GetPosition().z = DefaultZLiftPart + liftHeight; + pLiftPart->GetMatrix().UpdateRW(); + pLiftPart->UpdateRwFrame(); + if (pLiftRoad) + { + pLiftRoad->GetPosition().z = DefaultZLiftRoad + liftHeight; + pLiftRoad->GetMatrix().UpdateRW(); + pLiftRoad->UpdateRwFrame(); + } + pWeight->GetPosition().z = DefaultZLiftWeight - liftHeight; + pWeight->GetMatrix().UpdateRW(); + pWeight->UpdateRwFrame(); + + OldLift = liftHeight; + } + + if (State == STATE_LIFT_PART_ABOUT_TO_MOVE_UP && OldState == STATE_LIFT_PART_IS_DOWN) + ThePaths.SetLinksBridgeLights(-330.0, -230.0, -700.0, -588.0, true); + else if (State == STATE_LIFT_PART_IS_DOWN && OldState == STATE_LIFT_PART_MOVING_DOWN) + ThePaths.SetLinksBridgeLights(-330.0, -230.0, -700.0, -588.0, false); } bool CBridge::ShouldLightsBeFlashing() { return State != STATE_LIFT_PART_IS_DOWN; } diff --git a/src/control/CarAI.cpp b/src/control/CarAI.cpp new file mode 100644 index 00000000..faf27788 --- /dev/null +++ b/src/control/CarAI.cpp @@ -0,0 +1,6 @@ +#include "common.h" +#include "patcher.h" +#include "CarAI.h" + +WRAPPER void CCarAI::UpdateCarAI(CVehicle*) { EAXJMP(0x413E50); } +WRAPPER void CCarAI::MakeWayForCarWithSiren(CVehicle *veh) { EAXJMP(0x416280); } diff --git a/src/control/CarAI.h b/src/control/CarAI.h new file mode 100644 index 00000000..5112f769 --- /dev/null +++ b/src/control/CarAI.h @@ -0,0 +1,10 @@ +#pragma once + +class CVehicle; + +class CCarAI +{ +public: + static void UpdateCarAI(CVehicle*); + static void MakeWayForCarWithSiren(CVehicle *veh); +}; diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp index b0f4c1ed..5e436c84 100644 --- a/src/control/CarCtrl.cpp +++ b/src/control/CarCtrl.cpp @@ -12,3 +12,16 @@ WRAPPER void CCarCtrl::SwitchVehicleToRealPhysics(CVehicle*) { EAXJMP(0x41F7F0); WRAPPER void CCarCtrl::AddToCarArray(int32 id, int32 vehclass) { EAXJMP(0x4182F0); } WRAPPER void CCarCtrl::UpdateCarCount(CVehicle*, bool) { EAXJMP(0x4202E0); } WRAPPER int32 CCarCtrl::ChooseCarModel(int32 vehclass) { EAXJMP(0x418110); } +WRAPPER bool CCarCtrl::JoinCarWithRoadSystemGotoCoors(CVehicle*, CVector, bool) { EAXJMP(0x41FA00); } +WRAPPER void CCarCtrl::JoinCarWithRoadSystem(CVehicle*) { EAXJMP(0x41F820); } +WRAPPER void CCarCtrl::SteerAICarWithPhysics(CVehicle*) { EAXJMP(0x41DA60); } +WRAPPER void CCarCtrl::UpdateCarOnRails(CVehicle*) { EAXJMP(0x418880); } +WRAPPER void CCarCtrl::ScanForPedDanger(CVehicle *veh) { EAXJMP(0x418F40); } + +bool +CCarCtrl::MapCouldMoveInThisArea(float x, float y) +{ + // bridge moves up and down + return x > -342.0f && x < -219.0f && + y > -677.0f && y < -580.0f; +} diff --git a/src/control/CarCtrl.h b/src/control/CarCtrl.h index c54f747f..677dcf36 100644 --- a/src/control/CarCtrl.h +++ b/src/control/CarCtrl.h @@ -9,6 +9,12 @@ public: static void AddToCarArray(int32 id, int32 vehclass); static void UpdateCarCount(CVehicle*, bool); static int32 ChooseCarModel(int32 vehclass); + static bool JoinCarWithRoadSystemGotoCoors(CVehicle*, CVector, bool); + static void JoinCarWithRoadSystem(CVehicle*); + static void SteerAICarWithPhysics(CVehicle*); + static void UpdateCarOnRails(CVehicle*); + static bool MapCouldMoveInThisArea(float x, float y); + static void ScanForPedDanger(CVehicle *veh); static int32 &NumLawEnforcerCars; static int32 &NumAmbulancesOnDuty; diff --git a/src/control/Darkel.cpp b/src/control/Darkel.cpp index ab28f96e..ad8d1176 100644 --- a/src/control/Darkel.cpp +++ b/src/control/Darkel.cpp @@ -141,7 +141,7 @@ void CDarkel::RegisterKillByPlayer(CPed *victim, eWeaponType weapontype, bool he } #endif -void CDarkel::RegisterKillNotByPlayer() +void CDarkel::RegisterKillNotByPlayer(CPed* victim, eWeaponType weapontype) { ++CStats::NumberKillFrenziesPassed; } @@ -300,7 +300,7 @@ void CDarkel::Update() TimeOfFrenzyStart = CTimer::GetTimeInMilliseconds(); - FindPlayerPed()->m_pWanted->SetWantedLevel(NOTWANTED); + FindPlayerPed()->m_pWanted->SetWantedLevel(0); if (WeaponType == WEAPONTYPE_UZI_DRIVEBY) WeaponType = WEAPONTYPE_UZI; diff --git a/src/control/Darkel.h b/src/control/Darkel.h index 35d849d2..77a14bb8 100644 --- a/src/control/Darkel.h +++ b/src/control/Darkel.h @@ -42,7 +42,7 @@ public: static eKillFrenzyStatus ReadStatus(); static void RegisterCarBlownUpByPlayer(CVehicle *vehicle); static void RegisterKillByPlayer(CPed *victim, eWeaponType weapontype, bool headshot = false); - static void RegisterKillNotByPlayer(); + static void RegisterKillNotByPlayer(CPed* victim, eWeaponType weapontype); static void ResetModelsKilledByPlayer(); static void ResetOnPlayerDeath(); static void StartFrenzy(eWeaponType weaponType, int32 time, int16 kill, int32 modelId0, wchar *text, int32 modelId2, int32 modelId3, int32 modelId4, bool standardSound, bool needHeadShot); diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp index d601db8e..acc2b459 100644 --- a/src/control/Garages.cpp +++ b/src/control/Garages.cpp @@ -63,6 +63,8 @@ CGarages::IsModelIndexADoor(uint32 id) id == MI_CRUSHERLID; } +WRAPPER void CGarages::TriggerMessage(char *text, int16, uint16 time, int16) { EAXJMP(0x426B20); } + #if 0 WRAPPER void CGarages::PrintMessages(void) { EAXJMP(0x426310); } #else diff --git a/src/control/Garages.h b/src/control/Garages.h index f018401c..69f9d256 100644 --- a/src/control/Garages.h +++ b/src/control/Garages.h @@ -22,5 +22,6 @@ public: public: static bool IsModelIndexADoor(uint32 id); + static void TriggerMessage(char *text, int16, uint16 time, int16); static void PrintMessages(void); }; diff --git a/src/control/PathFind.cpp b/src/control/PathFind.cpp index a92882db..f90e0c8f 100644 --- a/src/control/PathFind.cpp +++ b/src/control/PathFind.cpp @@ -5,7 +5,7 @@ CPathFind &ThePaths = *(CPathFind*)0x8F6754; WRAPPER int32 CPathFind::FindNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bool disabled, bool betweenLevels) { EAXJMP(0x42CC30); } - +WRAPPER CPathNode** CPathFind::FindNextNodeWandering(uint8, CVector, CPathNode**, CPathNode**, uint8, uint8*) { EAXJMP(0x42B9F0); } int TempListLength; enum diff --git a/src/control/PathFind.h b/src/control/PathFind.h index 9b6be573..9d97de3f 100644 --- a/src/control/PathFind.h +++ b/src/control/PathFind.h @@ -129,6 +129,7 @@ public: void StoreNodeInfoCar(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, int16 width, int8 numLeft, int8 numRight); void RegisterMapObject(CTreadable *mapObject); int32 FindNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bool disabled, bool betweenLevels); + CPathNode** FindNextNodeWandering(uint8, CVector, CPathNode**, CPathNode**, uint8, uint8*); bool IsPathObject(int id) { return id < PATHNODESIZE && (InfoForTileCars[id*12].type != 0 || InfoForTilePeds[id*12].type != 0); } diff --git a/src/control/Phones.cpp b/src/control/Phones.cpp index 028d80a9..376e2757 100644 --- a/src/control/Phones.cpp +++ b/src/control/Phones.cpp @@ -2,12 +2,18 @@ #include "patcher.h" #include "Phones.h" #include "Pools.h" +#include "ModelIndices.h" +#include "Ped.h" +#include "Pad.h" +#include "Messages.h" CPhoneInfo &gPhoneInfo = *(CPhoneInfo*)0x732A20; bool &CPhoneInfo::isPhonePickedUp = *(bool*)0x6283AC; -bool &CPhoneInfo::isPhoneBeingPickedUp = *(bool*)0x6283B4; +uint32 &CPhoneInfo::phoneMessagesTimer = *(uint32*)0x6283A8; CPhone *&CPhoneInfo::pickedUpPhone = *(CPhone**)0x6283B0; +bool &CPhoneInfo::isPhoneBeingPickedUp = *(bool*)0x6283B4; +CPed *&CPhoneInfo::pedWhoPickingUpPhone = *(CPed**)0x6283B8; int CPhoneInfo::FindNearestFreePhone(CVector *pos) @@ -69,21 +75,20 @@ CPhoneInfo::Load(CPhoneInfo *source, uint8 buffer) CPhone *phone = &source->m_aPhones[phoneId]; m_aPhones[phoneId].m_vecPos = phone->m_vecPos; - memcpy(m_aPhones[phoneId].m_apMessages, phone->m_apMessages, sizeof(uint16*) * 6); + memcpy(m_aPhones[phoneId].m_apMessages, phone->m_apMessages, sizeof(wchar*) * 6); m_aPhones[phoneId].m_pEntity = phone->m_pEntity; m_aPhones[phoneId].m_nState = phone->m_nState; m_aPhones[phoneId].field_30 = phone->field_30; + // It's saved as building pool index in save file, convert it to true entity if (phone->m_pEntity) { - // It's saved as building pool index in save file, convert it to true entity - CBuilding *actualEntity = CPools::GetBuildingPool()->GetSlot((int)phone->m_pEntity - 1); - m_aPhones[phoneId].m_pEntity = actualEntity; + m_aPhones[phoneId].m_pEntity = CPools::GetBuildingPool()->GetSlot((int)phone->m_pEntity - 1); } } } void -CPhoneInfo::SetPhoneMessage_JustOnce(int phoneId, uint16 *msg1, uint16 *msg2, uint16 *msg3, uint16 *msg4, uint16 *msg5, uint16 *msg6) +CPhoneInfo::SetPhoneMessage_JustOnce(int phoneId, wchar *msg1, wchar *msg2, wchar *msg3, wchar *msg4, wchar *msg5, wchar *msg6) { // If there is at least one message, it should be msg1. if (msg1) { @@ -100,7 +105,7 @@ CPhoneInfo::SetPhoneMessage_JustOnce(int phoneId, uint16 *msg1, uint16 *msg2, ui } void -CPhoneInfo::SetPhoneMessage_Repeatedly(int phoneId, uint16 *msg1, uint16 *msg2, uint16 *msg3, uint16 *msg4, uint16 *msg5, uint16 *msg6) +CPhoneInfo::SetPhoneMessage_Repeatedly(int phoneId, wchar *msg1, wchar *msg2, wchar *msg3, wchar *msg4, wchar *msg5, wchar *msg6) { // If there is at least one message, it should be msg1. if (msg1) { @@ -116,6 +121,137 @@ CPhoneInfo::SetPhoneMessage_Repeatedly(int phoneId, uint16 *msg1, uint16 *msg2, } } +int +CPhoneInfo::GrabPhone(float xPos, float yPos) +{ + // "Grab" doesn't mean picking up the phone, it means allocating some particular phone to + // whoever called the 024A opcode first with the position parameters closest to phone. + // Same phone won't be available on next run of this function. + + int nearestPhoneId = -1; + CVector pos(xPos, yPos, 0.0f); + float nearestPhoneDist = 100.0f; + + for (int phoneId = m_nNum; phoneId < m_nMax; phoneId++) { + float phoneDistance = (m_aPhones[phoneId].m_vecPos - pos).Magnitude2D(); + if (phoneDistance < nearestPhoneDist) { + nearestPhoneDist = phoneDistance; + nearestPhoneId = phoneId; + } + } + m_aPhones[nearestPhoneId].m_nState = PHONE_STATE_MESSAGE_REMOVED; + + CPhone oldFirstPhone = m_aPhones[m_nNum]; + m_aPhones[m_nNum] = m_aPhones[nearestPhoneId]; + m_aPhones[nearestPhoneId] = oldFirstPhone; + m_nNum++; + return m_nNum - 1; +} + +void +CPhoneInfo::Initialise(void) +{ + CBuildingPool *pool = CPools::GetBuildingPool(); + pedWhoPickingUpPhone = nil; + isPhonePickedUp = false; + isPhoneBeingPickedUp = false; + pickedUpPhone = nil; + m_nMax = 0; + m_nNum = 0; + for (int v5 = pool->GetSize() - 1; v5 >= 0; v5--) { + CBuilding *building = pool->GetSlot(v5); + if (building) { + if (building->m_modelIndex == MI_PHONEBOOTH1) { + CPhone *maxPhone = &m_aPhones[m_nMax]; + maxPhone->m_nState = PHONE_STATE_FREE; + maxPhone->m_vecPos = *(building->GetPosition()); + maxPhone->m_pEntity = building; + m_nMax++; + } + } + } +} + +void +CPhoneInfo::Save(CPhoneInfo *destination, uint32 *size) +{ + *size = sizeof(CPhoneInfo); + destination->m_nMax = this->m_nMax; + destination->m_nNum = m_nNum; + for(int phoneId = 0; phoneId < 50; phoneId++) { + CPhone* phone = &destination->m_aPhones[phoneId]; + + phone->m_vecPos = m_aPhones[phoneId].m_vecPos; + memcpy(phone->m_apMessages, m_aPhones[phoneId].m_apMessages, sizeof(wchar*) * 6); + phone->m_pEntity = m_aPhones[phoneId].m_pEntity; + phone->m_nState = m_aPhones[phoneId].m_nState; + phone->field_30 = m_aPhones[phoneId].field_30; + + // Convert entity pointer to building pool index while saving + if (phone->m_pEntity) { + phone->m_pEntity = (CEntity*) CPools::GetBuildingPool()->GetJustIndex((CBuilding*)phone->m_pEntity) + 1; + } + } +} + +void +CPhoneInfo::Shutdown(void) +{ + m_nMax = 0; + m_nNum = 0; +} + +void +PhonePutDownCB(CAnimBlendAssociation *assoc, void *arg) +{ + assoc->flags |= ASSOC_DELETEFADEDOUT; + assoc->blendDelta = -1000.0f; + CPad::GetPad(0)->DisablePlayerControls &= ~PLAYERCONTROL_DISABLED_40; + CPed *ped = (CPed*)arg; + + if (assoc->blendAmount > 0.5f) + ped->m_ped_flagC10 = true; + + if (ped->m_nPedState == PED_MAKE_CALL) + ped->m_nPedState = PED_IDLE; +} + +void +PhonePickUpCB(CAnimBlendAssociation *assoc, void *arg) +{ + CPhone *phone = (CPhone*)arg; + int messagesDisplayTime = 0; + + for(int i=0; i < 6; i++) { + wchar *msg = phone->m_apMessages[i]; + if (msg) { + CMessages::AddMessage(msg, 3000, 0); + messagesDisplayTime += 3000; + } + } + + CPhoneInfo::isPhoneBeingPickedUp = false; + CPhoneInfo::isPhonePickedUp = true; + CPhoneInfo::pickedUpPhone = phone; + CPhoneInfo::phoneMessagesTimer = CTimer::GetTimeInMilliseconds() + messagesDisplayTime; + + if (phone->m_nState == PHONE_STATE_ONETIME_MESSAGE_SET) { + phone->m_nState = PHONE_STATE_ONETIME_MESSAGE_SHOWN; + } else { + phone->m_nState = PHONE_STATE_REPEATED_MESSAGE_SHOWN; + phone->m_lastTimeRepeatedMsgShown = CTimer::GetTimeInMilliseconds(); + } + + CPed *ped = CPhoneInfo::pedWhoPickingUpPhone; + ped->m_nMoveState = PEDMOVE_STILL; + CAnimManager::BlendAnimation((RpClump*)ped->m_rwObject, ASSOCGRP_STD, ANIM_IDLE_STANCE, 8.0f); + + if (assoc->blendAmount > 0.5f && ped) + CAnimManager::BlendAnimation((RpClump*)ped->m_rwObject, ASSOCGRP_STD, ANIM_PHONE_TALK, 8.0f); + + CPhoneInfo::pedWhoPickingUpPhone = nil; +} + STARTPATCHES InjectHook(0x42F720, &CPhoneInfo::FindNearestFreePhone, PATCH_JUMP); InjectHook(0x42FD50, &CPhoneInfo::PhoneAtThisPosition, PATCH_JUMP); @@ -124,7 +260,10 @@ STARTPATCHES InjectHook(0x430120, &CPhoneInfo::Load, PATCH_JUMP); InjectHook(0x42FF90, &CPhoneInfo::SetPhoneMessage_JustOnce, PATCH_JUMP); InjectHook(0x42FF30, &CPhoneInfo::SetPhoneMessage_Repeatedly, PATCH_JUMP); -ENDPATCHES - -WRAPPER void PhonePutDownCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x42F570); } -WRAPPER void PhonePickUpCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x42F470); } + InjectHook(0x430060, &CPhoneInfo::Save, PATCH_JUMP); + InjectHook(0x42F710, &CPhoneInfo::Shutdown, PATCH_JUMP); + InjectHook(0x42F640, &CPhoneInfo::Initialise, PATCH_JUMP); + InjectHook(0x42FDB0, &CPhoneInfo::GrabPhone, PATCH_JUMP); + InjectHook(0x42F570, &PhonePutDownCB, PATCH_JUMP); + InjectHook(0x42F470, &PhonePickUpCB, PATCH_JUMP); +ENDPATCHES
\ No newline at end of file diff --git a/src/control/Phones.h b/src/control/Phones.h index 74f24d25..35389f3f 100644 --- a/src/control/Phones.h +++ b/src/control/Phones.h @@ -1,7 +1,9 @@ #pragma once #include "Physical.h" -#include "AnimBlendAssociation.h" + +class CPed; +class CAnimBlendAssociation; enum { PHONE_STATE_FREE, @@ -19,7 +21,7 @@ enum { struct CPhone { CVector m_vecPos; - uint16 *m_apMessages[6]; + wchar *m_apMessages[6]; uint32 m_lastTimeRepeatedMsgShown; CEntity *m_pEntity; // it's building pool index in save files int32 m_nState; @@ -29,10 +31,13 @@ struct CPhone static_assert(sizeof(CPhone) == 0x34, "CPhone: error"); class CPhoneInfo { +public: static bool &isPhonePickedUp; - static bool &isPhoneBeingPickedUp; + static uint32 &phoneMessagesTimer; static CPhone *&pickedUpPhone; -public: + static bool &isPhoneBeingPickedUp; + static CPed *&pedWhoPickingUpPhone; + int32 m_nMax; int32 m_nNum; CPhone m_aPhones[50]; @@ -45,8 +50,12 @@ public: bool HasMessageBeenDisplayed(int); bool IsMessageBeingDisplayed(int); void Load(CPhoneInfo *source, uint8 buffer); - void SetPhoneMessage_JustOnce(int phoneId, uint16 *msg1, uint16 *msg2, uint16 *msg3, uint16 *msg4, uint16 *msg5, uint16 *msg6); - void SetPhoneMessage_Repeatedly(int phoneId, uint16 *msg1, uint16 *msg2, uint16 *msg3, uint16 *msg4, uint16 *msg5, uint16 *msg6); + void SetPhoneMessage_JustOnce(int phoneId, wchar *msg1, wchar *msg2, wchar *msg3, wchar *msg4, wchar *msg5, wchar *msg6); + void SetPhoneMessage_Repeatedly(int phoneId, wchar *msg1, wchar *msg2, wchar *msg3, wchar *msg4, wchar *msg5, wchar *msg6); + int GrabPhone(float, float); + void Initialise(void); + void Save(CPhoneInfo*, uint32*); + void Shutdown(void); }; extern CPhoneInfo &gPhoneInfo; diff --git a/src/control/Population.cpp b/src/control/Population.cpp index 1ae5962d..31c475f0 100644 --- a/src/control/Population.cpp +++ b/src/control/Population.cpp @@ -7,7 +7,9 @@ PedGroup *CPopulation::ms_pPedGroups = (PedGroup*)0x6E9248; bool &CPopulation::ms_bGivePedsWeapons = *(bool*)0x95CCF6; int32 &CPopulation::m_AllRandomPedsThisType = *(int32*)0x5FA570; float &CPopulation::PedDensityMultiplier = *(float*)0x5FA56C; +uint32 &CPopulation::ms_nTotalMissionPeds = *(uint32*)0x8F5F70; WRAPPER void CPopulation::UpdatePedCount(uint32, bool) { EAXJMP(0x4F5A60); } WRAPPER void CPopulation::DealWithZoneChange(eLevelName oldLevel, eLevelName newLevel, bool) { EAXJMP(0x4F6200); } WRAPPER CPed *CPopulation::AddPedInCar(CVehicle *vehicle) { EAXJMP(0x4F5800); } +WRAPPER bool CPopulation::IsPointInSafeZone(CVector *coors) { EAXJMP(0x4F60C0); } diff --git a/src/control/Population.h b/src/control/Population.h index 6bd2e3ae..e067562a 100644 --- a/src/control/Population.h +++ b/src/control/Population.h @@ -2,6 +2,7 @@ class CPed; class CVehicle; +enum eLevelName; struct PedGroup { @@ -15,8 +16,10 @@ public: static bool &ms_bGivePedsWeapons; static int32 &m_AllRandomPedsThisType; static float &PedDensityMultiplier; + static uint32 &ms_nTotalMissionPeds; static void UpdatePedCount(uint32, bool); static void DealWithZoneChange(eLevelName oldLevel, eLevelName newLevel, bool); static CPed *AddPedInCar(CVehicle *vehicle); + static bool IsPointInSafeZone(CVector *coors); }; diff --git a/src/control/Remote.cpp b/src/control/Remote.cpp new file mode 100644 index 00000000..8d8d08f2 --- /dev/null +++ b/src/control/Remote.cpp @@ -0,0 +1,5 @@ +#include "common.h" +#include "patcher.h" +#include "Remote.h" + +WRAPPER void CRemote::TakeRemoteControlledCarFromPlayer(void) { EAXJMP(0x435DA0); } diff --git a/src/control/Remote.h b/src/control/Remote.h new file mode 100644 index 00000000..f8ef96bf --- /dev/null +++ b/src/control/Remote.h @@ -0,0 +1,7 @@ +#pragma once + +class CRemote +{ +public: + static void TakeRemoteControlledCarFromPlayer(void); +}; diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp index 3ce9085f..d9453ad6 100644 --- a/src/control/Replay.cpp +++ b/src/control/Replay.cpp @@ -11,7 +11,7 @@ #include "FileMgr.h" #include "Heli.h" #include "main.h" -#include "math/Matrix.h" +#include "Matrix.h" #include "ModelIndices.h" #include "ModelInfo.h" #include "Object.h" @@ -25,7 +25,7 @@ #include "RpAnimBlend.h" #include "RwHelper.h" #include "CutsceneMgr.h" -#include "render/Skidmarks.h" +#include "Skidmarks.h" #include "Streaming.h" #include "Timer.h" #include "Train.h" @@ -625,9 +625,9 @@ void CReplay::StoreCarUpdate(CVehicle *vehicle, int id) vp->health = vehicle->m_fHealth / 4.0f; /* Not anticipated that health can be > 1000. */ vp->acceleration = vehicle->m_fGasPedal * 100.0f; vp->panels = vehicle->IsCar() ? ((CAutomobile*)vehicle)->Damage.m_panelStatus : 0; - vp->velocityX = 8000.0f * max(-4.0f, min(4.0f, vehicle->GetSpeed().x)); /* 8000!? */ - vp->velocityY = 8000.0f * max(-4.0f, min(4.0f, vehicle->GetSpeed().y)); - vp->velocityZ = 8000.0f * max(-4.0f, min(4.0f, vehicle->GetSpeed().z)); + vp->velocityX = 8000.0f * max(-4.0f, min(4.0f, vehicle->GetMoveSpeed().x)); /* 8000!? */ + vp->velocityY = 8000.0f * max(-4.0f, min(4.0f, vehicle->GetMoveSpeed().y)); + vp->velocityZ = 8000.0f * max(-4.0f, min(4.0f, vehicle->GetMoveSpeed().z)); vp->mi = vehicle->GetModelIndex(); vp->primary_color = vehicle->m_currentColour1; vp->secondary_color = vehicle->m_currentColour2; @@ -718,7 +718,7 @@ void CReplay::ProcessCarUpdate(CVehicle *vehicle, float interpolation, CAddressI } vehicle->bEngineOn = true; if (vehicle->IsCar()) - ((CAutomobile*)vehicle)->m_nWheelsOnGround = 4; + ((CAutomobile*)vehicle)->m_nDriveWheelsOnGround = 4; CWorld::Remove(vehicle); CWorld::Add(vehicle); if (vehicle->IsBoat()) @@ -850,10 +850,10 @@ bool CReplay::PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, flo TheCamera.GetMatrix().GetPosition() *= split; TheCamera.GetMatrix() += CMatrix(interpolation) * pg->camera_pos; RwMatrix* pm = RwFrameGetMatrix(RwCameraGetFrame(TheCamera.m_pRwCamera)); - pm->pos = *(RwV3d*)TheCamera.GetMatrix().GetPosition(); - pm->at = *(RwV3d*)TheCamera.GetMatrix().GetForward(); - pm->up = *(RwV3d*)TheCamera.GetMatrix().GetUp(); - pm->right = *(RwV3d*)TheCamera.GetMatrix().GetRight(); + pm->pos = *(RwV3d*)TheCamera.GetPosition(); + pm->at = *(RwV3d*)TheCamera.GetForward(); + pm->up = *(RwV3d*)TheCamera.GetUp(); + pm->right = *(RwV3d*)TheCamera.GetRight(); CameraFocusX = split * CameraFocusX + interpolation * pg->player_pos.x; CameraFocusY = split * CameraFocusY + interpolation * pg->player_pos.y; CameraFocusZ = split * CameraFocusZ + interpolation * pg->player_pos.z; @@ -979,15 +979,15 @@ void CReplay::ProcessReplayCamera(void) switch (CameraMode) { case REPLAYCAMMODE_TOPDOWN: { - TheCamera.GetMatrix().GetPosition() = CVector(CameraFocusX, CameraFocusY, CameraFocusZ + 15.0f); - TheCamera.GetMatrix().GetForward() = CVector(0.0f, 0.0f, -1.0f); - TheCamera.GetMatrix().GetUp() = CVector(0.0f, 1.0f, 0.0f); - TheCamera.GetMatrix().GetRight() = CVector(1.0f, 0.0f, 0.0f); + TheCamera.GetPosition() = CVector(CameraFocusX, CameraFocusY, CameraFocusZ + 15.0f); + TheCamera.GetForward() = CVector(0.0f, 0.0f, -1.0f); + TheCamera.GetUp() = CVector(0.0f, 1.0f, 0.0f); + TheCamera.GetRight() = CVector(1.0f, 0.0f, 0.0f); RwMatrix* pm = RwFrameGetMatrix(RwCameraGetFrame(TheCamera.m_pRwCamera)); - pm->pos = *(RwV3d*)&TheCamera.GetMatrix().GetPosition(); - pm->at = *(RwV3d*)&TheCamera.GetMatrix().GetForward(); - pm->up = *(RwV3d*)&TheCamera.GetMatrix().GetUp(); - pm->right = *(RwV3d*)&TheCamera.GetMatrix().GetRight(); + pm->pos = *(RwV3d*)&TheCamera.GetPosition(); + pm->at = *(RwV3d*)&TheCamera.GetForward(); + pm->up = *(RwV3d*)&TheCamera.GetUp(); + pm->right = *(RwV3d*)&TheCamera.GetRight(); break; } case REPLAYCAMMODE_FIXED: @@ -1113,7 +1113,7 @@ void CReplay::StoreStuffInMem(void) TimeStep = CTimer::GetTimeStep(); TimeScale = CTimer::GetTimeScale(); int size = CPools::GetPedPool()->GetSize(); - pPedAnims = (CStoredDetailedAnimationState*)malloc(size * sizeof(CStoredDetailedAnimationState)); + pPedAnims = new CStoredDetailedAnimationState[size]; for (int i = 0; i < size; i++) { CPed* ped = CPools::GetPedPool()->GetSlot(i); if (ped) @@ -1279,7 +1279,7 @@ void CReplay::RestoreStuffFromMem(void) continue; RetrieveDetailedPedAnimation(ped, &pPedAnims[i]); } - free(pPedAnims); + delete[] pPedAnims; pPedAnims = nil; DMAudio.ChangeMusicMode(0); DMAudio.SetRadioInCar(OldRadioStation); @@ -1525,15 +1525,15 @@ void CReplay::ProcessLookAroundCam(void) right.Normalise(); CVector up = CrossProduct(forward, right); up.Normalise(); - TheCamera.GetMatrix().GetForward() = forward; - TheCamera.GetMatrix().GetUp() = up; - TheCamera.GetMatrix().GetRight() = right; - TheCamera.GetMatrix().GetPosition() = camera_pt; + TheCamera.GetForward() = forward; + TheCamera.GetUp() = up; + TheCamera.GetRight() = right; + TheCamera.GetPosition() = camera_pt; RwMatrix* pm = RwFrameGetMatrix(RwCameraGetFrame(TheCamera.m_pRwCamera)); - pm->pos = *(RwV3d*)&TheCamera.GetMatrix().GetPosition(); - pm->at = *(RwV3d*)&TheCamera.GetMatrix().GetForward(); - pm->up = *(RwV3d*)&TheCamera.GetMatrix().GetUp(); - pm->right = *(RwV3d*)&TheCamera.GetMatrix().GetRight(); + pm->pos = *(RwV3d*)&TheCamera.GetPosition(); + pm->at = *(RwV3d*)&TheCamera.GetForward(); + pm->up = *(RwV3d*)&TheCamera.GetUp(); + pm->right = *(RwV3d*)&TheCamera.GetRight(); TheCamera.CalculateDerivedValues(); RwMatrixUpdate(RwFrameGetMatrix(RwCameraGetFrame(TheCamera.m_pRwCamera))); RwFrameUpdateObjects(RwCameraGetFrame(TheCamera.m_pRwCamera)); diff --git a/src/control/Replay.h b/src/control/Replay.h index cd8d9a45..6b11da75 100644 --- a/src/control/Replay.h +++ b/src/control/Replay.h @@ -176,7 +176,7 @@ class CReplay int8 velocityZ; union{ int8 car_gun; - uint8 wheel_state; + int8 wheel_state; }; uint8 wheel_susp_dist[4]; uint8 wheel_rotation[4]; diff --git a/src/control/Script.cpp b/src/control/Script.cpp index b50c101e..bd43d301 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -4,10 +4,17 @@ #include "Script.h" #include "ScriptCommands.h" +#include "Boat.h" #include "Camera.h" #include "CarCtrl.h" +#include "CivilianPed.h" +#include "Clock.h" +#include "CopPed.h" #include "DMAudio.h" +#include "EmergencyPed.h" #include "FileMgr.h" +#include "General.h" +#include "HandlingMgr.h" #include "Hud.h" #include "Messages.h" #include "ModelIndices.h" @@ -18,9 +25,11 @@ #include "Population.h" #include "Replay.h" #include "Streaming.h" +#include "Text.h" #include "User.h" #include "Weather.h" #include "World.h" +#include "Zones.h" uint8 (&CTheScripts::ScriptSpace)[SIZE_SCRIPT_SPACE] = *(uint8(*)[SIZE_SCRIPT_SPACE])*(uintptr*)0x74B248; CRunningScript(&CTheScripts::ScriptsArray)[MAX_NUM_SCRIPTS] = *(CRunningScript(*)[MAX_NUM_SCRIPTS])*(uintptr*)0x6F5C08; @@ -70,6 +79,7 @@ CMissionCleanup::CMissionCleanup() void CMissionCleanup::Init() { + m_nCount = 0; for (int i = 0; i < MAX_CLEANUP; i++){ m_sEntities[i].type = CLEANUP_UNUSED; m_sEntities[i].id = 0; @@ -93,7 +103,7 @@ void CMissionCleanup::AddEntityToList(int32 id, uint8 type) return; pNew->id = id; pNew->type = type; - m_bCount++; + m_nCount++; } void CMissionCleanup::RemoveEntityFromList(int32 id, uint8 type) @@ -102,6 +112,7 @@ void CMissionCleanup::RemoveEntityFromList(int32 id, uint8 type) if (m_sEntities[i].type == type && m_sEntities[i].id == id){ m_sEntities[i].id = 0; m_sEntities[i].type = CLEANUP_UNUSED; + m_nCount--; } } } @@ -124,8 +135,8 @@ void CMissionCleanup::Process() CHud::m_ItemToFlash = -1; CHud::SetHelpMessage(nil, false); CUserDisplay::OnscnTimer.m_bDisabled = false; - CWorld::Players[0].m_pPed->m_pWanted->m_IsIgnoredByCops = false; - CWorld::Players[0].m_pPed->m_pWanted->m_IsIgnoredByEveryOne = false; + CWorld::Players[0].m_pPed->m_pWanted->m_bIgnoredByCops = false; + CWorld::Players[0].m_pPed->m_pWanted->m_bIgnoredByEveryone = false; CWorld::Players[0].MakePlayerSafe(false); CTheScripts::StoreVehicleIndex = -1; CTheScripts::StoreVehicleWasRandom = true; @@ -594,7 +605,7 @@ void CTheScripts::Process() if (UseTextCommands){ for (int i = 0; i < MAX_NUM_INTRO_TEXT_LINES; i++) IntroTextLines[i].Reset(); - NumberOfIntroRectanglesThisFrame = 0; + NumberOfIntroTextLinesThisFrame = 0; for (int i = 0; i < MAX_NUM_INTRO_RECTANGLES; i++){ IntroRectangles[i].m_bIsUsed = false; IntroRectangles[i].m_bBeforeFade = false; @@ -701,7 +712,7 @@ int8 CRunningScript::ProcessCommandsFrom0To99(int32 command) return 0; case COMMAND_SHAKE_CAM: CollectParameters(&m_nIp, 1); - TheCamera.CamShake(ScriptParams[0] / 1000.0f); + CamShakeNoPos(&TheCamera, ScriptParams[0] / 1000.0f); return 0; case COMMAND_SET_VAR_INT: { @@ -1342,6 +1353,7 @@ int8 CRunningScript::ProcessCommandsFrom0To99(int32 command) *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) -= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); return 0; default: + assert(0); break; } return -1; @@ -1374,7 +1386,814 @@ void CRunningScript::UpdateCompareFlag(bool flag) } -WRAPPER int8 CRunningScript::ProcessCommandsFrom100To199(int32 command) { EAXJMP(0x43AEA0); } +int8 CRunningScript::ProcessCommandsFrom100To199(int32 command) +{ + switch (command) { + case COMMAND_SUB_INT_LVAR_FROM_INT_VAR: + *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) -= *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_SUB_INT_VAR_FROM_INT_LVAR: + *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) -= *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_SUB_FLOAT_LVAR_FROM_FLOAT_VAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) -= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_SUB_FLOAT_VAR_FROM_FLOAT_LVAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) -= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_MULT_INT_VAR_BY_INT_VAR: + *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) *= *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_MULT_INT_LVAR_BY_INT_VAR: + *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) *= *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_MULT_INT_VAR_BY_INT_LVAR: + *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) *= *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_MULT_INT_LVAR_BY_INT_LVAR: + *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) *= *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_MULT_FLOAT_VAR_BY_FLOAT_VAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) *= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_MULT_FLOAT_LVAR_BY_FLOAT_VAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) *= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_MULT_FLOAT_VAR_BY_FLOAT_LVAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) *= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_MULT_FLOAT_LVAR_BY_FLOAT_LVAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) *= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_DIV_INT_VAR_BY_INT_VAR: + *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) /= *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_DIV_INT_LVAR_BY_INT_VAR: + *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) /= *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_DIV_INT_VAR_BY_INT_LVAR: + *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) /= *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_DIV_INT_LVAR_BY_INT_LVAR: + *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) /= *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_DIV_FLOAT_VAR_BY_FLOAT_VAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) /= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_DIV_FLOAT_LVAR_BY_FLOAT_VAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) /= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_DIV_FLOAT_VAR_BY_FLOAT_LVAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) /= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_DIV_FLOAT_LVAR_BY_FLOAT_LVAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) /= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_ADD_TIMED_VAL_TO_FLOAT_VAR: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + *(float*)ptr += CTimer::GetTimeStep() * *(float*)&ScriptParams[0]; + return 0; + } + case COMMAND_ADD_TIMED_VAL_TO_FLOAT_LVAR: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + *(float*)ptr += CTimer::GetTimeStep() * *(float*)&ScriptParams[0]; + return 0; + } + case COMMAND_ADD_TIMED_FLOAT_VAR_TO_FLOAT_VAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) += CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_ADD_TIMED_FLOAT_LVAR_TO_FLOAT_VAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) += CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_ADD_TIMED_FLOAT_VAR_TO_FLOAT_LVAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) += CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_ADD_TIMED_FLOAT_LVAR_TO_FLOAT_LVAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) += CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_SUB_TIMED_VAL_FROM_FLOAT_VAR: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + *(float*)ptr -= CTimer::GetTimeStep() * *(float*)&ScriptParams[0]; + return 0; + } + case COMMAND_SUB_TIMED_VAL_FROM_FLOAT_LVAR: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + *(float*)ptr -= CTimer::GetTimeStep() * *(float*)&ScriptParams[0]; + return 0; + } + case COMMAND_SUB_TIMED_FLOAT_VAR_FROM_FLOAT_VAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) -= CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_SUB_TIMED_FLOAT_LVAR_FROM_FLOAT_VAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) -= CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_SUB_TIMED_FLOAT_VAR_FROM_FLOAT_LVAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) -= CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_SUB_TIMED_FLOAT_LVAR_FROM_FLOAT_LVAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) -= CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_SET_VAR_INT_TO_VAR_INT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + *ptr = *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + } + case COMMAND_SET_LVAR_INT_TO_VAR_INT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + *ptr = *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + } + case COMMAND_SET_VAR_INT_TO_LVAR_INT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + *ptr = *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + } + case COMMAND_SET_LVAR_INT_TO_LVAR_INT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + *ptr = *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + } + case COMMAND_SET_VAR_FLOAT_TO_VAR_FLOAT: + { + float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + *ptr = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + } + case COMMAND_SET_LVAR_FLOAT_TO_VAR_FLOAT: + { + float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + *ptr = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + } + case COMMAND_SET_VAR_FLOAT_TO_LVAR_FLOAT: + { + float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + *ptr = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + } + case COMMAND_SET_LVAR_FLOAT_TO_LVAR_FLOAT: + { + float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + *ptr = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + } + case COMMAND_CSET_VAR_INT_TO_VAR_FLOAT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + *ptr = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + } + case COMMAND_CSET_LVAR_INT_TO_VAR_FLOAT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + *ptr = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + } + case COMMAND_CSET_VAR_INT_TO_LVAR_FLOAT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + *ptr = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + } + case COMMAND_CSET_LVAR_INT_TO_LVAR_FLOAT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + *ptr = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + } + case COMMAND_CSET_VAR_FLOAT_TO_VAR_INT: + { + float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + *ptr = *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + } + case COMMAND_CSET_LVAR_FLOAT_TO_VAR_INT: + { + float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + *ptr = *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + } + case COMMAND_CSET_VAR_FLOAT_TO_LVAR_INT: + { + float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + *ptr = *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + } + case COMMAND_CSET_LVAR_FLOAT_TO_LVAR_INT: + { + float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + *ptr = *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + } + case COMMAND_ABS_VAR_INT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + *ptr = ABS(*ptr); + return 0; + } + case COMMAND_ABS_LVAR_INT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + *ptr = ABS(*ptr); + return 0; + } + case COMMAND_ABS_VAR_FLOAT: + { + float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + *ptr = ABS(*ptr); + return 0; + } + case COMMAND_ABS_LVAR_FLOAT: + { + float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + *ptr = ABS(*ptr); + return 0; + } + case COMMAND_GENERATE_RANDOM_FLOAT: + { + float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CGeneral::GetRandomNumber(); + CGeneral::GetRandomNumber(); + CGeneral::GetRandomNumber(); /* To make it EXTRA random! */ + *ptr = CGeneral::GetRandomNumber() / 65536.0f; + /* Between 0 and 0.5 on PC (oh well...), never used in original script. */ + return 0; + } + case COMMAND_GENERATE_RANDOM_INT: + /* On PC between 0 and 32767, even though script expects values between 0 and 65536 */ + *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) = CGeneral::GetRandomNumber(); + return 0; + case COMMAND_CREATE_CHAR: + { + CollectParameters(&m_nIp, 5); + switch (ScriptParams[1]) { + case MI_COP: + if (ScriptParams[0] == PEDTYPE_COP) + ScriptParams[1] = COP_STREET; + break; + case MI_SWAT: + if (ScriptParams[0] == PEDTYPE_COP) + ScriptParams[1] = COP_SWAT; + break; + case MI_FBI: + if (ScriptParams[0] == PEDTYPE_COP) + ScriptParams[1] = COP_FBI; + break; + case MI_ARMY: + if (ScriptParams[0] == PEDTYPE_COP) + ScriptParams[1] = COP_ARMY; + break; + case MI_MEDIC: + if (ScriptParams[0] == PEDTYPE_EMERGENCY) + ScriptParams[1] = PEDTYPE_EMERGENCY; + break; + case MI_FIREMAN: + if (ScriptParams[0] == PEDTYPE_FIREMAN) + ScriptParams[1] = PEDTYPE_FIREMAN; + break; + default: + break; + } + CPed* ped; + if (ScriptParams[0] == PEDTYPE_COP) + ped = new CCopPed((eCopType)ScriptParams[1]); + else if (ScriptParams[0] == PEDTYPE_EMERGENCY || ScriptParams[0] == PEDTYPE_FIREMAN) + ped = new CEmergencyPed(ScriptParams[1]); + else + ped = new CCivilianPed(ScriptParams[0], ScriptParams[1]); + ped->CharCreatedBy = MISSION_CHAR; + ped->bRespondsToThreats = false; + ped->m_ped_flagG2 = false; + CVector pos = *(CVector*)&ScriptParams[2]; + if (pos.z <= -100.0f) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + pos.z += 1.0f; + ped->GetPosition() = pos; + ped->SetOrientation(0.0f, 0.0f, 0.0f); + CTheScripts::ClearSpaceForMissionEntity(pos, ped); + CWorld::Add(ped); + ped->m_level = CTheZones::GetLevelFromPosition(pos); + CPopulation::ms_nTotalMissionPeds++; + ScriptParams[0] = CPools::GetPedPool()->GetIndex(ped); + StoreParameters(&m_nIp, 1); + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_CHAR); + return 0; + } + case COMMAND_DELETE_CHAR: + { + CollectParameters(&m_nIp, 1); + CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); + if (ped) { + if (ped->bInVehicle && ped->m_pMyVehicle) { + if (ped->m_pMyVehicle->pDriver == ped) { + ped->m_pMyVehicle->RemoveDriver(); + ped->m_pMyVehicle->m_status = STATUS_ABANDONED; + if (ped->m_pMyVehicle->m_nDoorLock == CARLOCK_LOCKED_INITIALLY) + ped->m_pMyVehicle->m_nDoorLock = CARLOCK_UNLOCKED; + if (ped->m_nPedType == PEDTYPE_COP && ped->m_pMyVehicle->IsLawEnforcementVehicle()) + ped->m_pMyVehicle->ChangeLawEnforcerState(0); + } + else { + ped->m_pMyVehicle->RemovePassenger(ped); + } + } + CWorld::RemoveReferencesToDeletedObject(ped); + delete ped; + --CPopulation::ms_nTotalMissionPeds; + } + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CHAR); + return 0; + } + case COMMAND_CHAR_WANDER_DIR: + { + CollectParameters(&m_nIp, 2); + CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(ped); + ped->ClearAll(); + int8 path = ScriptParams[1]; + if (ScriptParams[1] < 0 || ScriptParams[1] > 7) + path = CGeneral::GetRandomNumberInRange(0, 7); + ped->SetWanderPath(path); + return 0; + } + case COMMAND_CHAR_FOLLOW_PATH: + { + CollectParameters(&m_nIp, 4); + CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(ped); + CVector pos = *(CVector*)&ScriptParams[1]; + if (pos.z <= -100.0f) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + ped->ClearAll(); + ped->SetFollowPath(pos); + return 0; + } + case COMMAND_CHAR_SET_IDLE: + { + CollectParameters(&m_nIp, 1); + CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(ped); + ped->m_bScriptObjectiveCompleted = false; + ped->SetObjective(OBJECTIVE_IDLE); + return 0; + } + case COMMAND_GET_CHAR_COORDINATES: + { + CollectParameters(&m_nIp, 1); + CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(ped); + CVehicle* vehicle; + CVector pos; + /* Seems a bit clumsy but I'll leave original flow */ + if (ped->bInVehicle) + vehicle = ped->m_pMyVehicle; + else + vehicle = nil; + if (vehicle) + pos = vehicle->GetPosition(); + else + pos = ped->GetPosition(); + *(CVector*)&ScriptParams[0] = pos; + StoreParameters(&m_nIp, 3); + return 0; + } + case COMMAND_SET_CHAR_COORDINATES: + { + CollectParameters(&m_nIp, 4); + CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(ped); + CVehicle* vehicle; + if (ped->bInVehicle) + vehicle = ped->m_pMyVehicle; + else + vehicle = nil; + CVector pos = *(CVector*)&ScriptParams[1]; + if (pos.z <= -100.0f) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + /* The following block was once again written + * by someone not familiar with virtual functions. + * It doesn't require any ifs at all. + * To keep as close to original as possible, I'll keep it. + * Maybe there was more commented out/debug + * stuff, but I doubt it. + */ + if (!vehicle) { + pos.z += ped->GetDistanceFromCentreOfMassToBaseOfModel(); + ped->Teleport(pos); + CTheScripts::ClearSpaceForMissionEntity(pos, ped); + } + else if (vehicle->IsBoat()) { + pos.z += vehicle->GetDistanceFromCentreOfMassToBaseOfModel(); + vehicle->Teleport(pos); + CTheScripts::ClearSpaceForMissionEntity(pos, vehicle); + } + else { + pos.z += vehicle->GetDistanceFromCentreOfMassToBaseOfModel(); + vehicle->Teleport(pos); + CTheScripts::ClearSpaceForMissionEntity(pos, vehicle); + } + /* Short version of this command. + * + * CollectParameters(&m_nIp, 4); + * CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); + * assert(ped); + * CEntity* entityToMove = ped->bInVehicle ? ped->m_pMyVehicle : ped; + * CVector pos = *(CVector*)&ScriptParams[1]; + * if (pos.z <= -100.0f) + * pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + * pos.z += entityToMove->GetDistanceFromCentreOfMassToBaseOfModel(); + * entityToMove->Teleport(pos); + * CTheScripts::ClearSpaceForMissionEntity(pos, entityToMove); + * + */ + return 0; + } + case COMMAND_IS_CHAR_STILL_ALIVE: + { + CollectParameters(&m_nIp, 1); + CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); + UpdateCompareFlag(ped && ped->m_status != PED_DEAD && ped->m_status != PED_DIE); + return 0; + } + case COMMAND_IS_CHAR_IN_AREA_2D: + { + CollectParameters(&m_nIp, 6); + CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(ped); + CVehicle* vehicle; + if (ped->bInVehicle) + vehicle = ped->m_pMyVehicle; + else + vehicle = nil; + float x1, y1, x2, y2; + x1 = *(float*)&ScriptParams[1]; + y1 = *(float*)&ScriptParams[2]; + x2 = *(float*)&ScriptParams[3]; + y2 = *(float*)&ScriptParams[4]; + if (vehicle) + UpdateCompareFlag(ped->m_pMyVehicle->IsWithinArea(x1, y1, x2, y2)); + else + UpdateCompareFlag(ped->IsWithinArea(x1, y1, x2, y2)); + CTheScripts::HighlightImportantArea((uint32)this + m_nIp, x1, y1, x2, y2, -100.0f); + if (CTheScripts::DbgFlag) + CTheScripts::DrawDebugSquare(x1, y1, x2, y2); + return 0; + } + case COMMAND_IS_CHAR_IN_AREA_3D: + { + CollectParameters(&m_nIp, 8); + CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(ped); + CVehicle* vehicle; + if (ped->bInVehicle) + vehicle = ped->m_pMyVehicle; + else + vehicle = nil; + float x1, y1, z1, x2, y2, z2; + x1 = *(float*)&ScriptParams[1]; + y1 = *(float*)&ScriptParams[2]; + z1 = *(float*)&ScriptParams[3]; + x2 = *(float*)&ScriptParams[4]; + y2 = *(float*)&ScriptParams[5]; + z2 = *(float*)&ScriptParams[6]; + if (vehicle) + UpdateCompareFlag(ped->m_pMyVehicle->IsWithinArea(x1, y1, z1, x2, y2, z2)); + else + UpdateCompareFlag(ped->IsWithinArea(x1, y1, z1, x2, y2, z2)); + CTheScripts::HighlightImportantArea((uint32)this + m_nIp, x1, y1, x2, y2, -100.0f); + if (CTheScripts::DbgFlag) + CTheScripts::DrawDebugCube(x1, y1, z1, x2, y2, z2); + return 0; + } + case COMMAND_CREATE_CAR: + { + CollectParameters(&m_nIp, 4); + int32 handle; + if (CModelInfo::IsBoatModel(ScriptParams[0])) { + CBoat* boat = new CBoat(ScriptParams[0], MISSION_VEHICLE); + CVector pos = *(CVector*)&ScriptParams[1]; + if (pos.z <= -100.0f) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + pos.z += boat->GetDistanceFromCentreOfMassToBaseOfModel(); + boat->GetPosition() = pos; + CTheScripts::ClearSpaceForMissionEntity(pos, boat); + boat->m_status = STATUS_ABANDONED; + boat->bIsLocked = true; + boat->AutoPilot.m_nCarMission = MISSION_NONE; + boat->AutoPilot.m_nAnimationId = TEMPACT_NONE; /* Animation ID? */ + boat->AutoPilot.m_nCruiseSpeed = boat->AutoPilot.m_fMaxTrafficSpeed = 20.0f; + CWorld::Add(boat); + handle = CPools::GetVehiclePool()->GetIndex(boat); + } + else { + CVehicle* car; + if (!CModelInfo::IsBikeModel(ScriptParams[0])) + car = new CAutomobile(ScriptParams[0], MISSION_VEHICLE); + CVector pos = *(CVector*)&ScriptParams[1]; + if (pos.z <= -100.0f) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + pos.z += car->GetDistanceFromCentreOfMassToBaseOfModel(); + car->GetPosition() = pos; + CTheScripts::ClearSpaceForMissionEntity(pos, car); + car->m_status = STATUS_ABANDONED; + car->bIsLocked = true; + CCarCtrl::JoinCarWithRoadSystem(car); + car->AutoPilot.m_nCarMission = MISSION_NONE; + car->AutoPilot.m_nAnimationId = TEMPACT_NONE; /* Animation ID? */ + car->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS; + car->AutoPilot.m_nCruiseSpeed = car->AutoPilot.m_fMaxTrafficSpeed = 9.0f; + car->AutoPilot.m_nPreviousLane = car->AutoPilot.m_nCurrentLane = 0; + car->bEngineOn = false; + car->m_level = CTheZones::GetLevelFromPosition(pos); + car->bHasBeenOwnedByPlayer = true; + CWorld::Add(car); + handle = CPools::GetVehiclePool()->GetIndex(car); + } + ScriptParams[0] = handle; + StoreParameters(&m_nIp, 1); + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.AddEntityToList(handle, CLEANUP_CAR); + return 0; + } + case COMMAND_DELETE_CAR: + { + CollectParameters(&m_nIp, 1); + CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + if (car) { + CWorld::Remove(car); + CWorld::RemoveReferencesToDeletedObject(car); + delete car; + } + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CAR); + return 0; + } + case COMMAND_CAR_GOTO_COORDINATES: + { + CollectParameters(&m_nIp, 4); + CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(car); + CVector pos = *(CVector*)&ScriptParams[1]; + if (pos.z <= -100.0f) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + pos.z += car->GetDistanceFromCentreOfMassToBaseOfModel(); + if (CCarCtrl::JoinCarWithRoadSystemGotoCoors(car, pos, false)) + car->AutoPilot.m_nCarMission = MISSION_GOTOCOORDS_STRAIGHT; + else + car->AutoPilot.m_nCarMission = MISSION_GOTOCOORDS; + car->m_status = STATUS_PHYSICS; + car->bEngineOn = true; + car->AutoPilot.m_nCruiseSpeed = max(car->AutoPilot.m_nCruiseSpeed, 6); + car->AutoPilot.m_nTimeToStartMission = CTimer::GetTimeInMilliseconds(); + return 0; + } + case COMMAND_CAR_WANDER_RANDOMLY: + { + CollectParameters(&m_nIp, 1); + CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(car); + CCarCtrl::JoinCarWithRoadSystem(car); + car->AutoPilot.m_nCarMission = MISSION_CRUISE; + car->bEngineOn = true; + car->AutoPilot.m_nCruiseSpeed = max(car->AutoPilot.m_nCruiseSpeed, 6); + car->AutoPilot.m_nTimeToStartMission = CTimer::GetTimeInMilliseconds(); + return 0; + } + case COMMAND_CAR_SET_IDLE: + { + CollectParameters(&m_nIp, 1); + CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(car); + car->AutoPilot.m_nCarMission = MISSION_NONE; + return 0; + } + case COMMAND_GET_CAR_COORDINATES: + { + CollectParameters(&m_nIp, 1); + CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(car); + *(CVector*)&ScriptParams[0] = car->GetPosition(); + StoreParameters(&m_nIp, 3); + return 0; + } + case COMMAND_SET_CAR_COORDINATES: + { + CollectParameters(&m_nIp, 4); + CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(car); + CVector pos = *(CVector*)&ScriptParams[1]; + if (pos.z <= -100.0f) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + pos.z += car->GetDistanceFromCentreOfMassToBaseOfModel(); + car->bIsStatic = false; + /* Again weird usage of virtual functions. */ + if (car->IsBoat()) { + car->Teleport(pos); + CTheScripts::ClearSpaceForMissionEntity(pos, car); + } + else { + car->Teleport(pos); + CTheScripts::ClearSpaceForMissionEntity(pos, car); + /* May the following be inlined CCarCtrl function? */ + switch (car->AutoPilot.m_nCarMission) { + case MISSION_CRUISE: + CCarCtrl::JoinCarWithRoadSystem(car); + break; + case MISSION_RAMPLAYER_FARAWAY: + case MISSION_RAMPLAYER_CLOSE: + case MISSION_BLOCKPLAYER_FARAWAY: + case MISSION_BLOCKPLAYER_CLOSE: + case MISSION_BLOCKPLAYER_HANDBRAKESTOP: + CCarCtrl::JoinCarWithRoadSystemGotoCoors(car, FindPlayerCoors(), false); + break; + case MISSION_GOTOCOORDS: + case MISSION_GOTOCOORDS_STRAIGHT: + CCarCtrl::JoinCarWithRoadSystemGotoCoors(car, car->AutoPilot.m_vecDestinationCoors, false); + break; + case MISSION_GOTOCOORDS_ACCURATE: + case MISSION_GOTO_COORDS_STRAIGHT_ACCURATE: + CCarCtrl::JoinCarWithRoadSystemGotoCoors(car, car->AutoPilot.m_vecDestinationCoors, false); + break; + case MISSION_RAMCAR_FARAWAY: + case MISSION_RAMCAR_CLOSE: + case MISSION_BLOCKCAR_FARAWAY: + case MISSION_BLOCKCAR_CLOSE: + case MISSION_BLOCKCAR_HANDBRAKESTOP: + CCarCtrl::JoinCarWithRoadSystemGotoCoors(car, car->AutoPilot.m_pTargetCar->GetPosition(), false); + break; + default: + break; + } + } + return 0; + } + case COMMAND_IS_CAR_STILL_ALIVE: + { + CollectParameters(&m_nIp, 4); + CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + UpdateCompareFlag(car && car->m_status != STATUS_WRECKED && (car->IsBoat() || !car->bIsInWater)); + return 0; + } + case COMMAND_SET_CAR_CRUISE_SPEED: + { + CollectParameters(&m_nIp, 2); + CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(car); + car->AutoPilot.m_nCruiseSpeed = min(*(float*)&ScriptParams[1], 60.0f * car->pHandling->Transmission.fUnkMaxVelocity); + return 0; + } + case COMMAND_SET_CAR_DRIVING_STYLE: + { + CollectParameters(&m_nIp, 2); + CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(car); + car->AutoPilot.m_nDrivingStyle = (eCarDrivingStyle)ScriptParams[1]; + return 0; + } + case COMMAND_SET_CAR_MISSION: + { + CollectParameters(&m_nIp, 2); + CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(car); + car->AutoPilot.m_nCarMission = (eCarMission)ScriptParams[1]; + car->AutoPilot.m_nTimeToStartMission = CTimer::GetTimeInMilliseconds(); + car->bEngineOn = true; + return 0; + } + case COMMAND_IS_CAR_IN_AREA_2D: + { + CollectParameters(&m_nIp, 6); + CVehicle* vehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(vehicle); + float x1, y1, x2, y2; + x1 = *(float*)&ScriptParams[1]; + y1 = *(float*)&ScriptParams[2]; + x2 = *(float*)&ScriptParams[3]; + y2 = *(float*)&ScriptParams[4]; + UpdateCompareFlag(vehicle->IsWithinArea(x1, y1, x2, y2)); + CTheScripts::HighlightImportantArea((uint32)this + m_nIp, x1, y1, x2, y2, -100.0f); + if (CTheScripts::DbgFlag) + CTheScripts::DrawDebugSquare(x1, y1, x2, y2); + return 0; + } + case COMMAND_IS_CAR_IN_AREA_3D: + { + CollectParameters(&m_nIp, 8); + CVehicle* vehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(vehicle); + float x1, y1, z1, x2, y2, z2; + x1 = *(float*)&ScriptParams[1]; + y1 = *(float*)&ScriptParams[2]; + z1 = *(float*)&ScriptParams[3]; + x2 = *(float*)&ScriptParams[4]; + y2 = *(float*)&ScriptParams[5]; + z2 = *(float*)&ScriptParams[6]; + UpdateCompareFlag(vehicle->IsWithinArea(x1, y1, z1, x2, y2, z2)); + CTheScripts::HighlightImportantArea((uint32)this + m_nIp, x1, y1, x2, y2, -100.0f); + if (CTheScripts::DbgFlag) + CTheScripts::DrawDebugCube(x1, y1, z1, x2, y2, z2); + return 0; + } + case COMMAND_SPECIAL_0: + case COMMAND_SPECIAL_1: + case COMMAND_SPECIAL_2: + case COMMAND_SPECIAL_3: + case COMMAND_SPECIAL_4: + case COMMAND_SPECIAL_5: + case COMMAND_SPECIAL_6: + case COMMAND_SPECIAL_7: + assert(0); + return 0; + case COMMAND_PRINT_BIG: + { + wchar* key = TheText.Get((char*)&CTheScripts::ScriptSpace[m_nIp]); + m_nIp += 8; + CollectParameters(&m_nIp, 2); + CMessages::AddBigMessage(key, ScriptParams[0], ScriptParams[1] - 1); + return 0; + } + case COMMAND_PRINT: + { + wchar* key = TheText.Get((char*)&CTheScripts::ScriptSpace[m_nIp]); + m_nIp += 8; + CollectParameters(&m_nIp, 2); + CMessages::AddMessage(key, ScriptParams[0], ScriptParams[1]); + return 0; + } + case COMMAND_PRINT_NOW: + { + wchar* key = TheText.Get((char*)&CTheScripts::ScriptSpace[m_nIp]); + m_nIp += 8; + CollectParameters(&m_nIp, 2); + CMessages::AddMessageJumpQ(key, ScriptParams[0], ScriptParams[1]); + return 0; + } + case COMMAND_PRINT_SOON: + { + wchar* key = TheText.Get((char*)&CTheScripts::ScriptSpace[m_nIp]); + m_nIp += 8; + CollectParameters(&m_nIp, 2); + CMessages::AddMessage(key, ScriptParams[0], ScriptParams[1]); + return 0; + } + case COMMAND_CLEAR_PRINTS: + CMessages::ClearMessages(); + return 0; + case COMMAND_GET_TIME_OF_DAY: + ScriptParams[0] = CClock::GetHours(); + ScriptParams[1] = CClock::GetMinutes(); + StoreParameters(&m_nIp, 2); + return 0; + case COMMAND_SET_TIME_OF_DAY: + CollectParameters(&m_nIp, 2); + CClock::SetGameClock(ScriptParams[0], ScriptParams[1]); + return 0; + case COMMAND_GET_MINUTES_TO_TIME_OF_DAY: + CollectParameters(&m_nIp, 2); + ScriptParams[0] = CClock::GetGameClockMinutesUntil(ScriptParams[0], ScriptParams[1]); + StoreParameters(&m_nIp, 1); + return 0; + case COMMAND_IS_POINT_ON_SCREEN: + { + CollectParameters(&m_nIp, 4); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= -100) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + UpdateCompareFlag(TheCamera.IsSphereVisible(pos, *(float*)&ScriptParams[3])); + } + case COMMAND_DEBUG_ON: + CTheScripts::DbgFlag = true; + return 0; + case COMMAND_DEBUG_OFF: + CTheScripts::DbgFlag = false; + return 0; + case COMMAND_RETURN_TRUE: + UpdateCompareFlag(true); + return 0; + case COMMAND_RETURN_FALSE: + UpdateCompareFlag(false); + return 0; + default: + assert(0); + break; + } + return -1; +} + WRAPPER int8 CRunningScript::ProcessCommandsFrom200To299(int32 command) { EAXJMP(0x43D530); } WRAPPER int8 CRunningScript::ProcessCommandsFrom300To399(int32 command) { EAXJMP(0x43ED30); } WRAPPER int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) { EAXJMP(0x440CB0); } diff --git a/src/control/Script.h b/src/control/Script.h index 0cbd40c0..9e9d9ab6 100644 --- a/src/control/Script.h +++ b/src/control/Script.h @@ -137,7 +137,7 @@ enum { class CMissionCleanup { CMissionCleanupEntity m_sEntities[MAX_CLEANUP]; - uint8 m_bCount; + uint8 m_nCount; public: CMissionCleanup(); diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp index 166928c1..a66d6ac9 100644 --- a/src/core/Camera.cpp +++ b/src/core/Camera.cpp @@ -23,7 +23,7 @@ WRAPPER void CCamera::DrawBordersForWideScreen(void) { EAXJMP(0x46B430); } WRAPPER void CCamera::CalculateDerivedValues(void) { EAXJMP(0x46EEA0); } WRAPPER void CCamera::Restore(void) { EAXJMP(0x46F990); } WRAPPER void CCamera::SetWidescreenOff(void) { EAXJMP(0x46FF10); } -WRAPPER void CCamera::CamShake(float) { EAXJMP(0x46B100); } +WRAPPER void CamShakeNoPos(CCamera*, float) { EAXJMP(0x46B100); } bool CCamera::IsSphereVisible(const CVector ¢er, float radius, const CMatrix *mat) @@ -95,6 +95,14 @@ CCamera::GetLookDirection(void) return LOOKING_FORWARD;; } +bool +CCamera::GetLookingForwardFirstPerson() +{ + return Cams[ActiveCam].Mode == CCam::MODE_FIRSTPERSON && + Cams[ActiveCam].DirectionWasLooking == LOOKING_FORWARD; +} + + WRAPPER void CCamera::Fade(float timeout, int16 direction) { EAXJMP(0x46B3A0); } WRAPPER void CCamera::ProcessFade(void) { EAXJMP(0x46F080); } WRAPPER void CCamera::ProcessMusicFade(void) { EAXJMP(0x46F1E0); } diff --git a/src/core/Camera.h b/src/core/Camera.h index 84af9d55..1a2aae79 100644 --- a/src/core/Camera.h +++ b/src/core/Camera.h @@ -441,6 +441,7 @@ int m_iModeObbeCamIsInForCar; static bool &m_bUseMouse3rdPerson; + bool Get_Just_Switched_Status() { return m_bJust_Switched; } inline const CMatrix GetCameraMatrix(void) { return m_cameraMatrix; } CVector &GetGameCamPosition(void) { return m_vecGameCamPos; } bool IsPointVisible(const CVector ¢er, const CMatrix *mat); @@ -448,6 +449,7 @@ int m_iModeObbeCamIsInForCar; bool IsSphereVisible(const CVector ¢er, float radius); bool IsBoxVisible(RwV3d *box, const CMatrix *mat); int GetLookDirection(void); + bool GetLookingForwardFirstPerson(void); void Fade(float timeout, int16 direction); int GetScreenFadeStatus(void); @@ -466,7 +468,6 @@ int m_iModeObbeCamIsInForCar; void DrawBordersForWideScreen(void); void Restore(void); void SetWidescreenOff(void); - void CamShake(float); void dtor(void) { this->CCamera::~CCamera(); } }; @@ -479,3 +480,5 @@ static_assert(offsetof(CCamera, m_BlurBlue) == 0x9C, "CCamera: error"); static_assert(offsetof(CCamera, Cams) == 0x1A4, "CCamera: error"); static_assert(sizeof(CCamera) == 0xE9D8, "CCamera: wrong size"); extern CCamera &TheCamera; + +void CamShakeNoPos(CCamera*, float); diff --git a/src/core/Clock.cpp b/src/core/Clock.cpp index 707b0e57..a97dcb5f 100644 --- a/src/core/Clock.cpp +++ b/src/core/Clock.cpp @@ -15,7 +15,7 @@ uint8 &CClock::ms_Stored_nGameClockHours = *(uint8*)0x95CD7B; uint8 &CClock::ms_Stored_nGameClockMinutes = *(uint8*)0x95CD9B; uint16 &CClock::ms_Stored_nGameClockSeconds = *(uint16*)0x95CC9C; uint32 &CClock::ms_nMillisecondsPerGameMinute = *(uint32*)0x8F2C64; -int32 &CClock::ms_nLastClockTick = *(int32*)0x9430E4; +uint32 &CClock::ms_nLastClockTick = *(uint32*)0x9430E4; bool &CClock::ms_bClockHasBeenStored = *(bool*)0x95CD82; void @@ -67,10 +67,7 @@ CClock::Update(void) } } } - ms_nGameClockSeconds += - 60 - * (CTimer::GetTimeInMilliseconds() - ms_nLastClockTick) - / ms_nMillisecondsPerGameMinute; + ms_nGameClockSeconds = 60 * (CTimer::GetTimeInMilliseconds() - ms_nLastClockTick) / ms_nMillisecondsPerGameMinute; } void diff --git a/src/core/Clock.h b/src/core/Clock.h index e11b2293..ea4263bd 100644 --- a/src/core/Clock.h +++ b/src/core/Clock.h @@ -9,7 +9,7 @@ class CClock static uint8 &ms_Stored_nGameClockMinutes; static uint16 &ms_Stored_nGameClockSeconds; static uint32 &ms_nMillisecondsPerGameMinute; - static int32 &ms_nLastClockTick; + static uint32 &ms_nLastClockTick; static bool &ms_bClockHasBeenStored; public: diff --git a/src/core/Collision.cpp b/src/core/Collision.cpp index 1ed08867..7982e77d 100644 --- a/src/core/Collision.cpp +++ b/src/core/Collision.cpp @@ -18,6 +18,7 @@ #include "CutsceneMgr.h" #include "RenderBuffer.h" #include "SurfaceTable.h" +#include "Lines.h" #include "Collision.h" enum Direction @@ -1356,6 +1357,7 @@ CCollision::DistToLine(const CVector *l0, const CVector *l1, const CVector *poin void CCollision::CalculateTrianglePlanes(CColModel *model) { + assert(model); if(model->numTriangles == 0) return; @@ -1366,7 +1368,6 @@ CCollision::CalculateTrianglePlanes(CColModel *model) lptr->Remove(); ms_colModelCache.head.Insert(lptr); }else{ - assert(model); lptr = ms_colModelCache.Insert(model); if(lptr == nil){ // make room if we have to, remove last in list @@ -1387,6 +1388,223 @@ CCollision::CalculateTrianglePlanes(CColModel *model) void CCollision::DrawColModel(const CMatrix &mat, const CColModel &colModel) { + int i; + CVector min, max; + CVector verts[8]; + CVector c; + float r; + + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); + + min = colModel.boundingBox.min; + max = colModel.boundingBox.max; + + verts[0] = mat * CVector(min.x, min.y, min.z); + verts[1] = mat * CVector(min.x, min.y, max.z); + verts[2] = mat * CVector(min.x, max.y, min.z); + verts[3] = mat * CVector(min.x, max.y, max.z); + verts[4] = mat * CVector(max.x, min.y, min.z); + verts[5] = mat * CVector(max.x, min.y, max.z); + verts[6] = mat * CVector(max.x, max.y, min.z); + verts[7] = mat * CVector(max.x, max.y, max.z); + + CLines::RenderLineWithClipping( + verts[0].x, verts[0].y, verts[0].z, + verts[1].x, verts[1].y, verts[1].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[1].x, verts[1].y, verts[1].z, + verts[3].x, verts[3].y, verts[3].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[3].x, verts[3].y, verts[3].z, + verts[2].x, verts[2].y, verts[2].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[2].x, verts[2].y, verts[2].z, + verts[0].x, verts[0].y, verts[0].z, + 0xFF0000FF, 0xFF0000FF); + + CLines::RenderLineWithClipping( + verts[4].x, verts[4].y, verts[4].z, + verts[5].x, verts[5].y, verts[5].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[5].x, verts[5].y, verts[5].z, + verts[7].x, verts[7].y, verts[7].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[7].x, verts[7].y, verts[7].z, + verts[6].x, verts[6].y, verts[6].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[6].x, verts[6].y, verts[6].z, + verts[4].x, verts[4].y, verts[4].z, + 0xFF0000FF, 0xFF0000FF); + + CLines::RenderLineWithClipping( + verts[0].x, verts[0].y, verts[0].z, + verts[4].x, verts[4].y, verts[4].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[1].x, verts[1].y, verts[1].z, + verts[5].x, verts[5].y, verts[5].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[2].x, verts[2].y, verts[2].z, + verts[6].x, verts[6].y, verts[6].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[3].x, verts[3].y, verts[3].z, + verts[7].x, verts[7].y, verts[7].z, + 0xFF0000FF, 0xFF0000FF); + + for(i = 0; i < colModel.numSpheres; i++){ + c = mat * colModel.spheres[i].center; + r = colModel.spheres[i].radius; + + CLines::RenderLineWithClipping( + c.x, c.y, c.z-r, + c.x-r, c.y-r, c.z, + 0xFF00FFFF, 0xFF00FFFF); + CLines::RenderLineWithClipping( + c.x, c.y, c.z-r, + c.x-r, c.y+r, c.z, + 0xFF00FFFF, 0xFF00FFFF); + CLines::RenderLineWithClipping( + c.x, c.y, c.z-r, + c.x+r, c.y-r, c.z, + 0xFF00FFFF, 0xFF00FFFF); + CLines::RenderLineWithClipping( + c.x, c.y, c.z-r, + c.x+r, c.y+r, c.z, + 0xFF00FFFF, 0xFF00FFFF); + CLines::RenderLineWithClipping( + c.x-r, c.y-r, c.z, + c.x, c.y, c.z+r, + 0xFF00FFFF, 0xFF00FFFF); + CLines::RenderLineWithClipping( + c.x-r, c.y+r, c.z, + c.x, c.y, c.z+r, + 0xFF00FFFF, 0xFF00FFFF); + CLines::RenderLineWithClipping( + c.x+r, c.y-r, c.z, + c.x, c.y, c.z+r, + 0xFF00FFFF, 0xFF00FFFF); + CLines::RenderLineWithClipping( + c.x+r, c.y+r, c.z, + c.x, c.y, c.z+r, + 0xFF00FFFF, 0xFF00FFFF); + } + + for(i = 0; i < colModel.numLines; i++){ + verts[0] = colModel.lines[i].p0; + verts[1] = colModel.lines[i].p1; + + verts[0] = mat * verts[0]; + verts[1] = mat * verts[1]; + + CLines::RenderLineWithClipping( + verts[0].x, verts[0].y, verts[0].z, + verts[1].x, verts[1].y, verts[1].z, + 0x00FFFFFF, 0x00FFFFFF); + } + + for(i = 0; i < colModel.numBoxes; i++){ + min = colModel.boxes[i].min; + max = colModel.boxes[i].max; + + verts[0] = mat * CVector(min.x, min.y, min.z); + verts[1] = mat * CVector(min.x, min.y, max.z); + verts[2] = mat * CVector(min.x, max.y, min.z); + verts[3] = mat * CVector(min.x, max.y, max.z); + verts[4] = mat * CVector(max.x, min.y, min.z); + verts[5] = mat * CVector(max.x, min.y, max.z); + verts[6] = mat * CVector(max.x, max.y, min.z); + verts[7] = mat * CVector(max.x, max.y, max.z); + + CLines::RenderLineWithClipping( + verts[0].x, verts[0].y, verts[0].z, + verts[1].x, verts[1].y, verts[1].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[1].x, verts[1].y, verts[1].z, + verts[3].x, verts[3].y, verts[3].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[3].x, verts[3].y, verts[3].z, + verts[2].x, verts[2].y, verts[2].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[2].x, verts[2].y, verts[2].z, + verts[0].x, verts[0].y, verts[0].z, + 0xFFFFFFFF, 0xFFFFFFFF); + + CLines::RenderLineWithClipping( + verts[4].x, verts[4].y, verts[4].z, + verts[5].x, verts[5].y, verts[5].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[5].x, verts[5].y, verts[5].z, + verts[7].x, verts[7].y, verts[7].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[7].x, verts[7].y, verts[7].z, + verts[6].x, verts[6].y, verts[6].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[6].x, verts[6].y, verts[6].z, + verts[4].x, verts[4].y, verts[4].z, + 0xFFFFFFFF, 0xFFFFFFFF); + + CLines::RenderLineWithClipping( + verts[0].x, verts[0].y, verts[0].z, + verts[4].x, verts[4].y, verts[4].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[1].x, verts[1].y, verts[1].z, + verts[5].x, verts[5].y, verts[5].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[2].x, verts[2].y, verts[2].z, + verts[6].x, verts[6].y, verts[6].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[3].x, verts[3].y, verts[3].z, + verts[7].x, verts[7].y, verts[7].z, + 0xFFFFFFFF, 0xFFFFFFFF); + } + + for(i = 0; i < colModel.numTriangles; i++){ + colModel.GetTrianglePoint(verts[0], colModel.triangles[i].a); + colModel.GetTrianglePoint(verts[1], colModel.triangles[i].b); + colModel.GetTrianglePoint(verts[2], colModel.triangles[i].c); + verts[0] = mat * verts[0]; + verts[1] = mat * verts[1]; + verts[2] = mat * verts[2]; + CLines::RenderLineWithClipping( + verts[0].x, verts[0].y, verts[0].z, + verts[1].x, verts[1].y, verts[1].z, + 0x00FF00FF, 0x00FF00FF); + CLines::RenderLineWithClipping( + verts[0].x, verts[0].y, verts[0].z, + verts[2].x, verts[2].y, verts[2].z, + 0x00FF00FF, 0x00FF00FF); + CLines::RenderLineWithClipping( + verts[1].x, verts[1].y, verts[1].z, + verts[2].x, verts[2].y, verts[2].z, + 0x00FF00FF, 0x00FF00FF); + } + + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); } void @@ -1407,7 +1625,6 @@ CCollision::DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); -extern int gDbgSurf; for(i = 0; i < colModel.numTriangles; i++){ colModel.GetTrianglePoint(verts[0], colModel.triangles[i].a); @@ -1417,7 +1634,7 @@ extern int gDbgSurf; verts[1] = mat * verts[1]; verts[2] = mat * verts[2]; - // TODO: surface + // game doesn't do this r = 255; g = 128; b = 0; @@ -1457,10 +1674,15 @@ extern int gDbgSurf; b *= f; } - // TODO: make some surface types flicker? -//if(s != gDbgSurf) continue; + if(s == SURFACE_SCAFFOLD || s == SURFACE_METAL_FENCE || + s == SURFACE_BOLLARD || s == SURFACE_METAL_POLE) + if(CTimer::GetFrameCounter() & 1){ + r = 0; + g = 0; + b = 0; + } - if(s > SURFACE_32){ + if(s > SURFACE_GATE){ r = CGeneral::GetRandomNumber(); g = CGeneral::GetRandomNumber(); b = CGeneral::GetRandomNumber(); @@ -1533,8 +1755,13 @@ extern int gDbgSurf; b *= f; } - // TODO: make some surface types flicker? -//if(s != gDbgSurf) continue; + if(s == SURFACE_SCAFFOLD || s == SURFACE_METAL_FENCE || + s == SURFACE_BOLLARD || s == SURFACE_METAL_POLE) + if(CTimer::GetFrameCounter() & 1){ + r = 0; + g = 0; + b = 0; + } RenderBuffer::StartStoring(36, 8, &iptr, &vptr); RwIm3DVertexSetRGBA(&vptr[0], r, g, b, 255); diff --git a/src/core/EventList.cpp b/src/core/EventList.cpp new file mode 100644 index 00000000..a833cc8e --- /dev/null +++ b/src/core/EventList.cpp @@ -0,0 +1,238 @@ +#include "common.h" +#include "patcher.h" +#include "Pools.h" +#include "ModelIndices.h" +#include "World.h" +#include "Wanted.h" +#include "Eventlist.h" + +int32 CEventList::ms_nFirstFreeSlotIndex; +//CEvent gaEvent[NUMEVENTS]; +CEvent *gaEvent = (CEvent*)0x6EF830; + +enum +{ + EVENT_STATE_0, + EVENT_STATE_CANDELETE, + EVENT_STATE_CLEAR, +}; + +void +CEventList::Initialise(void) +{ + int i; + + debug("Initialising CEventList..."); + for(i = 0; i < NUMEVENTS; i++){ + gaEvent[i].type = EVENT_NULL; + gaEvent[i].entityType = EVENT_ENTITY_NONE; + gaEvent[i].entityRef = 0; + gaEvent[i].posn.x = 0.0f; + gaEvent[i].posn.y = 0.0f; + gaEvent[i].posn.z = 0.0f; + gaEvent[i].timeout = 0; + gaEvent[i].state = EVENT_STATE_0; + } + ms_nFirstFreeSlotIndex = 0; +} + +void +CEventList::Update(void) +{ + int i; + + ms_nFirstFreeSlotIndex = 0; + for(i = 0; i < NUMEVENTS; i++){ + if(gaEvent[i].type == EVENT_NULL) + continue; + if(CTimer::GetTimeInMilliseconds() > gaEvent[i].timeout || gaEvent[i].state == EVENT_STATE_CANDELETE){ + gaEvent[i].type = EVENT_NULL; + gaEvent[i].state = EVENT_STATE_0; + } + if(gaEvent[i].state == EVENT_STATE_CLEAR) + gaEvent[i].state = EVENT_STATE_CANDELETE; + } +} + +void +CEventList::RegisterEvent(eEventType type, eEventEntity entityType, CEntity *ent, CPed *criminal, int32 timeout) +{ + int i; + int ref; + bool copsDontCare; + + copsDontCare = false; + switch(entityType){ + case EVENT_ENTITY_PED: + ref = CPools::GetPedRef((CPed*)ent); + if(ent->GetModelIndex() >= MI_GANG01 && ent->GetModelIndex() <= MI_CRIMINAL02) + copsDontCare = true; + break; + case EVENT_ENTITY_VEHICLE: + ref = CPools::GetVehicleRef((CVehicle*)ent); + break; + case EVENT_ENTITY_OBJECT: + ref = CPools::GetObjectRef((CObject*)ent); + break; + default: + Error("Undefined entity type, RegisterEvent, EventList.cpp"); + ref = 0; + break; + } + + // only update time if event exists already + for(i = 0; i < NUMEVENTS; i++) + if(gaEvent[i].type == type && + gaEvent[i].entityType == entityType && + gaEvent[i].entityRef == ref){ + gaEvent[i].timeout = CTimer::GetTimeInMilliseconds() + timeout; + return; + } + + for(i = ms_nFirstFreeSlotIndex; i < NUMEVENTS; i++) + if(gaEvent[i].type == EVENT_NULL){ + ms_nFirstFreeSlotIndex = i; + break; + } + if(i < NUMEVENTS){ + gaEvent[i].type = type; + gaEvent[i].entityType = entityType; + gaEvent[i].timeout = CTimer::GetTimeInMilliseconds() + timeout; + gaEvent[i].entityRef = ref; + gaEvent[i].posn = ent->GetPosition(); + gaEvent[i].criminal = criminal; + if(gaEvent[i].criminal) + gaEvent[i].criminal->RegisterReference((CEntity**)&gaEvent[i].criminal); + if(type == EVENT_GUNSHOT) + gaEvent[i].state = EVENT_STATE_CLEAR; + else + gaEvent[i].state = EVENT_STATE_0; + } + + if(criminal == FindPlayerPed()) + ReportCrimeForEvent(type, (uintptr)ent, copsDontCare); +} + +void +CEventList::RegisterEvent(eEventType type, CVector posn, int32 timeout) +{ + int i; + + // only update time if event exists already + for(i = 0; i < NUMEVENTS; i++) + if(gaEvent[i].type == type && + gaEvent[i].posn.x == posn.x && + gaEvent[i].posn.y == posn.y && + gaEvent[i].posn.z == posn.z && + gaEvent[i].entityType == EVENT_ENTITY_NONE){ + gaEvent[i].timeout = CTimer::GetTimeInMilliseconds() + timeout; + return; + } + + for(i = ms_nFirstFreeSlotIndex; i < NUMEVENTS; i++) + if(gaEvent[i].type == EVENT_NULL){ + ms_nFirstFreeSlotIndex = i; + break; + } + if(i < NUMEVENTS){ + gaEvent[i].type = type; + gaEvent[i].entityType = EVENT_ENTITY_NONE; + gaEvent[i].timeout = CTimer::GetTimeInMilliseconds() + timeout; + gaEvent[i].posn = posn; + gaEvent[i].entityRef = 0; + if(type == EVENT_GUNSHOT) + gaEvent[i].state = EVENT_STATE_CLEAR; + else + gaEvent[i].state = EVENT_STATE_0; + } +} + +bool +CEventList::GetEvent(eEventType type, int32 *event) +{ + int i; + for(i = 0; i < NUMEVENTS; i++) + if(gaEvent[i].type == type){ + *event = i; + return true; + } + return false; +} + +void +CEventList::ClearEvent(int32 event) +{ + if(gaEvent[event].state != EVENT_STATE_CANDELETE) + gaEvent[event].state = EVENT_STATE_CLEAR; +} + +bool +CEventList::FindClosestEvent(eEventType type, CVector posn, int32 *event) +{ + int i; + float dist; + bool found = false; + float mindist = 60.0f; + + for(i = 0; i < NUMEVENTS; i++){ + if(gaEvent[i].type != type) + continue; + dist = (posn - gaEvent[i].posn).Magnitude(); + if(dist < mindist){ + mindist = dist; + found = true; + *event = i; + } + } + return found; +} + +void +CEventList::ReportCrimeForEvent(eEventType type, int32 crimeId, bool copsDontCare) +{ + eCrimeType crime; + switch(type){ + case EVENT_ASSAULT: crime = CRIME_HIT_PED; break; + case EVENT_RUN_REDLIGHT: crime = CRIME_RUN_REDLIGHT; break; + case EVENT_ASSAULT_POLICE: crime = CRIME_HIT_COP; break; + case EVENT_GUNSHOT: crime = CRIME_POSSESSION_GUN; break; + case EVENT_STEAL_CAR: crime = CRIME_STEAL_CAR; break; + case EVENT_HIT_AND_RUN: crime = CRIME_RUNOVER_PED; break; + case EVENT_HIT_AND_RUN_COP: crime = CRIME_RUNOVER_COP; break; + case EVENT_SHOOT_PED: crime = CRIME_SHOOT_PED; break; + case EVENT_SHOOT_COP: crime = CRIME_SHOOT_COP; break; + case EVENT_PED_SET_ON_FIRE: crime = CRIME_PED_BURNED; break; + case EVENT_COP_SET_ON_FIRE: crime = CRIME_COP_BURNED; break; + case EVENT_CAR_SET_ON_FIRE: crime = CRIME_VEHICLE_BURNED; break; + default: crime = CRIME_NONE; break; + } + + if(crime == CRIME_NONE) + return; + + CVector playerPedCoors = FindPlayerPed()->GetPosition(); + CVector playerCoors = FindPlayerCoors(); + + if(CWanted::WorkOutPolicePresence(playerCoors, 14.0f) != 0){ + FindPlayerPed()->m_pWanted->RegisterCrime_Immediately(crime, playerPedCoors, crimeId, copsDontCare); + FindPlayerPed()->m_pWanted->SetWantedLevelNoDrop(1); + }else + FindPlayerPed()->m_pWanted->RegisterCrime(crime, playerPedCoors, crimeId, copsDontCare); + + if(type == EVENT_ASSAULT_POLICE) + FindPlayerPed()->SetWantedLevelNoDrop(1); + if(type == EVENT_SHOOT_COP) + FindPlayerPed()->SetWantedLevelNoDrop(2); + +} + +STARTPATCHES + InjectHook(0x475B60, CEventList::Initialise, PATCH_JUMP); + InjectHook(0x475BE0, CEventList::Update, PATCH_JUMP); + InjectHook(0x475C50, (void (*)(eEventType,eEventEntity,CEntity *,CPed *,int32))CEventList::RegisterEvent, PATCH_JUMP); + InjectHook(0x475E10, (void (*)(eEventType,CVector,int32))CEventList::RegisterEvent, PATCH_JUMP); + InjectHook(0x475F40, CEventList::GetEvent, PATCH_JUMP); + InjectHook(0x475F70, CEventList::ClearEvent, PATCH_JUMP); + InjectHook(0x475F90, CEventList::FindClosestEvent, PATCH_JUMP); + InjectHook(0x476070, CEventList::ReportCrimeForEvent, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/EventList.h b/src/core/EventList.h new file mode 100644 index 00000000..9f5756be --- /dev/null +++ b/src/core/EventList.h @@ -0,0 +1,67 @@ +#pragma once + +class CEntity; +class CPed; + +enum eEventType +{ + EVENT_NULL, + EVENT_ASSAULT, + EVENT_RUN_REDLIGHT, + EVENT_ASSAULT_POLICE, + EVENT_GUNSHOT, + EVENT_INJURED_PED, + EVENT_DEAD_PED, + EVENT_FIRE, + EVENT_STEAL_CAR, + EVENT_HIT_AND_RUN, + EVENT_HIT_AND_RUN_COP, + EVENT_SHOOT_PED, + EVENT_SHOOT_COP, + EVENT_EXPLOSION, + EVENT_PED_SET_ON_FIRE, + EVENT_COP_SET_ON_FIRE, + EVENT_CAR_SET_ON_FIRE, + EVENT_ASSAULT_NASTYWEAPON, + EVENT_ASSAULT_NASTYWEAPON_POLICE, + EVENT_ICECREAM, + EVENT_ATM, + EVENT_SHOPSTALL, + EVENT_SHOPWINDOW, + EVENT_LAST_EVENT +}; + +enum eEventEntity +{ + EVENT_ENTITY_NONE, + EVENT_ENTITY_PED, + EVENT_ENTITY_VEHICLE, + EVENT_ENTITY_OBJECT +}; + +struct CEvent +{ + eEventType type; + eEventEntity entityType; + int32 entityRef; + CPed *criminal; + CVector posn; + uint32 timeout; + int32 state; +}; + +class CEventList +{ + static int32 ms_nFirstFreeSlotIndex; +public: + static void Initialise(void); + static void Update(void); + static void RegisterEvent(eEventType type, eEventEntity entityType, CEntity *ent, CPed *criminal, int32 timeout); + static void RegisterEvent(eEventType type, CVector posn, int32 timeout); + static bool GetEvent(eEventType type, int32 *event); + static void ClearEvent(int32 event); + static bool FindClosestEvent(eEventType type, CVector posn, int32 *event); + static void ReportCrimeForEvent(eEventType type, int32, bool); +}; + +extern CEvent *gaEvent;
\ No newline at end of file diff --git a/src/core/FileLoader.cpp b/src/core/FileLoader.cpp index 0c53ae66..14dc91cd 100644 --- a/src/core/FileLoader.cpp +++ b/src/core/FileLoader.cpp @@ -1,7 +1,7 @@ #include "common.h" #include "main.h" #include "patcher.h" -#include "math/Quaternion.h" +#include "Quaternion.h" #include "ModelInfo.h" #include "ModelIndices.h" #include "TempColModels.h" @@ -361,10 +361,10 @@ CFileLoader::LoadClumpFile(const char *filename) nodename = GetFrameNodeName(RpClumpGetFrame(clump)); GetNameAndLOD(nodename, name, &n); mi = (CClumpModelInfo*)CModelInfo::GetModelInfo(name, nil); - assert(mi->IsClump()); - if(mi) + if(mi){ + assert(mi->IsClump()); mi->SetClump(clump); - else + }else RpClumpDestroy(clump); } } diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index 77666b12..1de5c94f 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -26,46 +26,47 @@ #include "PlayerSkin.h" #include "PlayerInfo.h" #include "World.h" +#include "Renderer.h" #define ALL_ORIGINAL_FRONTEND 1 -int32 &CMenuManager::OS_Language = *(int32*)0x5F2F78; +int32 &CMenuManager::OS_Language = *(int32*)0x5F2F78; // 9 int8 &CMenuManager::m_PrefsUseVibration = *(int8*)0x95CD92; int8 &CMenuManager::m_DisplayControllerOnFoot = *(int8*)0x95CD8D; -int8 &CMenuManager::m_PrefsVsync = *(int8*)0x5F2E58; -int8 &CMenuManager::m_PrefsVsyncDisp = *(int8*)0x5F2E5C; -int8 &CMenuManager::m_PrefsFrameLimiter = *(int8*)0x5F2E60; -int8 &CMenuManager::m_PrefsShowSubtitles = *(int8*)0x5F2E54; +int8 &CMenuManager::m_PrefsVsync = *(int8*)0x5F2E58; // 1 +int8 &CMenuManager::m_PrefsVsyncDisp = *(int8*)0x5F2E5C; // 1 +int8 &CMenuManager::m_PrefsFrameLimiter = *(int8*)0x5F2E60; // 1 +int8 &CMenuManager::m_PrefsShowSubtitles = *(int8*)0x5F2E54; // 1 int8 &CMenuManager::m_PrefsSpeakers = *(int8*)0x95CD7E; -int8 &CMenuManager::m_ControlMethod = *(int8*)0x8F5F7C; -int8 &CMenuManager::m_PrefsDMA = *(int8*)0x5F2F74; -int8 &CMenuManager::m_PrefsLanguage = *(int8*)0x941238; +int32 &CMenuManager::m_ControlMethod = *(int32*)0x8F5F7C; +int8 &CMenuManager::m_PrefsDMA = *(int8*)0x5F2F74; // 1 +int32 &CMenuManager::m_PrefsLanguage = *(int32*)0x941238; -bool &CMenuManager::m_PrefsAllowNastyGame = *(bool*)0x5F2E64; +bool &CMenuManager::m_PrefsAllowNastyGame = *(bool*)0x5F2E64; // true bool &CMenuManager::m_bStartUpFrontEndRequested = *(bool*)0x95CCF4; bool &CMenuManager::m_bShutDownFrontEndRequested = *(bool*)0x95CD6A; int8 &CMenuManager::m_PrefsUseWideScreen = *(int8*)0x95CD23; int8 &CMenuManager::m_PrefsRadioStation = *(int8*)0x95CDA4; -int8 &CMenuManager::m_bDisableMouseSteering = *(int8*)0x60252C; -int32 &CMenuManager::m_PrefsBrightness = *(int32*)0x5F2E50; +int8 &CMenuManager::m_bDisableMouseSteering = *(int8*)0x60252C; // 1 +int32 &CMenuManager::m_PrefsBrightness = *(int32*)0x5F2E50; // 256 float &CMenuManager::m_PrefsLOD = *(float*)0x8F42C4; int8 &CMenuManager::m_bFrontEnd_ReloadObrTxtGxt = *(int8*)0x628CFC; -int32 &CMenuManager::m_PrefsMusicVolume = *(int32*)0x5F2E4C; -int32 &CMenuManager::m_PrefsSfxVolume = *(int32*)0x5F2E48; +int32 &CMenuManager::m_PrefsMusicVolume = *(int32*)0x5F2E4C; // 102 +int32 &CMenuManager::m_PrefsSfxVolume = *(int32*)0x5F2E48; // 102 -char *CMenuManager::m_PrefsSkinFile = (char*)0x5F2E74; +char *CMenuManager::m_PrefsSkinFile = (char*)0x5F2E74; //[256] "$$\"\"" -int32 &CMenuManager::m_KeyPressedCode = *(int32*)0x5F2E70; +int32 &CMenuManager::m_KeyPressedCode = *(int32*)0x5F2E70; // -1 CMenuManager &FrontEndMenuManager = *(CMenuManager*)0x8F59D8; // Move this somewhere else. -float lodMultiplier = *(float*)0x5F726C; +float &CRenderer::ms_lodDistScale = *(float*)0x5F726C; // 1.2 // Stuff not in CMenuManager: uint32 &VibrationTime = *(uint32*)0x628CF8; -char* pEditString = (char*)0x628D00; +char *&pEditString = *(char**)0x628D00; int32 *&pControlEdit = *(int32**)0x628D08; bool &DisplayComboButtonErrMsg = *(bool*)0x628D14; int32 &MouseButtonJustClicked = *(int32*)0x628D0C; @@ -74,7 +75,6 @@ int32 &nTimeForSomething = *(int32*)0x628D54; //int32 *pControlTemp = 0; // Frontend inputs. - bool GetPadBack(); bool GetPadExitEnter(); bool GetPadForward(); @@ -149,7 +149,7 @@ char *MenuFilenames[] = { nil, nil }; -#if ALL_ORIGINAL_FRONTEND +#if 0 WRAPPER void CMenuManager::BuildStatLine(char *text, float *stat, bool aFloat, float* stat2) { EAXJMP(0x483870); } #else void CMenuManager::BuildStatLine(char *text, float *stat, bool aFloat, float* stat2) @@ -177,7 +177,7 @@ void CMenuManager::BuildStatLine(char *text, float *stat, bool aFloat, float* st } #endif -#if ALL_ORIGINAL_FRONTEND +#if 0 WRAPPER void CMenuManager::CentreMousePointer() { EAXJMP(0x48ACE0); } #else void CMenuManager::CentreMousePointer() @@ -205,7 +205,7 @@ void CMenuManager::CheckCodesForControls(int, int) } #endif -#if ALL_ORIGINAL_FRONTEND +#if 0 WRAPPER bool CMenuManager::CheckHover(int, int, int, int) { EAXJMP(0x48ACA0); } #else bool CMenuManager::CheckHover(int x1, int x2, int y1, int y2) @@ -217,74 +217,35 @@ bool CMenuManager::CheckHover(int x1, int x2, int y1, int y2) void CMenuManager::CheckSliderMovement(int value) { - float fBrightness = 0.0f; - float fDrawDistance = 0.0f; - float fRadioVolume = 0.0f; - float fSfxVolume = 0.0f; - float fMouseSens = 0.0f; - switch (aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_Action) { case MENUACTION_BRIGHTNESS: - fBrightness = m_PrefsBrightness + (value * (512.0f) / 16.0f); - - if (fBrightness > 511.0f) - fBrightness = 511.0f; - else if (fBrightness < 0.0f) - fBrightness = 0.0f; - - m_PrefsBrightness = fBrightness; - SaveSettings(); + m_PrefsBrightness += m_PrefsBrightness + value * (512/16); + m_PrefsBrightness = clamp(m_PrefsBrightness, 0, 511); break; case MENUACTION_DRAWDIST: - fDrawDistance = m_PrefsLOD + (value * (1.8f - 0.8f) / 16.0f); - - if (fDrawDistance > 1.8f) - fDrawDistance = 1.8f; - else if (fDrawDistance < 0.8f) - fDrawDistance = 0.8f; - - m_PrefsLOD = fDrawDistance; - SaveSettings(); + m_PrefsLOD += value * ((1.8f - 0.8f)/16.0f); + m_PrefsLOD = clamp(m_PrefsLOD, 0.8f, 1.8f); + CRenderer::ms_lodDistScale = m_PrefsLOD; break; case MENUACTION_MUSICVOLUME: - fRadioVolume = m_PrefsMusicVolume + (value * (128.0f) / 16.0f); - - if (fRadioVolume > 127.0f) - fRadioVolume = 127.0f; - else if (fRadioVolume < 0.0f) - fRadioVolume = 0.0f; - - m_PrefsMusicVolume = fRadioVolume; - DMAudio.SetMusicMasterVolume(fRadioVolume); - SaveSettings(); + m_PrefsMusicVolume += value * (128/16); + m_PrefsMusicVolume = clamp(m_PrefsMusicVolume, 0, 127); + DMAudio.SetMusicMasterVolume(m_PrefsMusicVolume); break; case MENUACTION_SFXVOLUME: - fSfxVolume = m_PrefsSfxVolume + (value * (128.0f) / 16.0f); - - if (fSfxVolume > 127) - fSfxVolume = 127; - else if (fSfxVolume < 0.0f) - fSfxVolume = 0.0f; - - m_PrefsSfxVolume = fSfxVolume; - DMAudio.SetEffectsMasterVolume(fSfxVolume); - SaveSettings(); + m_PrefsSfxVolume += value * (128/16); + m_PrefsSfxVolume = clamp(m_PrefsSfxVolume, 0, 127); + DMAudio.SetEffectsMasterVolume(m_PrefsSfxVolume); break; case MENUACTION_MOUSESENS: - fMouseSens = TheCamera.m_fMouseAccelHorzntl + (value * (0.005f - 0.0003125f) / 16.0f); - - if (fMouseSens > 0.005f) - fMouseSens = 0.005f; - else if (fMouseSens < 0.0003125f) - fMouseSens = 0.0003125f; - - TheCamera.m_fMouseAccelHorzntl = fMouseSens; - - // BUG: game doesn't set Y Axis. - TheCamera.m_fMouseAccelVertical = fMouseSens; - SaveSettings(); + TheCamera.m_fMouseAccelHorzntl += value * 1.0f/200.0f/15.0f; // ??? + TheCamera.m_fMouseAccelHorzntl = clamp(TheCamera.m_fMouseAccelHorzntl, 1.0f/3200.0f, 1.0f/200.0f); + TheCamera.m_fMouseAccelVertical = TheCamera.m_fMouseAccelHorzntl; break; + default: + return; } + SaveSettings(); } #if 1 @@ -471,7 +432,7 @@ void CMenuManager::Draw() CFont::PrintString(SCREEN_SCALE_X(MENUACTION_POS_X), SCREEN_SCALE_Y(MENUACTION_POS_Y), str); } - for (int i = 0; i < MENUROWS; ++i) { + for (int i = 0; i < NUM_MENUROWS; ++i) { if (aScreens[m_nCurrScreen].m_aEntries[i].m_Action != MENUACTION_LABEL && aScreens[m_nCurrScreen].m_aEntries[i].m_EntryName[0]) { wchar *textToPrint[MENUCOLUMNS] = { nil, nil }; bool Locked = false; @@ -543,7 +504,7 @@ void CMenuManager::Draw() case AR_16_9: textToPrint[MENUCOLUMN_RIGHT] = (wchar*)L"16:9"; break; - } + } #endif break; case MENUACTION_RADIO: @@ -611,7 +572,7 @@ void CMenuManager::Draw() break; case MENUACTION_MOUSESTEER: textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_bDisableMouseSteering ? "FEM_ON" : "FEM_OFF"); - break; + break; } CFont::SetDropShadowPosition(MENUDROP_COLOR_SIZE); @@ -711,7 +672,7 @@ void CMenuManager::Draw() CFont::SetColor(CRGBA(255, 217, 106, FadeIn(255))); CSprite2d::DrawRect(CRect(SCREEN_STRETCH_X(11.0f), vecPositions.y - SCREEN_STRETCH_Y(fBarSize * 0.13f), SCREEN_STRETCH_FROM_RIGHT(11.0f), vecPositions.y + SCREEN_STRETCH_Y(fBarSize)), CRGBA(100, 200, 50, 50)); } - else + else CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255))); // Draw @@ -727,35 +688,27 @@ void CMenuManager::Draw() } // Mouse support. - // TODO: inputs for these pages. - if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) { - } - else if (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) { - - } - else { - static bool bIsMouseInPosition = false; - if (m_nMenuFadeAlpha >= 255 && GetMouseInput()) { - CVector2D vecInputSize = { SCREEN_SCALE_X(20.0f), SCREEN_SCALE_FROM_RIGHT(20.0f) }; - if (m_bShowMouse && - ((CheckHover(vecInputSize.x, vecInputSize.y, vecPositions.y, vecPositions.y + SCREEN_STRETCH_Y(20.0f))))) - bIsMouseInPosition = true; - else - bIsMouseInPosition = false; + static bool bIsMouseInPosition = false; + if (m_nMenuFadeAlpha >= 255 && GetMouseInput()) { + CVector2D vecInputSize = { SCREEN_SCALE_X(20.0f), SCREEN_SCALE_FROM_RIGHT(20.0f) }; + if (m_bShowMouse && + ((CheckHover(vecInputSize.x, vecInputSize.y, vecPositions.y, vecPositions.y + SCREEN_STRETCH_Y(20.0f))))) + bIsMouseInPosition = true; + else + bIsMouseInPosition = false; - if (bIsMouseInPosition) { - if (m_nCurrOption != i) { - m_nCurrOption = i; - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); - } + if (bIsMouseInPosition) { + if (m_nCurrOption != i) { + m_nCurrOption = i; + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); + } - m_nPrevOption = m_nCurrOption; + m_nPrevOption = m_nCurrOption; - if (GetMouseForward()) - m_nHoverOption = HOVEROPTION_NULL; - else - m_nHoverOption = HOVEROPTION_DEFAULT; - } + if (GetMouseForward()) + m_nHoverOption = HOVEROPTION_42; + else + m_nHoverOption = HOVEROPTION_DEFAULT; } } @@ -763,16 +716,16 @@ void CMenuManager::Draw() // TODO: CheckHover switch (aScreens[m_nCurrScreen].m_aEntries[i].m_Action) { case MENUACTION_BRIGHTNESS: - DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), m_PrefsBrightness/512.0f); + DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), m_PrefsBrightness / 512.0f); break; case MENUACTION_DRAWDIST: DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), (m_PrefsLOD - 0.8f) * 1.0f); break; case MENUACTION_MUSICVOLUME: - DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), m_PrefsMusicVolume/128.0f); + DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), m_PrefsMusicVolume / 128.0f); break; case MENUACTION_SFXVOLUME: - DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), m_PrefsSfxVolume/128.0f); + DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), m_PrefsSfxVolume / 128.0f); break; case MENUACTION_MOUSESENS: DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), TheCamera.m_fMouseAccelHorzntl * 200.0f); @@ -859,7 +812,7 @@ void CMenuManager::DrawControllerSetupScreen() } #endif -#if ALL_ORIGINAL_FRONTEND +#if 0 WRAPPER void CMenuManager::DrawFrontEnd(void) { EAXJMP(0x47A540); } #else void CMenuManager::DrawFrontEnd() @@ -867,7 +820,7 @@ void CMenuManager::DrawFrontEnd() CFont::SetAlphaFade(255.0f); if (m_nCurrScreen == MENUPAGE_NONE) { - m_nMenuFadeAlpha = 0; + // m_nMenuFadeAlpha = 0; if (m_bGameNotLoaded) m_nCurrScreen = MENUPAGE_START_MENU; @@ -875,31 +828,27 @@ void CMenuManager::DrawFrontEnd() m_nCurrScreen = MENUPAGE_PAUSE_MENU; } - if (!m_nCurrOption && aScreens[m_nCurrScreen].m_aEntries[0].m_Action == MENUACTION_LABEL) - m_nCurrOption = MENUROW_1; + if (m_nCurrOption == 0 && aScreens[m_nCurrScreen].m_aEntries[0].m_Action == MENUACTION_LABEL) + m_nCurrOption = 1; CMenuManager::DrawFrontEndNormal(); CMenuManager::PrintErrorMessage(); } #endif -#if ALL_ORIGINAL_FRONTEND +#if 0 WRAPPER void CMenuManager::DrawFrontEndNormal(void) { EAXJMP(0x47A5B0); } #else void CMenuManager::DrawFrontEndNormal() { - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE); RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); - RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void *)FALSE); - RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE); - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA); - RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA); - RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void *)rwTEXTUREADDRESSCLAMP); CSprite2d::InitPerFrame(); CFont::InitPerFrame(); - eMenuSprites previousSprite = MENUSPRITE_MAINMENU; + LoadSplash(nil); + + eMenuSprites previousSprite = MENUSPRITE_MAINMENU; // actually uninitialized if (m_nMenuFadeAlpha < 255) { switch (m_nPrevScreen) { case MENUPAGE_STATS: @@ -939,13 +888,16 @@ void CMenuManager::DrawFrontEndNormal() break; } - if (m_nPrevScreen == MENUPAGE_NONE) - CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(0, 0, 0, 255)); + if (m_nPrevScreen == m_nCurrScreen) + CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(0, 0, 0, 255-m_nMenuFadeAlpha)); else - m_aMenuSprites[previousSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255)); + m_aMenuSprites[previousSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255-m_nMenuFadeAlpha)); } - eMenuSprites currentSprite = MENUSPRITE_MAINMENU; + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); + + eMenuSprites currentSprite = MENUSPRITE_MAINMENU; // actually uninitialized switch (m_nCurrScreen) { case MENUPAGE_STATS: case MENUPAGE_START_MENU: @@ -984,38 +936,45 @@ void CMenuManager::DrawFrontEndNormal() break; } - uint32 savedShade; - uint32 savedAlpha; - RwRenderStateGet(rwRENDERSTATESHADEMODE, &savedShade); - RwRenderStateSet(rwRENDERSTATESHADEMODE, reinterpret_cast<void *>(rwSHADEMODEGOURAUD)); - RwRenderStateGet(rwRENDERSTATEVERTEXALPHAENABLE, &savedAlpha); - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, reinterpret_cast<void *>(TRUE)); - if (m_nMenuFadeAlpha >= 255) { - m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255)); - } - else { - if (m_nMenuFadeAlpha < 255) { - m_nMenuFadeAlpha += 0.1f * 255.0f; - - if (m_nMenuFadeAlpha >= 255) - m_nMenuFadeAlpha = 255; + if (m_nMenuFadeAlpha < 255) { + static int LastFade = 0; - m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, m_nMenuFadeAlpha)); + if(CTimer::GetTimeInMillisecondsPauseMode() - LastFade > 10){ + m_nMenuFadeAlpha += 20; + LastFade = CTimer::GetTimeInMillisecondsPauseMode(); } - else + + if (m_nMenuFadeAlpha > 255){ m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255)); + }else{ + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, m_nMenuFadeAlpha)); + } + } + else { + m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255)); + // TODO: what is this? waiting mouse? + if(field_518 == 4){ + if(m_nHoverOption == 3 || m_nHoverOption == 4 || m_nHoverOption == 5 || m_nHoverOption == 6 || m_nHoverOption == 7) + field_518 = 2; + else + field_518 = 1; + } } // GTA LOGO + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); if (m_nCurrScreen == MENUPAGE_START_MENU || m_nCurrScreen == MENUPAGE_PAUSE_MENU) { if (CGame::frenchGame || CGame::germanGame || !CGame::nastyGame) m_aMenuSprites[MENUSPRITE_GTA3LOGO].Draw(CRect((SCREEN_WIDTH / 2) - SCREEN_SCALE_X(115.0f), SCREEN_SCALE_Y(70.0f), (SCREEN_WIDTH / 2) + SCREEN_SCALE_X(115.0f), SCREEN_SCALE_Y(180.0f)), CRGBA(255, 255, 255, FadeIn(255))); else m_aMenuSprites[MENUSPRITE_GTALOGO].Draw(CRect((SCREEN_WIDTH / 2) - SCREEN_SCALE_X(95.0f), SCREEN_SCALE_Y(40.0f), (SCREEN_WIDTH / 2) + SCREEN_SCALE_X(95.0f), SCREEN_SCALE_Y(210.0f)), CRGBA(255, 255, 255, FadeIn(255))); } - RwRenderStateSet(rwRENDERSTATESHADEMODE, reinterpret_cast<void *>(savedShade)); - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, reinterpret_cast<void *>(savedAlpha)); + RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERNEAREST); + RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); switch (m_nCurrScreen) { case MENUPAGE_SKIN_SELECT: CMenuManager::DrawPlayerSetupScreen(); @@ -1031,8 +990,25 @@ void CMenuManager::DrawFrontEndNormal() CFont::DrawFonts(); // Draw mouse - if (m_bShowMouse) - m_aMenuSprites[MENUSPRITE_MOUSE].Draw(m_nMousePosX, m_nMousePosY, SCREEN_SCALE_X(60.0f), SCREEN_SCALE_Y(60.0f), CRGBA(255, 255, 255, 255)); + RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); + RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP); + if (m_bShowMouse) { + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + + CRect mouse(0.0f, 0.0f, SCREEN_SCALE_X(75.0f), SCREEN_SCALE_X(75.0f)); + mouse.Translate(m_nMousePosX, m_nMousePosY); + CRect shad = mouse; + shad.Translate(SCREEN_SCALE_X(10.0f), SCREEN_SCALE_Y(3.0f)); + if(field_518 == 4){ + m_aMenuSprites[MENUSPRITE_MOUSET].Draw(shad, CRGBA(100, 100, 100, 50)); + m_aMenuSprites[MENUSPRITE_MOUSET].Draw(mouse, CRGBA(255, 255, 255, 255)); + }else{ + m_aMenuSprites[MENUSPRITE_MOUSE].Draw(shad, CRGBA(100, 100, 100, 50)); + m_aMenuSprites[MENUSPRITE_MOUSE].Draw(mouse, CRGBA(255, 255, 255, 255)); + } + } } #endif @@ -1045,7 +1021,7 @@ void CMenuManager::DrawPlayerSetupScreen() } #endif -#if ALL_ORIGINAL_FRONTEND +#if 0 WRAPPER int CMenuManager::FadeIn(int alpha) { EAXJMP(0x48AC60); } #else int CMenuManager::FadeIn(int alpha) @@ -1054,11 +1030,7 @@ int CMenuManager::FadeIn(int alpha) m_nCurrScreen == MENUPAGE_SAVING_IN_PROGRESS || m_nCurrScreen == MENUPAGE_DELETING) return alpha; - - if (m_nMenuFadeAlpha >= alpha) - return alpha; - - return m_nMenuFadeAlpha; + return min(m_nMenuFadeAlpha, alpha); } #endif @@ -1116,7 +1088,7 @@ void CMenuManager::LoadAllTextures() CMenuManager::CentreMousePointer(); DMAudio.ChangeMusicMode(0); DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_STARTING, 0); - m_nCurrOption = MENUROW_0; + m_nCurrOption = 0; m_PrefsRadioStation = DMAudio.GetRadioInCar(); if (DMAudio.IsMP3RadioChannelAvailable()) { @@ -1165,7 +1137,7 @@ void CMenuManager::LoadAllTextures() } #endif -#if ALL_ORIGINAL_FRONTEND +#if 0 WRAPPER void CMenuManager::LoadSettings() { EAXJMP(0x488EE0); } #else void CMenuManager::LoadSettings() @@ -1173,46 +1145,47 @@ void CMenuManager::LoadSettings() CFileMgr::SetDirMyDocuments(); - uint8 prevLang = m_PrefsLanguage; + int32 prevLang = m_PrefsLanguage; + CMBlur::BlurOn = true; MousePointerStateHelper.bInvertVertically = true; static char Ver; int fileHandle = CFileMgr::OpenFile("gta3.set", "r"); if (fileHandle) { - CFileMgr::Read(fileHandle, buf(&Ver), sizeof(Ver)); + CFileMgr::Read(fileHandle, (char*)&Ver, sizeof(Ver)); if (strncmp(&Ver, "THIS FILE IS NOT VALID YET", 26)) { CFileMgr::Seek(fileHandle, 0, 0); ControlsManager.LoadSettings(fileHandle); - CFileMgr::Read(fileHandle, buf(gString), 20); - CFileMgr::Read(fileHandle, buf(gString), 20); - CFileMgr::Read(fileHandle, buf(gString), 4); - CFileMgr::Read(fileHandle, buf(gString), 4); - CFileMgr::Read(fileHandle, buf(gString), 1); - CFileMgr::Read(fileHandle, buf(gString), 1); - CFileMgr::Read(fileHandle, buf(gString), 1); - CFileMgr::Read(fileHandle, buf(&TheCamera.m_bHeadBob), 1); - CFileMgr::Read(fileHandle, buf(&TheCamera.m_fMouseAccelHorzntl), 4); - CFileMgr::Read(fileHandle, buf(&TheCamera.m_fMouseAccelVertical), 4); - CFileMgr::Read(fileHandle, buf(&MousePointerStateHelper.bInvertVertically), 1); - CFileMgr::Read(fileHandle, buf(&CVehicle::m_bDisableMouseSteering), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsSfxVolume), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsMusicVolume), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsRadioStation), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsSpeakers), 1); - CFileMgr::Read(fileHandle, buf(&m_nPrefsAudio3DProviderIndex), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsDMA), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsBrightness), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsLOD), 4); - CFileMgr::Read(fileHandle, buf(&m_PrefsShowSubtitles), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsUseWideScreen), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsVsyncDisp), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsFrameLimiter), 1); - CFileMgr::Read(fileHandle, buf(&m_nDisplayVideoMode), 1); - CFileMgr::Read(fileHandle, buf(&CMBlur::BlurOn), 1); - CFileMgr::Read(fileHandle, buf(m_PrefsSkinFile), 256); - CFileMgr::Read(fileHandle, buf(&m_ControlMethod), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsLanguage), 1); + CFileMgr::Read(fileHandle, gString, 20); + CFileMgr::Read(fileHandle, gString, 20); + CFileMgr::Read(fileHandle, gString, 4); + CFileMgr::Read(fileHandle, gString, 4); + CFileMgr::Read(fileHandle, gString, 1); + CFileMgr::Read(fileHandle, gString, 1); + CFileMgr::Read(fileHandle, gString, 1); + CFileMgr::Read(fileHandle, (char*)&TheCamera.m_bHeadBob, 1); + CFileMgr::Read(fileHandle, (char*)&TheCamera.m_fMouseAccelHorzntl, 4); + CFileMgr::Read(fileHandle, (char*)&TheCamera.m_fMouseAccelVertical, 4); + CFileMgr::Read(fileHandle, (char*)&MousePointerStateHelper.bInvertVertically, 1); + CFileMgr::Read(fileHandle, (char*)&CVehicle::m_bDisableMouseSteering, 1); + CFileMgr::Read(fileHandle, (char*)&m_PrefsSfxVolume, 1); + CFileMgr::Read(fileHandle, (char*)&m_PrefsMusicVolume, 1); + CFileMgr::Read(fileHandle, (char*)&m_PrefsRadioStation, 1); + CFileMgr::Read(fileHandle, (char*)&m_PrefsSpeakers, 1); + CFileMgr::Read(fileHandle, (char*)&m_nPrefsAudio3DProviderIndex, 1); + CFileMgr::Read(fileHandle, (char*)&m_PrefsDMA, 1); + CFileMgr::Read(fileHandle, (char*)&m_PrefsBrightness, 1); + CFileMgr::Read(fileHandle, (char*)&m_PrefsLOD, 4); + CFileMgr::Read(fileHandle, (char*)&m_PrefsShowSubtitles, 1); + CFileMgr::Read(fileHandle, (char*)&m_PrefsUseWideScreen, 1); + CFileMgr::Read(fileHandle, (char*)&m_PrefsVsyncDisp, 1); + CFileMgr::Read(fileHandle, (char*)&m_PrefsFrameLimiter, 1); + CFileMgr::Read(fileHandle, (char*)&m_nDisplayVideoMode, 1); + CFileMgr::Read(fileHandle, (char*)&CMBlur::BlurOn, 1); + CFileMgr::Read(fileHandle, m_PrefsSkinFile, 256); + CFileMgr::Read(fileHandle, (char*)&m_ControlMethod, 1); + CFileMgr::Read(fileHandle, (char*)&m_PrefsLanguage, 1); } } @@ -1220,7 +1193,7 @@ void CMenuManager::LoadSettings() CFileMgr::SetDir(""); m_PrefsVsync = m_PrefsVsyncDisp; - lodMultiplier = m_PrefsLOD; + CRenderer::ms_lodDistScale = m_PrefsLOD; if (m_nPrefsAudio3DProviderIndex == -1) m_nPrefsAudio3DProviderIndex = -2; @@ -1237,25 +1210,72 @@ void CMenuManager::LoadSettings() debug("The previously saved language is now in use"); } - /*struct _WIN32_FIND_DATAA FindFileData; - HANDLE H = FindFirstFileA("skins\*.bmp", &FindFileData); - char Dest; + struct _WIN32_FIND_DATAA FindFileData; + char skinfile[256+16]; // ?? + 16? bool SkinFound = false; - - for (int i = 1; H != (HANDLE)-1 && i; i = FindNextFileA(H, &FindFileData)) { - strcpy(&Dest, buf(m_PrefsSkinFile)); - strcat(&Dest, ".bmp"); - if (!strcmp(FindFileData.cFileName, &Dest)) + HANDLE handle = FindFirstFileA("skins\\*.bmp", &FindFileData); + for (int i = 1; handle != (HANDLE)-1 && i; i = FindNextFileA(handle, &FindFileData)) { + strcpy(skinfile, m_PrefsSkinFile); + strcat(skinfile, ".bmp"); + if (strcmp(FindFileData.cFileName, skinfile) == 0) SkinFound = true; } - - FindClose(H); + FindClose(handle); if (!SkinFound) { debug("Default skin set as no other skins are available OR saved skin not found!"); - strcpy((char *)CMenuManager::m_PrefsSkinFile, "$$\"\""); + strcpy(m_PrefsSkinFile, "$$\"\""); strcpy(m_aSkinName, "$$\"\""); - }*/ + } +} +#endif + +#if 0 +WRAPPER void CMenuManager::SaveSettings() { EAXJMP(0x488CC0); } +#else +void CMenuManager::SaveSettings() +{ + static char RubbishString[48] = "stuffmorestuffevenmorestuff etc"; + + CFileMgr::SetDirMyDocuments(); + + int fileHandle = CFileMgr::OpenFile("gta3.set", "w"); + if (fileHandle) { + + ControlsManager.SaveSettings(fileHandle); + CFileMgr::Write(fileHandle, RubbishString, 20); + CFileMgr::Write(fileHandle, RubbishString, 20); + CFileMgr::Write(fileHandle, RubbishString, 4); + CFileMgr::Write(fileHandle, RubbishString, 4); + CFileMgr::Write(fileHandle, RubbishString, 1); + CFileMgr::Write(fileHandle, RubbishString, 1); + CFileMgr::Write(fileHandle, RubbishString, 1); + CFileMgr::Write(fileHandle, (char*)&TheCamera.m_bHeadBob, 1); + CFileMgr::Write(fileHandle, (char*)&TheCamera.m_fMouseAccelHorzntl, 4); + CFileMgr::Write(fileHandle, (char*)&TheCamera.m_fMouseAccelVertical, 4); + CFileMgr::Write(fileHandle, (char*)&MousePointerStateHelper.bInvertVertically, 1); + CFileMgr::Write(fileHandle, (char*)&CVehicle::m_bDisableMouseSteering, 1); + CFileMgr::Write(fileHandle, (char*)&m_PrefsSfxVolume, 1); + CFileMgr::Write(fileHandle, (char*)&m_PrefsMusicVolume, 1); + CFileMgr::Write(fileHandle, (char*)&m_PrefsRadioStation, 1); + CFileMgr::Write(fileHandle, (char*)&m_PrefsSpeakers, 1); + CFileMgr::Write(fileHandle, (char*)&m_nPrefsAudio3DProviderIndex, 1); + CFileMgr::Write(fileHandle, (char*)&m_PrefsDMA, 1); + CFileMgr::Write(fileHandle, (char*)&m_PrefsBrightness, 1); + CFileMgr::Write(fileHandle, (char*)&m_PrefsLOD, sizeof(m_PrefsLOD)); + CFileMgr::Write(fileHandle, (char*)&m_PrefsShowSubtitles, 1); + CFileMgr::Write(fileHandle, (char*)&m_PrefsUseWideScreen, 1); + CFileMgr::Write(fileHandle, (char*)&m_PrefsVsyncDisp, 1); + CFileMgr::Write(fileHandle, (char*)&m_PrefsFrameLimiter, 1); + CFileMgr::Write(fileHandle, (char*)&m_nDisplayVideoMode, 1); + CFileMgr::Write(fileHandle, (char*)&CMBlur::BlurOn, 1); + CFileMgr::Write(fileHandle, m_PrefsSkinFile, 256); + CFileMgr::Write(fileHandle, (char*)&m_ControlMethod, 1); + CFileMgr::Write(fileHandle, (char*)&m_PrefsLanguage, 1); + } + + CFileMgr::CloseFile(fileHandle); + CFileMgr::SetDir(""); } #endif @@ -1319,7 +1339,7 @@ void CMenuManager::PrintStats() } #endif -#if ALL_ORIGINAL_FRONTEND +#if 0 WRAPPER void CMenuManager::Process(void) { EAXJMP(0x485100); } #else void CMenuManager::Process(void) @@ -1423,7 +1443,7 @@ void CMenuManager::Process(void) JoyButtonJustClicked = ControlsManager.GetJoyButtonJustDown(); - int32 TypeOfControl = 0; + int32 TypeOfControl = 0; if (JoyButtonJustClicked) TypeOfControl = 3; if (MouseButtonJustClicked) @@ -1468,11 +1488,10 @@ void CMenuManager::Process(void) CPad::StopPadsShaking(); VibrationTime = 0; } - } - else { + + } else { UnloadTextures(); field_452 = 0; - *(bool*)0x5F33E4 = true; // byte_5F33E4 = 1; // unused m_nPrevScreen = 0; m_nCurrScreen = m_nPrevScreen; @@ -1493,15 +1512,12 @@ WRAPPER void CMenuManager::ProcessButtonPresses() { EAXJMP(0x4856F0); } #else void CMenuManager::ProcessButtonPresses() { - if(pEditString) - return; - if(pControlEdit) + if (pEditString || pControlEdit) return; // Update mouse position m_nMouseOldPosX = m_nMousePosX; m_nMouseOldPosY = m_nMousePosY; - m_nMousePosX = m_nMouseTempPosX; m_nMousePosY = m_nMouseTempPosY; @@ -1521,28 +1537,58 @@ void CMenuManager::ProcessButtonPresses() m_bShowMouse = false; if (m_nCurrScreen == MENUPAGE_MULTIPLAYER_FIND_GAME || m_nCurrScreen == MENUPAGE_SKIN_SELECT || m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) { - if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) - field_440 = m_nSkinsTotal; + if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) + m_nCurrExSize = m_nSkinsTotal; - if (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) { - field_440 = m_ControlMethod ? 30 : 25; - - if (field_44C > field_440) - field_44C = field_440 - 1; - } + if (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) + m_nCurrExSize = m_ControlMethod ? 30 : 25; if (!GetPadBack() || m_nCurrScreen != MENUPAGE_KEYBOARD_CONTROLS || field_535) field_535 = 0; - else if (field_536 == 19) { - m_nHoverOption = 42; + else if (m_nCurrExLayer == 19) { + m_nHoverOption = HOVEROPTION_42; field_113 = 1; field_456 = 1; - m_bKeyChangeNotProcessed = 1; + m_bKeyChangeNotProcessed = true; pControlEdit = &m_KeyPressedCode; } + bool Trigger = false; + if (!Trigger) { + nTimeForSomething = 0; + Trigger = true; + } + + if ((CTimer::GetTimeInMillisecondsPauseMode() - nTimeForSomething) > 200) { + field_520 = 0; + field_521 = 0; + field_522 = 0; + field_523 = 0; + field_524 = 0; + nTimeForSomething = CTimer::GetTimeInMillisecondsPauseMode(); + } + + if (CPad::GetPad(0)->NewKeyState.TAB && !CPad::GetPad(0)->OldKeyState.TAB) { + switch (m_nCurrExLayer) { + case 9: + m_nCurrExLayer = 19; + break; + case 19: + m_nCurrExLayer = 21; + break; + case 21: + m_nCurrExLayer = 9; + break; + } + if (m_nCurrScreen == MENUPAGE_SKIN_SELECT && m_nCurrExLayer == 21 && !strcmp(m_aSkinName, m_PrefsSkinFile)) { + m_nCurrExLayer = 9; + } + if (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS && m_nCurrExLayer == 21) + m_nCurrExLayer = 9; + } + if (GetPadForward()) { - switch (field_536) { + switch (m_nCurrExLayer) { case 19: if (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) { field_113 = 1; @@ -1552,36 +1598,21 @@ void CMenuManager::ProcessButtonPresses() if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) { strcpy(m_PrefsSkinFile, m_aSkinName); CWorld::Players->SetPlayerSkin(m_PrefsSkinFile); - field_536 = 9; + m_nCurrExLayer = 9; } - m_nHoverOption = HOVEROPTION_NULL; + m_nHoverOption = HOVEROPTION_42; SaveSettings(); break; case 21: strcpy(m_PrefsSkinFile, m_aSkinName); CWorld::Players->SetPlayerSkin(m_PrefsSkinFile); - field_536 = 9; + m_nCurrExLayer = 9; break; default: break; } } - - bool once = false; - if (!once) { - once = true; - nTimeForSomething = 0; - } - - if ((CTimer::GetTimeInMillisecondsPauseMode() - nTimeForSomething) > 200) { - field_520 = 0; - field_521 = 0; - field_522 = 0; - field_523 = 0; - field_524 = 0; - nTimeForSomething = CTimer::GetTimeInMillisecondsPauseMode(); - } } // Get number of menu options. @@ -1591,31 +1622,41 @@ void CMenuManager::ProcessButtonPresses() if (GetPadMoveUp()) { m_nPrevOption = m_nCurrOption; m_nCurrOption -= 1; + m_nCurrExOption -= 1; + //field_438 -= 1; if (aScreens[m_nCurrScreen].m_aEntries[0].m_Action == MENUACTION_LABEL) { - if (m_nCurrOption < MENUROW_1) + if (m_nCurrOption < 1) m_nCurrOption = NumberOfMenuOptions; } else { - if (m_nCurrOption < MENUROW_0) + if (m_nCurrOption < 0) m_nCurrOption = NumberOfMenuOptions; } + if (m_nCurrExOption < 0) + m_nCurrExOption = 0; + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); } else if (GetPadMoveDown()) { m_nPrevOption = m_nCurrOption; m_nCurrOption += 1; + m_nCurrExOption += 1; + //field_438 = += 1; if (aScreens[m_nCurrScreen].m_aEntries[0].m_Action == MENUACTION_LABEL) { if (m_nCurrOption > NumberOfMenuOptions) - m_nCurrOption = MENUROW_1; + m_nCurrOption = 1; } else { if (m_nCurrOption > NumberOfMenuOptions) - m_nCurrOption = MENUROW_0; + m_nCurrOption = 0; } + if (m_nCurrExOption > m_nCurrExSize - 1) + m_nCurrExOption = m_nCurrExSize - 1; + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); } @@ -1637,6 +1678,8 @@ void CMenuManager::ProcessButtonPresses() } else SwitchToNewScreen(aScreens[m_nCurrScreen].m_PreviousPage[0]); + + PlayEscSound = true; break; default: SwitchToNewScreen(aScreens[m_nCurrScreen].m_PreviousPage[0]); @@ -1675,7 +1718,7 @@ void CMenuManager::ProcessButtonPresses() } break; default: - m_nHoverOption = HOVEROPTION_NULL; + m_nHoverOption = HOVEROPTION_42; break; } } @@ -1871,10 +1914,12 @@ void CMenuManager::ProcessOnOffMenuOptions() break; case MENUACTION_UPDATESAVE: PcSaveHelper.PopulateSlotInfo(); - if (aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_SaveSlot >= SAVESLOT_1 && aScreens[m_nCurrOption].m_aEntries[m_nCurrOption].m_SaveSlot <= SAVESLOT_8) { - m_nCurrSaveSlot = aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_SaveSlot - 2; + if (!m_bGameNotLoaded) { + if (aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_SaveSlot >= SAVESLOT_1 && aScreens[m_nCurrOption].m_aEntries[m_nCurrOption].m_SaveSlot <= SAVESLOT_8) { + m_nCurrSaveSlot = aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_SaveSlot - 2; - SwitchToNewScreen(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_TargetMenu); + SwitchToNewScreen(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_TargetMenu); + } } break; case MENUACTION_CHECKSAVE: @@ -2120,32 +2165,24 @@ void CMenuManager::SaveLoadFileError_SetUpErrorScreen() case 1: case 2: case 3: - m_nPrevScreen = m_nCurrScreen; - m_nCurrScreen = MENUPAGE_SAVE_FAILED; - m_nCurrOption = MENUROW_0; + SwitchToNewScreen(MENUPAGE_SAVE_FAILED); m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); break; break; case 4: case 5: case 6: - this->m_nPrevScreen = m_nCurrScreen; - this->m_nCurrScreen = MENUPAGE_LOAD_FAILED; - m_nCurrOption = MENUROW_0; + SwitchToNewScreen(MENUPAGE_LOAD_FAILED); m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); break; case 7: - this->m_nPrevScreen = m_nCurrScreen; - this->m_nCurrScreen = MENUPAGE_LOAD_FAILED_2; - m_nCurrOption = MENUROW_0; + SwitchToNewScreen(MENUPAGE_LOAD_FAILED_2); m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); break; case 8: case 9: case 10: - m_nPrevScreen = m_nCurrScreen; - m_nCurrScreen = MENUPAGE_DELETE_FAILED; - m_nCurrOption = MENUROW_0; + SwitchToNewScreen(MENUPAGE_DELETE_FAILED); m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); break; default: @@ -2165,53 +2202,6 @@ void CMenuManager::SetHelperText(int text) #endif #if ALL_ORIGINAL_FRONTEND -WRAPPER void CMenuManager::SaveSettings() { EAXJMP(0x488CC0); } -#else -void CMenuManager::SaveSettings() -{ - CFileMgr::SetDirMyDocuments(); - - int fileHandle = CFileMgr::OpenFile("gta3.set", "w"); - if (fileHandle) { - - ControlsManager.SaveSettings(fileHandle); - CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 20); - CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 20); - CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 4); - CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 4); - CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 1); - CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 1); - CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 1); - CFileMgr::Write(fileHandle, buf(&TheCamera.m_bHeadBob), 1); - CFileMgr::Write(fileHandle, buf(&TheCamera.m_fMouseAccelHorzntl), 4); - CFileMgr::Write(fileHandle, buf(&TheCamera.m_fMouseAccelVertical), 4); - CFileMgr::Write(fileHandle, buf(&MousePointerStateHelper.bInvertVertically), 1); - CFileMgr::Write(fileHandle, buf(&CVehicle::m_bDisableMouseSteering), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsSfxVolume), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsMusicVolume), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsRadioStation), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsSpeakers), 1); - CFileMgr::Write(fileHandle, buf(&m_nPrefsAudio3DProviderIndex), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsDMA), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsBrightness), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsLOD), sizeof(m_PrefsLOD)); - CFileMgr::Write(fileHandle, buf(&m_PrefsShowSubtitles), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsUseWideScreen), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsVsyncDisp), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsFrameLimiter), 1); - CFileMgr::Write(fileHandle, buf(&m_nDisplayVideoMode), 1); - CFileMgr::Write(fileHandle, buf(&CMBlur::BlurOn), 1); - CFileMgr::Write(fileHandle, buf(m_PrefsSkinFile), 256); - CFileMgr::Write(fileHandle, buf(&m_ControlMethod), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsLanguage), 1); - } - - CFileMgr::CloseFile(fileHandle); - CFileMgr::SetDir(""); -} -#endif - -#if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::ShutdownJustMenu() { EAXJMP(0x488920); } #else void CMenuManager::ShutdownJustMenu() @@ -2221,7 +2211,6 @@ void CMenuManager::ShutdownJustMenu() } #endif -// We won't ever use this again. #if ALL_ORIGINAL_FRONTEND WRAPPER float CMenuManager::StretchX(float) { EAXJMP(0x48ABE0); } #else @@ -2230,7 +2219,11 @@ float CMenuManager::StretchX(float x) if (SCREEN_WIDTH == 640) return x; else +#ifndef ASPECT_RATIO_SCALE return SCREEN_WIDTH * x * 0.0015625f; +#else + return SCREEN_SCALE_X(x); +#endif } #endif @@ -2337,10 +2330,11 @@ void CMenuManager::WaitForUserCD() #endif // New content: +#if 0 uint8 CMenuManager::GetNumberOfMenuOptions() { - uint8 Rows = MENUROW_NONE; - for (int i = 0; i < MENUROWS; i++) { + uint8 Rows = -1; + for (int i = 0; i < NUM_MENUROWS; i++) { if (aScreens[m_nCurrScreen].m_aEntries[i].m_Action == MENUACTION_NOTHING) break; @@ -2349,7 +2343,7 @@ uint8 CMenuManager::GetNumberOfMenuOptions() return Rows; } -void CMenuManager::SwitchToNewScreen(int8 screen) +void CMenuManager::SwitchToNewScreen(int32 screen) { ResetHelperText(); @@ -2372,21 +2366,24 @@ void CMenuManager::SwitchToNewScreen(int8 screen) if (screen) { m_nPrevScreen = m_nCurrScreen; m_nCurrScreen = screen; - m_nCurrOption = MENUROW_0; + m_nCurrOption = 0; + // + m_nCurrExOption = 0; + m_nCurrExLayer = 19; + // m_nMenuFadeAlpha = 0; m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); } else { m_nPrevScreen = MENUPAGE_NONE; m_nCurrScreen = MENUPAGE_NONE; - m_nCurrOption = MENUROW_0; + m_nCurrOption = 0; } } // Set player skin. if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) { CPlayerSkin::BeginFrontEndSkinEdit(); - field_535 = 19; m_bSkinsFound = false; } @@ -2399,7 +2396,7 @@ void CMenuManager::SwitchToNewScreen(int8 screen) DMAudio.StopFrontEndTrack(); } -void CMenuManager::SetDefaultPreferences(int8 screen) +void CMenuManager::SetDefaultPreferences(int32 screen) { switch (screen) { case MENUPAGE_SOUND_SETTINGS: @@ -2446,6 +2443,7 @@ void CMenuManager::SetDefaultPreferences(int8 screen) break; } } +#endif // Frontend inputs. bool GetPadBack() @@ -2480,7 +2478,7 @@ bool GetPadMoveUp() bool GetPadMoveDown() { - return + return (CPad::GetPad(0)->NewState.DPadDown && !CPad::GetPad(0)->OldState.DPadDown) || (CPad::GetPad(0)->NewKeyState.DOWN && !CPad::GetPad(0)->OldKeyState.DOWN) || (CPad::GetPad(0)->NewState.LeftStickY > 0 && !(CPad::GetPad(0)->OldState.LeftStickY > 0)); @@ -2540,7 +2538,7 @@ bool GetMouseForward() bool GetMouseBack() { - return GetMouseClickRight; + return GetMouseClickRight(); } bool GetMousePos() @@ -2581,7 +2579,8 @@ bool GetMouseInput() } STARTPATCHES -#ifndef ALL_ORIGINAL_FRONTEND +#if ALL_ORIGINAL_FRONTEND +#else InjectHook(0x47A230, &CMenuManager::LoadAllTextures, PATCH_JUMP); InjectHook(0x47A440, &CMenuManager::UnloadTextures, PATCH_JUMP); InjectHook(0x485100, &CMenuManager::Process, PATCH_JUMP); @@ -2589,8 +2588,13 @@ STARTPATCHES InjectHook(0x48AE60, &CMenuManager::ProcessOnOffMenuOptions, PATCH_JUMP); InjectHook(0x488EE0, &CMenuManager::LoadSettings, PATCH_JUMP); InjectHook(0x488CC0, &CMenuManager::SaveSettings, PATCH_JUMP); + InjectHook(0x48ABE0, &CMenuManager::StretchX, PATCH_JUMP); + InjectHook(0x48AC20, &CMenuManager::StretchY, PATCH_JUMP); for (int i = 1; i < ARRAY_SIZE(aScreens); i++) Patch(0x611930 + sizeof(CMenuScreen) * i, aScreens[i]); #endif + + InjectHook(0x488EE0, &CMenuManager::LoadSettings, PATCH_JUMP); + InjectHook(0x488CC0, &CMenuManager::SaveSettings, PATCH_JUMP); ENDPATCHES
\ No newline at end of file diff --git a/src/core/Frontend.h b/src/core/Frontend.h index 9a3cdd50..b588b1af 100644 --- a/src/core/Frontend.h +++ b/src/core/Frontend.h @@ -43,8 +43,6 @@ #define MENUSLIDER_X 306.0f -#define buf(a) (char*)(a) - enum eLanguages { LANGUAGE_AMERICAN, @@ -328,7 +326,7 @@ enum eCheckHover HOVEROPTION_19, HOVEROPTION_20, HOVEROPTION_CHANGESKIN, - HOVEROPTION_NULL = 42, + HOVEROPTION_42 = 42, }; enum eMenuColumns @@ -339,28 +337,9 @@ enum eMenuColumns MENUCOLUMNS, }; -enum eMenuRow +enum { - MENUROW_NONE = -1, - MENUROW_0, - MENUROW_1, - MENUROW_2, - MENUROW_3, - MENUROW_4, - MENUROW_5, - MENUROW_6, - MENUROW_7, - MENUROW_8, - MENUROW_9, - MENUROW_10, - MENUROW_11, - MENUROW_12, - MENUROW_13, - MENUROW_14, - MENUROW_15, - MENUROW_16, - MENUROW_17, - MENUROWS, + NUM_MENUROWS = 18, }; struct tSkinInfo @@ -377,7 +356,7 @@ struct CMenuScreen char m_ScreenName[8]; int32 unk; int32 m_PreviousPage[2]; // eMenuScreen - int32 m_ParentEntry[2]; // eMenuRow + int32 m_ParentEntry[2]; // row struct CMenuEntry { @@ -385,7 +364,7 @@ struct CMenuScreen char m_EntryName[8]; int32 m_SaveSlot; // eSaveSlot int32 m_TargetMenu; // eMenuScreen - } m_aEntries[MENUROWS]; + } m_aEntries[NUM_MENUROWS]; }; class CMenuManager @@ -413,10 +392,10 @@ public: tSkinInfo *m_pSelectedSkin; tSkinInfo *field_438; float field_43C; - int field_440; + int m_nCurrExSize; int m_nSkinsTotal; char _unk0[4]; - int field_44C; + int m_nCurrExOption; bool m_bSkinsFound; bool m_bQuitGameNoCD; char field_452; @@ -439,7 +418,7 @@ public: int field_530; char field_534; char field_535; - int8 field_536; + int8 m_nCurrExLayer; int m_nHelperTextAlpha; int m_nMouseOldPosX; int m_nMouseOldPosY; @@ -452,6 +431,7 @@ public: int m_nCurrSaveSlot; int m_nScreenChangeDelayTimer; +public: static int32 &OS_Language; static int8 &m_PrefsUseVibration; static int8 &m_DisplayControllerOnFoot; @@ -462,9 +442,9 @@ public: static int8 &m_PrefsFrameLimiter; static int8 &m_PrefsShowSubtitles; static int8 &m_PrefsSpeakers; - static int8 &m_ControlMethod; + static int32 &m_ControlMethod; static int8 &m_PrefsDMA; - static int8 &m_PrefsLanguage; + static int32 &m_PrefsLanguage; static int8 &m_bDisableMouseSteering; static int32 &m_PrefsBrightness; static float &m_PrefsLOD; @@ -516,17 +496,16 @@ public: void SaveSettings(); void SetHelperText(int text); void ShutdownJustMenu(); - static float StretchX(float); - static float StretchY(float); + float StretchX(float); + float StretchY(float); void SwitchMenuOnAndOff(); void UnloadTextures(); void WaitForUserCD(); // New content: uint8 GetNumberOfMenuOptions(); - void SwitchToNewScreen(int8 screen); - void SetDefaultPreferences(int8 screen); - + void SwitchToNewScreen(int32 screen); + void SetDefaultPreferences(int32 screen); }; static_assert(sizeof(CMenuManager) == 0x564, "CMenuManager: error"); diff --git a/src/core/General.h b/src/core/General.h index 64613478..7c0c9562 100644 --- a/src/core/General.h +++ b/src/core/General.h @@ -36,6 +36,22 @@ public: } } + static float LimitAngle(float angle) + { + float result = angle; + + while (result >= 180.0f) { + result -= 2 * 180.0f; + } + + while (result < -180.0f) { + result += 2 * 180.0f; + } + + return result; + } + + static float LimitRadianAngle(float angle) { float result; diff --git a/src/core/MenuScreens.h b/src/core/MenuScreens.h index 866dfc03..b464d657 100644 --- a/src/core/MenuScreens.h +++ b/src/core/MenuScreens.h @@ -2,15 +2,15 @@ const CMenuScreen aScreens[] = { // MENUPAGE_NONE = 0 - { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, }, + { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, // MENUPAGE_STATS = 1 - { "FET_STA", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_5, MENUROW_2, + { "FET_STA", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, 5, 2, MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, }, // MENUPAGE_NEW_GAME = 2 - { "FET_SGA", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_0, MENUROW_1, + { "FET_SGA", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, 0, 1, MENUACTION_CHANGEMENU, "FES_SNG", SAVESLOT_NONE, MENUPAGE_NEW_GAME_RELOAD, MENUACTION_CHANGEMENU, "GMLOAD", SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT, MENUACTION_CHANGEMENU, "FES_DGA", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT, @@ -18,17 +18,17 @@ const CMenuScreen aScreens[] = { }, // MENUPAGE_BRIEFS = 3 - { "FET_BRE", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_6, MENUROW_3, + { "FET_BRE", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, 6, 3, MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, }, // MENU_CONTROLLER_SETTINGS = 4 - { "FET_CON", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_0, MENUROW_0, + { "FET_CON", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 0, 0, }, // MENUPAGE_SOUND_SETTINGS = 5 - { "FET_AUD", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_1, MENUROW_1, + { "FET_AUD", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 1, 1, MENUACTION_MUSICVOLUME, "FEA_MUS", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, MENUACTION_SFXVOLUME, "FEA_SFX", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, MENUACTION_AUDIOHW, "FEA_3DH", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, @@ -40,7 +40,7 @@ const CMenuScreen aScreens[] = { }, // MENUPAGE_GRAPHICS_SETTINGS = 6 - { "FET_DIS", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_2, MENUROW_2, + { "FET_DIS", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 2, 2, MENUACTION_BRIGHTNESS, "FED_BRI", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, MENUACTION_DRAWDIST, "FEM_LOD", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, MENUACTION_FRAMESYNC, "FEM_VSC", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, @@ -54,7 +54,7 @@ const CMenuScreen aScreens[] = { }, // MENUPAGE_LANGUAGE_SETTINGS = 7 - { "FET_LAN", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_3, MENUROW_3, + { "FET_LAN", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 3, 3, MENUACTION_LANG_ENG, "FEL_ENG", SAVESLOT_NONE, MENUPAGE_NONE, MENUACTION_LANG_FRE, "FEL_FRE", SAVESLOT_NONE, MENUPAGE_NONE, MENUACTION_LANG_GER, "FEL_GER", SAVESLOT_NONE, MENUPAGE_NONE, @@ -64,7 +64,7 @@ const CMenuScreen aScreens[] = { }, // MENUPAGE_CHOOSE_LOAD_SLOT = 8 - { "FET_LG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUROW_1, MENUROW_1, + { "FET_LG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, 1, 1, MENUACTION_CHANGEMENU, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NEW_GAME, MENUACTION_CHECKSAVE, "FEM_SL1", SAVESLOT_1, MENUPAGE_LOAD_SLOT_CONFIRM, MENUACTION_CHECKSAVE, "FEM_SL2", SAVESLOT_2, MENUPAGE_LOAD_SLOT_CONFIRM, @@ -77,7 +77,7 @@ const CMenuScreen aScreens[] = { }, // MENUPAGE_CHOOSE_DELETE_SLOT = 9 - { "FET_DG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUROW_2, MENUROW_2, + { "FET_DG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, 2, 2, MENUACTION_CHANGEMENU, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NEW_GAME, MENUACTION_CHECKSAVE, "FEM_SL1", SAVESLOT_1, MENUPAGE_DELETE_SLOT_CONFIRM, MENUACTION_CHECKSAVE, "FEM_SL2", SAVESLOT_2, MENUPAGE_DELETE_SLOT_CONFIRM, @@ -90,96 +90,96 @@ const CMenuScreen aScreens[] = { }, // MENUPAGE_NEW_GAME_RELOAD = 10 - { "FET_NG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUROW_0, MENUROW_0, + { "FET_NG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, 0, 0, MENUACTION_LABEL, "FESZ_QR", SAVESLOT_NONE, MENUPAGE_NONE, MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_NEW_GAME, MENUACTION_NEWGAME, "FEM_YES", SAVESLOT_NONE, MENUPAGE_NONE, }, // MENUPAGE_LOAD_SLOT_CONFIRM = 11 - { "FET_LG", MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, MENUROW_0, MENUROW_0, + { "FET_LG", MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, 0, 0, MENUACTION_LABEL, "FESZ_QL", SAVESLOT_NONE, MENUPAGE_NONE, MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT, MENUACTION_CHANGEMENU, "FEM_YES", SAVESLOT_NONE, MENUPAGE_LOADING_IN_PROGRESS, }, // MENUPAGE_DELETE_SLOT_CONFIRM = 12 - { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUROW_0, MENUROW_0, + { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, 0, 0, MENUACTION_LABEL, "FESZ_QD", SAVESLOT_NONE, MENUPAGE_NONE, MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT, MENUACTION_CHANGEMENU, "FEM_YES", SAVESLOT_NONE, MENUPAGE_DELETING, }, // MENUPAGE_13 = 13 - { "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, // MENUPAGE_LOADING_IN_PROGRESS = 14 - { "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, MENUACTION_LABEL, "FED_LDW", SAVESLOT_NONE, MENUPAGE_LOAD_SLOT_CONFIRM, }, // MENUPAGE_DELETING_IN_PROGRESS = 15 - { "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, MENUACTION_LABEL, "FEDL_WR", SAVESLOT_NONE, MENUPAGE_NONE, }, // MENUPAGE_16 = 16 - { "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, MENUACTION_LABEL, "FES_LOE", SAVESLOT_NONE, MENUPAGE_NONE, }, // MENUPAGE_DELETE_FAILED = 17 - { "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, MENUACTION_LABEL, "FES_DEE", SAVESLOT_NONE, MENUPAGE_NONE, MENUACTION_CHANGEMENU, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT, }, // MENUPAGE_DEBUG_MENU = 18 - { "FED_DBG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FED_DBG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, // MENUPAGE_MEMORY_CARD_1 = 19 - { "FEM_MCM", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FEM_MCM", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, // MENUPAGE_MEMORY_CARD_2 = 20 - { "FEM_MC2", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FEM_MC2", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, // MENUPAGE_MULTIPLAYER_MAIN = 21 - { "FET_MP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FET_MP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, // MENUPAGE_SAVE_FAILED_1 = 22 - { "MCDNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "MCDNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, MENUACTION_MEMCARDSAVECONFIRM, "JAILB_U", SAVESLOT_NONE, MENUPAGE_NONE, }, // MENUPAGE_SAVE_FAILED_2 = 23 - { "MCGNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "MCGNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, MENUACTION_MEMCARDSAVECONFIRM, "JAILB_U", SAVESLOT_NONE, MENUPAGE_NONE, }, // MENUPAGE_SAVE = 24 - { "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, MENUACTION_LABEL, "FES_SCG", SAVESLOT_NONE, MENUPAGE_NONE, MENUACTION_UPDATESAVE, "GMSAVE", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT, MENUACTION_UPDATEMEMCARDSAVE, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NONE, }, // MENUPAGE_NO_MEMORY_CARD = 25 - { "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, // MENUPAGE_CHOOSE_SAVE_SLOT = 26 - { "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, MENUACTION_UPDATEMEMCARDSAVE, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NONE, MENUACTION_UPDATESAVE, "FEM_SL1", SAVESLOT_1, MENUPAGE_SAVE_OVERWRITE_CONFIRM, MENUACTION_UPDATESAVE, "FEM_SL2", SAVESLOT_2, MENUPAGE_SAVE_OVERWRITE_CONFIRM, @@ -192,49 +192,49 @@ const CMenuScreen aScreens[] = { }, // MENUPAGE_SAVE_OVERWRITE_CONFIRM = 27 - { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0, + { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0, MENUACTION_LABEL, "FESZ_QO", SAVESLOT_NONE, MENUPAGE_NONE, MENUACTION_CHANGEMENU, "FEM_YES", SAVESLOT_NONE, MENUPAGE_SAVING_IN_PROGRESS, MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT, }, // MENUPAGE_MULTIPLAYER_MAP = 28 - { "FET_MAP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FET_MAP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, // MENUPAGE_MULTIPLAYER_CONNECTION = 29 - { "FET_CON", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FET_CON", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, // MENUPAGE_MULTIPLAYER_FIND_GAME = 30 - { "FET_FG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FET_FG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, // MENUPAGE_MULTIPLAYER_MODE = 31 - { "FET_GT", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FET_GT", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, // MENUPAGE_MULTIPLAYER_CREATE = 32 - { "FET_HG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FET_HG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, // MENUPAGE_MULTIPLAYER_START = 33 - { "FEN_STA", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FEN_STA", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, // MENUPAGE_SKIN_SELECT_OLD = 34 - { "FET_PS", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FET_PS", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, // MENUPAGE_CONTROLLER_PC = 35 - { "FET_CTL", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_0, MENUROW_0, + { "FET_CTL", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 0, 0, MENUACTION_CTRLMETHOD, "FET_CME", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC, MENUACTION_CHANGEMENU, "FET_RDK", SAVESLOT_NONE, MENUPAGE_KEYBOARD_CONTROLS, MENUACTION_CHANGEMENU, "FET_AMS", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS, @@ -243,32 +243,32 @@ const CMenuScreen aScreens[] = { }, // MENUPAGE_CONTROLLER_PC_OLD1 = 36 - { "FET_CTL", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUROW_0, MENUROW_0, + { "FET_CTL", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 0, 0, }, // MENUPAGE_CONTROLLER_PC_OLD2 = 37 - { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, // MENUPAGE_CONTROLLER_PC_OLD3 = 38 - { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, // MENUPAGE_CONTROLLER_PC_OLD4 = 39 - { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, // MENUPAGE_CONTROLLER_DEBUG = 40 - { "FEC_DBG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FEC_DBG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, // MENUPAGE_OPTIONS = 41 - { "FET_OPT", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_1, MENUROW_4, + { "FET_OPT", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, 1, 4, MENUACTION_CHANGEMENU, "FET_CTL", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC, MENUACTION_CHANGEMENU, "FET_AUD", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, MENUACTION_CHANGEMENU, "FET_DIS", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, @@ -278,65 +278,65 @@ const CMenuScreen aScreens[] = { }, // MENUPAGE_EXIT = 42 - { "FET_QG", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_2, MENUROW_5, + { "FET_QG", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, 2, 5, MENUACTION_LABEL, "FEQ_SRE", SAVESLOT_NONE, MENUPAGE_NONE, MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_NONE, MENUACTION_CANCLEGAME, "FEM_YES", SAVESLOT_NONE, MENUPAGE_NONE, }, // MENUPAGE_SAVING_IN_PROGRESS = 43 - { "", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0, + { "", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0, MENUACTION_LABEL, "FES_WAR", SAVESLOT_NONE, MENUPAGE_NONE, }, // MENUPAGE_SAVE_SUCCESSFUL = 44 - { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0, + { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0, MENUACTION_LABEL, "FES_SSC", SAVESLOT_LABEL, MENUPAGE_NONE, MENUACTION_UPDATEMEMCARDSAVE, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT, }, // MENUPAGE_DELETING = 45 - { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUROW_0, MENUROW_0, + { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, 0, 0, MENUACTION_LABEL, "FED_DLW", SAVESLOT_NONE, MENUPAGE_NONE, }, // MENUPAGE_DELETE_SUCCESS = 46 - { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUROW_0, MENUROW_0, + { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, 0, 0, MENUACTION_LABEL, "DEL_FNM", SAVESLOT_NONE, MENUPAGE_NONE, MENUACTION_CHANGEMENU, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT, }, // MENUPAGE_SAVE_FAILED = 47 - { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0, + { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0, MENUACTION_LABEL, "FEC_SVU", SAVESLOT_NONE, MENUPAGE_NONE, MENUACTION_CHANGEMENU, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT, }, // MENUPAGE_LOAD_FAILED = 48 - { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0, + { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0, MENUACTION_LABEL, "FEC_SVU", SAVESLOT_NONE, MENUPAGE_NONE, }, // MENUPAGE_LOAD_FAILED_2 = 49 - { "FET_LG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0, + { "FET_LG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0, MENUACTION_LABEL, "FEC_LUN", SAVESLOT_NONE, MENUPAGE_NONE, MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT, }, // MENUPAGE_FILTER_GAME = 50 - { "FIL_FLT", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FIL_FLT", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, // MENUPAGE_START_MENU = 51 - { "FEM_MM", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FEM_MM", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, MENUACTION_CHANGEMENU, "FEN_STA", SAVESLOT_NONE, MENUPAGE_NEW_GAME, MENUACTION_CHANGEMENU, "FET_OPT", SAVESLOT_NONE, MENUPAGE_OPTIONS, MENUACTION_CHANGEMENU, "FEM_QT", SAVESLOT_NONE, MENUPAGE_EXIT, }, // MENUPAGE_PAUSE_MENU = 52 - { "FET_PAU", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FET_PAU", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, MENUACTION_RESUME, "FEM_RES", SAVESLOT_NONE, MENUPAGE_NONE, MENUACTION_CHANGEMENU, "FEN_STA", SAVESLOT_NONE, MENUPAGE_NEW_GAME, MENUACTION_CHANGEMENU, "FEP_STA", SAVESLOT_NONE, MENUPAGE_STATS, @@ -346,22 +346,22 @@ const CMenuScreen aScreens[] = { }, // MENUPAGE_CHOOSE_MODE = 53 - { "FEN_STA", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "FEN_STA", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, // MENUPAGE_SKIN_SELECT = 54 - { "FET_PSU", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_4, MENUROW_4, + { "FET_PSU", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 4, 4, //MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_MULTIPLAYER_MAIN, }, // MENUPAGE_KEYBOARD_CONTROLS = 55 - { "FET_STI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUROW_1, MENUROW_1, + { "FET_STI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 1, 1, //MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC, }, // MENUPAGE_MOUSE_CONTROLS = 56 - { "FET_MTI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUROW_2, MENUROW_2, + { "FET_MTI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 2, 2, MENUACTION_MOUSESENS, "FEC_MSH", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS, MENUACTION_INVVERT, "FEC_IVV", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS, MENUACTION_MOUSESTEER, "FET_MST", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS, @@ -369,12 +369,12 @@ const CMenuScreen aScreens[] = { }, // MENUPAGE_57 = 57 - { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, // MENUPAGE_58 = 58 - { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, }; diff --git a/src/core/Messages.cpp b/src/core/Messages.cpp index 7fc23593..c6f3bc1b 100644 --- a/src/core/Messages.cpp +++ b/src/core/Messages.cpp @@ -9,6 +9,11 @@ WRAPPER char CMessages::WideStringCompare(wchar* str1, wchar* str2, unsigned sho WRAPPER void CMessages::InsertNumberInString(wchar* src, int n1, int n2, int n3, int n4, int n5, int n6, wchar* dst) { EAXJMP(0x52A1A0); } WRAPPER void CMessages::InsertPlayerControlKeysInString(wchar* src) { EAXJMP(0x52A490); } WRAPPER int CMessages::GetWideStringLength(wchar* src) { EAXJMP(0x529490); } +WRAPPER void CMessages::AddBigMessage(wchar* key, uint32 time, uint16 pos) { EAXJMP(0x529EB0); } +WRAPPER void CMessages::AddMessage(wchar* key, uint32 time, uint16 pos) { EAXJMP(0x529900); } +WRAPPER void CMessages::AddMessageJumpQ(wchar* key, uint32 time, uint16 pos) { EAXJMP(0x529A10); } +WRAPPER void CMessages::AddMessageSoon(wchar* key, uint32 time, uint16 pos) { EAXJMP(0x529AF0); } +WRAPPER void CMessages::ClearMessages() { EAXJMP(0x529CE0); } tPreviousBrief *CMessages::PreviousBriefs = (tPreviousBrief *)0x713C08; tMessage *CMessages::BriefMessages = (tMessage *)0x8786E0; diff --git a/src/core/Messages.h b/src/core/Messages.h index 69cf117c..51c36212 100644 --- a/src/core/Messages.h +++ b/src/core/Messages.h @@ -41,4 +41,9 @@ public: static void InsertNumberInString(wchar* src, int n1, int n2, int n3, int n4, int n5, int n6, wchar* dst); static void InsertPlayerControlKeysInString(wchar* src); static int GetWideStringLength(wchar *src); + static void AddBigMessage(wchar* key, uint32 time, uint16 pos); + static void AddMessage(wchar* key, uint32 time, uint16 pos); + static void AddMessageJumpQ(wchar* key, uint32 time, uint16 pos); + static void AddMessageSoon(wchar* key, uint32 time, uint16 pos); + static void ClearMessages(); }; diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp index 9c5e1c8a..736e1e9d 100644 --- a/src/core/Pad.cpp +++ b/src/core/Pad.cpp @@ -155,7 +155,7 @@ void CPad::Clear(bool bResetPlayerControls) ShakeDur = 0; if ( bResetPlayerControls ) - DisablePlayerControls = false; + DisablePlayerControls = PLAYERCONTROL_ENABLED; bApplyBrakes = false; @@ -659,7 +659,7 @@ CPad *CPad::GetPad(int32 pad) int16 CPad::GetSteeringLeftRight(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return 0; switch ( Mode ) @@ -692,7 +692,7 @@ int16 CPad::GetSteeringLeftRight(void) int16 CPad::GetSteeringUpDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return 0; switch ( Mode ) @@ -725,7 +725,7 @@ int16 CPad::GetSteeringUpDown(void) int16 CPad::GetCarGunUpDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return 0; switch ( Mode ) @@ -752,7 +752,7 @@ int16 CPad::GetCarGunUpDown(void) int16 CPad::GetCarGunLeftRight(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return 0; switch ( Mode ) @@ -779,7 +779,7 @@ int16 CPad::GetCarGunLeftRight(void) int16 CPad::GetPedWalkLeftRight(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return 0; switch ( Mode ) @@ -813,7 +813,7 @@ int16 CPad::GetPedWalkLeftRight(void) int16 CPad::GetPedWalkUpDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return 0; switch ( Mode ) @@ -876,7 +876,7 @@ int16 CPad::GetAnalogueUpDown(void) bool CPad::GetLookLeft(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; return !!(NewState.LeftShoulder2 && !NewState.RightShoulder2); @@ -884,7 +884,7 @@ bool CPad::GetLookLeft(void) bool CPad::GetLookRight(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; return !!(NewState.RightShoulder2 && !NewState.LeftShoulder2); @@ -893,7 +893,7 @@ bool CPad::GetLookRight(void) bool CPad::GetLookBehindForCar(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; return !!(NewState.RightShoulder2 && NewState.LeftShoulder2); @@ -901,7 +901,7 @@ bool CPad::GetLookBehindForCar(void) bool CPad::GetLookBehindForPed(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; return !!NewState.RightShock; @@ -909,7 +909,7 @@ bool CPad::GetLookBehindForPed(void) bool CPad::GetHorn(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -948,7 +948,7 @@ bool CPad::GetHorn(void) bool CPad::HornJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -988,7 +988,7 @@ bool CPad::HornJustDown(void) bool CPad::GetCarGunFired(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1015,7 +1015,7 @@ bool CPad::GetCarGunFired(void) bool CPad::CarGunJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1042,7 +1042,7 @@ bool CPad::CarGunJustDown(void) int16 CPad::GetHandBrake(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return 0; switch ( Mode ) @@ -1075,7 +1075,7 @@ int16 CPad::GetHandBrake(void) int16 CPad::GetBrake(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return 0; switch ( Mode ) @@ -1113,7 +1113,7 @@ int16 CPad::GetBrake(void) bool CPad::GetExitVehicle(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1140,7 +1140,7 @@ bool CPad::GetExitVehicle(void) bool CPad::ExitVehicleJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1167,7 +1167,7 @@ bool CPad::ExitVehicleJustDown(void) int32 CPad::GetWeapon(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1200,7 +1200,7 @@ int32 CPad::GetWeapon(void) bool CPad::WeaponJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1233,7 +1233,7 @@ bool CPad::WeaponJustDown(void) int16 CPad::GetAccelerate(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return 0; switch ( Mode ) @@ -1319,7 +1319,7 @@ bool CPad::CycleCameraModeDownJustDown(void) bool CPad::ChangeStationJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1359,7 +1359,7 @@ bool CPad::ChangeStationJustDown(void) bool CPad::CycleWeaponLeftJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; return !!(NewState.LeftShoulder2 && !OldState.LeftShoulder2); @@ -1367,7 +1367,7 @@ bool CPad::CycleWeaponLeftJustDown(void) bool CPad::CycleWeaponRightJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; return !!(NewState.RightShoulder2 && !OldState.RightShoulder2); @@ -1375,7 +1375,7 @@ bool CPad::CycleWeaponRightJustDown(void) bool CPad::GetTarget(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1402,7 +1402,7 @@ bool CPad::GetTarget(void) bool CPad::TargetJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1429,7 +1429,7 @@ bool CPad::TargetJustDown(void) bool CPad::JumpJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; return !!(NewState.Square && !OldState.Square); @@ -1437,7 +1437,7 @@ bool CPad::JumpJustDown(void) bool CPad::GetSprint(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1464,7 +1464,7 @@ bool CPad::GetSprint(void) bool CPad::ShiftTargetLeftJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; return !!(NewState.LeftShoulder2 && !OldState.LeftShoulder2); @@ -1472,7 +1472,7 @@ bool CPad::ShiftTargetLeftJustDown(void) bool CPad::ShiftTargetRightJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; return !!(NewState.RightShoulder2 && !OldState.RightShoulder2); @@ -1592,7 +1592,7 @@ bool CPad::GetAnaloguePadRightJustUp(void) bool CPad::ForceCameraBehindPlayer(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1625,7 +1625,7 @@ bool CPad::ForceCameraBehindPlayer(void) bool CPad::SniperZoomIn(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1652,7 +1652,7 @@ bool CPad::SniperZoomIn(void) bool CPad::SniperZoomOut(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1824,7 +1824,7 @@ char *CPad::EditString(char *pStr, int32 nSize) } // numbers - for ( int32 i = 0; i < ('0' - '9' + 1); i++ ) + for ( int32 i = 0; i < ('9' - '0' + 1); i++ ) { if ( GetPad(0)->GetCharJustDown(i + '0') && pos < nSize - 1 ) { diff --git a/src/core/Pad.h b/src/core/Pad.h index 62585377..4f129e85 100644 --- a/src/core/Pad.h +++ b/src/core/Pad.h @@ -51,6 +51,17 @@ enum Key }; */ +enum { + PLAYERCONTROL_ENABLED = 0, + PLAYERCONTROL_DISABLED_1 = 1, + PLAYERCONTROL_DISABLED_2 = 2, + PLAYERCONTROL_DISABLED_4 = 4, + PLAYERCONTROL_DISABLED_8 = 8, + PLAYERCONTROL_DISABLED_10 = 16, + PLAYERCONTROL_DISABLED_20 = 32, + PLAYERCONTROL_DISABLED_40 = 64, // used on phone calls + PLAYERCONTROL_DISABLED_80 = 128, +}; class CControllerState { @@ -186,9 +197,9 @@ public: int16 Mode; int16 ShakeDur; uint8 ShakeFreq; - int8 bHornHistory[5]; + bool bHornHistory[5]; uint8 iCurrHornHistory; - bool DisablePlayerControls; + uint8 DisablePlayerControls; int8 bApplyBrakes; char _unk[12]; //int32 unk[3]; char _pad0[3]; @@ -289,6 +300,10 @@ public: // mouse bool GetLeftMouseJustDown() { return !!(NewMouseControllerState.LMB && !OldMouseControllerState.LMB); } + bool GetRightMouseJustDown() { return !!(NewMouseControllerState.RMB && !OldMouseControllerState.RMB); } + bool GetMiddleMouseJustDown() { return !!(NewMouseControllerState.MMB && !OldMouseControllerState.MMB); } + float GetMouseX() { return NewMouseControllerState.x; } + float GetMouseY() { return NewMouseControllerState.y; } // keyboard @@ -354,6 +369,13 @@ public: bool GetRightShoulder1JustDown() { return !!(NewState.RightShoulder1 && !OldState.RightShoulder1); } bool GetRightShoulder2JustDown() { return !!(NewState.RightShoulder2 && !OldState.RightShoulder2); } +/* + int32 GetLeftShoulder1(void) { return NewState.LeftShoulder1; } + int32 GetLeftShoulder2(void) { return NewState.LeftShoulder2; } + int32 GetRightShoulder1(void) { return NewState.RightShoulder1; } + int32 GetRightShoulder2(void) { return NewState.RightShoulder2; } +*/ + bool GetTriangle() { return !!NewState.Triangle; } bool GetCircle() { return !!NewState.Circle; } bool GetCross() { return !!NewState.Cross; } @@ -366,10 +388,11 @@ public: bool GetLeftShoulder2(void) { return !!NewState.LeftShoulder2; } bool GetRightShoulder1(void) { return !!NewState.RightShoulder1; } bool GetRightShoulder2(void) { return !!NewState.RightShoulder2; } + + bool ArePlayerControlsDisabled(void) { return DisablePlayerControls != PLAYERCONTROL_ENABLED; } }; VALIDATE_SIZE(CPad, 0xFC); +extern CPad *Pads; //[2] #define IsButtonJustDown(pad, btn) \ (!(pad)->OldState.btn && (pad)->NewState.btn) - -void LittleTest(void); diff --git a/src/core/Pools.cpp b/src/core/Pools.cpp index f7f93292..404cd558 100644 --- a/src/core/Pools.cpp +++ b/src/core/Pools.cpp @@ -9,11 +9,13 @@ CBuildingPool *&CPools::ms_pBuildingPool = *(CBuildingPool**)0x8F2C04; CTreadablePool *&CPools::ms_pTreadablePool = *(CTreadablePool**)0x8F2568; CObjectPool *&CPools::ms_pObjectPool = *(CObjectPool**)0x880E28; CDummyPool *&CPools::ms_pDummyPool = *(CDummyPool**)0x8F2C18; +CAudioScriptObjectPool *&CPools::ms_pAudioScriptObjectPool = *(CAudioScriptObjectPool**)0x8F1B6C; void CPools::Initialise(void) { // TODO: unused right now + assert(0); ms_pPtrNodePool = new CCPtrNodePool(NUMPTRNODES); ms_pEntryInfoNodePool = new CEntryInfoNodePool(NUMENTRYINFOS); ms_pPedPool = new CPedPool(NUMPEDS); @@ -22,4 +24,12 @@ CPools::Initialise(void) ms_pTreadablePool = new CTreadablePool(NUMTREADABLES); ms_pObjectPool = new CObjectPool(NUMOBJECTS); ms_pDummyPool = new CDummyPool(NUMDUMMIES); + ms_pAudioScriptObjectPool = new CAudioScriptObjectPool(NUMAUDIOSCRIPTOBJECTS); } + +int32 CPools::GetPedRef(CPed *ped) { return ms_pPedPool->GetIndex(ped); } +CPed *CPools::GetPed(int32 handle) { return ms_pPedPool->GetAt(handle); } +int32 CPools::GetVehicleRef(CVehicle *vehicle) { return ms_pVehiclePool->GetIndex(vehicle); } +CVehicle *CPools::GetVehicle(int32 handle) { return ms_pVehiclePool->GetAt(handle); } +int32 CPools::GetObjectRef(CObject *object) { return ms_pObjectPool->GetIndex(object); } +CObject *CPools::GetObject(int32 handle) { return ms_pObjectPool->GetAt(handle); } diff --git a/src/core/Pools.h b/src/core/Pools.h index 3496064c..bdf668c2 100644 --- a/src/core/Pools.h +++ b/src/core/Pools.h @@ -8,6 +8,7 @@ #include "PlayerPed.h" #include "Automobile.h" #include "DummyPed.h" +#include "AudioManager.h" typedef CPool<CPtrNode> CCPtrNodePool; typedef CPool<CEntryInfoNode> CEntryInfoNodePool; @@ -17,6 +18,7 @@ typedef CPool<CBuilding> CBuildingPool; typedef CPool<CTreadable> CTreadablePool; typedef CPool<CObject, CCutsceneHead> CObjectPool; typedef CPool<CDummy, CDummyPed> CDummyPool; +typedef CPool<cAudioScriptObject, cAudioScriptObject> CAudioScriptObjectPool; class CPools { @@ -28,7 +30,7 @@ class CPools static CTreadablePool *&ms_pTreadablePool; static CObjectPool *&ms_pObjectPool; static CDummyPool *&ms_pDummyPool; - // ms_pAudioScriptObjectPool + static CAudioScriptObjectPool *&ms_pAudioScriptObjectPool; public: static CCPtrNodePool *GetPtrNodePool(void) { return ms_pPtrNodePool; } static CEntryInfoNodePool *GetEntryInfoNodePool(void) { return ms_pEntryInfoNodePool; } @@ -38,6 +40,13 @@ public: static CTreadablePool *GetTreadablePool(void) { return ms_pTreadablePool; } static CObjectPool *GetObjectPool(void) { return ms_pObjectPool; } static CDummyPool *GetDummyPool(void) { return ms_pDummyPool; } + static CAudioScriptObjectPool *GetAudioScriptObjectPool(void) { return ms_pAudioScriptObjectPool; } static void Initialise(void); + static int32 GetPedRef(CPed *ped); + static CPed *GetPed(int32 handle); + static int32 GetVehicleRef(CVehicle *vehicle); + static CVehicle *GetVehicle(int32 handle); + static int32 GetObjectRef(CObject *object); + static CObject *GetObject(int32 handle); }; diff --git a/src/core/Stats.cpp b/src/core/Stats.cpp index 921586bb..01bbf82e 100644 --- a/src/core/Stats.cpp +++ b/src/core/Stats.cpp @@ -4,6 +4,7 @@ int32 &CStats::DaysPassed = *(int32*)0x8F2BB8; int32 &CStats::HeadShots = *(int32*)0x8F647C; bool& CStats::CommercialPassed = *(bool*)0x8F4334; +bool& CStats::IndustrialPassed = *(bool*)0x8E2A68; int32 &CStats::NumberKillFrenziesPassed = *(int32*)0x8E287C; int32 &CStats::PeopleKilledByOthers = *(int32*)0x8E2C50; diff --git a/src/core/Stats.h b/src/core/Stats.h index 30058a59..c536465f 100644 --- a/src/core/Stats.h +++ b/src/core/Stats.h @@ -6,6 +6,7 @@ public: static int32 &DaysPassed; static int32 &HeadShots; static bool& CommercialPassed; + static bool& IndustrialPassed; static int32 &NumberKillFrenziesPassed; static int32 &PeopleKilledByOthers; diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp index a23e35be..9d9241e4 100644 --- a/src/core/Streaming.cpp +++ b/src/core/Streaming.cpp @@ -1048,8 +1048,6 @@ CStreaming::RemoveReferencedTxds(int32 mem) return false; } -// TODO: RemoveCurrentZonesModels - void CStreaming::RemoveUnusedModelsInLoadedList(void) { diff --git a/src/core/SurfaceTable.h b/src/core/SurfaceTable.h index e1882e69..27f4ecca 100644 --- a/src/core/SurfaceTable.h +++ b/src/core/SurfaceTable.h @@ -77,6 +77,8 @@ enum eSurfaceType SURFACE_LOOSE30, SURFACE_BOLLARD, SURFACE_GATE, + + // These are illegal SURFACE_SAND33, SURFACE_ROAD34, }; diff --git a/src/core/Wanted.cpp b/src/core/Wanted.cpp index 4608bfef..7b865311 100644 --- a/src/core/Wanted.cpp +++ b/src/core/Wanted.cpp @@ -1,65 +1,102 @@ #include "common.h" #include "patcher.h" +#include "Pools.h" +#include "ModelIndices.h" +#include "Timer.h" +#include "World.h" +#include "ZoneCull.h" +#include "Darkel.h" +#include "DMAudio.h" #include "Wanted.h" -int32 &CWanted::MaximumWantedLevel = *(int32*)0x5F7714; +int32 &CWanted::MaximumWantedLevel = *(int32*)0x5F7714; // 6 +int32 &CWanted::nMaximumWantedLevel = *(int32*)0x5F7718; // 6400 -bool CWanted::AreSwatRequired() +void +CWanted::Initialise() +{ + int i; + + m_nChaos = 0; + m_nLastUpdateTime = 0; + m_nLastWantedLevelChange = 0; + m_CurrentCops = 0; + m_MaxCops = 0; + m_MaximumLawEnforcerVehicles = 0; + m_RoadblockDensity = 0; + m_bIgnoredByCops = false; + m_bIgnoredByEveryone = false; + m_bSwatRequired = false; + m_bFbiRequired = false; + m_bArmyRequired = false; + m_fCrimeSensitivity = 1.0f; + m_nWantedLevel = 0; + m_CopsBeatingSuspect = 0; + for(i = 0; i < 10; i++) + m_pCops[i] = nil; + ClearQdCrimes(); +} + +bool +CWanted::AreSwatRequired() { return m_nWantedLevel >= 4; } -bool CWanted::AreFbiRequired() +bool +CWanted::AreFbiRequired() { return m_nWantedLevel >= 5; } -bool CWanted::AreArmyRequired() +bool +CWanted::AreArmyRequired() { return m_nWantedLevel >= 6; } -int CWanted::NumOfHelisRequired() +int32 +CWanted::NumOfHelisRequired() { - if (m_IsIgnoredByCops) + if (m_bIgnoredByCops) return 0; - // Return value is number of helicopters, no need to name them. switch (m_nWantedLevel) { - case WANTEDLEVEL_3: - case WANTEDLEVEL_4: + case 3: + case 4: return 1; - case WANTEDLEVEL_5: - case WANTEDLEVEL_6: + case 5: + case 6: return 2; default: return 0; } } -void CWanted::SetWantedLevel(int32 level) +void +CWanted::SetWantedLevel(int32 level) { ClearQdCrimes(); switch (level) { - case NOTWANTED: + case 0: m_nChaos = 0; break; - case WANTEDLEVEL_1: + case 1: m_nChaos = 60; break; - case WANTEDLEVEL_2: + case 2: m_nChaos = 220; break; - case WANTEDLEVEL_3: + case 3: m_nChaos = 420; break; - case WANTEDLEVEL_4: + case 4: m_nChaos = 820; break; - case WANTEDLEVEL_5: + case 5: m_nChaos = 1620; break; - case WANTEDLEVEL_6: + case 6: m_nChaos = 3220; break; default: @@ -70,61 +107,212 @@ void CWanted::SetWantedLevel(int32 level) UpdateWantedLevel(); } -void CWanted::SetWantedLevelNoDrop(int32 level) +void +CWanted::SetWantedLevelNoDrop(int32 level) { if (level > m_nWantedLevel) SetWantedLevel(level); } -void CWanted::ClearQdCrimes() +void +CWanted::SetMaximumWantedLevel(int32 level) { - for (int i = 0; i < 16; i++) { - m_sCrimes[i].m_eCrimeType = CRIME_NONE; + switch(level){ + case 0: + nMaximumWantedLevel = 0; + MaximumWantedLevel = 0; + break; + case 1: + nMaximumWantedLevel = 120; + MaximumWantedLevel = 1; + break; + case 2: + nMaximumWantedLevel = 300; + MaximumWantedLevel = 2; + break; + case 3: + nMaximumWantedLevel = 600; + MaximumWantedLevel = 3; + break; + case 4: + nMaximumWantedLevel = 1200; + MaximumWantedLevel = 4; + break; + case 5: + nMaximumWantedLevel = 2400; + MaximumWantedLevel = 5; + break; + case 6: + nMaximumWantedLevel = 4800; + MaximumWantedLevel = 6; + break; } } -void CWanted::UpdateWantedLevel() +void +CWanted::RegisterCrime(eCrimeType type, const CVector &coors, uint32 id, bool policeDoesntCare) +{ + AddCrimeToQ(type, id, coors, false, policeDoesntCare); +} + +void +CWanted::RegisterCrime_Immediately(eCrimeType type, const CVector &coors, uint32 id, bool policeDoesntCare) +{ + if(!AddCrimeToQ(type, id, coors, false, policeDoesntCare)) + ReportCrimeNow(type, coors, policeDoesntCare); +} + +void +CWanted::ClearQdCrimes() +{ + for (int i = 0; i < 16; i++) + m_aCrimes[i].m_nType = CRIME_NONE; +} + +// returns whether the crime had been reported already +bool +CWanted::AddCrimeToQ(eCrimeType type, int32 id, const CVector &coors, bool reported, bool policeDoesntCare) +{ + int i; + + for(i = 0; i < 16; i++) + if(m_aCrimes[i].m_nType == type && m_aCrimes[i].m_nId == id){ + if(m_aCrimes[i].m_bReported) + return true; + if(reported) + m_aCrimes[i].m_bReported = reported; + return false; + } + + for(i = 0; i < 16; i++) + if(m_aCrimes[i].m_nType == CRIME_NONE) + break; + if(i < 16){ + m_aCrimes[i].m_nType = type; + m_aCrimes[i].m_nId = id; + m_aCrimes[i].m_vecPosn = coors; + m_aCrimes[i].m_nTime = CTimer::GetTimeInMilliseconds(); + m_aCrimes[i].m_bReported = reported; + m_aCrimes[i].m_bPoliceDoesntCare = policeDoesntCare; + } + return false; +} + +void +CWanted::ReportCrimeNow(eCrimeType type, const CVector &coors, bool policeDoesntCare) +{ + float sensitivity, chaos; + int wantedLevelDrop; + + if(CDarkel::FrenzyOnGoing()) + sensitivity = m_fCrimeSensitivity*0.3f; + else + sensitivity = m_fCrimeSensitivity; + + wantedLevelDrop = min(CCullZones::GetWantedLevelDrop(), 100); + + chaos = (1.0f - wantedLevelDrop/100.0f) * sensitivity; + if (policeDoesntCare) + chaos *= 0.333f; + switch(type){ + case CRIME_POSSESSION_GUN: + break; + case CRIME_HIT_PED: + m_nChaos += 5.0f*chaos; + break; + case CRIME_HIT_COP: + m_nChaos += 45.0f*chaos; + break; + case CRIME_SHOOT_PED: + m_nChaos += 30.0f*chaos; + break; + case CRIME_SHOOT_COP: + m_nChaos += 80.0f*chaos; + break; + case CRIME_STEAL_CAR: + m_nChaos += 15.0f*chaos; + break; + case CRIME_RUN_REDLIGHT: + m_nChaos += 10.0f*chaos; + break; + case CRIME_RECKLESS_DRIVING: + m_nChaos += 5.0f*chaos; + break; + case CRIME_SPEEDING: + m_nChaos += 5.0f*chaos; + break; + case CRIME_RUNOVER_PED: + m_nChaos += 18.0f*chaos; + break; + case CRIME_RUNOVER_COP: + m_nChaos += 80.0f*chaos; + break; + case CRIME_SHOOT_HELI: + m_nChaos += 400.0f*chaos; + break; + case CRIME_PED_BURNED: + m_nChaos += 20.0f*chaos; + break; + case CRIME_COP_BURNED: + m_nChaos += 80.0f*chaos; + break; + case CRIME_VEHICLE_BURNED: + m_nChaos += 20.0f*chaos; + break; + case CRIME_DESTROYED_CESSNA: + m_nChaos += 500.0f*chaos; + break; + default: + // Error("Undefined crime type, RegisterCrime, Crime.cpp"); // different file for some reason + Error("Undefined crime type, RegisterCrime, Wanted.cpp"); + } + DMAudio.ReportCrime(type, coors); + UpdateWantedLevel(); +} + +void +CWanted::UpdateWantedLevel() { int32 CurrWantedLevel = m_nWantedLevel; if (m_nChaos >= 0 && m_nChaos < 40) { - m_nWantedLevel = NOTWANTED; + m_nWantedLevel = 0; m_MaximumLawEnforcerVehicles = 0; m_MaxCops = 0; m_RoadblockDensity = 0; } else if (m_nChaos >= 40 && m_nChaos < 200) { - m_nWantedLevel = WANTEDLEVEL_1; + m_nWantedLevel = 1; m_MaximumLawEnforcerVehicles = 1; m_MaxCops = 1; m_RoadblockDensity = 0; } else if (m_nChaos >= 200 && m_nChaos < 400) { - m_nWantedLevel = WANTEDLEVEL_2; + m_nWantedLevel = 2; m_MaximumLawEnforcerVehicles = 2; m_MaxCops = 3; m_RoadblockDensity = 0; } else if (m_nChaos >= 400 && m_nChaos < 800) { - m_nWantedLevel = WANTEDLEVEL_3; + m_nWantedLevel = 3; m_MaximumLawEnforcerVehicles = 2; m_MaxCops = 4; m_RoadblockDensity = 4; } else if (m_nChaos >= 800 && m_nChaos < 1600) { - m_nWantedLevel = WANTEDLEVEL_4; + m_nWantedLevel = 4; m_MaximumLawEnforcerVehicles = 2; m_MaxCops = 6; m_RoadblockDensity = 8; } else if (m_nChaos >= 1600 && m_nChaos < 3200) { - m_nWantedLevel = WANTEDLEVEL_5; + m_nWantedLevel = 5; m_MaximumLawEnforcerVehicles = 3; m_MaxCops = 8; m_RoadblockDensity = 10; } else if (m_nChaos >= 3200) { - m_nWantedLevel = WANTEDLEVEL_6; + m_nWantedLevel = 6; m_MaximumLawEnforcerVehicles = 3; m_MaxCops = 10; m_RoadblockDensity = 12; @@ -132,4 +320,58 @@ void CWanted::UpdateWantedLevel() if (CurrWantedLevel != m_nWantedLevel) m_nLastWantedLevelChange = CTimer::GetTimeInMilliseconds(); -}
\ No newline at end of file +} + +int32 +CWanted::WorkOutPolicePresence(CVector posn, float radius) +{ + int i; + CPed *ped; + CVehicle *vehicle; + int numPolice = 0; + + i = CPools::GetPedPool()->GetSize(); + while(--i >= 0){ + ped = CPools::GetPedPool()->GetSlot(i); + if(ped && + IsPolicePedModel(ped->GetModelIndex()) && + (posn - ped->GetPosition()).Magnitude() < radius) + numPolice++; + } + + i = CPools::GetVehiclePool()->GetSize(); + while(--i >= 0){ + vehicle = CPools::GetVehiclePool()->GetSlot(i); + if(vehicle && + vehicle->bIsLawEnforcer && + IsPoliceVehicleModel(vehicle->GetModelIndex()) && + vehicle != FindPlayerVehicle() && + vehicle->m_status != STATUS_ABANDONED && vehicle->m_status != STATUS_WRECKED && + (posn - vehicle->GetPosition()).Magnitude() < radius) + numPolice++; + } + + return numPolice; +} + +STARTPATCHES + InjectHook(0x4AD6E0, &CWanted::Initialise, PATCH_JUMP); +// InjectHook(0x4AD790, &CWanted::Reset, PATCH_JUMP); +// InjectHook(0x4AD7B0, &CWanted::Update, PATCH_JUMP); + InjectHook(0x4AD900, &CWanted::UpdateWantedLevel, PATCH_JUMP); + InjectHook(0x4AD9F0, &CWanted::RegisterCrime, PATCH_JUMP); + InjectHook(0x4ADA10, &CWanted::RegisterCrime_Immediately, PATCH_JUMP); + InjectHook(0x4ADA50, &CWanted::SetWantedLevel, PATCH_JUMP); + InjectHook(0x4ADAC0, &CWanted::SetWantedLevelNoDrop, PATCH_JUMP); + InjectHook(0x4ADAE0, &CWanted::SetMaximumWantedLevel, PATCH_JUMP); + InjectHook(0x4ADBA0, &CWanted::AreSwatRequired, PATCH_JUMP); + InjectHook(0x4ADBC0, &CWanted::AreFbiRequired, PATCH_JUMP); + InjectHook(0x4ADBE0, &CWanted::AreArmyRequired, PATCH_JUMP); + InjectHook(0x4ADC00, &CWanted::NumOfHelisRequired, PATCH_JUMP); +// InjectHook(0x4ADC40, &CWanted::ResetPolicePursuit, PATCH_JUMP); + InjectHook(0x4ADD00, &CWanted::WorkOutPolicePresence, PATCH_JUMP); + InjectHook(0x4ADF20, &CWanted::ClearQdCrimes, PATCH_JUMP); + InjectHook(0x4ADFD0, &CWanted::AddCrimeToQ, PATCH_JUMP); +// InjectHook(0x4AE090, &CWanted::UpdateCrimesQ, PATCH_JUMP); + InjectHook(0x4AE110, &CWanted::ReportCrimeNow, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/Wanted.h b/src/core/Wanted.h index d3f6638b..1a72f839 100644 --- a/src/core/Wanted.h +++ b/src/core/Wanted.h @@ -1,16 +1,38 @@ #pragma once -#include "Entity.h" -#include "math/Vector.h" -#include "CopPed.h" - -enum eWantedLevel { - NOTWANTED, - WANTEDLEVEL_1, - WANTEDLEVEL_2, - WANTEDLEVEL_3, - WANTEDLEVEL_4, - WANTEDLEVEL_5, - WANTEDLEVEL_6, + +class CEntity; +class CCopPed; + +enum eCrimeType +{ + CRIME_NONE, + CRIME_POSSESSION_GUN, + CRIME_HIT_PED, + CRIME_HIT_COP, + CRIME_SHOOT_PED, + CRIME_SHOOT_COP, + CRIME_STEAL_CAR, + CRIME_RUN_REDLIGHT, + CRIME_RECKLESS_DRIVING, + CRIME_SPEEDING, + CRIME_RUNOVER_PED, + CRIME_RUNOVER_COP, + CRIME_SHOOT_HELI, + CRIME_PED_BURNED, + CRIME_COP_BURNED, + CRIME_VEHICLE_BURNED, + CRIME_DESTROYED_CESSNA, +}; + +class CCrimeBeingQd +{ +public: + eCrimeType m_nType; + uint32 m_nId; + int32 m_nTime; + CVector m_vecPosn; + bool m_bReported; + bool m_bPoliceDoesntCare; }; class CWanted @@ -23,28 +45,37 @@ public: uint8 m_CurrentCops; uint8 m_MaxCops; uint8 m_MaximumLawEnforcerVehicles; - int8 field_19; + uint8 m_CopsBeatingSuspect; int16 m_RoadblockDensity; - uint8 m_IsIgnoredByCops : 1; - uint8 m_IsIgnoredByEveryOne : 1; - uint8 m_IsSwatRequired : 1; - uint8 m_IsFbiRequired : 1; - uint8 m_IdArmyRequired : 1; - int8 field_23; + uint8 m_bIgnoredByCops : 1; + uint8 m_bIgnoredByEveryone : 1; + uint8 m_bSwatRequired : 1; + uint8 m_bFbiRequired : 1; + uint8 m_bArmyRequired : 1; int32 m_nWantedLevel; - CCrime m_sCrimes[16]; + CCrimeBeingQd m_aCrimes[16]; CCopPed *m_pCops[10]; + static int32 &MaximumWantedLevel; + static int32 &nMaximumWantedLevel; public: + void Initialise(); bool AreSwatRequired(); bool AreFbiRequired(); bool AreArmyRequired(); - int NumOfHelisRequired(); + int32 NumOfHelisRequired(); void SetWantedLevel(int32); void SetWantedLevelNoDrop(int32 level); + void RegisterCrime(eCrimeType type, const CVector &coors, uint32 id, bool policeDoesntCare); + void RegisterCrime_Immediately(eCrimeType type, const CVector &coors, uint32 id, bool policeDoesntCare); void ClearQdCrimes(); + bool AddCrimeToQ(eCrimeType type, int32 id, const CVector &pos, bool reported, bool policeDoesntCare); + void ReportCrimeNow(eCrimeType type, const CVector &coors, bool policeDoesntCare); void UpdateWantedLevel(); + + static int32 WorkOutPolicePresence(CVector posn, float radius); + static void SetMaximumWantedLevel(int32 level); }; static_assert(sizeof(CWanted) == 0x204, "CWanted: error"); diff --git a/src/core/World.cpp b/src/core/World.cpp index a31f87a7..829a64d4 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -11,11 +11,13 @@ #include "Garages.h" #include "TempColModels.h" #include "World.h" +#include "ModelIndices.h" CPtrList *CWorld::ms_bigBuildingsList = (CPtrList*)0x6FAB60; CPtrList &CWorld::ms_listMovingEntityPtrs = *(CPtrList*)0x8F433C; CSector (*CWorld::ms_aSectors)[NUMSECTORS_X] = (CSector (*)[NUMSECTORS_Y])0x665608; uint16 &CWorld::ms_nCurrentScanCode = *(uint16*)0x95CC64; +CColPoint &CWorld::ms_testSpherePoint = *(CColPoint*)0x6E64C0; uint8 &CWorld::PlayerInFocus = *(uint8 *)0x95CD61; CPlayerInfo *CWorld::Players = (CPlayerInfo *)0x9412F0; @@ -26,6 +28,8 @@ bool &CWorld::bSecondShift = *(bool*)0x95CD54; bool &CWorld::bForceProcessControl = *(bool*)0x95CD6C; bool &CWorld::bProcessCutsceneOnly = *(bool*)0x95CD8B; +WRAPPER void CWorld::RemoveReferencesToDeletedObject(CEntity*) { EAXJMP(0x4B3BF0); } + void CWorld::Add(CEntity *ent) { @@ -603,12 +607,12 @@ CWorld::FindObjectsInRange(CVector ¢re, float distance, bool ignoreZ, short minY = 0; int maxX = GetSectorIndexX(centre.x + distance); - if (maxX >= 100) - maxX = 100; + if (maxX >= NUMSECTORS_X) + maxX = NUMSECTORS_X; int maxY = GetSectorIndexY(centre.y + distance); - if (maxY >= 100) - maxY = 100; + if (maxY >= NUMSECTORS_Y) + maxY = NUMSECTORS_Y; AdvanceCurrentScanCode(); @@ -617,27 +621,156 @@ CWorld::FindObjectsInRange(CVector ¢re, float distance, bool ignoreZ, short for(int curX = minX; curX <= maxX; curX++) { CSector *sector = GetSector(curX, curY); if (checkBuildings) { - CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, distance, ignoreZ, nextObject, lastObject, objects); - CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, distance, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); + } + if (checkVehicles) { + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, distance, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); + } + if (checkPeds) { + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, distance, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); + } + if (checkObjects) { + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, distance, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); + } + if (checkDummies) { + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, distance, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); + } + } + } +} + +CEntity* +CWorld::TestSphereAgainstWorld(CVector centre, float distance, CEntity* entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects) +{ + CEntity* foundE = nil; + + int minX = GetSectorIndexX(centre.x - distance); + if (minX <= 0) + minX = 0; + + int minY = GetSectorIndexY(centre.y - distance); + if (minY <= 0) + minY = 0; + + int maxX = GetSectorIndexX(centre.x + distance); + if (maxX >= NUMSECTORS_X) + maxX = NUMSECTORS_X; + + int maxY = GetSectorIndexY(centre.y + distance); + if (maxY >= NUMSECTORS_Y) + maxY = NUMSECTORS_Y; + + AdvanceCurrentScanCode(); + + for (int curY = minY; curY <= maxY; curY++) { + for (int curX = minX; curX <= maxX; curX++) { + CSector* sector = GetSector(curX, curY); + if (checkBuildings) { + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, distance, entityToIgnore, false); + if (foundE) + return foundE; + + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, distance, entityToIgnore, false); + if (foundE) + return foundE; } if (checkVehicles) { - CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, distance, ignoreZ, nextObject, lastObject, objects); - CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, distance, entityToIgnore, false); + if (foundE) + return foundE; + + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, distance, entityToIgnore, false); + if (foundE) + return foundE; } if (checkPeds) { - CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, distance, ignoreZ, nextObject, lastObject, objects); - CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, distance, entityToIgnore, false); + if (foundE) + return foundE; + + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, distance, entityToIgnore, false); + if (foundE) + return foundE; } if (checkObjects) { - CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, distance, ignoreZ, nextObject, lastObject, objects); - CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, distance, entityToIgnore, ignoreSomeObjects); + if (foundE) + return foundE; + + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, distance, entityToIgnore, ignoreSomeObjects); + if (foundE) + return foundE; } if (checkDummies) { - CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, distance, ignoreZ, nextObject, lastObject, objects); - CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, distance, entityToIgnore, false); + if (foundE) + return foundE; + + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, distance, entityToIgnore, false); + if (foundE) + return foundE; } } } + return foundE; +} + +CEntity* +CWorld::TestSphereAgainstSectorList(CPtrList &list, CVector spherePos, float radius, CEntity *entityToIgnore, bool ignoreSomeObjects) +{ + static CColModel sphereCol; + + sphereCol.boundingSphere.center.x = 0.0f; + sphereCol.boundingSphere.center.y = 0.0f; + sphereCol.boundingSphere.center.z = 0.0f; + sphereCol.boundingSphere.radius = radius; + sphereCol.boundingBox.min.x = -radius; + sphereCol.boundingBox.min.y = -radius; + sphereCol.boundingBox.min.z = -radius; + sphereCol.boundingBox.max.x = radius; + sphereCol.boundingBox.max.y = radius; + sphereCol.boundingBox.max.z = radius; + sphereCol.numSpheres = 1; + sphereCol.spheres = &sphereCol.boundingSphere; + sphereCol.numLines = 0; + sphereCol.numBoxes = 0; + sphereCol.numTriangles = 0; + sphereCol.ownsCollisionVolumes = false; + + CMatrix sphereMat; + sphereMat.SetTranslate(spherePos); + + for(CPtrNode *node=list.first; node; node = node->next) { + CEntity *e = (CEntity*)node->item; + + if (e->m_scanCode != GetCurrentScanCode()) { + e->m_scanCode = GetCurrentScanCode(); + + if (e != entityToIgnore && e->bUsesCollision && !(ignoreSomeObjects && CameraToIgnoreThisObject(e))) { + CVector diff = spherePos - e->GetPosition(); + float distance = diff.Magnitude(); + + if (e->GetBoundRadius() + radius > distance) { + CColModel *eCol = CModelInfo::GetModelInfo(e->m_modelIndex)->GetColModel(); + int collidedSpheres = CCollision::ProcessColModels(sphereMat, sphereCol, e->GetMatrix(), + *eCol, &ms_testSpherePoint, nil, nil); + + if (collidedSpheres != 0 || + (e->IsVehicle() && ((CVehicle*)e)->m_vehType == VEHICLE_TYPE_CAR && + e->m_modelIndex != MI_DODO && radius + eCol->boundingBox.max.x > distance)) { + return e; + } + } + } + } + } + + return nil; } float @@ -790,6 +923,8 @@ STARTPATCHES InjectHook(0x4B2200, CWorld::FindObjectsInRange, PATCH_JUMP); InjectHook(0x4B2540, CWorld::FindObjectsInRangeSectorList, PATCH_JUMP); + InjectHook(0x4B4AC0, CWorld::TestSphereAgainstSectorList, PATCH_JUMP); + InjectHook(0x4B4710, CWorld::TestSphereAgainstWorld, PATCH_JUMP); InjectHook(0x4B3A80, CWorld::FindGroundZForCoord, PATCH_JUMP); InjectHook(0x4B3AE0, CWorld::FindGroundZFor3DCoord, PATCH_JUMP); InjectHook(0x4B3B50, CWorld::FindRoofZFor3DCoord, PATCH_JUMP); diff --git a/src/core/World.h b/src/core/World.h index d6063d70..fd9d6fc3 100644 --- a/src/core/World.h +++ b/src/core/World.h @@ -56,6 +56,7 @@ class CWorld static CPtrList &ms_listMovingEntityPtrs; static CSector (*ms_aSectors)[NUMSECTORS_X]; // [NUMSECTORS_Y][NUMSECTORS_X]; static uint16 &ms_nCurrentScanCode; + static CColPoint &ms_testSpherePoint; public: static uint8 &PlayerInFocus; @@ -94,11 +95,14 @@ public: static bool GetIsLineOfSightSectorClear(CSector §or, const CColLine &line, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false); static bool GetIsLineOfSightSectorListClear(CPtrList &list, const CColLine &line, bool ignoreSeeThrough, bool ignoreSomeObjects = false); + static CEntity* TestSphereAgainstWorld(CVector, float, CEntity*, bool, bool, bool, bool, bool, bool); + static CEntity* TestSphereAgainstSectorList(CPtrList&, CVector, float, CEntity*, bool); static void FindObjectsInRangeSectorList(CPtrList&, CVector&, float, bool, short*, short, CEntity**); static void FindObjectsInRange(CVector&, float, bool, short*, short, CEntity**, bool, bool, bool, bool, bool); static float FindGroundZForCoord(float x, float y); static float FindGroundZFor3DCoord(float x, float y, float z, bool *found); static float FindRoofZFor3DCoord(float x, float y, float z, bool *found); + static void RemoveReferencesToDeletedObject(CEntity*); static float GetSectorX(float f) { return ((f - WORLD_MIN_X)/SECTOR_SIZE_X); } static float GetSectorY(float f) { return ((f - WORLD_MIN_Y)/SECTOR_SIZE_Y); } diff --git a/src/core/common.h b/src/core/common.h index 71c27492..9a5683c6 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -97,11 +97,11 @@ extern void **rwengine; #define SCREEN_SCALE_AR(a) (a) #endif -#include "math/maths.h" -#include "math/Vector.h" -#include "math/Vector2D.h" -#include "math/Matrix.h" -#include "math/Rect.h" +#include "maths.h" +#include "Vector.h" +#include "Vector2D.h" +#include "Matrix.h" +#include "Rect.h" class CRGBA { @@ -139,7 +139,8 @@ inline float sq(float x) { return x*x; } #define SQR(x) ((x) * (x)) #define PI M_PI -#define TWOPI PI*2 +#define TWOPI (PI*2) +#define HALFPI (PI/2) #define DEGTORAD(x) ((x) * PI / 180.0f) #define RADTODEG(x) ((x) * 180.0f / PI) @@ -178,6 +179,7 @@ void re3_assert(const char *expr, const char *filename, unsigned int lineno, con #define max(a, b) (((a) > (b)) ? (a) : (b)) #define min(a, b) (((a) < (b)) ? (a) : (b)) +#define ABS(a) (((a) < 0) ? (-a) : (a)) #define STRINGIFY(x) #x @@ -294,4 +296,4 @@ _TWEEKCLASS(CTweakInt32, int32); _TWEEKCLASS(CTweakUInt32, uint32); _TWEEKCLASS(CTweakFloat, float); -#undef _TWEEKCLASS
\ No newline at end of file +#undef _TWEEKCLASS diff --git a/src/core/config.h b/src/core/config.h index 2dbfc95f..892a06b6 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -63,6 +63,7 @@ enum Config { NUMONSCREENTIMERENTRIES = 1, NUMRADARBLIPS = 32, NUMPICKUPS = 336, + NUMEVENTS = 64, }; // We'll use this once we're ready to become independent of the game diff --git a/src/core/main.cpp b/src/core/main.cpp index e301b470..04fee197 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -295,6 +295,8 @@ void RenderDebugShit(void) { // CTheScripts::RenderTheScriptDebugLines() + if(gbShowCollisionLines) + CRenderer::RenderCollisionLines(); } void diff --git a/src/core/main.h b/src/core/main.h index 9f27e05e..9b3c27f5 100644 --- a/src/core/main.h +++ b/src/core/main.h @@ -27,4 +27,5 @@ void LoadingIslandScreen(const char *levelName); CSprite2d *LoadSplash(const char *name); char *GetLevelSplashScreen(int level); char *GetRandomSplashScreen(void); -void ValidateVersion();
\ No newline at end of file +void LittleTest(void); +void ValidateVersion(); diff --git a/src/core/re3.cpp b/src/core/re3.cpp index e3aece97..a0032bc6 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -10,6 +10,7 @@ #include "Clock.h" #include "World.h" #include "Vehicle.h" +#include "ModelIndices.h" #include "Streaming.h" #include "PathFind.h" #include "Boat.h" @@ -58,8 +59,6 @@ mysrand(unsigned int seed) myrand_seed = seed; } -int gDbgSurf; - void (*DebugMenuProcess)(void); void (*DebugMenuRender)(void); static void stub(void) { } @@ -102,60 +101,43 @@ void ChittyChittyBangBangCheat(); void StrongGripCheat(); void NastyLimbsCheat(); -// needs too much stuff for now -#if 0 +DebugMenuEntry *carCol1; +DebugMenuEntry *carCol2; + void -spawnCar(int id) +SpawnCar(int id) { CVector playerpos; CStreaming::RequestModel(id, 0); CStreaming::LoadAllRequestedModels(false); if(CStreaming::HasModelLoaded(id)){ - FindPlayerCoors(playerpos); + playerpos = FindPlayerCoors(); int node = ThePaths.FindNodeClosestToCoors(playerpos, 0, 100.0f, false, false); if(node < 0) return; CVehicle *v; - if(CModelInfo::IsBoatModel(id)){ -// CBoat* boat = (CBoat*)CVehicle__new(0x484); -// boat = boat->ctor(id, 1); -// v = (CVehicle*)(boat); - }else{ -// CAutomobile *au = (CAutomobile*)CVehicle__new(0x5A8); -// au = au->ctor(id, 1); -// v = (CVehicle*)au; - } -/* - // unlock doors - FIELD(int, v, 0x224) = 1; - // set player owned - FIELD(uint8, v, 0x1F7) |= 4; - - DebugMenuEntrySetAddress(carCol1, &FIELD(uchar, v, 0x19C)); - DebugMenuEntrySetAddress(carCol2, &FIELD(uchar, v, 0x19D)); - //if(id == MODELID_ESPERANTO) - // FIELD(uchar, v, 0x19C) = 54; - - v->matrix.matrix.pos.x = ThePaths.nodes[node].x; - v->matrix.matrix.pos.y = ThePaths.nodes[node].y; - v->matrix.matrix.pos.z = ThePaths.nodes[node].z + 4.0f; - float x = v->matrix.matrix.pos.x; - float y = v->matrix.matrix.pos.y; - float z = v->matrix.matrix.pos.z; - v->matrix.SetRotate(0.0f, 0.0f, 3.49f); - v->matrix.matrix.pos.x += x; - v->matrix.matrix.pos.y += y; - v->matrix.matrix.pos.z += z; - v->bfTypeStatus = v->bfTypeStatus & 7 | 0x20; - FIELD(int, v, 0x224) = 1; -*/ + if(CModelInfo::IsBoatModel(id)) + return; + else + v = new CAutomobile(id, RANDOM_VEHICLE); + + v->bHasBeenOwnedByPlayer = true; + if(carCol1) + DebugMenuEntrySetAddress(carCol1, &v->m_currentColour1); + if(carCol2) + DebugMenuEntrySetAddress(carCol2, &v->m_currentColour2); + + v->GetPosition() = ThePaths.m_pathNodes[node].pos; + v->GetPosition().z += 4.0f; + v->SetOrientation(0.0f, 0.0f, 3.49f); + v->m_status = STATUS_ABANDONED; + v->m_nDoorLock = CARLOCK_UNLOCKED; CWorld::Add(v); } } -#endif -void +static void FixCar(void) { CVehicle *veh = FindPlayerVehicle(); @@ -168,6 +150,34 @@ FixCar(void) ((CAutomobile*)veh)->Fix(); } +static void +ToggleComedy(void) +{ + CVehicle *veh = FindPlayerVehicle(); + if(veh == nil) + return; + veh->bComedyControls = !veh->bComedyControls; +} + +static void +PlaceOnRoad(void) +{ + CVehicle *veh = FindPlayerVehicle(); + if(veh == nil) + return; + + if(veh->IsCar()) + ((CAutomobile*)veh)->PlaceOnRoadProperly(); +} + +static const char *carnames[] = { + "landstal", "idaho", "stinger", "linerun", "peren", "sentinel", "patriot", "firetruk", "trash", "stretch", "manana", "infernus", "blista", "pony", + "mule", "cheetah", "ambulan", "fbicar", "moonbeam", "esperant", "taxi", "kuruma", "bobcat", "mrwhoop", "bfinject", "corpse", "police", "enforcer", + "securica", "banshee", "predator", "bus", "rhino", "barracks", "train", "chopper", "dodo", "coach", "cabbie", "stallion", "rumpo", "rcbandit", + "bellyup", "mrwongs", "mafia", "yardie", "yakuza", "diablos", "columb", "hoods", "airtrain", "deaddodo", "speeder", "reefer", "panlant", "flatbed", + "yankee", "escape", "borgnine", "toyz", "ghost", +}; + static std::list<CTweakVar *> TweakVarsList; static bool bAddTweakVarsNow = false; static const char *pTweakVarsDefaultPath = NULL; @@ -259,15 +269,48 @@ DebugMenuPopulate(void) DebugMenuAddCmd("Cheats", "Strong grip", StrongGripCheat); DebugMenuAddCmd("Cheats", "Nasty limbs", NastyLimbsCheat); + static int spawnCarId = MI_LANDSTAL; + e = DebugMenuAddVar("Spawn", "Spawn Car ID", &spawnCarId, nil, 1, MI_LANDSTAL, MI_GHOST, carnames); + DebugMenuEntrySetWrap(e, true); + DebugMenuAddCmd("Spawn", "Spawn Car", [](){ + if(spawnCarId == MI_TRAIN || + spawnCarId == MI_CHOPPER || + spawnCarId == MI_AIRTRAIN || + spawnCarId == MI_DEADDODO || + spawnCarId == MI_ESCAPE) + return; + SpawnCar(spawnCarId); + }); + static uint8 dummy; + carCol1 = DebugMenuAddVar("Spawn", "First colour", &dummy, nil, 1, 0, 255, nil); + carCol2 = DebugMenuAddVar("Spawn", "Second colour", &dummy, nil, 1, 0, 255, nil); + DebugMenuAddCmd("Spawn", "Spawn Stinger", [](){ SpawnCar(MI_STINGER); }); + DebugMenuAddCmd("Spawn", "Spawn Infernus", [](){ SpawnCar(MI_INFERNUS); }); + DebugMenuAddCmd("Spawn", "Spawn Cheetah", [](){ SpawnCar(MI_CHEETAH); }); + DebugMenuAddCmd("Spawn", "Spawn Esperanto", [](){ SpawnCar(MI_ESPERANT); }); + DebugMenuAddCmd("Spawn", "Spawn Stallion", [](){ SpawnCar(MI_STALLION); }); + DebugMenuAddCmd("Spawn", "Spawn Kuruma", [](){ SpawnCar(MI_KURUMA); }); + DebugMenuAddCmd("Spawn", "Spawn Taxi", [](){ SpawnCar(MI_TAXI); }); + DebugMenuAddCmd("Spawn", "Spawn Police", [](){ SpawnCar(MI_POLICE); }); + DebugMenuAddCmd("Spawn", "Spawn Enforcer", [](){ SpawnCar(MI_ENFORCER); }); + DebugMenuAddCmd("Spawn", "Spawn Banshee", [](){ SpawnCar(MI_BANSHEE); }); + DebugMenuAddCmd("Spawn", "Spawn Yakuza", [](){ SpawnCar(MI_YAKUZA); }); + DebugMenuAddCmd("Spawn", "Spawn Dodo", [](){ SpawnCar(MI_DODO); }); + + DebugMenuAddCmd("Debug", "Fix Car", FixCar); + DebugMenuAddCmd("Debug", "Toggle Comedy Controls", ToggleComedy); + DebugMenuAddCmd("Debug", "Place Car on Road", PlaceOnRoad); + DebugMenuAddVarBool8("Debug", "Show Ped Road Groups", (int8*)&gbShowPedRoadGroups, nil); DebugMenuAddVarBool8("Debug", "Show Car Road Groups", (int8*)&gbShowCarRoadGroups, nil); + DebugMenuAddVarBool8("Debug", "Show Collision Lines", (int8*)&gbShowCollisionLines, nil); DebugMenuAddVarBool8("Debug", "Show Collision Polys", (int8*)&gbShowCollisionPolys, nil); DebugMenuAddVarBool8("Debug", "Don't render Buildings", (int8*)&gbDontRenderBuildings, nil); DebugMenuAddVarBool8("Debug", "Don't render Big Buildings", (int8*)&gbDontRenderBigBuildings, nil); DebugMenuAddVarBool8("Debug", "Don't render Peds", (int8*)&gbDontRenderPeds, nil); + DebugMenuAddVarBool8("Debug", "Don't render Vehicles", (int8*)&gbDontRenderVehicles, nil); DebugMenuAddVarBool8("Debug", "Don't render Objects", (int8*)&gbDontRenderObjects, nil); - DebugMenuAddVar("Debug", "Dbg Surface", &gDbgSurf, nil, 1, 0, 34, nil); DebugMenuAddCmd("Debug", "Start Credits", CCredits::Start); DebugMenuAddCmd("Debug", "Stop Credits", CCredits::Stop); diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp index 0749e8e7..b795931f 100644 --- a/src/entities/Entity.cpp +++ b/src/entities/Entity.cpp @@ -13,11 +13,11 @@ #include "Glass.h" #include "Clock.h" #include "Weather.h" -#include "TimeCycle.h" +#include "Timecycle.h" #include "Bridge.h" #include "TrafficLights.h" #include "Coronas.h" -#include "Pointlights.h" +#include "PointLights.h" #include "Shadows.h" #include "Pickups.h" #include "SpecialFX.h" @@ -42,7 +42,7 @@ CEntity::CEntity(void) bUseCollisionRecords = false; bWasPostponed = false; - m_flagB2 = false; + bExplosionProof = false; bIsVisible = true; bHasCollided = false; bRenderScorched = false; @@ -535,7 +535,7 @@ CEntity::ResolveReferences(void) for(ref = m_pFirstReference; ref->next; ref = ref->next) ; ref->next = CReferences::pEmptyList; - CReferences::pEmptyList = ref; + CReferences::pEmptyList = m_pFirstReference; m_pFirstReference = nil; } } diff --git a/src/entities/Entity.h b/src/entities/Entity.h index 12a631d2..cdc9a173 100644 --- a/src/entities/Entity.h +++ b/src/entities/Entity.h @@ -13,14 +13,11 @@ enum eEntityType ENTITY_TYPE_PED, ENTITY_TYPE_OBJECT, ENTITY_TYPE_DUMMY, - ENTITY_TYPE_6, - ENTITY_TYPE_7, }; enum eEntityStatus { - // from SA MTA! let's hope they didn't change from III - STATUS_PLAYER = 0, + STATUS_PLAYER, STATUS_PLAYER_PLAYBACKFROMBUFFER, STATUS_SIMPLE, STATUS_PHYSICS, @@ -32,8 +29,6 @@ enum eEntityStatus STATUS_PLANE, STATUS_PLAYER_REMOTE, STATUS_PLAYER_DISABLED, - //STATUS_TRAILER, - //STATUS_SIMPLE_TRAILER }; class CEntity : public CPlaceable @@ -55,7 +50,7 @@ public: // flagsB uint32 bWasPostponed : 1; - uint32 m_flagB2 : 1; // explosion proof? + uint32 bExplosionProof : 1; uint32 bIsVisible : 1; uint32 bHasCollided : 1; // uint32 bRenderScorched : 1; @@ -78,7 +73,7 @@ public: uint32 bRemoveFromWorld : 1; uint32 bHasHitWall : 1; uint32 bImBeingRendered : 1; - uint32 m_flagD8 : 1; + uint32 m_flagD8 : 1; // used by cBuoyancy::ProcessBuoyancy uint32 bIsSubway : 1; // set when subway, but maybe different meaning? uint32 bDrawLast : 1; uint32 m_flagD40 : 1; @@ -122,6 +117,15 @@ public: bool IsObject(void) { return m_type == ENTITY_TYPE_OBJECT; } bool IsDummy(void) { return m_type == ENTITY_TYPE_DUMMY; } + RpAtomic *GetAtomic(void) { + assert(RwObjectGetType(m_rwObject) == rpATOMIC); + return (RpAtomic*)m_rwObject; + } + RpClump *GetClump(void) { + assert(RwObjectGetType(m_rwObject) == rpCLUMP); + return (RpClump*)m_rwObject; + } + void GetBoundCentre(CVector &out); CVector GetBoundCentre(void) { CVector v; GetBoundCentre(v); return v; } float GetBoundRadius(void) { return CModelInfo::GetModelInfo(m_modelIndex)->GetColModel()->boundingSphere.radius; } diff --git a/src/math/Matrix.h b/src/math/Matrix.h index 2c0108c1..05a6eb03 100644 --- a/src/math/Matrix.h +++ b/src/math/Matrix.h @@ -240,7 +240,6 @@ public: m_matrix.at.y = 0.0f; m_matrix.at.z = 1.0f; m_matrix.pos.x = 0.0f; - m_matrix.pos.x = 0.0f; m_matrix.pos.y = 0.0f; m_matrix.pos.z = 0.0f; } diff --git a/src/math/Vector.h b/src/math/Vector.h index de8092eb..f794a57f 100644 --- a/src/math/Vector.h +++ b/src/math/Vector.h @@ -22,6 +22,7 @@ public: return *((RwV3d*)this); } #endif + // (0,1,0) means no rotation. So get right vector and its atan float Heading(void) const { return Atan2(-x, y); } float Magnitude(void) const { return Sqrt(x*x + y*y + z*z); } float MagnitudeSqr(void) const { return x*x + y*y + z*z; } diff --git a/src/modelinfo/ModelIndices.h b/src/modelinfo/ModelIndices.h index 0d9ffb53..a0d3f70c 100644 --- a/src/modelinfo/ModelIndices.h +++ b/src/modelinfo/ModelIndices.h @@ -315,6 +315,11 @@ enum MI_TOYZ, MI_GHOST, + // leftovers on PC + MI_MIAMI_RCBARON = 154, + MI_MIAMI_RCRAIDER = 155, + MI_MIAMI_SPARROW = 159, + MI_GRENADE = 170, MI_AK47, MI_BASEBALL_BAT, @@ -465,3 +470,21 @@ IsPickupModel(int16 id) id == MI_PICKUP_KILLFRENZY || id == MI_PICKUP_CAMERA; } + +inline bool +IsPolicePedModel(int16 id) +{ + return id == MI_COP || + id == MI_SWAT || + id == MI_FBI || + id == MI_ARMY; +} + +inline bool +IsPoliceVehicleModel(int16 id) +{ + return id == MI_CHOPPER || + id == MI_PREDATOR || + id == MI_POLICE || + id == MI_ENFORCER; +} diff --git a/src/modelinfo/ModelInfo.cpp b/src/modelinfo/ModelInfo.cpp index 454a73f1..0c3ec76a 100644 --- a/src/modelinfo/ModelInfo.cpp +++ b/src/modelinfo/ModelInfo.cpp @@ -175,6 +175,13 @@ CModelInfo::IsBoatModel(int32 id) ((CVehicleModelInfo*)GetModelInfo(id))->m_vehicleType == VEHICLE_TYPE_BOAT; } +bool +CModelInfo::IsBikeModel(int32 id) +{ + return GetModelInfo(id)->m_type == MITYPE_VEHICLE && + ((CVehicleModelInfo*)GetModelInfo(id))->m_vehicleType == VEHICLE_TYPE_BIKE; +} + void CModelInfo::RemoveColModelsFromOtherLevels(eLevelName level) { diff --git a/src/modelinfo/ModelInfo.h b/src/modelinfo/ModelInfo.h index d20367d1..ee82276d 100644 --- a/src/modelinfo/ModelInfo.h +++ b/src/modelinfo/ModelInfo.h @@ -36,5 +36,6 @@ public: } static bool IsBoatModel(int32 id); + static bool IsBikeModel(int32 id); static void RemoveColModelsFromOtherLevels(eLevelName level); }; diff --git a/src/modelinfo/PedModelInfo.cpp b/src/modelinfo/PedModelInfo.cpp index 747cbc99..c5242ef6 100644 --- a/src/modelinfo/PedModelInfo.cpp +++ b/src/modelinfo/PedModelInfo.cpp @@ -1,5 +1,6 @@ #include "common.h" #include "patcher.h" +#include "Ped.h" #include "NodeName.h" #include "VisibilityPlugins.h" #include "ModelInfo.h" @@ -14,7 +15,7 @@ CPedModelInfo::DeleteRwObject(void) } RwObjectNameIdAssocation CPedModelInfo::m_pPedIds[12] = { - { "Smid", PED_TORSO, 0, }, // that is strange... + { "Smid", PED_MID, 0, }, // that is strange... { "Shead", PED_HEAD, 0, }, { "Supperarml", PED_UPPERARML, 0, }, { "Supperarmr", PED_UPPERARMR, 0, }, @@ -109,17 +110,16 @@ struct ColNodeInfo float radius; }; -// TODO: find out piece types #define NUMPEDINFONODES 8 ColNodeInfo m_pColNodeInfos[NUMPEDINFONODES] = { - { nil, PED_HEAD, 6, 0.0f, 0.05f, 0.2f }, - { "Storso", 0, 0, 0.0f, 0.15f, 0.2f }, - { "Storso", 0, 0, 0.0f, -0.05f, 0.3f }, - { nil, PED_TORSO, 1, 0.0f, -0.07f, 0.3f }, - { nil, PED_UPPERARML, 2, 0.07f, -0.1f, 0.2f }, - { nil, PED_UPPERARMR, 3, -0.07f, -0.1f, 0.2f }, - { "Slowerlegl", 0, 4, 0.0f, 0.07f, 0.25f }, - { nil, PED_LOWERLEGR, 5, 0.0f, 0.07f, 0.25f }, + { nil, PED_HEAD, PEDPIECE_HEAD, 0.0f, 0.05f, 0.2f }, + { "Storso", 0, PEDPIECE_TORSO, 0.0f, 0.15f, 0.2f }, + { "Storso", 0, PEDPIECE_TORSO, 0.0f, -0.05f, 0.3f }, + { nil, PED_MID, PEDPIECE_MID, 0.0f, -0.07f, 0.3f }, + { nil, PED_UPPERARML, PEDPIECE_LEFTARM, 0.07f, -0.1f, 0.2f }, + { nil, PED_UPPERARMR, PEDPIECE_RIGHTARM, -0.07f, -0.1f, 0.2f }, + { "Slowerlegl", 0, PEDPIECE_LEFTLEG, 0.0f, 0.07f, 0.25f }, + { nil, PED_LOWERLEGR, PEDPIECE_RIGHTLEG, 0.0f, 0.07f, 0.25f }, }; RwObject* diff --git a/src/modelinfo/PedModelInfo.h b/src/modelinfo/PedModelInfo.h index bec46b4e..483d13f8 100644 --- a/src/modelinfo/PedModelInfo.h +++ b/src/modelinfo/PedModelInfo.h @@ -3,8 +3,8 @@ #include "ClumpModelInfo.h" enum PedNode { - PED_WAIST, - PED_TORSO, // Smid on PS2/PC, Storso on mobile/xbox + PED_TORSO, + PED_MID, // Smid on PS2/PC, Storso on mobile/xbox PED_HEAD, PED_UPPERARML, PED_UPPERARMR, diff --git a/src/objects/ObjectData.cpp b/src/objects/ObjectData.cpp index ef5bcc5e..775a87a1 100644 --- a/src/objects/ObjectData.cpp +++ b/src/objects/ObjectData.cpp @@ -93,7 +93,7 @@ CObjectData::SetObjectData(int32 modelId, CObject &object) if(object.m_fMass >= 99998.0){ object.bInfiniteMass = true; object.bAffectedByGravity = false; - object.m_flagB2 = true; + object.bExplosionProof = true; } } diff --git a/src/peds/CivilianPed.cpp b/src/peds/CivilianPed.cpp index cf8a0580..3b1f9e1c 100644 --- a/src/peds/CivilianPed.cpp +++ b/src/peds/CivilianPed.cpp @@ -1,18 +1,41 @@ #include "common.h" #include "patcher.h" #include "CivilianPed.h" +#include "Phones.h" WRAPPER void CCivilianPed::ProcessControl(void) { EAXJMP(0x4BFFE0); } CCivilianPed::CCivilianPed(int pedtype, int mi) : CPed(pedtype) { - CPed::SetModelIndex(mi); + SetModelIndex(mi); for (int i = 0; i < 10; i++) { m_nearPeds[i] = nil; } } +bool +CCivilianPed::ProcessNearestFreePhone(int unused) +{ + if (m_nPedState == PED_SEEK_POS) + return false; + + int phoneId = gPhoneInfo.FindNearestFreePhone(&GetPosition()); + + if (phoneId == -1) + return false; + + if (gPhoneInfo.m_aPhones[phoneId].m_nState != PHONE_STATE_FREE) + return false; + + field_31C = 1; + SetMoveState(PEDMOVE_RUN); + SetSeek(gPhoneInfo.m_aPhones[phoneId].m_vecPos, 0.3f); + m_phoneId = phoneId; + m_lookingForPhone = unused; + return true; +} + class CCivilianPed_ : public CCivilianPed { public: @@ -23,4 +46,5 @@ public: STARTPATCHES InjectHook(0x4BFF30, &CCivilianPed_::ctor, PATCH_JUMP); InjectHook(0x4BFFC0, &CCivilianPed_::dtor, PATCH_JUMP); + InjectHook(0x4C10C0, &CCivilianPed::ProcessNearestFreePhone, PATCH_JUMP); ENDPATCHES diff --git a/src/peds/CivilianPed.h b/src/peds/CivilianPed.h index 14859a5c..e5e63682 100644 --- a/src/peds/CivilianPed.h +++ b/src/peds/CivilianPed.h @@ -9,5 +9,6 @@ public: ~CCivilianPed(void) { } void ProcessControl(void); + bool ProcessNearestFreePhone(int); }; static_assert(sizeof(CCivilianPed) == 0x53C, "CCivilianPed: error"); diff --git a/src/peds/CopPed.cpp b/src/peds/CopPed.cpp index 0ac0473f..5bc67e15 100644 --- a/src/peds/CopPed.cpp +++ b/src/peds/CopPed.cpp @@ -1,6 +1,64 @@ #include "common.h" #include "patcher.h" #include "CopPed.h" +#include "ModelIndices.h" + +WRAPPER void CCopPed::ProcessControl() { EAXJMP(0x4C1400); } + +CCopPed::CCopPed(eCopType copType) : CPed(PEDTYPE_COP) +{ + m_nCopType = copType; + switch (copType) { + case COP_STREET: + SetModelIndex(MI_COP); + GiveWeapon(WEAPONTYPE_COLT45, 1000); + m_currentWeapon = WEAPONTYPE_UNARMED; + m_fArmour = 0.0f; + m_wepSkills = 208; /* TODO: what is this? seems unused */ + m_wepAccuracy = 60; + break; + case COP_FBI: + SetModelIndex(MI_FBI); + GiveWeapon(WEAPONTYPE_COLT45, 1000); + GiveWeapon(WEAPONTYPE_AK47, 1000); + SetCurrentWeapon(WEAPONTYPE_AK47); + m_fArmour = 100.0f; + m_wepSkills = 176; /* TODO: what is this? seems unused */ + m_wepAccuracy = 76; + break; + case COP_SWAT: + SetModelIndex(MI_SWAT); + GiveWeapon(WEAPONTYPE_COLT45, 1000); + GiveWeapon(WEAPONTYPE_UZI, 1000); + SetCurrentWeapon(WEAPONTYPE_UZI); + m_fArmour = 50.0f; + m_wepSkills = 32; /* TODO: what is this? seems unused */ + m_wepAccuracy = 64; + break; + case COP_ARMY: + SetModelIndex(MI_ARMY); + GiveWeapon(WEAPONTYPE_COLT45, 1000); + GiveWeapon(WEAPONTYPE_M16, 1000); + GiveWeapon(WEAPONTYPE_GRENADE, 10); + SetCurrentWeapon(WEAPONTYPE_M16); + m_fArmour = 100.0f; + m_wepSkills = 32; /* TODO: what is this? seems unused */ + m_wepAccuracy = 84; + break; + default: + break; + } + m_bIsInPursuit = false; + field_1350 = 1; + m_bIsDisabledCop = false; + field_1356 = 0; + m_attackTimer = 0; + field_1351 = 0; + m_bZoneDisabledButClose = false; + m_bZoneDisabled = false; + field_1364 = -1; + m_pPointGunAt = nil; +} CCopPed::~CCopPed() { @@ -12,9 +70,11 @@ WRAPPER void CCopPed::ClearPursuit(void) { EAXJMP(0x4C28C0); } class CCopPed_ : public CCopPed { public: + CCopPed *ctor(eCopType type) { return ::new (this) CCopPed(type); }; void dtor(void) { CCopPed::~CCopPed(); } }; STARTPATCHES + InjectHook(0x4C11B0, &CCopPed_::ctor, PATCH_JUMP); InjectHook(0x4C13E0, &CCopPed_::dtor, PATCH_JUMP); ENDPATCHES diff --git a/src/peds/CopPed.h b/src/peds/CopPed.h index 5827f9bc..162f14a6 100644 --- a/src/peds/CopPed.h +++ b/src/peds/CopPed.h @@ -1,27 +1,6 @@ #pragma once #include "Ped.h" -enum eCrimeType -{ - CRIME_NONE, - CRIME_POSSESSION_GUN, - CRIME_HIT_PED, - CRIME_HIT_COP, - CRIME_SHOOT_PED, - CRIME_SHOOT_COP, - CRIME_STEAL_CAR, - CRIME_RUN_REDLIGHT, - CRIME_RECKLESS_DRIVING, - CRIME_SPEEDING, - CRIME_RUNOVER_PED, - CRIME_RUNOVER_COP, - CRIME_SHOOT_HELI, - CRIME_PED_BURNED, - CRIME_COP_BURNED, - CRIME_VEHICLE_BURNED, - CRIME_DESTROYED_CESSNA, -}; - enum eCopType { COP_STREET = 0, @@ -30,18 +9,6 @@ enum eCopType COP_ARMY = 3, }; -class CCrime -{ -public: - eCrimeType m_eCrimeType; - CEntity *m_pVictim; - int32 m_nCrimeTime; - CVector m_vecCrimePos; - int8 m_bReported; - int8 m_bMultiplier; - int8 pad_20[2]; -}; - class CCopPed : public CPed { public: @@ -64,9 +31,11 @@ public: int8 field_1366; int8 field_1367; + CCopPed(eCopType); ~CCopPed(); void ClearPursuit(void); + void ProcessControl(void); }; static_assert(sizeof(CCopPed) == 0x558, "CCopPed: error"); diff --git a/src/peds/EmergencyPed.cpp b/src/peds/EmergencyPed.cpp index 664bd6f6..cbcfb403 100644 --- a/src/peds/EmergencyPed.cpp +++ b/src/peds/EmergencyPed.cpp @@ -1,13 +1,38 @@ #include "common.h" #include "patcher.h" #include "EmergencyPed.h" +#include "ModelIndices.h" class CEmergencyPed_ : public CEmergencyPed { public: + CEmergencyPed *ctor(int pedtype) { return ::new (this) CEmergencyPed(pedtype); }; void dtor(void) { CEmergencyPed::~CEmergencyPed(); } }; +WRAPPER void CEmergencyPed::ProcessControl(void) { EAXJMP(0x4C2F10); } + +CEmergencyPed::CEmergencyPed(uint32 type) : CPed(type) +{ + switch (type){ + case PEDTYPE_EMERGENCY: + SetModelIndex(MI_MEDIC); + m_pRevivedPed = nil; + field_1360 = 0; + break; + case PEDTYPE_FIREMAN: + SetModelIndex(MI_FIREMAN); + m_pRevivedPed = nil; + break; + default: + break; + } + m_nEmergencyPedState = 0; + m_pAttendedAccident = nil; + field_1356 = 0; +} + STARTPATCHES + InjectHook(0x4C2E40, &CEmergencyPed_::ctor, PATCH_JUMP); InjectHook(0x4C2EF0, &CEmergencyPed_::dtor, PATCH_JUMP); ENDPATCHES diff --git a/src/peds/EmergencyPed.h b/src/peds/EmergencyPed.h index f21996e8..f55fa4e2 100644 --- a/src/peds/EmergencyPed.h +++ b/src/peds/EmergencyPed.h @@ -1,11 +1,20 @@ #pragma once +#include "Fire.h" #include "Ped.h" class CEmergencyPed : public CPed { public: // 0x53C - uint8 stuff[24]; + CPed* m_pRevivedPed; + int32 m_nEmergencyPedState; // looks like flags + void* m_pAttendedAccident; //TODO: CAccident* + CFire* m_pAttendedFire; + int8 field_1356; + int32 field_1360; + + CEmergencyPed(uint32); + void ProcessControl(void); }; static_assert(sizeof(CEmergencyPed) == 0x554, "CEmergencyPed: error"); diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index 4ad4ac1b..0c4e33d6 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -25,16 +25,15 @@ #include "PointLights.h" #include "Pad.h" #include "Phones.h" +#include "EventList.h" +#include "Darkel.h" +#include "PathFind.h" +#include "ModelIndices.h" WRAPPER void CPed::KillPedWithCar(CVehicle *veh, float impulse) { EAXJMP(0x4EC430); } WRAPPER void CPed::Say(uint16 audio) { EAXJMP(0x4E5A10); } -WRAPPER void CPed::SetDie(AnimationId anim, float arg1, float arg2) { EAXJMP(0x4D37D0); } WRAPPER void CPed::SetDead(void) { EAXJMP(0x4D3970); } WRAPPER void CPed::SpawnFlyingComponent(int, int8) { EAXJMP(0x4EB060); } -WRAPPER void CPed::RestorePreviousState(void) { EAXJMP(0x4C5E30); } -WRAPPER void CPed::ClearAttack(void) { EAXJMP(0x4E6790); } -WRAPPER void CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *dragAssoc, void *arg) { EAXJMP(0x4E2480); } -WRAPPER void CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation *dragAssoc, void *arg) { EAXJMP(0x4E2920); } WRAPPER void CPed::SetPedPositionInCar(void) { EAXJMP(0x4D4970); } WRAPPER void CPed::ProcessControl(void) { EAXJMP(0x4C8910); } WRAPPER void CPed::PreRender(void) { EAXJMP(0x4CFDD0); } @@ -45,11 +44,14 @@ WRAPPER void CPed::SetFollowRoute(int16, int16) { EAXJMP(0x4DD690); } WRAPPER void CPed::SetDuck(uint32) { EAXJMP(0x4E4920); } WRAPPER void CPed::RegisterThreatWithGangPeds(CEntity*) { EAXJMP(0x4E3870); } WRAPPER void CPed::MakeChangesForNewWeapon(int8) { EAXJMP(0x4F2560); } +WRAPPER void CPed::SetSeek(CVector, float) { EAXJMP(0x4D14B0); } WRAPPER bool CPed::Seek(void) { EAXJMP(0x4D1640); } +WRAPPER void CPed::SetFollowPath(CVector) { EAXJMP(0x4D2EA0); } bool &CPed::bNastyLimbsCheat = *(bool*)0x95CD44; bool &CPed::bPedCheat2 = *(bool*)0x95CD5A; bool &CPed::bPedCheat3 = *(bool*)0x95CD59; +CColPoint &CPed::ms_tempColPoint = *(CColPoint*)0x62DB14; uint16 &CPed::distanceMultToCountPedNear = *(uint16*)0x5F8C98; @@ -272,8 +274,8 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) bPedPhysics = true; bUseCollisionRecords = true; - m_vecAnimMoveDelta.x = 0.0; - m_vecAnimMoveDelta.y = 0.0; + m_vecAnimMoveDelta.x = 0.0f; + m_vecAnimMoveDelta.y = 0.0f; m_fHealth = 100.0f; m_fArmour = 0.0f; m_nPedType = pedType; @@ -290,9 +292,9 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) bInVehicle = 0; m_pMyVehicle = nil; m_pVehicleAnim = nil; - m_vecOffsetSeek.x = 0.0; - m_vecOffsetSeek.y = 0.0; - m_vecOffsetSeek.z = 0.0; + m_vecOffsetSeek.x = 0.0f; + m_vecOffsetSeek.y = 0.0f; + m_vecOffsetSeek.z = 0.0f; m_pedFormation = 0; m_lastThreatTimer = 0; m_nPedStateTimer = 0; @@ -379,10 +381,10 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) m_ped_flagC1 = false; bRespondsToThreats = true; - m_ped_flagC4 = true; - m_ped_flagC8 = false; + bRenderPedInCar = true; + bChangedSeat = false; m_ped_flagC10 = false; - m_ped_flagC20 = false; + bBodyPartJustCameOff = false; m_ped_flagC40 = false; m_ped_flagC80 = false; @@ -390,10 +392,10 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) m_ped_flagD2 = false; m_ped_flagD4 = false; m_ped_flagD8 = false; - m_ped_flagD10 = false; + bIsPedDieAnimPlaying = false; m_ped_flagD20 = false; m_ped_flagD40 = false; - m_ped_flagD80 = false; + m_bScriptObjectiveCompleted = false; m_ped_flagE1 = false; m_ped_flagE2 = false; @@ -668,7 +670,7 @@ CPed::AimGun(void) if (m_pSeekTarget) { if (m_pSeekTarget->IsPed()) { - ((CPed*)m_pSeekTarget)->m_pedIK.GetComponentPosition(&pos, PED_TORSO); + ((CPed*)m_pSeekTarget)->m_pedIK.GetComponentPosition(&pos, PED_MID); vector.x = pos.x; vector.y = pos.y; vector.z = pos.z; @@ -708,7 +710,7 @@ CPed::ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer) CPed::SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); } - m_ped_flagC20 = true; + bBodyPartJustCameOff = true; m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 150; CParticle::AddParticle(PARTICLE_TEST, pos2, @@ -732,7 +734,7 @@ CPed::ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer) } void -CPed::RemoveBodyPart(PedNode nodeId, int8 unk) +CPed::RemoveBodyPart(PedNode nodeId, int8 direction) { RwFrame *frame; RwV3d pos; @@ -741,7 +743,7 @@ CPed::RemoveBodyPart(PedNode nodeId, int8 unk) if (frame) { if (CGame::nastyGame) { if (nodeId != PED_HEAD) - CPed::SpawnFlyingComponent(nodeId, unk); + SpawnFlyingComponent(nodeId, direction); RecurseFrameChildrenVisibilityCB(frame, nil); pos.x = 0.0f; @@ -763,7 +765,7 @@ CPed::RemoveBodyPart(PedNode nodeId, int8 unk) nil, 0.0f, 0, 0, 0, 0); } } - m_ped_flagC20 = true; + bBodyPartJustCameOff = true; m_bodyPartBleeding = nodeId; } } else { @@ -907,8 +909,8 @@ CPed::ClearAimFlag(void) m_pedIK.m_flags &= ~CPedIK:: FLAG_4; } - if (CPed::IsPlayer()) - ((CPlayerPed*)this)->m_fFPSMoveHeading = 0.0; + if (IsPlayer()) + ((CPlayerPed*)this)->m_fFPSMoveHeading = 0.0f; } void @@ -919,14 +921,14 @@ CPed::ClearLookFlag(void) { m_ped_flagI1 = false; m_pedIK.m_flags &= ~CPedIK::FLAG_2; - if (CPed::IsPlayer()) + if (IsPlayer()) m_lookTimer = CTimer::GetTimeInMilliseconds() + 2000; else m_lookTimer = CTimer::GetTimeInMilliseconds() + 4000; if (m_nPedState == PED_LOOK_HEADING || m_nPedState == PED_LOOK_ENTITY) { - CPed::RestorePreviousState(); - CPed::ClearLookFlag(); + RestorePreviousState(); + ClearLookFlag(); } } } @@ -1042,184 +1044,186 @@ CPed::Attack(void) weaponAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_WEAPON_THROWU); delayBetweenAnimAndFire = 0.2f; } - } - if (weaponAnimAssoc) { - animStart = ourWeapon->m_fAnimLoopStart; - weaponAnimTime = weaponAnimAssoc->currentTime; - if (weaponAnimTime > animStart && weaponAnimTime - weaponAnimAssoc->timeStep <= animStart) { - if (ourWeapon->m_bCanAimWithArm) - m_pedIK.m_flags |= CPedIK::FLAG_4; - else - m_pedIK.m_flags &= ~CPedIK::FLAG_4; + + if (!weaponAnimAssoc) { + if (lastReloadWasInFuture) { + if (ourWeaponFire != WEAPON_FIRE_PROJECTILE || !IsPlayer() || ((CPlayerPed*)this)->field_1380) { + if (!CGame::nastyGame || ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(((CPlayerPed*)this), nil) < PED_ON_THE_FLOOR) { + weaponAnimAssoc = CAnimManager::BlendAnimation((RpClump*)m_rwObject, ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f); + } + else { + weaponAnimAssoc = CAnimManager::BlendAnimation((RpClump*)m_rwObject, ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f); + } + + weaponAnimAssoc->SetFinishCallback(CPed::FinishedAttackCB, this); + weaponAnimAssoc->flags |= ASSOC_RUNNING; + + if (weaponAnimAssoc->currentTime == weaponAnimAssoc->hierarchy->totalLength) + weaponAnimAssoc->SetCurrentTime(0.0f); + + if (IsPlayer()) { + ((CPlayerPed*)this)->field_1376 = 0.0f; + ((CPlayerPed*)this)->field_1380 = false; + } + } + } else + FinishedAttackCB(nil, this); + + return; } + } - if (weaponAnimTime <= delayBetweenAnimAndFire || weaponAnimTime - weaponAnimAssoc->timeStep > delayBetweenAnimAndFire || !weaponAnimAssoc->IsRunning()) { - if (weaponAnimAssoc->speed < 1.0f) - weaponAnimAssoc->speed = 1.0f; + animStart = ourWeapon->m_fAnimLoopStart; + weaponAnimTime = weaponAnimAssoc->currentTime; + if (weaponAnimTime > animStart && weaponAnimTime - weaponAnimAssoc->timeStep <= animStart) { + if (ourWeapon->m_bCanAimWithArm) + m_pedIK.m_flags |= CPedIK::FLAG_4; + else + m_pedIK.m_flags &= ~CPedIK::FLAG_4; + } - } else { - firePos = ourWeapon->m_vecFireOffset; - if (ourWeaponType == WEAPONTYPE_BASEBALLBAT) { - if (weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay) - firePos.z = 0.7f * ourWeapon->m_fRadius - 1.0f; - - firePos = GetMatrix() * firePos; - } else if (ourWeaponType != WEAPONTYPE_UNARMED) { - if (weaponAnimAssoc->animId == ANIM_KICK_FLOOR) - frame = GetNodeFrame(PED_FOOTR); - else - frame = GetNodeFrame(PED_HANDR); + if (weaponAnimTime <= delayBetweenAnimAndFire || weaponAnimTime - weaponAnimAssoc->timeStep > delayBetweenAnimAndFire || !weaponAnimAssoc->IsRunning()) { + if (weaponAnimAssoc->speed < 1.0f) + weaponAnimAssoc->speed = 1.0f; - for (; frame; frame = RwFrameGetParent(frame)) - RwV3dTransformPoints((RwV3d*)firePos, (RwV3d*)firePos, 1, RwFrameGetMatrix(frame)); - } else { - firePos = GetMatrix() * firePos; - } + } else { + firePos = ourWeapon->m_vecFireOffset; + if (ourWeaponType == WEAPONTYPE_BASEBALLBAT) { + if (weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay) + firePos.z = 0.7f * ourWeapon->m_fRadius - 1.0f; + + firePos = GetMatrix() * firePos; + } else if (ourWeaponType != WEAPONTYPE_UNARMED) { + if (weaponAnimAssoc->animId == ANIM_KICK_FLOOR) + frame = GetNodeFrame(PED_FOOTR); + else + frame = GetNodeFrame(PED_HANDR); + + for (; frame; frame = RwFrameGetParent(frame)) + RwV3dTransformPoints((RwV3d*)firePos, (RwV3d*)firePos, 1, RwFrameGetMatrix(frame)); + } else { + firePos = GetMatrix() * firePos; + } - GetWeapon()->Fire(this, &firePos); + GetWeapon()->Fire(this, &firePos); - if (ourWeaponType == WEAPONTYPE_MOLOTOV || ourWeaponType == WEAPONTYPE_GRENADE) { - RemoveWeaponModel(ourWeapon->m_nModelId); + if (ourWeaponType == WEAPONTYPE_MOLOTOV || ourWeaponType == WEAPONTYPE_GRENADE) { + RemoveWeaponModel(ourWeapon->m_nModelId); + } + if (!GetWeapon()->m_nAmmoTotal && ourWeaponFire != WEAPON_FIRE_MELEE && FindPlayerPed() != this) { + SelectGunIfArmed(); + } + + if (GetWeapon()->m_eWeaponState != WEAPONSTATE_MELEE_MADECONTACT) { + // If reloading just began, start the animation + if (GetWeapon()->m_eWeaponState == WEAPONSTATE_RELOADING && reloadAnim != NUM_ANIMS && !reloadAnimAssoc) { + CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, reloadAnim, 8.0f); + ClearLookFlag(); + ClearAimFlag(); + m_ped_flagA4 = false; + bIsPointingGunAt = false; + m_lastHitTime = CTimer::GetTimeInMilliseconds(); + return; } - if (!GetWeapon()->m_nAmmoTotal && ourWeaponFire != WEAPON_FIRE_MELEE && FindPlayerPed() != this) { - SelectGunIfArmed(); + } else { + if (weaponAnimAssoc->animId == ANIM_WEAPON_BAT_V || weaponAnimAssoc->animId == ANIM_WEAPON_BAT_H) { + DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_BAT_ATTACK, 1.0f); + } else if (weaponAnimAssoc->animId == ANIM_FIGHT_PPUNCH) { + DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_PUNCH_ATTACK, 0.0f); } - if (GetWeapon()->m_eWeaponState != WEAPONSTATE_MELEE_MADECONTACT) { - // If reloading just began, start the animation - if (GetWeapon()->m_eWeaponState == WEAPONSTATE_RELOADING && reloadAnim != NUM_ANIMS && !reloadAnimAssoc) { - CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, reloadAnim, 8.0f); - ClearLookFlag(); - ClearAimFlag(); - m_ped_flagA4 = false; - bIsPointingGunAt = false; - m_lastHitTime = CTimer::GetTimeInMilliseconds(); - return; - } - } else { - if (weaponAnimAssoc->animId == ANIM_WEAPON_BAT_V || weaponAnimAssoc->animId == ANIM_WEAPON_BAT_H) { - DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_BAT_ATTACK, 1.0f); - } else if (weaponAnimAssoc->animId == ANIM_FIGHT_PPUNCH) { - DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_PUNCH_ATTACK, 0.0f); - } - - weaponAnimAssoc->speed = 0.5f; + weaponAnimAssoc->speed = 0.5f; - // BUG: We currently don't know any situation this cond. could be true. - if (m_ped_flagA4 || CTimer::GetTimeInMilliseconds() < m_lastHitTime) { - weaponAnimAssoc->callbackType = 0; - } + // BUG: We currently don't know any situation this cond. could be true. + if (m_ped_flagA4 || CTimer::GetTimeInMilliseconds() < m_lastHitTime) { + weaponAnimAssoc->callbackType = 0; } - - lastReloadWasInFuture = false; } - if (ourWeaponType == WEAPONTYPE_SHOTGUN) { - weaponAnimTime = weaponAnimAssoc->currentTime; - firePos = ourWeapon->m_vecFireOffset; + lastReloadWasInFuture = false; + } - if (weaponAnimTime > 1.0f && weaponAnimTime - weaponAnimAssoc->timeStep <= 1.0f && weaponAnimAssoc->IsRunning()) { - for (frame = GetNodeFrame(PED_HANDR); frame; frame = RwFrameGetParent(frame)) - RwV3dTransformPoints((RwV3d*)firePos, (RwV3d*)firePos, 1, RwFrameGetMatrix(frame)); + if (ourWeaponType == WEAPONTYPE_SHOTGUN) { + weaponAnimTime = weaponAnimAssoc->currentTime; + firePos = ourWeapon->m_vecFireOffset; - CVector gunshellPos( - firePos.x - 0.6f * GetForward().x, - firePos.y - 0.6f * GetForward().y, - firePos.z - 0.15f * GetUp().z - ); + if (weaponAnimTime > 1.0f && weaponAnimTime - weaponAnimAssoc->timeStep <= 1.0f && weaponAnimAssoc->IsRunning()) { + for (frame = GetNodeFrame(PED_HANDR); frame; frame = RwFrameGetParent(frame)) + RwV3dTransformPoints((RwV3d*)firePos, (RwV3d*)firePos, 1, RwFrameGetMatrix(frame)); - CVector2D gunshellRot( - GetRight().x, - GetRight().y - ); + CVector gunshellPos( + firePos.x - 0.6f * GetForward().x, + firePos.y - 0.6f * GetForward().y, + firePos.z - 0.15f * GetUp().z + ); - gunshellRot.Normalise(); - GetWeapon()->AddGunshell(this, gunshellPos, gunshellRot, 0.025f); - } + CVector2D gunshellRot( + GetRight().x, + GetRight().y + ); + + gunshellRot.Normalise(); + GetWeapon()->AddGunshell(this, gunshellPos, gunshellRot, 0.025f); } - animLoopEnd = ourWeapon->m_fAnimLoopEnd; - if (ourWeaponFire == WEAPON_FIRE_MELEE && weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay) - animLoopEnd = 3.4f/6.0f; + } + animLoopEnd = ourWeapon->m_fAnimLoopEnd; + if (ourWeaponFire == WEAPON_FIRE_MELEE && weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay) + animLoopEnd = 3.4f/6.0f; - weaponAnimTime = weaponAnimAssoc->currentTime; + weaponAnimTime = weaponAnimAssoc->currentTime; - // Anim loop end, either start the loop again or finish the attack - if (weaponAnimTime > animLoopEnd || !weaponAnimAssoc->IsRunning() && ourWeaponFire != WEAPON_FIRE_PROJECTILE) { + // Anim loop end, either start the loop again or finish the attack + if (weaponAnimTime > animLoopEnd || !weaponAnimAssoc->IsRunning() && ourWeaponFire != WEAPON_FIRE_PROJECTILE) { - if (weaponAnimTime - 2.0f * weaponAnimAssoc->timeStep <= animLoopEnd - && (m_ped_flagA4 || CTimer::GetTimeInMilliseconds() < m_lastHitTime) - && GetWeapon()->m_eWeaponState != WEAPONSTATE_RELOADING) { + if (weaponAnimTime - 2.0f * weaponAnimAssoc->timeStep <= animLoopEnd + && (m_ped_flagA4 || CTimer::GetTimeInMilliseconds() < m_lastHitTime) + && GetWeapon()->m_eWeaponState != WEAPONSTATE_RELOADING) { - weaponAnim = weaponAnimAssoc->animId; - if (ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(((CPlayerPed*)this), nil) < PED_ON_THE_FLOOR) { - if (weaponAnim != ourWeapon->m_Anim2ToPlay || weaponAnim == ANIM_RBLOCK_CSHOOT) { - weaponAnimAssoc->Start(ourWeapon->m_fAnimLoopStart); - } else { - CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f); - } + weaponAnim = weaponAnimAssoc->animId; + if (ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(((CPlayerPed*)this), nil) < PED_ON_THE_FLOOR) { + if (weaponAnim != ourWeapon->m_Anim2ToPlay || weaponAnim == ANIM_RBLOCK_CSHOOT) { + weaponAnimAssoc->Start(ourWeapon->m_fAnimLoopStart); } else { - if (weaponAnim == ourWeapon->m_Anim2ToPlay) - weaponAnimAssoc->SetCurrentTime(0.1f); - else - CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f); + CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f); } } else { - ClearAimFlag(); - - // Echoes of bullets, at the end of the attack. (Bug: doesn't play while reloading) - if (weaponAnimAssoc->currentTime - weaponAnimAssoc->timeStep <= ourWeapon->m_fAnimLoopEnd) { - switch (ourWeaponType) { - case WEAPONTYPE_UZI: - DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_UZI_BULLET_ECHO, 0.0f); - break; - case WEAPONTYPE_AK47: - DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_AK47_BULLET_ECHO, 0.0f); - break; - case WEAPONTYPE_M16: - DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_M16_BULLET_ECHO, 0.0f); - break; - default: - break; - } - } - - // Fun fact: removing this part leds to reloading flamethrower - if (ourWeaponType == WEAPONTYPE_FLAMETHROWER && weaponAnimAssoc->IsRunning()) { - weaponAnimAssoc->flags |= ASSOC_DELETEFADEDOUT; - weaponAnimAssoc->flags &= ~ASSOC_RUNNING; - weaponAnimAssoc->blendDelta = -4.0f; - } + if (weaponAnim == ourWeapon->m_Anim2ToPlay) + weaponAnimAssoc->SetCurrentTime(0.1f); + else + CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f); } - } - if (weaponAnimAssoc->currentTime > delayBetweenAnimAndFire) - lastReloadWasInFuture = false; - - m_ped_flagA4 = lastReloadWasInFuture; - return; - } - - if (lastReloadWasInFuture) { - if (ourWeaponFire != WEAPON_FIRE_PROJECTILE || !CPed::IsPlayer() || ((CPlayerPed*)this)->field_1380) { - if (!CGame::nastyGame || ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(((CPlayerPed*)this), nil) < PED_ON_THE_FLOOR) { - weaponAnimAssoc = CAnimManager::BlendAnimation((RpClump*)m_rwObject, ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f); - } else { - weaponAnimAssoc = CAnimManager::BlendAnimation((RpClump*)m_rwObject, ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f); + } else { + ClearAimFlag(); + + // Echoes of bullets, at the end of the attack. (Bug: doesn't play while reloading) + if (weaponAnimAssoc->currentTime - weaponAnimAssoc->timeStep <= ourWeapon->m_fAnimLoopEnd) { + switch (ourWeaponType) { + case WEAPONTYPE_UZI: + DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_UZI_BULLET_ECHO, 0.0f); + break; + case WEAPONTYPE_AK47: + DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_AK47_BULLET_ECHO, 0.0f); + break; + case WEAPONTYPE_M16: + DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_M16_BULLET_ECHO, 0.0f); + break; + default: + break; + } } - weaponAnimAssoc->SetFinishCallback(CPed::FinishedAttackCB, this); - weaponAnimAssoc->flags |= ASSOC_RUNNING; - - if (weaponAnimAssoc->currentTime == weaponAnimAssoc->hierarchy->totalLength) - weaponAnimAssoc->SetCurrentTime(0.0f); - - if (CPed::IsPlayer()) { - ((CPlayerPed*)this)->field_1376 = 0.0f; - ((CPlayerPed*)this)->field_1380 = false; + // Fun fact: removing this part leds to reloading flamethrower + if (ourWeaponType == WEAPONTYPE_FLAMETHROWER && weaponAnimAssoc->IsRunning()) { + weaponAnimAssoc->flags |= ASSOC_DELETEFADEDOUT; + weaponAnimAssoc->flags &= ~ASSOC_RUNNING; + weaponAnimAssoc->blendDelta = -4.0f; } } } - else - CPed::FinishedAttackCB(nil, this); + if (weaponAnimAssoc->currentTime > delayBetweenAnimAndFire) + lastReloadWasInFuture = false; + + m_ped_flagA4 = lastReloadWasInFuture; } void @@ -1272,25 +1276,26 @@ CPed::Duck(void) void CPed::ClearDuck(void) { - CAnimBlendAssociation *animAssoc; + CAnimBlendAssociation* animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_DUCK_DOWN); + if (!animAssoc) { + animAssoc = RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_DUCK_LOW); - animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_DUCK_DOWN); - if (!animAssoc) - animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_DUCK_LOW); + if (!animAssoc) { + bIsDucking = false; + return; + } + } - if (animAssoc) { + if (!bCrouchWhenShooting) + return; - if (bCrouchWhenShooting) { + if (m_nPedState != PED_ATTACK && m_nPedState != PED_AIM_GUN) + return; - if (m_nPedState == PED_ATTACK || m_nPedState == PED_AIM_GUN) { - animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_RBLOCK_CSHOOT); - if (!animAssoc || animAssoc->blendDelta < 0.0f) { - CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ANIM_RBLOCK_CSHOOT, 4.0f); - } - } - } - } else - bIsDucking = false; + animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_RBLOCK_CSHOOT); + if (!animAssoc || animAssoc->blendDelta < 0.0f) { + CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ANIM_RBLOCK_CSHOOT, 4.0f); + } } void @@ -1404,7 +1409,7 @@ CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg) if (vehicle->pDriver == ped) { vehicle->RemoveDriver(); - if (vehicle->m_nDoorLock == CARLOCK_COP_CAR) + if (vehicle->m_nDoorLock == CARLOCK_LOCKED_INITIALLY) vehicle->m_nDoorLock = CARLOCK_UNLOCKED; if (ped->m_nPedType == PEDTYPE_COP && vehicle->IsLawEnforcementVehicle()) @@ -1456,7 +1461,7 @@ CPed::GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enter seatOffset = 0.0f; vehDoorOffset = offsetToOpenVanDoor; } else { - seatOffset = veh->m_handling->fSeatOffsetDistance * seatPosMult; + seatOffset = veh->pHandling->fSeatOffsetDistance * seatPosMult; if (veh->bLowVehicle) { vehDoorOffset = offsetToOpenLowCarDoor; } else { @@ -1559,7 +1564,7 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) if (CReplay::IsPlayingBack()) return; - if (!m_ped_flagC8 && phase != LINE_UP_TO_CAR_2) { + if (!bChangedSeat && phase != LINE_UP_TO_CAR_2) { if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_SIT)) { SetPedPositionInCar(); return; @@ -1576,7 +1581,7 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) SetPedPositionInCar(); return; } - m_ped_flagC8 = 1; + bChangedSeat = true; } if (phase == LINE_UP_TO_CAR_START) { m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); @@ -1739,10 +1744,10 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) float limitedAngle = CGeneral::LimitRadianAngle(m_fRotationDest); float timeUntilStateChange = (m_nPedStateTimer - CTimer::GetTimeInMilliseconds())/600.0f; - m_vecOffsetSeek.z = 0.0; + m_vecOffsetSeek.z = 0.0f; if (timeUntilStateChange <= 0.0f) { - m_vecOffsetSeek.x = 0.0; - m_vecOffsetSeek.y = 0.0; + m_vecOffsetSeek.x = 0.0f; + m_vecOffsetSeek.y = 0.0f; } else { neededPos -= timeUntilStateChange * m_vecOffsetSeek; } @@ -1911,7 +1916,7 @@ CPed::PlayFootSteps(void) bool CPed::IsPointerValid(void) { - int8 pedIndex = CPools::GetPedPool()->GetIndex(this) >> 8; + int pedIndex = CPools::GetPedPool()->GetIndex(this) >> 8; if (pedIndex < 0 || pedIndex >= NUMPEDS) return false; @@ -1966,7 +1971,7 @@ CPed::BuildPedLists(void) static CPed *unsortedNearPeds[10]; uint16 nextNearPedSlot = 0; - if ((CTimer::GetFrameCounter() + m_randomSeed) & 15) { + if ((CTimer::GetFrameCounter() + m_randomSeed) % 16) { for(int i = 0; i < 10; ) { if (m_nearPeds[i]) { @@ -2261,7 +2266,7 @@ CPed::CanSeeEntity(CEntity *entity, float threshold) { float neededAngle = CGeneral::GetRadianAngleBetweenPoints( entity->GetPosition().x, - entity->GetPosition().x, + entity->GetPosition().y, GetPosition().x, GetPosition().y); @@ -2456,7 +2461,7 @@ CPed::SetObjective(eObjective newObj, void *entity) // In this special case, entity parameter isn't CEntity, but int. SetObjectiveTimer((int)entity); - return; + break; case OBJECTIVE_KILL_CHAR_ON_FOOT: case OBJECTIVE_KILL_CHAR_ANY_MEANS: case OBJECTIVE_MUG_CHAR: @@ -2467,7 +2472,7 @@ CPed::SetObjective(eObjective newObj, void *entity) m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); m_pLookTarget = (CEntity*)entity; m_pLookTarget->RegisterReference((CEntity**)&m_pLookTarget); - return; + break; case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: case OBJECTIVE_GOTO_CHAR_ON_FOOT: @@ -2475,18 +2480,26 @@ CPed::SetObjective(eObjective newObj, void *entity) m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f); m_pedInObjective = (CPed*)entity; m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); - return; + break; case OBJECTIVE_FOLLOW_PED_IN_FORMATION: m_pedInObjective = (CPed*)entity; m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); m_pedFormation = 1; - return; + break; case OBJECTIVE_LEAVE_VEHICLE: case OBJECTIVE_FLEE_CAR: m_carInObjective = (CVehicle*)entity; m_carInObjective->RegisterReference((CEntity **)&m_carInObjective); if (!m_carInObjective->bIsBus || m_leaveCarTimer) - return; + break; + + for (int i = 0; i < m_carInObjective->m_nNumMaxPassengers; i++) { + if (m_carInObjective->pPassengers[i] == this) { + m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 1200 * i; + break; + } + } + break; case OBJECTIVE_ENTER_CAR_AS_PASSENGER: case OBJECTIVE_ENTER_CAR_AS_DRIVER: @@ -2495,7 +2508,7 @@ CPed::SetObjective(eObjective newObj, void *entity) if (((CVehicle*)entity)->m_vehType == VEHICLE_TYPE_BOAT && !IsPlayer()) { RestorePreviousObjective(); - return; + break; } // fall through case OBJECTIVE_DESTROY_CAR: @@ -2509,24 +2522,18 @@ CPed::SetObjective(eObjective newObj, void *entity) if (newObj == OBJECTIVE_SOLICIT) { m_objectiveTimer = CTimer::GetTimeInMilliseconds() + 10000; } else if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == MISSION_CHAR && - (m_carInObjective->m_status == STATUS_PLAYER_DISABLED || CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls)) { + (m_carInObjective->m_status == STATUS_PLAYER_DISABLED || CPad::GetPad(CWorld::PlayerInFocus)->ArePlayerControlsDisabled())) { SetObjectiveTimer(14000); } else { m_objectiveTimer = 0; } - return; + break; case OBJECTIVE_SET_LEADER: SetLeader((CEntity*)entity); RestorePreviousObjective(); - return; + break; default: - return; - } - for (int i=0; i < m_carInObjective->m_nNumMaxPassengers; i++) { - if (m_carInObjective->pPassengers[i] == this) { - m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 1200 * i; - return; - } + break; } } @@ -2701,7 +2708,7 @@ CPed::QuitEnteringCar(void) if (veh->m_nNumGettingIn != 0) veh->m_nNumGettingIn--; - veh->m_nGettingInFlags = ~GetVehDoorFlag(m_vehEnterType); + veh->m_nGettingInFlags &= ~GetVehDoorFlag(m_vehEnterType); } bUsesCollision = true; @@ -2729,8 +2736,8 @@ CPed::QuitEnteringCar(void) m_pVehicleAnim = nil; if (veh) { - if (veh->m_autoPilot.m_nCruiseSpeed == 0) - veh->m_autoPilot.m_nCruiseSpeed = 17; + if (veh->AutoPilot.m_nCruiseSpeed == 0) + veh->AutoPilot.m_nCruiseSpeed = 17; } } @@ -2906,6 +2913,1203 @@ CPed::CheckAroundForPossibleCollisions(void) } } +bool +CPed::MakePhonecall(void) +{ + if (CTimer::GetTimeInMilliseconds() <= m_phoneTalkTimer) + return false; + + SetIdle(); + gPhoneInfo.m_aPhones[m_phoneId].m_nState = PHONE_STATE_FREE; + m_phoneId = -1; + return true; +} + +bool +CPed::FacePhone(void) +{ + // FIX: I don't think this function was working correctly, they confused LimitAngle with LimitRadianAngle etc., so I fixed them + float currentRot = m_fRotationCur; + float phoneDir = CGeneral::GetRadianAngleBetweenPoints( + gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.x, + gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.y, + GetPosition().x, + GetPosition().y); + + SetLookFlag(phoneDir, 0); + + phoneDir = CGeneral::LimitRadianAngle(phoneDir); + m_moved = CVector2D(0.0f, 0.0f); + + if (currentRot - PI > phoneDir) + phoneDir += 2 * PI; + else if (PI + currentRot < phoneDir) + phoneDir -= 2 * PI; + + float neededTurn = currentRot - phoneDir; + + if (Abs(neededTurn) <= 0.75f) { + SetIdle(); + ClearLookFlag(); + m_phoneTalkTimer = CTimer::GetTimeInMilliseconds() + 10000; + return true; + } else { + m_fRotationCur -= neededTurn * 0.2f; + return false; + } +} + +CPed * +CPed::CheckForDeadPeds(void) +{ + int event; + if (CEventList::FindClosestEvent(EVENT_DEAD_PED, GetPosition(), &event)) { + int pedHandle = gaEvent[event].entityRef; + if (pedHandle && gaEvent[event].entityType == EVENT_ENTITY_PED) { + m_ped_flagD2 = true; + return CPools::GetPed(pedHandle); + } + } + m_ped_flagD2 = false; + return nil; +} + +bool +CPed::CheckForExplosions(CVector2D &area) +{ + int event = 0; + if (CEventList::FindClosestEvent(EVENT_EXPLOSION, GetPosition(), &event)) { + area.x = gaEvent[event].posn.x; + area.y = gaEvent[event].posn.y; + CEntity *actualEntity = nil; + + switch (gaEvent[event].entityType) { + case EVENT_ENTITY_PED: + actualEntity = CPools::GetPed(gaEvent[event].entityRef); + break; + case EVENT_ENTITY_VEHICLE: + actualEntity = CPools::GetVehicle(gaEvent[event].entityRef); + break; + case EVENT_ENTITY_OBJECT: + actualEntity = CPools::GetObject(gaEvent[event].entityRef); + break; + default: + break; + } + + if (actualEntity) { + m_pEventEntity = actualEntity; + m_pEventEntity->RegisterReference((CEntity **) &m_pEventEntity); + m_ped_flagD2 = true; + } else + m_ped_flagD2 = false; + + CEventList::ClearEvent(event); + return true; + } else if (CEventList::FindClosestEvent(EVENT_FIRE, GetPosition(), &event)) { + area.x = gaEvent[event].posn.x; + area.y = gaEvent[event].posn.y; + CEventList::ClearEvent(event); + m_ped_flagD2 = false; + return true; + } + + m_ped_flagD2 = false; + return false; +} + +CPed * +CPed::CheckForGunShots(void) +{ + int event; + if (CEventList::FindClosestEvent(EVENT_GUNSHOT, GetPosition(), &event)) { + int pedHandle = gaEvent[event].entityRef; + if (pedHandle && gaEvent[event].entityType == EVENT_ENTITY_PED) { + // Is that a bug?!? + m_ped_flagD2 = false; + return CPools::GetPed(pedHandle); + } + } + m_ped_flagD2 = false; + return nil; +} + +uint8 +CPed::CheckForPointBlankPeds(CPed *pedToVerify) +{ + float pbDistance = 1.1f; + if (GetWeapon()->IsType2Handed()) + pbDistance = 1.6f; + + for(int i=0; i<m_numNearPeds; i++) { + CPed *nearPed = m_nearPeds[i]; + + if (!pedToVerify || pedToVerify == nearPed) { + + CVector diff = nearPed->GetPosition() - GetPosition(); + if (diff.Magnitude() < pbDistance) { + + float neededAngle = CGeneral::GetRadianAngleBetweenPoints( + nearPed->GetPosition().x, nearPed->GetPosition().y, + GetPosition().x, GetPosition().y); + neededAngle = CGeneral::LimitRadianAngle(neededAngle); + m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); + + float neededTurn = Abs(neededAngle - m_fRotationCur); + + if (neededTurn > PI) + neededTurn = 2*PI - neededTurn; + + PedState nearPedState = nearPed->m_nPedState; + + if (nearPedState == PED_FALL || nearPedState == PED_GETUP || nearPedState == PED_DIE || nearPedState == PED_DEAD || nearPedState == PED_DIVE_AWAY) + return 0; + + if (neededTurn < DEGTORAD(60.0f)) { + if (pedToVerify == nearPed) + return 1; + else + return 2; + } + } + } + } + return 0; +} + +bool +CPed::CheckIfInTheAir(void) +{ + if (bInVehicle) + return false; + + CVector pos = GetPosition(); + CColPoint foundColPoint; + CEntity *foundEntity; + + float startZ = pos.z - 1.54f; + bool foundGround = CWorld::ProcessVerticalLine(pos, startZ, foundColPoint, foundEntity, true, true, false, true, false, false, false); + if (!foundGround && m_nPedState != PED_JUMP) + { + pos.z -= 1.04f; + if (CWorld::TestSphereAgainstWorld(pos, 0.15f, this, true, false, false, false, false, false)) + foundGround = true; + } + return !foundGround; +} + +void +CPed::ClearAll(void) +{ + if (!IsPedInControl() && m_nPedState != PED_DEAD) + return; + + m_nPedState = PED_NONE; + m_nMoveState = PEDMOVE_NONE; + m_pSeekTarget = nil; + m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f); + m_fleeFromPosX = 0.0f; + m_fleeFromPosY = 0.0f; + m_fleeFrom = nil; + m_fleeTimer = 0; + bUsesCollision = true; + ClearAimFlag(); + ClearLookFlag(); + bIsPointingGunAt = false; + bRenderPedInCar = true; + m_ped_flagH1 = false; + m_pCollidingEntity = nil; +} + +void +CPed::ClearAttack(void) +{ + if (m_nPedState != PED_ATTACK || bIsDucking || m_nWaitState == WAITSTATE_PLAYANIM_DUCK) + return; + + if (bIsPointingGunAt) { + if (m_pLookTarget) + SetPointGunAt(m_pLookTarget); + else + ClearPointGunAt(); + } else if (m_objective != OBJECTIVE_NONE) { + SetIdle(); + } else { + RestorePreviousState(); + } +} + +void +CPed::ClearAttackByRemovingAnim(void) +{ + if (m_nPedState != PED_ATTACK || bIsDucking) + return; + + CWeaponInfo *weapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + CAnimBlendAssociation *weaponAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, weapon->m_AnimToPlay); + if (!weaponAssoc) { + weaponAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, weapon->m_Anim2ToPlay); + + if (!weaponAssoc && weapon->m_bThrow) + weaponAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_WEAPON_THROWU); + + if (!weaponAssoc) { + ClearAttack(); + return; + } + } + weaponAssoc->blendDelta = -8.0f; + weaponAssoc->flags &= ~ASSOC_RUNNING; + weaponAssoc->flags |= ASSOC_DELETEFADEDOUT; + weaponAssoc->SetDeleteCallback(FinishedAttackCB, this); +} + +void +CPed::StopNonPartialAnims(void) +{ + CAnimBlendAssociation* assoc; + + for (assoc = RpAnimBlendClumpGetFirstAssociation((RpClump*)m_rwObject); assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { + if (!assoc->IsPartial()) + assoc->flags &= ~ASSOC_RUNNING; + } +} + +void +CPed::SetStoredState(void) +{ + if (m_nLastPedState != PED_NONE || !CanPedReturnToState()) + return; + + if (m_nPedState == PED_WANDER_PATH) { + m_ped_flagC80 = true; + if (m_nMoveState == PEDMOVE_NONE || m_nMoveState == PEDMOVE_STILL) + m_nMoveState = PEDMOVE_WALK; + } + m_nLastPedState = m_nPedState; + if (m_nMoveState >= m_nPrevActionState) + m_nPrevActionState = m_nMoveState; +} + +void +CPed::SetDie(AnimationId animId, float delta, float speed) +{ + CPlayerPed *player = FindPlayerPed(); + if (player == this) { + if (!player->m_bCanBeDamaged) + return; + } + + m_threatEntity = nil; + if (m_nPedState == PED_DIE || m_nPedState == PED_DEAD) + return; + + if (m_nPedState == PED_FALL || m_nPedState == PED_GETUP) + delta *= 0.5f; + + SetStoredState(); + ClearAll(); + m_fHealth = 0.0f; + if (m_nPedState == PED_DRIVING) { + if (!IsPlayer()) + FlagToDestroyWhenNextProcessed(); + } else if (bInVehicle) { + if (m_pVehicleAnim) + m_pVehicleAnim->blendDelta = -1000.0f; + } else if (m_nPedState == PED_ENTER_CAR || m_nPedState == PED_CARJACK) { + QuitEnteringCar(); + } + + m_nPedState = PED_DIE; + if (animId == NUM_ANIMS) { + bIsPedDieAnimPlaying = false; + } else { + CAnimBlendAssociation *dieAssoc = CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, animId, delta); + if (speed > 0.0f) + dieAssoc->speed = speed; + + dieAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; + if (dieAssoc->IsRunning()) { + dieAssoc->SetFinishCallback(FinishDieAnimCB, this); + bIsPedDieAnimPlaying = true; + } + } + + Say(SOUND_PED_DEATH); + if (m_nLastPedState == PED_ENTER_CAR || m_nLastPedState == PED_CARJACK) + QuitEnteringCar(); + if (!bInVehicle) + StopNonPartialAnims(); + + // ??? + m_bloodyFootprintCount = CTimer::GetTimeInMilliseconds(); +} + +bool +CPed::InflictDamage(CEntity* damagedBy, eWeaponType method, float damage, ePedPieceTypes pedPiece, uint8 direction) +{ + CPlayerPed *player = FindPlayerPed(); + float dieDelta = 4.0f; + float dieSpeed = 0.0f; + AnimationId dieAnim = ANIM_KO_SHOT_FRONT1; + bool headShot = false; + bool willLinger = false; + int random; + + if (player == this) { + if (!player->m_bCanBeDamaged) + return false; + + player->AnnoyPlayerPed(false); + } + + if (m_nPedState == PED_DIE || m_nPedState == PED_DEAD) + return false; + + if (!bUsesCollision && method != WEAPONTYPE_WATER) + return false; + + if (bOnlyDamagedByPlayer && damagedBy != player && damagedBy != FindPlayerVehicle() && + method != WEAPONTYPE_WATER && method != WEAPONTYPE_EXPLOSION) + return false; + + float healthImpact; + if (IsPlayer()) + healthImpact = damage * 0.33f; + else + healthImpact = damage * m_pedStats->m_defendWeakness; + + bool detectDieAnim = true; + if (m_nPedState == PED_FALL || m_nPedState == PED_GETUP) { + if (!IsPedHeadAbovePos(-0.3f)) { + if (RpAnimBlendClumpGetFirstAssociation((RpClump*) m_rwObject, ASSOC_FLAG800)) + dieAnim = ANIM_FLOOR_HIT_F; + else + dieAnim = ANIM_FLOOR_HIT; + dieDelta *= 2.0f; + dieSpeed = 0.5f; + detectDieAnim = false; + } else if (m_nPedState == PED_FALL) { + dieAnim = NUM_ANIMS; + detectDieAnim = false; + } + } + if (detectDieAnim) { + switch (method) { + case WEAPONTYPE_UNARMED: + if (bMeleeProof) + return false; + + if (m_nPedState == PED_FALL) { + if (IsPedHeadAbovePos(-0.3f)) { + dieAnim = NUM_ANIMS; + } else { + if (RpAnimBlendClumpGetFirstAssociation((RpClump*) m_rwObject, ASSOC_FLAG800)) + dieAnim = ANIM_FLOOR_HIT_F; + else + dieAnim = ANIM_FLOOR_HIT; + dieDelta = dieDelta * 2.0f; + dieSpeed = 0.5f; + } + } else { + switch (direction) { + case 0: + dieAnim = ANIM_KO_SKID_FRONT; + break; + case 1: + dieAnim = ANIM_KO_SPIN_R; + break; + case 2: + dieAnim = ANIM_KO_SKID_BACK; + break; + case 3: + dieAnim = ANIM_KO_SPIN_L; + break; + default: + break; + } + } + break; + case WEAPONTYPE_BASEBALLBAT: + if (bMeleeProof) + return false; + + if (m_nPedState == PED_FALL) { + if (IsPedHeadAbovePos(-0.3f)) { + dieAnim = NUM_ANIMS; + } else { + if (RpAnimBlendClumpGetFirstAssociation((RpClump*) m_rwObject, 0x800u)) + dieAnim = ANIM_FLOOR_HIT_F; + else + dieAnim = ANIM_FLOOR_HIT; + dieDelta = dieDelta * 2.0f; + dieSpeed = 0.5f; + } + } else { + switch (direction) { + case 0: + dieAnim = ANIM_KO_SKID_FRONT; + break; + case 1: + dieAnim = ANIM_KO_SPIN_R; + break; + case 2: + dieAnim = ANIM_KO_SKID_BACK; + break; + case 3: + dieAnim = ANIM_KO_SPIN_L; + break; + default: + break; + } + } + break; + case WEAPONTYPE_COLT45: + case WEAPONTYPE_UZI: + case WEAPONTYPE_SHOTGUN: + case WEAPONTYPE_AK47: + case WEAPONTYPE_M16: + case WEAPONTYPE_SNIPERRIFLE: + if (bBulletProof) + return false; + + bool dontRemoveLimb; + if (IsPlayer() || m_ped_flagI2) + dontRemoveLimb = true; + else { + switch (method) + { + case WEAPONTYPE_SNIPERRIFLE: + dontRemoveLimb = false; + break; + case WEAPONTYPE_M16: + dontRemoveLimb = false; + break; + case WEAPONTYPE_SHOTGUN: + dontRemoveLimb = CGeneral::GetRandomNumberInRange(0,7); + break; + default: + dontRemoveLimb = CGeneral::GetRandomNumberInRange(0,15); + break; + } + } + + if (dontRemoveLimb) { + if (method == WEAPONTYPE_SHOTGUN) { + switch (direction) { + case 0: + dieAnim = ANIM_KO_SKID_FRONT; + break; + case 1: + dieAnim = ANIM_KO_SPIN_R; + break; + case 2: + dieAnim = ANIM_KO_SKID_BACK; + break; + case 3: + dieAnim = ANIM_KO_SPIN_L; + break; + default: + break; + } + } else + dieAnim = ANIM_KO_SHOT_FRONT1; + + willLinger = false; + } else { + switch (pedPiece) { + case PEDPIECE_TORSO: + willLinger = false; + dieAnim = ANIM_KO_SHOT_FRONT1; + break; + case PEDPIECE_MID: + willLinger = false; + dieAnim = ANIM_KO_SHOT_STOM; + break; + case PEDPIECE_LEFTARM: + dieAnim = ANIM_KO_SHOT_ARML; + RemoveBodyPart(PED_UPPERARML, direction); + willLinger = true; + break; + case PEDPIECE_RIGHTARM: + dieAnim = ANIM_KO_SHOT_ARMR; + RemoveBodyPart(PED_UPPERARMR, direction); + willLinger = true; + break; + case PEDPIECE_LEFTLEG: + dieAnim = ANIM_KO_SHOT_LEGL; + RemoveBodyPart(PED_UPPERLEGL, direction); + willLinger = true; + break; + case PEDPIECE_RIGHTLEG: + dieAnim = ANIM_KO_SHOT_LEGR; + RemoveBodyPart(PED_UPPERLEGR, direction); + willLinger = true; + break; + case PEDPIECE_HEAD: + dieAnim = ANIM_KO_SHOT_FACE; + RemoveBodyPart(PED_HEAD, direction); + headShot = true; + willLinger = true; + break; + default: + break; + } + } + break; + case WEAPONTYPE_ROCKETLAUNCHER: + case WEAPONTYPE_GRENADE: + case WEAPONTYPE_EXPLOSION: + if (bExplosionProof) + return false; + + if (CGame::nastyGame && !IsPlayer() && !bInVehicle && + 1.0f + healthImpact > m_fArmour + m_fHealth) { + + random = CGeneral::GetRandomNumber(); + if (random & 1) + RemoveBodyPart(PED_UPPERARML, direction); + if (random & 2) + RemoveBodyPart(PED_UPPERLEGR, direction); + if (random & 4) + RemoveBodyPart(PED_HEAD, direction); + if (random & 8) + RemoveBodyPart(PED_UPPERARMR, direction); + if (random & 0x10) + RemoveBodyPart(PED_UPPERLEGL, direction); + if (bBodyPartJustCameOff) + willLinger = true; + } + // fall through + case WEAPONTYPE_MOLOTOV: + if (bExplosionProof) + return false; + + switch (direction) { + case 0: + dieAnim = ANIM_KO_SKID_FRONT; + break; + case 1: + dieAnim = ANIM_KO_SPIN_R; + break; + case 2: + dieAnim = ANIM_KO_SKID_BACK; + break; + case 3: + dieAnim = ANIM_KO_SPIN_L; + break; + default: + break; + } + break; + case WEAPONTYPE_FLAMETHROWER: + if (bFireProof) + return false; + + dieAnim = ANIM_KO_SHOT_FRONT1; + break; + case WEAPONTYPE_RAMMEDBYCAR: + case WEAPONTYPE_RUNOVERBYCAR: + if (bCollisionProof) + return false; + + random = CGeneral::GetRandomNumberInRange(0, 3); + switch (random) { + case 0: + if ((pedPiece != PEDPIECE_LEFTARM || random <= 1) + && (pedPiece != PEDPIECE_MID || random != 1)) { + if (pedPiece == PEDPIECE_RIGHTARM && random > 1 + || pedPiece == PEDPIECE_MID && random == 2) + + dieAnim = ANIM_KO_SPIN_L; + else + dieAnim = ANIM_KO_SKID_FRONT; + } else + dieAnim = ANIM_KO_SPIN_R; + + break; + case 1: + if (m_nPedState == PED_DIVE_AWAY) + dieAnim = ANIM_KD_LEFT; + else + dieAnim = ANIM_KO_SPIN_R; + break; + case 2: + if ((pedPiece != PEDPIECE_LEFTARM || random <= 1) + && (pedPiece != PEDPIECE_MID || random != 1)) { + if ((pedPiece != PEDPIECE_RIGHTARM || random <= 1) + && (pedPiece != PEDPIECE_MID || random != 2)) { + dieAnim = ANIM_KO_SKID_BACK; + } else { + dieAnim = ANIM_KD_RIGHT; + } + } else + dieAnim = ANIM_KD_LEFT; + break; + case 3: + if (m_nPedState == PED_DIVE_AWAY) + dieAnim = ANIM_KD_RIGHT; + else + dieAnim = ANIM_KO_SPIN_L; + break; + default: + break; + } + if (damagedBy) { + CVehicle *vehicle = (CVehicle*)damagedBy; + if (method == WEAPONTYPE_RAMMEDBYCAR) { + float vehSpeed = vehicle->m_vecMoveSpeed.Magnitude(); + dieDelta = 8.0f * vehSpeed + 4.0f; + } else { + float vehSpeed = vehicle->m_vecMoveSpeed.Magnitude(); + dieDelta = 12.0f * vehSpeed + 4.0f; + dieSpeed = 16.0f * vehSpeed + 1.0f; + } + } + break; + case WEAPONTYPE_WATER: + dieAnim = ANIM_DROWN; + break; + case WEAPONTYPE_FALL_DAMAGE: + if (bCollisionProof) + return false; + + switch (direction) { + case 0: + dieAnim = ANIM_KO_SKID_FRONT; + break; + case 1: + dieAnim = ANIM_KO_SPIN_R; + break; + case 2: + dieAnim = ANIM_KO_SKID_BACK; + break; + case 3: + dieAnim = ANIM_KO_SPIN_L; + break; + default: + break; + } + break; + default: + break; + } + } + + if (m_fArmour != 0.0f && method != WEAPONTYPE_WATER) { + if (player == this) + CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastArmourLoss = CTimer::GetTimeInMilliseconds(); + + if (healthImpact < m_fArmour) { + m_fArmour = m_fArmour - healthImpact; + healthImpact = 0.0f; + } else { + healthImpact = healthImpact - m_fArmour; + m_fArmour = 0.0f; + } + } + + if (healthImpact != 0.0f) { + if (player == this) + CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss = CTimer::GetTimeInMilliseconds(); + + m_lastWepDam = method; + } + + if (m_fHealth - healthImpact >= 1.0f && !willLinger) { + m_fHealth -= healthImpact; + return false; + } + + if (bInVehicle) { + if (method != WEAPONTYPE_WATER) { + m_fHealth = 1.0f; + return false; + } + m_fHealth = 0.0f; + if (player == this) + m_pMyVehicle->m_status = STATUS_PLAYER_DISABLED; + + SetDie(NUM_ANIMS, 4.0f, 0.0f); + return true; + } else { + m_fHealth = 0.0f; + SetDie(dieAnim, dieDelta, dieSpeed); + + if (damagedBy == player || damagedBy && damagedBy == FindPlayerVehicle()) { + CDarkel::RegisterKillByPlayer(this, method, headShot); + m_threatEntity = player; + } else { + CDarkel::RegisterKillNotByPlayer(this, method); + } + // WAT? + if (method == WEAPONTYPE_WATER) + bIsInTheAir = false; + + return true; + } +} + +void +CPed::ClearFlee(void) +{ + RestorePreviousState(); + m_ped_flagD20 = false; + m_standardTimer = 0; + m_fleeTimer = 0; +} + +void +CPed::ClearFall(void) +{ + SetGetUp(); +} + +void +CPed::SetGetUp(void) +{ + if (m_nPedState == PED_GETUP && m_ped_flagE20) + return; + + if (!CanSetPedState()) + return; + + if (m_fHealth >= 1.0f || IsPedHeadAbovePos(-0.3f)) { + if (m_ped_flagC10) { + m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); + m_fRotationCur -= 0.5*PI; + m_ped_flagC10 = false; + } + if (m_nPedState != PED_GETUP) { + SetStoredState(); + m_nPedState = PED_GETUP; + } + + CVehicle* collidingVeh = (CVehicle*)m_pCollidingEntity; + CVehicle *veh = (CVehicle*)CPedPlacement::IsPositionClearOfCars(&GetPosition()); + if (veh && veh->m_vehType != VEHICLE_TYPE_BIKE || + collidingVeh && collidingVeh->IsVehicle() && collidingVeh->m_vehType != VEHICLE_TYPE_BIKE + && ((CTimer::GetFrameCounter() + m_randomSeed % 256 + 5) % 8 + || CCollision::ProcessColModels(GetMatrix(), *CModelInfo::GetModelInfo(m_modelIndex)->GetColModel(), + collidingVeh->GetMatrix(), *CModelInfo::GetModelInfo(collidingVeh->m_modelIndex)->GetColModel(), + &ms_tempColPoint, nil, nil) > 0)) { + + m_ped_flagE20 = false; + if (IsPlayer()) + InflictDamage(nil, WEAPONTYPE_RUNOVERBYCAR, CTimer::GetTimeStep(), PEDPIECE_TORSO, 0); + else { + if (!CPad::GetPad(0)->ArePlayerControlsDisabled()) + return; + + InflictDamage(nil, WEAPONTYPE_RUNOVERBYCAR, 1000.0f, PEDPIECE_TORSO, 0); + } + return; + } + m_ped_flagE20 = true; + m_pCollidingEntity = nil; + m_ped_flagH1 = false; + CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_SPRINT); + if (animAssoc) { + if (RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_RUN)) { + CAnimManager::BlendAnimation((RpClump*) m_rwObject, m_animGroup, ANIM_RUN, 8.0f); + } else { + CAnimManager::BlendAnimation((RpClump*) m_rwObject, m_animGroup, ANIM_IDLE_STANCE, 8.0f); + } + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + + if (RpAnimBlendClumpGetFirstAssociation((RpClump*) m_rwObject, ASSOC_FLAG800)) + animAssoc = CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ANIM_GETUP_FRONT, 1000.0f); + else + animAssoc = CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ANIM_GETUP1, 1000.0f); + + animAssoc->SetFinishCallback(PedGetupCB,this); + } else { + m_fHealth = 0.0f; + SetDie(NUM_ANIMS, 4.0f, 0.0f); + } +} + +void +CPed::ClearInvestigateEvent(void) +{ + CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_ROAD_CROSS); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_XPRESS_SCRATCH); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_HBHB); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_CHAT); + if (animAssoc) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + if (m_eventType > EVENT_EXPLOSION) + m_standardTimer = CTimer::GetTimeInMilliseconds() + 15000; + + m_ped_flagD2 = false; + m_pEventEntity = nil; + ClearLookFlag(); + RestorePreviousState(); + if(m_nMoveState == PEDMOVE_NONE || m_nMoveState == PEDMOVE_STILL) + SetMoveState(PEDMOVE_WALK); +} + +void +CPed::ClearLeader(void) +{ + if (!m_leader) + return; + + m_leader = nil; + if (IsPedInControl()) { + SetObjective(OBJECTIVE_NONE); + if (CharCreatedBy == MISSION_CHAR) { + SetIdle(); + } else { + SetWanderPath(CGeneral::GetRandomNumberInRange(0,8)); + } + } else if (m_objective != OBJECTIVE_NONE) { + m_ped_flagH8 = true; + } +} + +void +CPed::ClearLook(void) +{ + RestorePreviousState(); + ClearLookFlag(); +} + +void +CPed::ClearObjective(void) +{ + if (IsPedInControl() || m_nPedState == PED_DRIVING) { + + m_objective = OBJECTIVE_NONE; + if (m_nPedState == PED_DRIVING && m_pMyVehicle) { + + if (m_pMyVehicle->pDriver != this) { + + m_ped_flagF1 = true; + SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); + } + } else { + SetIdle(); + SetMoveState(PEDMOVE_STILL); + } + } else { + m_ped_flagH8 = true; + } +} + +void +CPed::ClearPause(void) +{ + RestorePreviousState(); +} + +void +CPed::ClearSeek(void) +{ + SetIdle(); + field_31C = 0; +} + +bool +CPed::SetWanderPath(int8 pathStateDest) +{ + uint8 nextPathState; + + if (IsPedInControl()) { + if (m_ped_flagE1) { + SetIdle(); + return false; + } else { + + // m_nPathState is pure direction for values 1,2,3 and 5,6,7 + + m_nPathState = pathStateDest; + if (pathStateDest == 0) + pathStateDest = CGeneral::GetRandomNumberInRange(1, 7); + + ThePaths.FindNextNodeWandering(1, GetPosition(), &m_pNextPathNode, &m_pLastPathNode, + m_nPathState, &nextPathState); + + // Circular loop until we find a node for current m_nPathState + while (!m_pLastPathNode) { + m_nPathState = (m_nPathState+1) % 8; + + // We're at where we started and couldn't find any node + if (m_nPathState == pathStateDest) { + ClearAll(); + SetIdle(); + return false; + } + ThePaths.FindNextNodeWandering(1, GetPosition(), &m_pNextPathNode, &m_pLastPathNode, + m_nPathState, &nextPathState); + } + + // We did it, save next path state and return true + m_nPathState = nextPathState; + m_nPedState = PED_WANDER_PATH; + SetMoveState(PEDMOVE_WALK); + m_ped_flagB20 = false; + return true; + } + } else { + m_nPathState = pathStateDest; + m_ped_flagG8 = true; + return false; + } +} + +void +CPed::ClearWeapons(void) +{ + CWeaponInfo *currentWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + RemoveWeaponModel(currentWeapon->m_nModelId); + + m_maxWeaponTypeAllowed = WEAPONTYPE_BASEBALLBAT; + m_currentWeapon = WEAPONTYPE_UNARMED; + + currentWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + AddWeaponModel(currentWeapon->m_nModelId); + for(int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++) + { + CWeapon &weapon = GetWeapon(i); + weapon.m_eWeaponType = WEAPONTYPE_UNARMED; + weapon.m_eWeaponState = WEAPONSTATE_READY; + weapon.m_nAmmoInClip = 0; + weapon.m_nAmmoTotal = 0; + weapon.m_nTimer = 0; + } +} + +void +CPed::RestoreGunPosition(void) +{ + if (bIsLooking) { + m_pedIK.m_flags &= ~CPedIK::FLAG_2; + bIsRestoringGun = false; + } else if (m_pedIK.RestoreGunPosn()) { + bIsRestoringGun = false; + } else { + if (IsPlayer()) + ((CPlayerPed*)this)->m_fFPSMoveHeading = 0.0f; + } +} + +void +CPed::RestoreHeadingRate(void) +{ + m_headingRate = m_pedStats->m_headingChangeRate; +} + +void +CPed::RestoreHeadingRateCB(CAnimBlendAssociation* assoc, void* arg) +{ + ((CPed*)arg)->m_headingRate = ((CPed*)arg)->m_pedStats->m_headingChangeRate; +} + +void +CPed::RestorePreviousState(void) +{ + if(!CanSetPedState() || m_nPedState == PED_FALL) + return; + + if (m_nPedState == PED_GETUP && !m_ped_flagE20) + return; + + if (bInVehicle && m_pMyVehicle) { + m_nPedState = PED_DRIVING; + m_nLastPedState = PED_NONE; + } else { + if (m_nLastPedState == PED_NONE) { + if (!IsPlayer() && CharCreatedBy != MISSION_CHAR && m_objective == OBJECTIVE_NONE) { + if (SetWanderPath(CGeneral::GetRandomNumberInRange(0, 7)) != 0) + return; + } + SetIdle(); + return; + } + + switch (m_nLastPedState) { + case PED_IDLE: + SetIdle(); + break; + case PED_WANDER_PATH: + m_nPedState = PED_WANDER_PATH; + m_ped_flagB20 = false; + if (!m_ped_flagC80) { + if (m_pLastPathNode) { + CVector diff = m_pLastPathNode->pos - GetPosition(); + if (diff.MagnitudeSqr() < 49.0f) { + SetMoveState(PEDMOVE_WALK); + break; + } + } + } + SetWanderPath(CGeneral::GetRandomNumberInRange(0, 7)); + break; + default: + m_nPedState = m_nLastPedState; + SetMoveState((eMoveState) m_nPrevActionState); + break; + } + m_nLastPedState = PED_NONE; + } +} + +void +CPed::SetAimFlag(CEntity *to) +{ + bIsAimingGun = true; + bIsRestoringGun = false; + m_pLookTarget = to; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + m_pSeekTarget = to; + m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); + m_lookTimer = 0; +} + +void +CPed::SetAimFlag(float angle) +{ + bIsAimingGun = true; + bIsRestoringGun = false; + m_fLookDirection = angle; + m_lookTimer = 0; + m_pLookTarget = nil; + m_pSeekTarget = nil; + if (CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bCanAimWithArm) + m_pedIK.m_flags |= CPedIK::FLAG_4; + else + m_pedIK.m_flags &= ~CPedIK::FLAG_4; +} + +void +CPed::SetPointGunAt(CEntity *to) +{ + if (to) { + SetLookFlag(to,1); + SetAimFlag(to); + } + + if (m_nPedState == PED_AIM_GUN || bIsDucking || m_nWaitState == WAITSTATE_PLAYANIM_DUCK) + return; + + if (m_nPedState != PED_ATTACK) + SetStoredState(); + + m_nPedState = PED_AIM_GUN; + bIsPointingGunAt = true; + CWeaponInfo *curWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + SetMoveState(PEDMOVE_NONE); + + CAnimBlendAssociation *aimAssoc; + + if (bCrouchWhenShooting) + aimAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, curWeapon->m_Anim2ToPlay); + else + aimAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, curWeapon->m_AnimToPlay); + + if (!aimAssoc || aimAssoc->blendDelta < 0.0f) { + if (bCrouchWhenShooting) + aimAssoc = CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, curWeapon->m_Anim2ToPlay, 4.0f); + else + aimAssoc = CAnimManager::AddAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, curWeapon->m_AnimToPlay); + + aimAssoc->blendAmount = 0.0f; + aimAssoc->blendDelta = 8.0f; + } + if (to) + Say(SOUND_PED_ATTACK); +} + +void +CPed::SetAmmo(eWeaponType weaponType, uint32 ammo) +{ + if (HasWeapon(weaponType)) { + GetWeapon(weaponType).m_nAmmoTotal = ammo; + } else { + GetWeapon(weaponType).Initialise(weaponType, ammo); + m_maxWeaponTypeAllowed++; + } +} + +void +CPed::SetEvasiveStep(CEntity *reason, uint8 animType) +{ + AnimationId stepAnim; + + if (m_nPedState == PED_STEP_AWAY || !IsPedInControl() || ((IsPlayer() || !bRespondsToThreats) && animType == 0)) + return; + + float angleToFace = CGeneral::GetRadianAngleBetweenPoints( + reason->GetPosition().x, reason->GetPosition().y, + GetPosition().x, GetPosition().y); + angleToFace = CGeneral::LimitRadianAngle(angleToFace); + m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); + float neededTurn = Abs(angleToFace - m_fRotationCur); + bool vehPressedHorn = false; + + if (neededTurn > PI) + neededTurn = 2 * PI - neededTurn; + + CVehicle *veh = (CVehicle*)reason; + if (reason->IsVehicle() && veh->m_vehType == VEHICLE_TYPE_CAR) { + if (veh->m_nCarHornTimer) { + vehPressedHorn = true; + if (!IsPlayer()) + animType = 1; + } + } + if (neededTurn <= DEGTORAD(90.0f) || veh->m_modelIndex == MI_RCBANDIT || vehPressedHorn || animType != 0) { + SetLookFlag(veh, 1); + if (CGeneral::GetRandomNumberInRange(0,1) && veh->m_modelIndex != MI_RCBANDIT && animType == 0) { + stepAnim = ANIM_IDLE_TAXI; + } else { + + // I didn't get these things too much. + float vehDirection = CGeneral::GetRadianAngleBetweenPoints( + veh->m_vecMoveSpeed.x, veh->m_vecMoveSpeed.y, + 0.0f, 0.0f); + + float inversedAngleToFace = angleToFace + PI; + if (inversedAngleToFace > PI) + inversedAngleToFace -= 2*PI; + + neededTurn = inversedAngleToFace - vehDirection; + neededTurn = CGeneral::LimitRadianAngle(neededTurn); + if (neededTurn <= 0.0) + angleToFace = 0.5*PI + vehDirection; + else + angleToFace = vehDirection - 0.5*PI; + + if (animType == 2) + stepAnim = ANIM_HANDSCOWER; + else if (animType < 2) + stepAnim = ANIM_EV_STEP; + else + stepAnim = NUM_ANIMS; + } + if (!RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, stepAnim)) { + CAnimBlendAssociation *stepAssoc = CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, stepAnim, 8.0f); + stepAssoc->flags &= ~ASSOC_DELETEFADEDOUT; + stepAssoc->SetFinishCallback(PedEvadeCB, this); + + if (animType == 0) + Say(SOUND_PED_EVADE); + + m_fRotationCur = CGeneral::LimitRadianAngle(angleToFace); + ClearAimFlag(); + SetStoredState(); + m_nPedState = PED_STEP_AWAY; + } + } +} + WRAPPER void CPed::PedGetupCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE810); } WRAPPER void CPed::PedStaggerCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8D0); } WRAPPER void CPed::PedEvadeCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D36E0); } @@ -2921,6 +4125,8 @@ WRAPPER void CPed::SetInCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP( WRAPPER void CPed::PedSetOutCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8F0); } WRAPPER void CPed::PedAnimAlignCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DE130); } WRAPPER void CPed::PedAnimStepOutCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DF5C0); } +WRAPPER void CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation* dragAssoc, void* arg) { EAXJMP(0x4E2480); } +WRAPPER void CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation* dragAssoc, void* arg) { EAXJMP(0x4E2920); } WRAPPER void CPed::PedSetInTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E3290); } WRAPPER void CPed::PedSetOutTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E36E0); } WRAPPER void CPed::FinishFightMoveCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E9830); } @@ -2928,7 +4134,6 @@ WRAPPER void CPed::PedAnimDoorCloseRollingCB(CAnimBlendAssociation *assoc, void WRAPPER void CPed::FinishJumpCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D7A50); } WRAPPER void CPed::PedLandCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8A0); } WRAPPER void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4C6580); } -WRAPPER void CPed::RestoreHeadingRateCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D6550); } class CPed_ : public CPed { @@ -2999,4 +4204,38 @@ STARTPATCHES InjectHook(0x4D1390, &CPed::TurnBody, PATCH_JUMP); InjectHook(0x4D3AC0, &CPed::Chat, PATCH_JUMP); InjectHook(0x4D0490, &CPed::CheckAroundForPossibleCollisions, PATCH_JUMP); + InjectHook(0x4D3E20, &CPed::MakePhonecall, PATCH_JUMP); + InjectHook(0x4D3CC0, &CPed::FacePhone, PATCH_JUMP); + InjectHook(0x4D4860, &CPed::CheckForDeadPeds, PATCH_JUMP); + InjectHook(0x4D4650, &CPed::CheckForExplosions, PATCH_JUMP); + InjectHook(0x4D47D0, &CPed::CheckForGunShots, PATCH_JUMP); + InjectHook(0x4E6990, &CPed::CheckForPointBlankPeds, PATCH_JUMP); + InjectHook(0x4D0BE0, &CPed::CheckIfInTheAir, PATCH_JUMP); + InjectHook(0x4C7F20, &CPed::ClearAll, PATCH_JUMP); + InjectHook(0x4E6790, &CPed::ClearAttack, PATCH_JUMP); + InjectHook(0x4E67F0, &CPed::ClearAttackByRemovingAnim, PATCH_JUMP); + InjectHook(0x4D37D0, &CPed::SetDie, PATCH_JUMP); + InjectHook(0x4C5D50, &CPed::StopNonPartialAnims, PATCH_JUMP); + InjectHook(0x4C5DB0, &CPed::SetStoredState, PATCH_JUMP); + InjectHook(0x4EA420, &CPed::InflictDamage, PATCH_JUMP); + InjectHook(0x4D1EA0, &CPed::ClearFlee, PATCH_JUMP); + InjectHook(0x4D0BB0, &CPed::ClearFall, PATCH_JUMP); + InjectHook(0x4D0F20, &CPed::SetGetUp, PATCH_JUMP); + InjectHook(0x4D6550, &CPed::RestoreHeadingRateCB, PATCH_JUMP); + InjectHook(0x4C5E30, &CPed::RestorePreviousState, PATCH_JUMP); + InjectHook(0x4E5F70, &CPed::SetPointGunAt, PATCH_JUMP); + InjectHook(0x4D2750, &CPed::SetWanderPath, PATCH_JUMP); + InjectHook(0x4D30C0, &CPed::SetEvasiveStep, PATCH_JUMP); + InjectHook(0x4EA360, &CPed::ClearInvestigateEvent, PATCH_JUMP); + InjectHook(0x4D8E80, &CPed::ClearLeader, PATCH_JUMP); + InjectHook(0x4D1360, &CPed::ClearLook, PATCH_JUMP); + InjectHook(0x4D8DF0, &CPed::ClearObjective, PATCH_JUMP); + InjectHook(0x4D0970, &CPed::ClearPause, PATCH_JUMP); + InjectHook(0x4D1620, &CPed::ClearSeek, PATCH_JUMP); + InjectHook(0x4CFB70, &CPed::ClearWeapons, PATCH_JUMP); + InjectHook(0x4C6BB0, &CPed::RestoreGunPosition, PATCH_JUMP); + InjectHook(0x4D6540, &CPed::RestoreHeadingRate, PATCH_JUMP); + InjectHook(0x4C69E0, (void (CPed::*)(CEntity*)) &CPed::SetAimFlag, PATCH_JUMP); + InjectHook(0x4C6960, (void (CPed::*)(float)) &CPed::SetAimFlag, PATCH_JUMP); + InjectHook(0x4CFB20, &CPed::SetAmmo, PATCH_JUMP); ENDPATCHES diff --git a/src/peds/Ped.h b/src/peds/Ped.h index cd7d88af..7b8bc2ce 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -13,6 +13,17 @@ struct CPathNode; +enum ePedPieceTypes +{ + PEDPIECE_TORSO, + PEDPIECE_MID, + PEDPIECE_LEFTARM, + PEDPIECE_RIGHTARM, + PEDPIECE_LEFTLEG, + PEDPIECE_RIGHTLEG, + PEDPIECE_HEAD, +}; + enum eWaitState { WAITSTATE_FALSE, WAITSTATE_TRAFFIC_LIGHTS, @@ -196,28 +207,28 @@ public: uint8 m_ped_flagC1 : 1; uint8 bRespondsToThreats : 1; - uint8 m_ped_flagC4 : 1; // false when in bus, bRenderPedInCar? - uint8 m_ped_flagC8 : 1; - uint8 m_ped_flagC10 : 1; - uint8 m_ped_flagC20 : 1; // just left some body part? + uint8 bRenderPedInCar : 1; + uint8 bChangedSeat : 1; + uint8 m_ped_flagC10 : 1; // related with phone + uint8 bBodyPartJustCameOff : 1; uint8 m_ped_flagC40 : 1; uint8 m_ped_flagC80 : 1; uint8 m_ped_flagD1 : 1; - uint8 m_ped_flagD2 : 1; + uint8 m_ped_flagD2 : 1; // seen an event uint8 m_ped_flagD4 : 1; uint8 m_ped_flagD8 : 1; - uint8 m_ped_flagD10 : 1; + uint8 bIsPedDieAnimPlaying : 1; uint8 m_ped_flagD20 : 1; uint8 m_ped_flagD40 : 1; // reset when objective changes - uint8 m_ped_flagD80 : 1; + uint8 m_bScriptObjectiveCompleted : 1; uint8 m_ped_flagE1 : 1; uint8 m_ped_flagE2 : 1; uint8 bNotAllowedToDuck : 1; uint8 bCrouchWhenShooting : 1; uint8 bIsDucking : 1; // set if you don't want ped to attack - uint8 m_ped_flagE20 : 1; + uint8 m_ped_flagE20 : 1; // getup complete? uint8 bDoBloodyFootprints : 1; uint8 m_ped_flagE80 : 1; @@ -225,7 +236,7 @@ public: uint8 m_ped_flagF2 : 1; uint8 m_ped_flagF4 : 1; uint8 m_ped_flagF8 : 1; - uint8 m_ped_flagF10 : 1; + uint8 m_ped_flagF10 : 1; // set before "quickjack" uint8 m_ped_flagF20 : 1; uint8 m_ped_flagF40 : 1; uint8 m_ped_flagF80 : 1; @@ -249,7 +260,7 @@ public: uint8 m_ped_flagH80 : 1; uint8 m_ped_flagI1 : 1; - uint8 m_ped_flagI2 : 1; + uint8 m_ped_flagI2 : 1; // if set, limbs won't came off uint8 m_ped_flagI4 : 1; uint8 bHasAlreadyBeenRecorded : 1; uint8 m_ped_flagI10 : 1; @@ -325,10 +336,10 @@ public: bool bInVehicle; uint8 pad_315[3]; float field_318; - uint8 field_31C; + uint8 field_31C; // may be cutscene or phone cutscene status uint8 field_31D; int16 m_phoneId; - uint32 m_lookingForPhone; + uint32 m_lookingForPhone; // unused uint32 m_phoneTalkTimer; void *m_lastAccident; int32 m_nPedType; @@ -416,8 +427,8 @@ public: void SetDie(AnimationId anim, float arg1, float arg2); void SetDead(void); void ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer); - void RemoveBodyPart(PedNode nodeId, int8 unknown); - void SpawnFlyingComponent(int, int8 unknown); + void RemoveBodyPart(PedNode nodeId, int8 direction); + void SpawnFlyingComponent(int, int8); bool OurPedCanSeeThisOne(CEntity *target); void Avoid(void); void Attack(void); @@ -459,7 +470,39 @@ public: void Chat(void); void MakeChangesForNewWeapon(int8); void CheckAroundForPossibleCollisions(void); + void SetSeek(CVector, float); + bool MakePhonecall(void); + bool FacePhone(void); + CPed *CheckForDeadPeds(void); + bool CheckForExplosions(CVector2D &area); + CPed *CheckForGunShots(void); + uint8 CheckForPointBlankPeds(CPed*); + bool CheckIfInTheAir(void); + void ClearAll(void); + void SetPointGunAt(CEntity*); bool Seek(void); + bool SetWanderPath(int8); + void SetFollowPath(CVector); + void ClearAttackByRemovingAnim(void); + void SetStoredState(void); + void StopNonPartialAnims(void); + bool InflictDamage(CEntity*, eWeaponType, float, ePedPieceTypes, uint8); + void ClearFlee(void); + void ClearFall(void); + void SetGetUp(void); + void ClearInvestigateEvent(void); + void ClearLeader(void); + void ClearLook(void); + void ClearObjective(void); + void ClearPause(void); + void ClearSeek(void); + void ClearWeapons(void); + void RestoreGunPosition(void); + void RestoreHeadingRate(void); + void SetAimFlag(CEntity* to); + void SetAimFlag(float angle); + void SetAmmo(eWeaponType weaponType, uint32 ammo); + void SetEvasiveStep(CEntity*, uint8); // Static methods static void GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float offset); @@ -533,6 +576,7 @@ public: static bool &bNastyLimbsCheat; static bool &bPedCheat2; static bool &bPedCheat3; + static CColPoint &ms_tempColPoint; }; void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg); diff --git a/src/peds/PedIK.cpp b/src/peds/PedIK.cpp index 9b3f401f..3d5bcfb5 100644 --- a/src/peds/PedIK.cpp +++ b/src/peds/PedIK.cpp @@ -8,6 +8,8 @@ WRAPPER bool CPedIK::PointGunAtPosition(CVector *position) { EAXJMP(0x4ED920); } WRAPPER void CPedIK::ExtractYawAndPitchLocal(RwMatrixTag*, float*, float*) { EAXJMP(0x4ED2C0); } WRAPPER void CPedIK::ExtractYawAndPitchWorld(RwMatrixTag*, float*, float*) { EAXJMP(0x4ED140); } +LimbMovementInfo &CPedIK::ms_torsoInfo = *(LimbMovementInfo*)0x5F9F8C; + CPedIK::CPedIK(CPed *ped) { m_ped = ped; @@ -102,8 +104,61 @@ CPedIK::GetWorldMatrix(RwFrame *source, RwMatrix *destination) return destination; } +// A helper function that adjusts "limb" parameter according to limitations. Doesn't move the limb. +int8 +CPedIK::MoveLimb(LimbOrientation &limb, float approxPhi, float approxTheta, LimbMovementInfo &moveInfo) +{ + int result = 1; + + // phi + + if (limb.phi > approxPhi) { + limb.phi -= moveInfo.yawD; + } else if (limb.phi < approxPhi) { + limb.phi += moveInfo.yawD; + } + + if (Abs(limb.phi - approxPhi) < moveInfo.yawD) { + limb.phi = approxPhi; + result = 2; + } + if (limb.phi > moveInfo.maxYaw || limb.phi < moveInfo.minYaw) { + limb.phi = clamp(limb.phi, moveInfo.minYaw, moveInfo.maxYaw); + result = 0; + } + + // theta + + if (limb.theta > approxTheta) { + limb.theta -= moveInfo.pitchD; + } else if (limb.theta < approxTheta) { + limb.theta += moveInfo.pitchD; + } + + if (Abs(limb.theta - approxTheta) < moveInfo.pitchD) + limb.theta = approxTheta; + else + result = 1; + + if (limb.theta > moveInfo.maxPitch || limb.theta < moveInfo.minPitch) { + limb.theta = clamp(limb.theta, moveInfo.minPitch, moveInfo.maxPitch); + result = 0; + } + return result; +} + +bool +CPedIK::RestoreGunPosn(void) +{ + int limbStatus = MoveLimb(m_torsoOrient, 0.0f, 0.0f, ms_torsoInfo); + RotateTorso(m_ped->m_pFrames[PED_MID], &m_torsoOrient, false); + return limbStatus == 2; +} + STARTPATCHES InjectHook(0x4ED0F0, &CPedIK::GetComponentPosition, PATCH_JUMP); InjectHook(0x4ED060, &CPedIK::GetWorldMatrix, PATCH_JUMP); InjectHook(0x4EDDB0, &CPedIK::RotateTorso, PATCH_JUMP); + InjectHook(0x4ED440, &CPedIK::MoveLimb, PATCH_JUMP); + InjectHook(0x4EDD70, &CPedIK::RestoreGunPosn, PATCH_JUMP); ENDPATCHES
\ No newline at end of file diff --git a/src/peds/PedIK.h b/src/peds/PedIK.h index e17d52eb..5f321280 100644 --- a/src/peds/PedIK.h +++ b/src/peds/PedIK.h @@ -9,6 +9,15 @@ struct LimbOrientation float theta; }; +struct LimbMovementInfo { + float maxYaw; + float minYaw; + float yawD; + float maxPitch; + float minPitch; + float pitchD; +}; + class CPed; class CPedIK @@ -28,6 +37,8 @@ public: LimbOrientation m_lowerArmOrient; int32 m_flags; + static LimbMovementInfo &ms_torsoInfo; + CPedIK(CPed *ped); bool PointGunInDirection(float phi, float theta); bool PointGunAtPosition(CVector *position); @@ -36,5 +47,7 @@ public: void RotateTorso(AnimBlendFrameData* animBlend, LimbOrientation* limb, bool changeRoll); void ExtractYawAndPitchLocal(RwMatrixTag*, float*, float*); void ExtractYawAndPitchWorld(RwMatrixTag*, float*, float*); + int8 MoveLimb(LimbOrientation &a1, float a2, float a3, LimbMovementInfo &a4); + bool RestoreGunPosn(void); }; static_assert(sizeof(CPedIK) == 0x28, "CPedIK: error"); diff --git a/src/peds/PedPlacement.cpp b/src/peds/PedPlacement.cpp index e9a3f7d9..f292f4fa 100644 --- a/src/peds/PedPlacement.cpp +++ b/src/peds/PedPlacement.cpp @@ -35,6 +35,13 @@ CPedPlacement::FindZCoorForPed(CVector* pos) pos->z = 1.04f + zForPed; } +CEntity* +CPedPlacement::IsPositionClearOfCars(CVector* pos) +{ + return CWorld::TestSphereAgainstWorld(*pos, 0.25f, false, true, true, false, false, false, false); +} + STARTPATCHES InjectHook(0x4EE340, &CPedPlacement::FindZCoorForPed, PATCH_JUMP); + InjectHook(0x4EE310, &CPedPlacement::IsPositionClearOfCars, PATCH_JUMP); ENDPATCHES diff --git a/src/peds/PedPlacement.h b/src/peds/PedPlacement.h index 4bd48b62..1edb50b4 100644 --- a/src/peds/PedPlacement.h +++ b/src/peds/PedPlacement.h @@ -1,8 +1,10 @@ #pragma once class CVector; +class CEntity; class CPedPlacement { public: static void FindZCoorForPed(CVector* pos); + static CEntity* IsPositionClearOfCars(CVector*); };
\ No newline at end of file diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp index 4b484a7f..24eb4a35 100644 --- a/src/peds/PlayerPed.cpp +++ b/src/peds/PlayerPed.cpp @@ -13,6 +13,8 @@ WRAPPER void CPlayerPed::ReApplyMoveAnims(void) { EAXJMP(0x4F07C0); } WRAPPER void CPlayerPed::SetupPlayerPed(int32) { EAXJMP(0x4EFB60); } WRAPPER void CPlayerPed::DeactivatePlayerPed(int32) { EAXJMP(0x4EFC00); } WRAPPER void CPlayerPed::ReactivatePlayerPed(int32) { EAXJMP(0x4EFC20); } +WRAPPER void CPlayerPed::KeepAreaAroundPlayerClear(void) { EAXJMP(0x4F3460); } + void CPlayerPed::ClearWeaponTarget() { @@ -36,6 +38,22 @@ CPlayerPed::SetWantedLevelNoDrop(int32 level) m_pWanted->SetWantedLevelNoDrop(level); } +// I don't know the actual purpose of parameter +void +CPlayerPed::AnnoyPlayerPed(bool itsPolice) +{ + if (m_pedStats->m_temper < 52) { + m_pedStats->m_temper++; + } else { + if (itsPolice) { + if (m_pedStats->m_temper < 55) { + m_pedStats->m_temper++; + } else { + m_pedStats->m_temper = 46; + } + } + } +} class CPlayerPed_ : public CPlayerPed { @@ -46,4 +64,5 @@ public: STARTPATCHES InjectHook(0x4EFB30, &CPlayerPed_::dtor, PATCH_JUMP); InjectHook(0x4F28A0, &CPlayerPed::ClearWeaponTarget, PATCH_JUMP); + InjectHook(0x4F3700, &CPlayerPed::AnnoyPlayerPed, PATCH_JUMP); ENDPATCHES diff --git a/src/peds/PlayerPed.h b/src/peds/PlayerPed.h index 51a45203..fa6d9d43 100644 --- a/src/peds/PlayerPed.h +++ b/src/peds/PlayerPed.h @@ -29,7 +29,7 @@ public: bool m_bHasLockOnTarget; int8 field_1406; int8 field_1407; - bool m_bAdrenalineTime; + uint32 m_bAdrenalineTime; bool m_bCanBeDamaged; int8 field_1413; int8 field_1414; @@ -45,6 +45,8 @@ public: void ClearWeaponTarget(); void SetWantedLevel(int32 level); void SetWantedLevelNoDrop(int32 level); + void KeepAreaAroundPlayerClear(void); + void AnnoyPlayerPed(bool); static void SetupPlayerPed(int32); static void DeactivatePlayerPed(int32); diff --git a/src/render/Draw.h b/src/render/Draw.h index ad14e5a9..75b2b75f 100644 --- a/src/render/Draw.h +++ b/src/render/Draw.h @@ -2,9 +2,12 @@ enum eAspectRatio { - AR_AUTO, + // Make sure these work the same as FrontEndMenuManager.m_PrefsUseWideScreen + // without widescreen support AR_4_3, AR_16_9, + + AR_AUTO, }; class CDraw diff --git a/src/render/Fluff.cpp b/src/render/Fluff.cpp index b1b8aa92..7c35319f 100644 --- a/src/render/Fluff.cpp +++ b/src/render/Fluff.cpp @@ -1,5 +1,830 @@ #include "common.h" +#include "main.h" #include "patcher.h" #include "Fluff.h" +#include "Camera.h" +#include "Sprite.h" +#include "Coronas.h" +#include "General.h" +#include "Timer.h" +#include "Clock.h" +#include "Weather.h" +#include "Stats.h" +#include "math/maths.h" +#include "Frontend.h" -WRAPPER void CMovingThings::Render(void) { EAXJMP(0x4FF210); } +uint8 ScrollCharSet[59][5] = { + { 0x00, 0x00, 0x00, 0x00, 0x00 }, // ' ' + { 0x00, 0x00, 0x1D, 0x00, 0x00 }, // '!' + { 0x00, 0x00, 0x00, 0x00, 0x00 }, // '"' + { 0x0A, 0x1F, 0x0A, 0x1F, 0x0A }, // '#' + { 0x00, 0x09, 0x1F, 0x12, 0x00 }, // '$' + { 0x18, 0x18, 0x00, 0x03, 0x03 }, // '%' + { 0x00, 0x00, 0x00, 0x00, 0x00 }, // '&' + { 0x00, 0x00, 0x00, 0x00, 0x00 }, // ''' + { 0x01, 0x02, 0x04, 0x08, 0x10 }, // '(' + { 0x00, 0x00, 0x18, 0x00, 0x00 }, // ')' + { 0x15, 0x04, 0x1F, 0x04, 0x15 }, // '*' + { 0x00, 0x04, 0x0E, 0x04, 0x00 }, // '+' + { 0x00, 0x00, 0x03, 0x00, 0x00 }, // ',' + { 0x00, 0x04, 0x04, 0x04, 0x00 }, // '-' + { 0x00, 0x00, 0x01, 0x00, 0x00 }, // '.' + { 0x00, 0x00, 0x00, 0x00, 0x00 }, // '/' + { 0x0E, 0x11, 0x11, 0x11, 0x0E }, // '0' + { 0x01, 0x09, 0x1F, 0x01, 0x01 }, // '1' + { 0x03, 0x15, 0x15, 0x15, 0x09 }, // '2' + { 0x11, 0x11, 0x15, 0x15, 0x0A }, // '3' + { 0x02, 0x06, 0x0A, 0x1F, 0x02 }, // '4' + { 0x1D, 0x15, 0x15, 0x15, 0x12 }, // '5' + { 0x0E, 0x15, 0x15, 0x15, 0x12 }, // '6' + { 0x18, 0x10, 0x13, 0x14, 0x18 }, // '7' + { 0x0A, 0x15, 0x15, 0x15, 0x0A }, // '8' + { 0x08, 0x15, 0x15, 0x15, 0x0E }, // '9' + { 0x00, 0x00, 0x0A, 0x00, 0x00 }, // ':' + { 0x18, 0x18, 0x00, 0x03, 0x03 }, // ';' + { 0x04, 0x08, 0x1F, 0x08, 0x04 }, // '<' + { 0x00, 0x0A, 0x0A, 0x0A, 0x00 }, // '=' + { 0x04, 0x02, 0x1F, 0x02, 0x04 }, // '>' + { 0x10, 0x10, 0x15, 0x14, 0x1D }, // '?' + { 0x00, 0x1C, 0x14, 0x1C, 0x00 }, // '@' + { 0x0F, 0x12, 0x12, 0x12, 0x0F }, // 'A' + { 0x1F, 0x15, 0x15, 0x15, 0x0A }, // 'B' + { 0x0E, 0x11, 0x11, 0x11, 0x0A }, // 'C' + { 0x1F, 0x11, 0x11, 0x11, 0x0E }, // 'D' + { 0x1F, 0x15, 0x15, 0x11, 0x11 }, // 'E' + { 0x1F, 0x14, 0x14, 0x10, 0x10 }, // 'F' + { 0x0E, 0x11, 0x15, 0x15, 0x06 }, // 'G' + { 0x1F, 0x04, 0x04, 0x04, 0x1F }, // 'H' + { 0x11, 0x11, 0x1F, 0x11, 0x11 }, // 'I' + { 0x02, 0x01, 0x01, 0x01, 0x1E }, // 'J' + { 0x1F, 0x04, 0x0C, 0x12, 0x01 }, // 'K' + { 0x1F, 0x01, 0x01, 0x01, 0x01 }, // 'L' + { 0x1F, 0x08, 0x06, 0x08, 0x1F }, // 'M' + { 0x1F, 0x08, 0x04, 0x02, 0x1F }, // 'N' + { 0x0E, 0x11, 0x11, 0x11, 0x0E }, // 'O' + { 0x1F, 0x12, 0x12, 0x12, 0x0C }, // 'P' + { 0x0C, 0x12, 0x12, 0x13, 0x0D }, // 'Q' + { 0x1F, 0x14, 0x14, 0x16, 0x09 }, // 'R' + { 0x09, 0x15, 0x15, 0x15, 0x02 }, // 'S' + { 0x10, 0x10, 0x1F, 0x10, 0x10 }, // 'T' + { 0x1E, 0x01, 0x01, 0x01, 0x1E }, // 'U' + { 0x1C, 0x02, 0x01, 0x02, 0x1C }, // 'V' + { 0x1E, 0x01, 0x06, 0x01, 0x1E }, // 'W' + { 0x11, 0x0A, 0x04, 0x0A, 0x11 }, // 'X' + { 0x18, 0x04, 0x03, 0x04, 0x18 }, // 'Y' + { 0x11, 0x13, 0x15, 0x19, 0x11 } // 'Z' +}; + +// ---------- CMovingThings ---------- +enum eScrollBarTypes +{ + SCROLL_BUSINESS, + SCROLL_TRAFFIC, + SCROLL_ENTERTAINMENT, + SCROLL_AIRPORT_DOORS, + SCROLL_AIRPORT_FRONT, + SCROLL_STORE, + SCROLL_USED_CARS +}; + +CScrollBar aScrollBars[11]; +CTowerClock aTowerClocks[2]; +CDigitalClock aDigitalClocks[3]; + +void CMovingThings::Init() +{ + /* + * Some unused code about CMovingThing was here... + */ + + // Initialize scroll bars + aScrollBars[0].Init(CVector( 228.3f, -669.0f, 39.0f ), SCROLL_BUSINESS, 0.0, 0.5, 0.5, 255, 128, 0, 0.3); + aScrollBars[1].Init(CVector( 772.0f, 164.0f, -9.5f ), SCROLL_TRAFFIC, 0.0, 0.5, 0.25, 128, 255, 0, 0.3); + aScrollBars[2].Init(CVector(-1089.61f, -584.224f, 13.246f), SCROLL_AIRPORT_DOORS, 0.0, -0.1706, 0.107, 255, 0, 0, 0.11); + aScrollBars[3].Init(CVector(-1089.61f, -602.04602f, 13.246f), SCROLL_AIRPORT_DOORS, 0.0, -0.1706, 0.107, 0, 255, 0, 0.11); + aScrollBars[4].Init(CVector(-1089.61f, -619.81702f, 13.246f), SCROLL_AIRPORT_DOORS, 0.0, -0.1706, 0.107, 255, 128, 0, 0.11); + aScrollBars[5].Init(CVector(-754.578f, -633.50897f, 18.411f), SCROLL_AIRPORT_FRONT, 0.0, 0.591, 0.52, 100, 100, 255, 0.3); + aScrollBars[6].Init(CVector( -754.578f, -586.672f, 18.411f), SCROLL_AIRPORT_FRONT, 0.0, 0.591, 0.52, 100, 100, 255, 0.3); + aScrollBars[7].Init(CVector( 85.473f, -1069.512f, 30.5f ), SCROLL_STORE, 0.625, -0.3125, 0.727, 100, 100, 255, 0.5); + aScrollBars[8].Init(CVector( 74.823f, -1086.879f, 31.495f), SCROLL_ENTERTAINMENT, -0.2083, 0.1041, 0.5, 255, 255, 128, 0.3); + aScrollBars[9].Init(CVector( -36.459f, -1031.2371f, 32.534f), SCROLL_ENTERTAINMENT, -0.1442, 0.0721, 0.229, 150, 255, 50, 0.3); + aScrollBars[10].Init(CVector( 1208.0f, -62.208f, 19.157f), SCROLL_USED_CARS, 0.0642, -0.20365, 0.229, 255, 128, 0, 0.3); + + // Initialize tower clocks + aTowerClocks[0].Init(CVector(59.4f, -1081.3f, 54.15f), -1.0f, 0.0f, 0, 0, 0, 80.0f, 2.0f); + aTowerClocks[1].Init(CVector(55.4f, -1083.6f, 54.15f), 0.0f, -1.0f, 0, 0, 0, 80.0f, 2.0f); + + // Initialize digital clocks + CVector2D sz(3.7f, 2.144f); + sz.Normalise(); + aDigitalClocks[0].Init( + CVector(54.485f - sz.x * 0.05f + sz.y * 0.3f, -1081.679f - sz.y * 0.05f - sz.x * 0.3f, 32.803f), + sz.y, -sz.x, 255, 0, 0, 100.0f, 0.8f + ); + aDigitalClocks[1].Init( + CVector(60.564f + sz.x * 0.05f - sz.y * 0.3f, -1083.089f + sz.y * 0.05f + sz.x * 0.3f, 32.803f), + -sz.y, sz.x, 0, 0, 255, 100.0f, 0.8f + ); + aDigitalClocks[2].Init( + CVector(58.145f - sz.y * 0.05f - sz.x * 0.3f, -1079.268f + sz.x * 0.05f - sz.y * 0.3f, 32.803f), + -sz.x, -sz.y, 0, 255, 0, 100.0f, 0.8f + ); +} + +void CMovingThings::Shutdown() +{ + int i; + for (i = 0; i < 11; ++i) + aScrollBars[i].SetVisibility(false); + for (i = 0; i < 2; ++i) + aTowerClocks[i].SetVisibility(false); + for (i = 0; i < 3; ++i) + aDigitalClocks[i].SetVisibility(false); +} + +void CMovingThings::Update() +{ + /* + * Some unused code about CMovingThing was here... + */ + + int i; + for (i = 0; i < 11; ++i) + { + if (aScrollBars[i].IsVisible() || (CTimer::GetFrameCounter() + i) % 8 == 0) + aScrollBars[i].Update(); + } + for (i = 0; i < 2; ++i) + { + if (aTowerClocks[i].IsVisible() || (CTimer::GetFrameCounter() + i) % 8 == 0) + aTowerClocks[i].Update(); + } + for (i = 0; i < 3; ++i) + { + if (aDigitalClocks[i].IsVisible() || (CTimer::GetFrameCounter() + i) % 8 == 0) + aDigitalClocks[i].Update(); + } +} + +void CMovingThings::Render() +{ + int i; + for (i = 0; i < 11; ++i) + { + if (aScrollBars[i].IsVisible()) + aScrollBars[i].Render(); + } + for (i = 0; i < 2; ++i) + { + if (aTowerClocks[i].IsVisible()) + aTowerClocks[i].Render(); + } + for (i = 0; i < 3; ++i) + { + if (aDigitalClocks[i].IsVisible()) + aDigitalClocks[i].Render(); + } +} + +// ---------- CMovingThing ---------- +WRAPPER void CMovingThing::Update() { EAXJMP(0x4FF290); } +WRAPPER void CMovingThing::AddToList() { EAXJMP(0x4FF320); } +WRAPPER void CMovingThing::RemoveFromList() { EAXJMP(0x4FF340); } + +// ---------- Find message functions ---------- +const char* FindTunnelMessage() +{ + if (CStats::CommercialPassed) + return "LIBERTY TUNNEL HAS BEEN OPENED TO ALL TRAFFIC . . . "; + + if (CStats::IndustrialPassed) + return "FIRST PHASE LIBERTY TUNNEL HAS BEEN COMPLETED . . . "; + + return "FIRST PHASE LIBERTY TUNNEL ABOUT TO BE COMPLETED . . . "; +} + +const char* FindBridgeMessage() +{ + if (CStats::CommercialPassed) + return "STAUNTON LIFT BRIDGE IS OPERATIONAL AGAIN "; + + if (CStats::IndustrialPassed) + return "LONG DELAYS BEHIND US AS CALLAHAN BRIDGE IS FIXED . . . STAUNTON LIFT BRIDGE STUCK OPEN "; + + return "CHAOS AS CALLAHAN BRIDGE IS UNDER REPAIR. . . "; +} + +char String_Time[] = "THE TIME IS 12:34 "; +const char* FindTimeMessage() +{ + String_Time[12] = '0' + CClock::GetHours() / 10; + String_Time[13] = '0' + CClock::GetHours() % 10; + String_Time[15] = '0' + CClock::GetMinutes() / 10; + String_Time[16] = '0' + CClock::GetMinutes() % 10; + return String_Time; +} + +char String_DigitalClock[] = "12:34"; +const char* FindDigitalClockMessage() +{ + if (((CTimer::GetTimeInMilliseconds() >> 10) & 7) < 6) + { + String_DigitalClock[0] = '0' + CClock::GetHours() / 10; + String_DigitalClock[1] = '0' + CClock::GetHours() % 10; + String_DigitalClock[2] = CTimer::GetTimeInMilliseconds() & 0x200 ? ':' : ' '; + String_DigitalClock[3] = '0' + CClock::GetMinutes() / 10; + String_DigitalClock[4] = '0' + CClock::GetMinutes() % 10; + } + else + { + int temperature = 13.0f - 6.0f * Cos((CClock::GetMinutes() + 60.0f * CClock::GetHours()) * 0.0043611112f - 1.0f); + String_DigitalClock[0] = '0' + temperature / 10; + if (String_DigitalClock[0] == '0') + String_DigitalClock[0] = ' '; + String_DigitalClock[1] = '0' + temperature % 10; + String_DigitalClock[2] = ' '; + String_DigitalClock[3] = '@'; + String_DigitalClock[4] = 'C'; + } + return String_DigitalClock; +} + +// ---------- CScrollBar ---------- +void CScrollBar::Init(CVector position, uint8 type, float sizeX, float sizeY, float sizeZ, uint8 red, uint8 green, uint8 blue, float scale) +{ + for (int i = 0; i < 40; ++i) + m_MessageBar[i] = 0; + + m_pMessage = ". "; + m_MessageCurrentChar = 0; + m_MessageLength = 2; + + m_Counter = 0; + m_bVisible = false; + m_Position = position; + m_Type = type; + m_Size.x = sizeX; + m_Size.y = sizeY; + m_Size.z = sizeZ; + m_uRed = red; + m_uGreen = green; + m_uBlue = blue; + m_fScale = scale; +} + +void CScrollBar::Update() +{ + float distanceFromCamera = (TheCamera.GetPosition() - m_Position).Magnitude(); + if (distanceFromCamera > 100.0f) + { + m_bVisible = false; + return; + } + + m_bVisible = true; + + if (distanceFromCamera < 75.0f) + m_fIntensity = 1.0f; + else + m_fIntensity = 1.0f - 4.0f * (distanceFromCamera - 75.0f) / 100.0f; + + m_Counter = (m_Counter + 1) % 8; + + // if message is fully printed, load up the next one + if (m_Counter == 0 && ++m_MessageCurrentChar >= m_MessageLength) + { + const char* previousMessage = m_pMessage; + switch (m_Type) + { + case SCROLL_BUSINESS: + while (previousMessage == m_pMessage) + { + switch (CGeneral::GetRandomNumber() % 7) + { + case 0: + m_pMessage = "SHARES UYE<10% DWD<20% NDWE>22% . . . "; + break; + case 1: + m_pMessage = "CRIME WAVE HITS LIBERTY CITY . . . "; + break; + case 2: + m_pMessage = "SHARES OBR>29% MADD<76% LEZ<11% ADAMSKI>53% AAG>110%. . . "; + break; + case 3: + m_pMessage = FindTunnelMessage(); + break; + case 4: + m_pMessage = FindBridgeMessage(); + break; + case 5: + m_pMessage = FindTimeMessage(); + break; + case 6: + if (CMenuManager::m_PrefsLanguage == LANGUAGE_FRENCH || CMenuManager::m_PrefsLanguage == LANGUAGE_GERMAN) + m_pMessage = FindTimeMessage(); + else + m_pMessage = "WWW.GRANDTHEFTAUTO3.COM "; + break; + } + } + break; + case SCROLL_TRAFFIC: + while (previousMessage == m_pMessage) + { + switch (CGeneral::GetRandomNumber() % 8) + { + case 0: + m_pMessage = "DRIVE CAREFULLY . . . "; + break; + case 1: + m_pMessage = "RECENT WAVE OF CARJACKINGS. KEEP YOUR DOORS LOCKED !!! "; + break; + case 2: + m_pMessage = "CHECK YOUR SPEED . . . "; + break; + case 3: + m_pMessage = "KEEP YOUR EYES ON THE ROAD AND NOT ON THIS SIGN "; + break; + case 4: + if (CWeather::Foggyness > 0.5) + m_pMessage = "POOR VISIBILITY ! "; + else if (CWeather::WetRoads > 0.5) + m_pMessage = "ROADS ARE SLIPPERY ! "; + else + m_pMessage = "ENJOY YOUR TRIP "; + break; + case 5: + m_pMessage = FindTunnelMessage(); + break; + case 6: + m_pMessage = FindBridgeMessage(); + break; + case 7: + m_pMessage = FindTimeMessage(); + break; + } + } + break; + case SCROLL_ENTERTAINMENT: + while (previousMessage == m_pMessage) + { + switch (CGeneral::GetRandomNumber() % 12) + { + case 0: + m_pMessage = " )69TH STREET) STILL HOLDS TOP POSITION THIS MONTH AT THE BOX-OFFICE WITH )MY FAIR LADYBOY) JUST CREEPING UP BEHIND. "; + break; + case 1: + m_pMessage = " TALKING OF )FANNIE). THERE IS STILL TIME TO CATCH THIS LOVELY FAMILY MUSICAL, ABOUT THE ORPHAN WHO IS SO EASILY TAKEN IN BY ANY MAN WITH LOADS OF MONEY. "; + break; + case 2: + m_pMessage = " DO NOT MISS )GTA3, THE MUSICAL) . . . "; + break; + case 3: + m_pMessage = + " STILL RUNNING ARE )RATS) AND )GUYS AND DOGS), BETWEEN THEN THEY SHOULD HAVE THE LEGS TO LAST TILL THE AND OF THE YEAR. . . " + " ALSO FOR FOUR LEGGED FANS, THE STAGE VERSION OF THE GRITTY REALISTIC )SATERDAY NIGHT BEAVER) OPENED LAST WEEKEND," + " AND I FOR ONE CERTAINLY ENJOYED THAT. "; + break; + case 4: + m_pMessage = + " NOW SHOWING STATE-WIDE, ARNOLD STEELONE, HOLLYWOODS BEST LIVING SPECIAL EFFECT, APPEARS AGAIN AS A HALF_MAN," + " HALF ANDROID IN THE HALF-BAKED ROMP, )TOP DOWN CITY). AN HOMAGE TO HIS EARLIER TWO MULTI_MILLION MAKING MOVIES," + " IN WHICH HE PLAYED TWO-DEE, AN OUT OF CONTROL MONSTER, INTENT ON CORRUPTING CIVILISATION! "; + break; + case 5: + m_pMessage = + " ALSO APPEARING THIS WEEK )HALF-COCKED) SEES CHUCK SCHWARTZ UP TO HIS USUAL NONSENSE AS HE TAKES ON HALF OF LIBERTY CITY" + " IN AN ATTEMPT TO SAVE HIS CROSS-DRESSING LADY-BOY SIDEKICK, )MISS PING-PONG), FROM A GANG OF RUTHLESS COSMETIC SURGEONS. "; + break; + case 6: + m_pMessage = + " STILL SHOWING: )SOLDIERS OF MISFORTUNE), ATTROCIOUS ACTING WHICH SEES BOYZ 2 GIRLZ) TRANSITION FROM THE CHARTS TO THE BIG SCREEN," + " AT LEAST THEY ALL DIE AT THE END. . . "; + break; + case 7: + m_pMessage = + " )BADFELLAS) IS STILL GOING STRONG WITH CROWDS ALMOST BEING PUSHED INTO CINEMAS TO SEE THIS ONE." + " ANOTHER ONE WORTH LOOKING INTO IS )THE TUNNEL). "; + break; + case 8: + m_pMessage = FindTunnelMessage(); + break; + case 9: + m_pMessage = FindBridgeMessage(); + break; + case 10: + m_pMessage = FindTimeMessage(); + break; + case 11: + m_pMessage = "WWW.ROCKSTARGAMES.COM "; + break; + } + } + break; + case SCROLL_AIRPORT_DOORS: + while (previousMessage == m_pMessage) + { + switch (CGeneral::GetRandomNumber() % 4) + { + case 0: + m_pMessage = "WELCOME TO LIBERTY CITY . . . "; + break; + case 1: + m_pMessage = "PLEASE HAVE YOUR PASSPORT READY . . . "; + break; + case 2: + m_pMessage = "PLACE KEYS, FIREARMS, CHANGE AND OTHER METAL OBJECTS ON THE TRAY PLEASE . . . "; + break; + case 3: + m_pMessage = FindTimeMessage(); + break; + } + } + break; + case SCROLL_AIRPORT_FRONT: + while (previousMessage == m_pMessage) + { + switch (CGeneral::GetRandomNumber() % 4) + { + case 0: + m_pMessage = "WELCOME TO FRANCIS INTERNATIONAL AIRPORT . . . "; + break; + case 1: + m_pMessage = "PLEASE DO NOT LEAVE LUGGAGE UNATTENDED . . . "; + break; + case 2: + m_pMessage = "FOLLOW 1 FOR LONG AND SHORT TERM PARKING "; + break; + case 3: + m_pMessage = FindTimeMessage(); + break; + } + } + break; + case SCROLL_STORE: + while (previousMessage == m_pMessage) + { + switch (CGeneral::GetRandomNumber() % 10) + { + case 0: + m_pMessage = "WWW.ROCKSTARGAMES.COM "; + break; + case 1: + m_pMessage = "GTA3 OUT NOW . . . "; + break; + case 2: + m_pMessage = "OUR STUFF IS CHEAP CHEAP CHEAP "; + break; + case 3: + m_pMessage = "BUY 12 CDS GET ONE FREE . . . "; + break; + case 4: + m_pMessage = "APPEARING IN SHOP SOON, )THE BLOODY CHOPPERS), WITH THEIR NEW ALBUM, )IS THAT MY DAUGHTER?) "; + break; + case 5: + m_pMessage = "THIS MONTH IS OUR CRAZY CLEAROUT MONTH, EVERYTHING MUST GO, CDS, DVDS, STAFF, EVEN OUR CARPETS! "; + break; + case 6: + m_pMessage = + "OUT THIS WEEK: THE THEME TUNE TO )BOYS TO GIRLS) FIRST MOVIE )SOLDIERS OF MISFORTUNE), " + "THE SINGLE )LET ME IN YOU)RE BODY-BAG) IS TAKEN FROM THE SOUNDTRACK ALBUM, )BOOT CAMP BOYS). " + "ALSO INCLUDES THE SMASH SINGLE, )PRAY IT GOES OK). "; + break; + case 7: + m_pMessage = + "ALBUMS OUT THIS WEEK: MARYDANCING, )MUTHA O) CHRIST), FEATURING THE SINGLE )WASH HIM OFF), " + "ALSO CRAIG GRAYS) DEBUT, )FADE AWAY), INCLUDES THE SINGLE OF THE SAME NAME. . . "; + break; + case 8: + m_pMessage = + "ON THE FILM FRONT, A NELY COMPILED COMPILATION OF ARNOLD STEELONES GREATEST MOVIES ON DVD. " + "THE PACK INCLUDES THE EARLY )BY-CEP), THE CULT CLASSIC )FUTURE ANNHILATOR), AND THE HILARIOUS CROSS-DRESSING COMEDY )SISTERS). " + "ONE FOR ALL THE FAMILY. . . "; + break; + case 9: + m_pMessage = (char*)FindTimeMessage(); + break; + } + } + break; + case SCROLL_USED_CARS: + while (previousMessage == m_pMessage) + { + switch (CGeneral::GetRandomNumber() % 11) + { + case 0: + m_pMessage = "QUICK, TAKE A LOOK AT OUR CURRENT STOCK )CAUSE THESE AUTOS ARE MOVIN) FAST . . . "; + break; + case 1: + m_pMessage = "THAT)S RIGHT, HERE AT )CAPITAL AUTO SALES) OUR VEHICLES ARE SO GOOD THAT THEY PRACTICALLY DRIVE THEMSELVES OFF OUR LOT . . . "; + break; + case 2: + m_pMessage = "EASY CREDIT ON ALL CARS . . . "; + break; + case 3: + m_pMessage = "FEEL LIKE A STUD IN ONE OF OUR STALLIONS OR TEST-DRIVE OUR BANSHEE, IT)S A REAL STEAL!!! "; + break; + case 4: + m_pMessage = "TRY OUR HARDY PERENNIAL, IT)LL LAST YOU THE WHOLE YEAR. OUR BOBCATS AIN)T NO PUSSIES EITHER!!! "; + break; + case 5: + m_pMessage = "IF IT)S A GUARANTEE YOU'RE AFTER, GO SOMEWHERE ELSE, )CAPITAL) CARS ARE THAT GOOD THEY DON)T NEED GUARANTEES!!! "; + break; + case 6: + m_pMessage = "TOP DOLLAR OFFERED FOR YOUR OLD WHEELS, NOT YOUR CAR, JUST IT)S WHEELS. . . "; + break; + case 7: + m_pMessage = "THAT)S RIGHT WE)RE CAR SILLY. TEST DRIVE ANY CAR, YOU WON)T WANT TO BRING IT BACK!!! "; + break; + case 8: + m_pMessage = "FREE FLUFFY DICE WITH ALL PURCHASES. . ."; + break; + case 9: + if (CMenuManager::m_PrefsLanguage == LANGUAGE_FRENCH || CMenuManager::m_PrefsLanguage == LANGUAGE_GERMAN) + m_pMessage = "QUICK, TAKE A LOOK AT OUR CURRENT STOCK )CAUSE THESE AUTOS ARE MOVIN) FAST . . . "; + else + m_pMessage = "HTTP:((ROCKSTARGAMES.COM(GRANDTHEFTAUTO3(CAPITALAUTOS "; + break; + case 10: + m_pMessage = FindTimeMessage(); + break; + } + } + break; + } + + m_MessageLength = strlen(m_pMessage); + m_MessageCurrentChar = 0; + } + + // Scroll + for (int i = 0; i < 39; i++) + m_MessageBar[i] = m_MessageBar[i + 1]; + m_MessageBar[39] = m_Counter < 5 ? ScrollCharSet[m_pMessage[m_MessageCurrentChar] - ' '][m_Counter] : 0; + + // Introduce some random displaying glitches; signs aren't supposed to be perfect :P + switch (CGeneral::GetRandomNumber() & 0xFF) + { + case 0x0D: m_MessageBar[39] = 0; break; + case 0xE3: m_MessageBar[39] = 0xE3; break; + case 0x64: m_MessageBar[39] = ~m_MessageBar[39]; break; + } +} + +void CScrollBar::Render() +{ + if (!TheCamera.IsSphereVisible(m_Position, 2.0f * 20.0f * (ABS(m_Size.x) + ABS(m_Size.y)))) + return; + + CSprite::InitSpriteBuffer(); + + // Calculate intensity of colours + uint8 r = m_fIntensity * m_uRed; + uint8 g = m_fIntensity * m_uGreen; + uint8 b = m_fIntensity * m_uBlue; + + // Set render states + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); + RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[0])); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); + + CVector coronaCoord, screenCoord; + float screenW, screenH; + for (int i = 1; i < 40; ++i) + { + for (int j = 0; j < 5; ++j) + { + coronaCoord.x = m_Position.x + m_Size.x * i; + coronaCoord.y = m_Position.y + m_Size.y * i; + coronaCoord.z = m_Position.z + m_Size.z * j; + + // Render main coronas + if (m_MessageBar[i] & (1 << j)) + { + if (CSprite::CalcScreenCoors(coronaCoord, screenCoord, &screenW, &screenH, true)) + { + CSprite::RenderBufferedOneXLUSprite( + screenCoord.x, screenCoord.y, screenCoord.z, + screenW * m_fScale, screenH * m_fScale, + r, g, b, + 255, 1.0f / screenCoord.z, 255); + } + } + // Render smaller and faded coronas for a trailing effect + else if (m_MessageBar[i - 1] & (1 << j)) + { + if (CSprite::CalcScreenCoors(coronaCoord, screenCoord, &screenW, &screenH, true)) + { + CSprite::RenderBufferedOneXLUSprite( + screenCoord.x, screenCoord.y, screenCoord.z, + screenW * m_fScale * 0.8f, + screenH * m_fScale * 0.8f, + r / 2, + g / 2, + b / 2, + 255, 1.0 / screenCoord.z, 255); + } + } + } + } + + CSprite::FlushSpriteBuffer(); +} + +// ---------- CTowerClock ---------- +void CTowerClock::Init(CVector position, float sizeX, float sizeY, uint8 red, uint8 green, uint8 blue, float drawDistance, float scale) +{ + m_bVisible = false; + m_Position = position; + m_Size.x = sizeX; + m_Size.y = sizeY; + m_Size.z = 0.0f; + m_uRed = red; + m_uGreen = green; + m_uBlue = blue; + m_fDrawDistance = drawDistance; + m_fScale = scale; +} + +void CTowerClock::Update() +{ + float distanceFromCamera = (TheCamera.GetPosition() - m_Position).Magnitude(); + if (distanceFromCamera < m_fDrawDistance) + { + m_bVisible = true; + if (distanceFromCamera < 0.75f * m_fDrawDistance) + m_fIntensity = 1.0f; + else + m_fIntensity = 1.0f - (distanceFromCamera - 0.75f * m_fDrawDistance) * 4.0f / m_fDrawDistance; + } + else + m_bVisible = false; +} + +RwIm3DVertex TempV[4]; +void CTowerClock::Render() +{ + if (TheCamera.IsSphereVisible(m_Position, m_fScale)) + { + // Calculate angle for each clock index + float angleHour = 2.0f * (float)PI * (CClock::GetMinutes() + 60.0f * CClock::GetHours()) / 720.0f; + float angleMinute = 2.0f * (float)PI * (CClock::GetSeconds() + 60.0f * CClock::GetMinutes()) / 3600.0f; + + // Prepare render states + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); + + // Set vertices colors + RwIm3DVertexSetRGBA(&TempV[0], m_uRed, m_uGreen, m_uBlue, (uint8)(m_fIntensity * 255.0f)); + RwIm3DVertexSetRGBA(&TempV[1], m_uRed, m_uGreen, m_uBlue, (uint8)(m_fIntensity * 255.0f)); + RwIm3DVertexSetRGBA(&TempV[2], m_uRed, m_uGreen, m_uBlue, (uint8)(m_fIntensity * 255.0f)); + RwIm3DVertexSetRGBA(&TempV[3], m_uRed, m_uGreen, m_uBlue, (uint8)(m_fIntensity * 255.0f)); + + // Set vertices position + RwIm3DVertexSetPos(&TempV[0], m_Position.x, m_Position.y, m_Position.z); + RwIm3DVertexSetPos( + &TempV[1], + m_Position.x + Sin(angleMinute) * m_fScale * m_Size.x, + m_Position.y + Sin(angleMinute) * m_fScale * m_Size.y, + m_Position.z + Cos(angleMinute) * m_fScale; + ); + RwIm3DVertexSetPos(&TempV[2], m_Position.x, m_Position.y, m_Position.z); + RwIm3DVertexSetPos( + &TempV[3], + m_Position.x + Sin(angleHour) * 0.75f * m_fScale * m_Size.x, + m_Position.y + Sin(angleHour) * 0.75f * m_fScale * m_Size.y, + m_Position.z + Cos(angleHour) * 0.75f * m_fScale; + ); + + LittleTest(); + + // Draw lines + if (RwIm3DTransform(TempV, 4, nil, 0)) + { + RwIm3DRenderLine(0, 1); + RwIm3DRenderLine(2, 3); + RwIm3DEnd(); + } + } +} + +// ---------- CDigitalClock ---------- +void CDigitalClock::Init(CVector position, float sizeX, float sizeY, uint8 red, uint8 green, uint8 blue, float drawDistance, float scale) +{ + m_bVisible = false; + m_Position = position; + m_Size.x = sizeX; + m_Size.y = sizeY; + m_Size.z = 0.0f; + m_uRed = red; + m_uGreen = green; + m_uBlue = blue; + m_fDrawDistance = drawDistance; + m_fScale = scale; +} + +void CDigitalClock::Update() +{ + float distanceFromCamera = (TheCamera.GetPosition() - m_Position).Magnitude(); + if (distanceFromCamera < m_fDrawDistance) + { + m_bVisible = true; + if (distanceFromCamera < 0.75f * m_fDrawDistance) + m_fIntensity = 1.0f; + else + m_fIntensity = 1.0f - (distanceFromCamera - 0.75f * m_fDrawDistance) * 4.0f / m_fDrawDistance; + } + else + m_bVisible = false; +} + +void CDigitalClock::Render() +{ + if (TheCamera.IsSphereVisible(m_Position, 5.0f * m_fScale)) + { + CSprite::InitSpriteBuffer(); + + // Simulate flicker + float currentIntensity = m_fIntensity * CGeneral::GetRandomNumberInRange(0x300, 0x400) / 1024.0f; + + uint8 r = currentIntensity * m_uRed; + uint8 g = currentIntensity * m_uGreen; + uint8 b = currentIntensity * m_uBlue; + + // Set render states + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); + RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[0])); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); + + const char* clockMessage = FindDigitalClockMessage(); + + CVector coronaCoord, screenCoord; + float screenW, screenH; + for (int c = 0; c < 5; ++c) // for each char to be displayed + { + for (int i = 0; i < 5; ++i) // for each column of coronas + { + for (int j = 0; j < 5; ++j) // for each row of coronas + { + if (ScrollCharSet[clockMessage[c] - ' '][i] & (1 << j)) + { + coronaCoord.x = m_Position.x + (8 * c + i) * m_Size.x * m_fScale / 8.0f; + coronaCoord.y = m_Position.y + (8 * c + i) * m_Size.y * m_fScale / 8.0f; + coronaCoord.z = m_Position.z + j * m_fScale / 8.0f; + + if (CSprite::CalcScreenCoors(coronaCoord, screenCoord, &screenW, &screenH, true)) + { + CSprite::RenderBufferedOneXLUSprite( + screenCoord.x, screenCoord.y, screenCoord.z, + screenW * m_fScale * 0.12, + screenW * m_fScale * 0.12, + r, g, b, + 255, + 1.0 / screenCoord.z, + 255); + } + } + } + } + } + + CSprite::FlushSpriteBuffer(); + } +} + +STARTPATCHES +InjectHook(0x4FE7C0, &CMovingThings::Init, PATCH_JUMP); +InjectHook(0x4FF020, &CMovingThings::Shutdown, PATCH_JUMP); +InjectHook(0x4FF0D0, &CMovingThings::Update, PATCH_JUMP); +InjectHook(0x4FF210, &CMovingThings::Render, PATCH_JUMP); + +InjectHook(0x4FF360, &FindTunnelMessage, PATCH_JUMP); +InjectHook(0x4FF390, &FindBridgeMessage, PATCH_JUMP); +InjectHook(0x4FF3C0, &FindTimeMessage, PATCH_JUMP); +InjectHook(0x4FF450, &FindDigitalClockMessage, PATCH_JUMP); + +InjectHook(0x4FF610, &CScrollBar::Init, PATCH_JUMP); +InjectHook(0x4FF6E0, &CScrollBar::Update, PATCH_JUMP); +InjectHook(0x4FFCE0, &CScrollBar::Render, PATCH_JUMP); + +InjectHook(0x5000D0, &CTowerClock::Init, PATCH_JUMP); +InjectHook(0x500130, &CTowerClock::Update, PATCH_JUMP); +InjectHook(0x5001D0, &CTowerClock::Render, PATCH_JUMP); + +InjectHook(0x5004F0, &CDigitalClock::Init, PATCH_JUMP); +InjectHook(0x500550, &CDigitalClock::Update, PATCH_JUMP); +InjectHook(0x5005F0, &CDigitalClock::Render, PATCH_JUMP); +ENDPATCHES
\ No newline at end of file diff --git a/src/render/Fluff.h b/src/render/Fluff.h index 33532efa..f33b016e 100644 --- a/src/render/Fluff.h +++ b/src/render/Fluff.h @@ -1,7 +1,91 @@ #pragma once +#include "common.h" +#include "math/Vector.h" class CMovingThings { public: - static void Render(void); + static void Init(); + static void Shutdown(); + static void Update(); + static void Render(); }; + +class CMovingThing +{ +public: + void Update(); + void AddToList(); + void RemoveFromList(); +}; + +class CScrollBar +{ +private: + uint8 m_Counter; + const char* m_pMessage; + CVector m_Position; + uint32 m_MessageCurrentChar; + uint32 m_MessageLength; + CVector m_Size; + float m_fIntensity; + uint8 m_MessageBar[40]; + uint8 m_Type; + bool m_bVisible; + uint8 m_uRed; + uint8 m_uGreen; + uint8 m_uBlue; + float m_fScale; + +public: + void SetVisibility(bool visible) { m_bVisible = visible; } + bool IsVisible() { return m_bVisible; } + + void Init(CVector, uint8, float, float, float, uint8, uint8, uint8, float); + void Update(); + void Render(); +}; + +class CTowerClock +{ +private: + CVector m_Position; + CVector m_Size; + float m_fDrawDistance; + float m_fScale; + uint8 m_uRed; + uint8 m_uGreen; + uint8 m_uBlue; + bool m_bVisible; + float m_fIntensity; + +public: + void SetVisibility(bool visible) { m_bVisible = visible; } + bool IsVisible() { return m_bVisible; } + + void Init(CVector, float, float, uint8, uint8, uint8, float, float); + void Update(); + void Render(); +}; + +class CDigitalClock +{ +private: + CVector m_Position; + CVector m_Size; + float m_fDrawDistance; + float m_fScale; + uint8 m_uRed; + uint8 m_uGreen; + uint8 m_uBlue; + bool m_bVisible; + float m_fIntensity; + +public: + void SetVisibility(bool visible) { m_bVisible = visible; } + bool IsVisible() { return m_bVisible; } + + void Init(CVector, float, float, uint8, uint8, uint8, float, float); + void Update(); + void Render(); +};
\ No newline at end of file diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp index 81f27153..1db7b07c 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -325,7 +325,7 @@ void CHud::Draw() else { Clip = AmmoInClip; - if (TotalAmmo - AmmoInClip > 9999) + if ((TotalAmmo - AmmoInClip) > 9999) Ammo = 9999; else Ammo = TotalAmmo - AmmoInClip; diff --git a/src/render/Lines.cpp b/src/render/Lines.cpp new file mode 100644 index 00000000..ea433048 --- /dev/null +++ b/src/render/Lines.cpp @@ -0,0 +1,74 @@ +#include "common.h" +#include "patcher.h" +#include "main.h" +#include "Lines.h" + +// This is super inefficient, why split the line into segments at all? +void +CLines::RenderLineWithClipping(float x1, float y1, float z1, float x2, float y2, float z2, uint32 c1, uint32 c2) +{ + static RwIm3DVertex v[2]; +#ifdef THIS_IS_STUPID + int i; + float f1, f2; + float len = sqrt(sq(x1-x2) + sq(y1-y2) + sq(z1-z2)); + int numsegs = len/1.5f + 1.0f; + + RwRGBA col1; + col1.red = c1>>24; + col1.green = c1>>16; + col1.blue = c1>>8; + col1.alpha = c1; + RwRGBA col2; + col2.red = c2>>24; + col2.green = c2>>16; + col2.blue = c2>>8; + col2.alpha = c2; + + float dx = x2 - x1; + float dy = y2 - y1; + float dz = z2 - z1; + for(i = 0; i < numsegs; i++){ + f1 = (float)i/numsegs; + f2 = (float)(i+1)/numsegs; + + RwIm3DVertexSetRGBA(&v[0], (int)(col1.red + (col2.red-col1.red)*f1), + (int)(col1.green + (col2.green-col1.green)*f1), + (int)(col1.blue + (col2.blue-col1.blue)*f1), + (int)(col1.alpha + (col2.alpha-col1.alpha)*f1)); + RwIm3DVertexSetRGBA(&v[1], (int)(col1.red + (col2.red-col1.red)*f2), + (int)(col1.green + (col2.green-col1.green)*f2), + (int)(col1.blue + (col2.blue-col1.blue)*f2), + (int)(col1.alpha + (col2.alpha-col1.alpha)*f2)); + RwIm3DVertexSetPos(&v[0], x1 + dx*f1, y1 + dy*f1, z1 + dz*f1); + RwIm3DVertexSetPos(&v[1], x1 + dx*f2, y1 + dy*f2, z1 + dz*f2); + + LittleTest(); + if(RwIm3DTransform(v, 2, nil, 0)){ + RwIm3DRenderLine(0, 1); + RwIm3DEnd(); + } + } +#else + RwRGBA col1; + col1.red = c1>>24; + col1.green = c1>>16; + col1.blue = c1>>8; + col1.alpha = c1; + RwRGBA col2; + col2.red = c2>>24; + col2.green = c2>>16; + col2.blue = c2>>8; + col2.alpha = c2; + + RwIm3DVertexSetRGBA(&v[0], col1.red, col1.green, col1.blue, col1.alpha); + RwIm3DVertexSetRGBA(&v[1], col2.red, col2.green, col2.blue, col2.alpha); + RwIm3DVertexSetPos(&v[0], x1, y1, z1); + RwIm3DVertexSetPos(&v[1], x2, y2, z2); + LittleTest(); + if(RwIm3DTransform(v, 2, nil, 0)){ + RwIm3DRenderLine(0, 1); + RwIm3DEnd(); + } +#endif +} diff --git a/src/render/Lines.h b/src/render/Lines.h new file mode 100644 index 00000000..f2694fc0 --- /dev/null +++ b/src/render/Lines.h @@ -0,0 +1,7 @@ +#pragma once + +class CLines +{ +public: + static void RenderLineWithClipping(float x1, float y1, float z1, float x2, float y2, float z2, uint32 c1, uint32 c2); +}; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 69df63ba..7bf4593f 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -23,11 +23,13 @@ bool gbShowPedRoadGroups; bool gbShowCarRoadGroups; bool gbShowCollisionPolys; +bool gbShowCollisionLines; bool gbDontRenderBuildings; bool gbDontRenderBigBuildings; bool gbDontRenderPeds; bool gbDontRenderObjects; +bool gbDontRenderVehicles; struct EntityInfo { @@ -132,6 +134,10 @@ CRenderer::RenderOneNonRoad(CEntity *e) else if(e->IsObject() || e->IsDummy()){ if(gbDontRenderObjects) return; + }else if(e->IsVehicle()){ + // re3 addition + if(gbDontRenderVehicles) + return; } #endif @@ -285,6 +291,21 @@ CRenderer::RenderFadingInEntities(void) CVisibilityPlugins::RenderFadingEntities(); } +void +CRenderer::RenderCollisionLines(void) +{ + int i; + + // game doesn't draw fading in entities + // this should probably be fixed + for(i = 0; i < ms_nNoOfVisibleEntities; i++){ + CEntity *e = ms_aVisibleEntityPtrs[i]; + if(Abs(e->GetPosition().x - ms_vecCameraPosition.x) < 100.0f && + Abs(e->GetPosition().y - ms_vecCameraPosition.y) < 100.0f) + CCollision::DrawColModel(e->GetMatrix(), *e->GetColModel()); + } +} + enum Visbility { VIS_INVISIBLE, diff --git a/src/render/Renderer.h b/src/render/Renderer.h index 4b96c775..817cdaae 100644 --- a/src/render/Renderer.h +++ b/src/render/Renderer.h @@ -5,11 +5,13 @@ class CEntity; extern bool gbShowPedRoadGroups; extern bool gbShowCarRoadGroups; extern bool gbShowCollisionPolys; +extern bool gbShowCollisionLines; extern bool gbDontRenderBuildings; extern bool gbDontRenderBigBuildings; extern bool gbDontRenderPeds; extern bool gbDontRenderObjects; +extern bool gbDontRenderVehicles; class CVehicle; class CPtrList; @@ -23,7 +25,9 @@ class CRenderer static CVector &ms_vecCameraPosition; static CVehicle *&m_pFirstPersonVehicle; + public: + static float &ms_lodDistScale; // defined in Frontend.cpp static bool &m_loadingPriority; static void Init(void); @@ -39,6 +43,8 @@ public: static void RenderOneNonRoad(CEntity *); static void RenderFirstPersonVehicle(void); + static void RenderCollisionLines(void); + static int32 SetupEntityVisibility(CEntity *ent); static int32 SetupBigBuildingVisibility(CEntity *ent); diff --git a/src/render/Rubbish.cpp b/src/render/Rubbish.cpp index 975f2554..c925df1c 100644 --- a/src/render/Rubbish.cpp +++ b/src/render/Rubbish.cpp @@ -3,3 +3,4 @@ #include "Rubbish.h" WRAPPER void CRubbish::Render(void) { EAXJMP(0x512190); } +WRAPPER void CRubbish::StirUp(CVehicle *veh) { EAXJMP(0x512690); } diff --git a/src/render/Rubbish.h b/src/render/Rubbish.h index f4f976e9..9f946dc2 100644 --- a/src/render/Rubbish.h +++ b/src/render/Rubbish.h @@ -1,7 +1,10 @@ #pragma once +class CVehicle; + class CRubbish { public: static void Render(void); + static void StirUp(CVehicle *veh); // CAutomobile on PS2 }; diff --git a/src/render/WaterLevel.cpp b/src/render/WaterLevel.cpp index 07c88d3e..247b9f3d 100644 --- a/src/render/WaterLevel.cpp +++ b/src/render/WaterLevel.cpp @@ -1,4 +1,5 @@ #include "common.h" +#include "main.h" #include "FileMgr.h" #include "TxdStore.h" #include "Timer.h" @@ -172,9 +173,8 @@ CWaterLevel::CreateWavyAtomic() { wavyMorphTarget = RpGeometryGetMorphTarget(wavyGeometry, 0); - wavyVert = RpMorphTargetGetVertices(wavyMorphTarget); - ASSERT(wavyMorphTarget != NULL); + wavyVert = RpMorphTargetGetVertices(wavyMorphTarget); ASSERT(wavyVert != NULL); for ( int32 i = 0; i < 9; i++ ) @@ -1148,10 +1148,10 @@ CWaterLevel::AllocateBoatWakeArray() ASSERT(ms_pWavyAtomic != NULL ); RpGeometry *wavyGeometry = RpAtomicGetGeometry(ms_pWavyAtomic); + ASSERT(wavyGeometry != NULL ); RpMorphTarget *wavyMorphTarget = RpGeometryGetMorphTarget(wavyGeometry, 0); RpMaterial *wavyMaterial = RpGeometryGetMaterial(wavyGeometry, 0); - ASSERT(wavyGeometry != NULL ); ASSERT(wavyMorphTarget != NULL ); ASSERT(wavyMaterial != NULL ); @@ -1240,7 +1240,7 @@ STARTPATCHES InjectHook(0x554FE0, &CWaterLevel::Shutdown, PATCH_JUMP); InjectHook(0x555010, &CWaterLevel::CreateWavyAtomic, PATCH_JUMP); InjectHook(0x5552A0, &CWaterLevel::DestroyWavyAtomic, PATCH_JUMP); - InjectHook(0x5552C0, &CWaterLevel::GetWaterLevel, PATCH_JUMP); + InjectHook(0x5552C0, (bool (*)(float,float,float,float*,bool))&CWaterLevel::GetWaterLevel, PATCH_JUMP); InjectHook(0x555440, &CWaterLevel::GetWaterLevelNoWaves, PATCH_JUMP); InjectHook(0x5554E0, &CWaterLevel::RenderWater, PATCH_JUMP); InjectHook(0x556C30, &CWaterLevel::RenderOneFlatSmallWaterPoly, PATCH_JUMP); diff --git a/src/render/WaterLevel.h b/src/render/WaterLevel.h index b8ec7a4d..afc6eac3 100644 --- a/src/render/WaterLevel.h +++ b/src/render/WaterLevel.h @@ -82,6 +82,7 @@ public: static void CreateWavyAtomic(); static void DestroyWavyAtomic(); static bool GetWaterLevel(float fX, float fY, float fZ, float *pfOutLevel, bool bDontCheckZ); + static bool GetWaterLevel(CVector coors, float *pfOutLevel, bool bDontCheckZ) { return GetWaterLevel(coors.x, coors.y, coors.z, pfOutLevel, bDontCheckZ); } static bool GetWaterLevelNoWaves(float fX, float fY, float fZ, float *pfOutLevel); static void RenderWater(); static void RenderOneFlatSmallWaterPoly (float fX, float fY, float fZ, RwRGBA const &color); diff --git a/src/skel/events.cpp b/src/skel/events.cpp index 877b969e..60e1482e 100644 --- a/src/skel/events.cpp +++ b/src/skel/events.cpp @@ -775,7 +775,7 @@ HandlePadButtonUp(RsPadButtonStatus *padButtonStatus) bool bCam = false; int16 mode = TheCamera.Cams[TheCamera.ActiveCam].Mode; if ( mode == CCam::MODE_FLYBY || mode == CCam::MODE_FIXED ) - bool bCam = true; + bCam = true; ControlsManager.UpdateJoyButtonState(padNumber); diff --git a/src/skel/win/win.rc b/src/skel/win/win.rc index 051f31ed..676b8ef7 100644 --- a/src/skel/win/win.rc +++ b/src/skel/win/win.rc @@ -4,11 +4,11 @@ // // Generated from the TEXTINCLUDE 2 resource. // -#if !defined(__GNU_C__) -#include "afxres.h" -#else +//#if !defined(__GNU_C__) +//#include "afxres.h" +//#else #include "winresrc.h" -#endif /* !defined(__GNU_C__) */ +//#endif /* !defined(__GNU_C__) */ ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 7d3f8ee3..fb42e6e6 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -1,32 +1,187 @@ #include "common.h" +#include "main.h" #include "patcher.h" #include "General.h" +#include "RwHelper.h" +#include "Pad.h" #include "ModelIndices.h" #include "VisibilityPlugins.h" #include "DMAudio.h" #include "Camera.h" #include "Darkel.h" +#include "Rubbish.h" #include "Fire.h" #include "Explosion.h" +#include "Particle.h" #include "World.h" #include "SurfaceTable.h" #include "HandlingMgr.h" +#include "Record.h" +#include "Remote.h" +#include "Population.h" #include "CarCtrl.h" +#include "CarAI.h" +#include "Garages.h" #include "PathFind.h" +#include "AnimManager.h" +#include "RpAnimBlend.h" #include "Ped.h" #include "PlayerPed.h" #include "Object.h" #include "Automobile.h" +bool bAllCarCheat; // unused + RwObject *GetCurrentAtomicObjectCB(RwObject *object, void *data); bool &CAutomobile::m_sAllTaxiLights = *(bool*)0x95CD21; -WRAPPER CAutomobile* CAutomobile::ctor(int, uint8) { EAXJMP(0x52C6B0); } - -CAutomobile::CAutomobile(int mi, uint8 CreatedBy) +CAutomobile::CAutomobile(int32 id, uint8 CreatedBy) + : CVehicle(CreatedBy) { - ctor(mi, CreatedBy); + int i; + + m_vehType = VEHICLE_TYPE_CAR; + + CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(id); + m_fFireBlowUpTimer = 0.0f; + field_4E0 = 0; + bTaxiLight = m_sAllTaxiLights; + m_auto_flagA20 = false; + m_auto_flagA40 = false; + m_auto_flagA80 = false; + + SetModelIndex(id); + + pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)mi->m_handlingId); + + field_49C = 20.0f; + field_4D8 = 0; + + mi->ChooseVehicleColour(m_currentColour1, m_currentColour2); + + bIsVan = !!(pHandling->Flags & HANDLING_IS_VAN); + bIsBig = !!(pHandling->Flags & HANDLING_IS_BIG); + bIsBus = !!(pHandling->Flags & HANDLING_IS_BUS); + bLowVehicle = !!(pHandling->Flags & HANDLING_IS_LOW); + + // Doors + if(bIsBus){ + Doors[DOOR_FRONT_LEFT].Init(-HALFPI, 0.0f, 0, 2); + Doors[DOOR_FRONT_RIGHT].Init(0.0f, HALFPI, 1, 2); + }else{ + Doors[DOOR_FRONT_LEFT].Init(-PI*0.4f, 0.0f, 0, 2); + Doors[DOOR_FRONT_RIGHT].Init(0.0f, PI*0.4f, 1, 2); + } + if(bIsVan){ + Doors[DOOR_REAR_LEFT].Init(-HALFPI, 0.0f, 1, 2); + Doors[DOOR_REAR_RIGHT].Init(0.0f, HALFPI, 0, 2); + }else{ + Doors[DOOR_REAR_LEFT].Init(-PI*0.4f, 0.0f, 0, 2); + Doors[DOOR_REAR_RIGHT].Init(0.0f, PI*0.4f, 1, 2); + } + if(pHandling->Flags & HANDLING_REV_BONNET) + Doors[DOOR_BONNET].Init(-PI*0.3f, 0.0f, 1, 0); + else + Doors[DOOR_BONNET].Init(0.0f, PI*0.3f, 1, 0); + if(pHandling->Flags & HANDLING_HANGING_BOOT) + Doors[DOOR_BOOT].Init(PI*0.4f, 0.0f, 0, 0); + else if(pHandling->Flags & HANDLING_TAILGATE_BOOT) + Doors[DOOR_BOOT].Init(0.0, HALFPI, 1, 0); + else + Doors[DOOR_BOOT].Init(-PI*0.3f, 0.0f, 1, 0); + if(pHandling->Flags & HANDLING_NO_DOORS){ + Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_MISSING); + Damage.SetDoorStatus(DOOR_FRONT_RIGHT, DOOR_STATUS_MISSING); + Damage.SetDoorStatus(DOOR_REAR_LEFT, DOOR_STATUS_MISSING); + Damage.SetDoorStatus(DOOR_REAR_RIGHT, DOOR_STATUS_MISSING); + } + + for(i = 0; i < 6; i++) + m_randomValues[i] = CGeneral::GetRandomNumberInRange(-0.15f, 0.15f); + + m_fMass = pHandling->fMass; + m_fTurnMass = pHandling->fTurnMass; + m_vecCentreOfMass = pHandling->CentreOfMass; + m_fAirResistance = pHandling->Dimension.x*pHandling->Dimension.z/m_fMass; + m_fElasticity = 0.05f; + m_fBuoyancy = pHandling->fBuoyancy; + + m_nBusDoorTimerEnd = 0; + m_nBusDoorTimerStart = 0; + + m_fSteerAngle = 0.0f; + m_fGasPedal = 0.0f; + m_fBrakePedal = 0.0f; + m_pSetOnFireEntity = nil; + field_594 = 0; + bNotDamagedUpsideDown = false; + bMoreResistantToDamage = false; + m_fVelocityChangeForAudio = 0.f; + field_4E2 = 0; + + for(i = 0; i < 4; i++){ + m_aGroundPhysical[i] = nil; + m_aGroundOffset[i] = CVector(0.0f, 0.0f, 0.0f); + m_aSuspensionSpringRatio[i] = 1.0f; + m_aSuspensionSpringRatioPrev[i] = m_aSuspensionSpringRatio[i]; + m_aWheelTimer[i] = 0.0f; + m_aWheelRotation[i] = 0.0f; + m_aWheelSpeed[i] = 0.0f; + m_aWheelState[i] = WHEEL_STATE_0; + m_aWheelSkidmarkMuddy[i] = false; + m_aWheelSkidmarkBloody[i] = false; + } + + m_nWheelsOnGround = 0; + m_nDriveWheelsOnGround = 0; + m_nDriveWheelsOnGroundPrev = 0; + m_fHeightAboveRoad = 0.0f; + m_fTraction = 1.0f; + + CColModel *colModel = mi->GetColModel(); + if(colModel->lines == nil){ + colModel->lines = (CColLine*)RwMalloc(4*sizeof(CColLine)); + colModel->numLines = 4; + } + + SetupSuspensionLines(); + + m_status = STATUS_SIMPLE; + bUseCollisionRecords = true; + + m_nNumPassengers = 0; + + m_bombType = CARBOMB_NONE; + bHadDriver = false; + m_pBombRigger = nil; + + if(m_nDoorLock == CARLOCK_UNLOCKED && + (id == MI_POLICE || id == MI_ENFORCER || id == MI_RHINO)) + m_nDoorLock = CARLOCK_LOCKED_INITIALLY; + + m_fCarGunLR = 0.0f; + m_fCarGunUD = 0.05f; + m_fWindScreenRotation = 0.0f; + m_weaponDoorTimerLeft = 0.0f; + m_weaponDoorTimerRight = m_weaponDoorTimerLeft; + + if(GetModelIndex() == MI_DODO){ + RpAtomicSetFlags(GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]), 0); + CMatrix mat1; + mat1.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF])); + CMatrix mat2(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LF])); + mat1.GetPosition() += CVector(mat2.GetPosition().x + 0.1f, 0.0f, mat2.GetPosition().z); + mat1.UpdateRW(); + }else if(GetModelIndex() == MI_MIAMI_SPARROW || GetModelIndex() == MI_MIAMI_RCRAIDER){ + RpAtomicSetFlags(GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]), 0); + RpAtomicSetFlags(GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]), 0); + RpAtomicSetFlags(GetFirstObject(m_aCarNodes[CAR_WHEEL_LB]), 0); + RpAtomicSetFlags(GetFirstObject(m_aCarNodes[CAR_WHEEL_RB]), 0); + }else if(GetModelIndex() == MI_RHINO){ + bExplosionProof = true; + bBulletProof = true; + } } @@ -37,7 +192,998 @@ CAutomobile::SetModelIndex(uint32 id) SetupModelNodes(); } -WRAPPER void CAutomobile::ProcessControl(void) { EAXJMP(0x531470); } +CVector vecDAMAGE_ENGINE_POS_SMALL(-0.1f, -0.1f, 0.0f); +CVector vecDAMAGE_ENGINE_POS_BIG(-0.5f, -0.3f, 0.0f); + +void +CAutomobile::ProcessControl(void) +{ + int i; + CColModel *colModel; + + if(m_veh_flagC80) + colModel = &CWorld::Players[CWorld::PlayerInFocus].m_ColModel; + else + colModel = GetColModel(); + bWarnedPeds = false; + + // skip if the collision isn't for the current level + if(colModel->level > LEVEL_NONE && colModel->level != CCollision::ms_collisionInMemory) + return; + + // Improve grip of vehicles in certain cases + bool strongGrip1 = false; + bool strongGrip2 = false; + if(FindPlayerVehicle() && this != FindPlayerVehicle()){ + switch(AutoPilot.m_nCarMission){ + case MISSION_RAMPLAYER_FARAWAY: + case MISSION_RAMPLAYER_CLOSE: + case MISSION_BLOCKPLAYER_FARAWAY: + case MISSION_BLOCKPLAYER_CLOSE: + if(FindPlayerSpeed().Magnitude() > 0.3f){ + strongGrip1 = true; + if(FindPlayerSpeed().Magnitude() > 0.4f){ + if(m_vecMoveSpeed.Magnitude() < 0.3f) + strongGrip2 = true; + }else{ + if((GetPosition() - FindPlayerCoors()).Magnitude() > 50.0f) + strongGrip2 = true; + } + } + } + } + + if(bIsBus) + ProcessAutoBusDoors(); + + ProcessCarAlarm(); + + // Scan if this car is committing a crime that the police can see + if(m_status != STATUS_ABANDONED && m_status != STATUS_WRECKED && + m_status != STATUS_PLAYER && m_status != STATUS_PLAYER_REMOTE && m_status != STATUS_PLAYER_DISABLED){ + switch(GetModelIndex()) + case MI_FBICAR: + case MI_POLICE: + case MI_ENFORCER: + case MI_SECURICA: + case MI_RHINO: + case MI_BARRACKS: + ScanForCrimes(); + } + + // Process driver + if(pDriver){ + if(!bHadDriver && m_bombType == CARBOMB_ONIGNITIONACTIVE){ + // If someone enters the car and there is a bomb, detonate + m_nBombTimer = 1000; + m_pBlowUpEntity = m_pBombRigger; + if(m_pBlowUpEntity) + m_pBlowUpEntity->RegisterReference((CEntity**)&m_pBlowUpEntity); + DMAudio.PlayOneShot(m_audioEntityId, SOUND_BOMB_TICK, 1.0f); + } + bHadDriver = true; + + if(IsUpsideDown() && CanPedEnterCar()){ + if(!pDriver->IsPlayer() && + !(pDriver->m_leader && pDriver->m_leader->bInVehicle) && + pDriver->CharCreatedBy != MISSION_CHAR) + pDriver->SetObjective(OBJECTIVE_LEAVE_VEHICLE, this); + } + }else + bHadDriver = false; + + // Process passengers + if(m_nNumPassengers != 0 && IsUpsideDown() && CanPedEnterCar()){ + for(i = 0; i < m_nNumMaxPassengers; i++) + if(pPassengers[i]) + if(!pPassengers[i]->IsPlayer() && + !(pPassengers[i]->m_leader && pPassengers[i]->m_leader->bInVehicle) && + pPassengers[i]->CharCreatedBy != MISSION_CHAR) + pPassengers[i]->SetObjective(OBJECTIVE_LEAVE_VEHICLE, this); + } + + CRubbish::StirUp(this); + + // blend in clump + int clumpAlpha = CVisibilityPlugins::GetClumpAlpha((RpClump*)m_rwObject); + if(bFadeOut){ + clumpAlpha -= 8; + if(clumpAlpha < 0) + clumpAlpha = 0; + }else if(clumpAlpha < 255){ + clumpAlpha += 16; + if(clumpAlpha > 255) + clumpAlpha = 255; + } + CVisibilityPlugins::SetClumpAlpha((RpClump*)m_rwObject, clumpAlpha); + + AutoPilot.m_flag1 = false; + AutoPilot.m_flag2 = false; + + // Set Center of Mass to make car more stable + if(strongGrip1 || bCheat3) + m_vecCentreOfMass.z = 0.3f*m_aSuspensionSpringLength[0] + -1.0*m_fHeightAboveRoad; + else if(pHandling->Flags & HANDLING_NONPLAYER_STABILISER && m_status == STATUS_PHYSICS) + m_vecCentreOfMass.z = pHandling->CentreOfMass.z - 0.2f*pHandling->Dimension.z; + else + m_vecCentreOfMass.z = pHandling->CentreOfMass.z; + + // Process depending on status + + bool playerRemote = false; + switch(m_status){ + case STATUS_PLAYER_REMOTE: + if(CPad::GetPad(0)->WeaponJustDown()){ + BlowUpCar(FindPlayerPed()); + CRemote::TakeRemoteControlledCarFromPlayer(); + } + + if(GetModelIndex() == MI_RCBANDIT){ + CVector pos = GetPosition(); + // FindPlayerCoors unused + if(RcbanditCheckHitWheels() || bIsInWater || CPopulation::IsPointInSafeZone(&pos)){ + if(CPopulation::IsPointInSafeZone(&pos)) + CGarages::TriggerMessage("HM2_5", -1, 5000, -1); + CRemote::TakeRemoteControlledCarFromPlayer(); + BlowUpCar(FindPlayerPed()); + } + } + + if(CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle == this) + playerRemote = true; + // fall through + case STATUS_PLAYER: + if(playerRemote || + pDriver && pDriver->GetPedState() != PED_EXIT_CAR && pDriver->GetPedState() != PED_DRAG_FROM_CAR){ + // process control input if controlled by player + if(playerRemote || pDriver->m_nPedType == PEDTYPE_PLAYER1) + ProcessControlInputs(0); + + PruneReferences(); + + if(m_status == STATUS_PLAYER && CRecordDataForChase::Status != RECORDSTATE_1) + DoDriveByShootings(); + } + break; + + case STATUS_SIMPLE: + CCarAI::UpdateCarAI(this); + CPhysical::ProcessControl(); + CCarCtrl::UpdateCarOnRails(this); + + m_nWheelsOnGround = 4; + m_nDriveWheelsOnGroundPrev = m_nDriveWheelsOnGround; + m_nDriveWheelsOnGround = 4; + + pHandling->Transmission.CalculateGearForSimpleCar(AutoPilot.m_fMaxTrafficSpeed/50.0f, m_nCurrentGear); + + { + float wheelRot = ProcessWheelRotation(WHEEL_STATE_0, GetForward(), m_vecMoveSpeed, 0.35f); + for(i = 0; i < 4; i++) + m_aWheelRotation[i] += wheelRot; + } + + PlayHornIfNecessary(); + ReduceHornCounter(); + bVehicleColProcessed = false; + // that's all we do for simple vehicles + return; + + case STATUS_PHYSICS: + CCarAI::UpdateCarAI(this); + CCarCtrl::SteerAICarWithPhysics(this); + PlayHornIfNecessary(); + break; + + case STATUS_ABANDONED: + m_fBrakePedal = 0.2f; + bIsHandbrakeOn = false; + + m_fSteerAngle = 0.0f; + m_fGasPedal = 0.0f; + m_nCarHornTimer = 0; + break; + + case STATUS_WRECKED: + m_fBrakePedal = 0.05f; + bIsHandbrakeOn = true; + + m_fSteerAngle = 0.0f; + m_fGasPedal = 0.0f; + m_nCarHornTimer = 0; + break; + + case STATUS_PLAYER_DISABLED: + m_fBrakePedal = 1.0f; + bIsHandbrakeOn = true; + + m_fSteerAngle = 0.0f; + m_fGasPedal = 0.0f; + m_nCarHornTimer = 0; + break; + } + + // what's going on here? + if(GetPosition().z < -0.6f && + Abs(m_vecMoveSpeed.x) < 0.05f && + Abs(m_vecMoveSpeed.y) < 0.05f) + m_vecTurnSpeed *= Pow(0.95f, CTimer::GetTimeStep()); + + // Skip physics if object is found to have been static recently + bool skipPhysics = false; + if(!bIsStuck && (m_status == STATUS_ABANDONED || m_status == STATUS_WRECKED)){ + bool makeStatic = false; + float moveSpeedLimit, turnSpeedLimit, distanceLimit; + + if(!bVehicleColProcessed && + m_vecMoveSpeed.IsZero() && + // BUG? m_aSuspensionSpringRatioPrev[3] is checked twice in the game. also, why 3? + m_aSuspensionSpringRatioPrev[3] != 1.0f) + makeStatic = true; + + if(m_status == STATUS_WRECKED){ + moveSpeedLimit = 0.006f; + turnSpeedLimit = 0.0015f; + distanceLimit = 0.015f; + }else{ + moveSpeedLimit = 0.003f; + turnSpeedLimit = 0.0009f; + distanceLimit = 0.005f; + } + + m_vecMoveSpeedAvg = (m_vecMoveSpeedAvg + m_vecMoveSpeed)/2.0f; + m_vecTurnSpeedAvg = (m_vecTurnSpeedAvg + m_vecTurnSpeed)/2.0f; + + if(m_vecMoveSpeedAvg.MagnitudeSqr() <= sq(moveSpeedLimit*CTimer::GetTimeStep()) && + m_vecTurnSpeedAvg.MagnitudeSqr() <= sq(turnSpeedLimit*CTimer::GetTimeStep()) && + m_fDistanceTravelled < distanceLimit || + makeStatic){ + m_nStaticFrames++; + + if(m_nStaticFrames > 10 || makeStatic) + if(!CCarCtrl::MapCouldMoveInThisArea(GetPosition().x, GetPosition().y)){ + if(!makeStatic || m_nStaticFrames > 10) + m_nStaticFrames = 10; + + skipPhysics = true; + + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); + } + }else + m_nStaticFrames = 0; + } + + // Postpone + for(i = 0; i < 4; i++) + if(m_aGroundPhysical[i] && !CWorld::bForceProcessControl && m_aGroundPhysical[i]->bIsInSafePosition){ + bWasPostponed = true; + return; + } + + VehicleDamage(0.0f, 0); + + // special control + switch(GetModelIndex()){ + case MI_FIRETRUCK: + FireTruckControl(); + break; + case MI_RHINO: + TankControl(); + BlowUpCarsInPath(); + break; + case MI_YARDIE: + // beta also had esperanto here it seems + HydraulicControl(); + break; + default: + if(CVehicle::bCheat3){ + // Make vehicle jump when horn is sounded + if(m_status == STATUS_PLAYER && m_vecMoveSpeed.MagnitudeSqr() > sq(0.2f) && + // BUG: game checks [0] four times, instead of all wheels + m_aSuspensionSpringRatio[0] < 1.0f && + CPad::GetPad(0)->HornJustDown()){ + + DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRALIC_1, 0.0f); + DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_JUMP, 1.0f); + + CParticle::AddParticle(PARTICLE_ENGINE_STEAM, + m_aWheelColPoints[0].point + 0.5f*GetUp(), + 1.3f*m_vecMoveSpeed, nil, 2.5f); + CParticle::AddParticle(PARTICLE_ENGINE_SMOKE, + m_aWheelColPoints[0].point + 0.5f*GetUp(), + 1.2f*m_vecMoveSpeed, nil, 2.0f); + + CParticle::AddParticle(PARTICLE_ENGINE_STEAM, + m_aWheelColPoints[2].point + 0.5f*GetUp(), + 1.3f*m_vecMoveSpeed, nil, 2.5f); + CParticle::AddParticle(PARTICLE_ENGINE_SMOKE, + m_aWheelColPoints[2].point + 0.5f*GetUp(), + 1.2f*m_vecMoveSpeed, nil, 2.0f); + + CParticle::AddParticle(PARTICLE_ENGINE_STEAM, + m_aWheelColPoints[0].point + 0.5f*GetUp() - GetForward(), + 1.3f*m_vecMoveSpeed, nil, 2.5f); + CParticle::AddParticle(PARTICLE_ENGINE_SMOKE, + m_aWheelColPoints[0].point + 0.5f*GetUp() - GetForward(), + 1.2f*m_vecMoveSpeed, nil, 2.0f); + + CParticle::AddParticle(PARTICLE_ENGINE_STEAM, + m_aWheelColPoints[2].point + 0.5f*GetUp() - GetForward(), + 1.3f*m_vecMoveSpeed, nil, 2.5f); + CParticle::AddParticle(PARTICLE_ENGINE_SMOKE, + m_aWheelColPoints[2].point + 0.5f*GetUp() - GetForward(), + 1.2f*m_vecMoveSpeed, nil, 2.0f); + + ApplyMoveForce(CVector(0.0f, 0.0f, 1.0f)*m_fMass*0.4f); + ApplyTurnForce(GetUp()*m_fMass*0.035f, GetForward()*1.0f); + } + } + break; + } + + float brake; + if(skipPhysics){ + bHasContacted = false; + bIsInSafePosition = false; + bWasPostponed = false; + bHasHitWall = false; + m_nCollisionRecords = 0; + bHasCollided = false; + bVehicleColProcessed = false; + m_nDamagePieceType = 0; + m_fDamageImpulse = 0.0f; + m_pDamageEntity = nil; + m_vecTurnFriction = CVector(0.0f, 0.0f, 0.0f); + m_vecMoveFriction = CVector(0.0f, 0.0f, 0.0f); + }else{ + + // This has to be done if ProcessEntityCollision wasn't called + if(!bVehicleColProcessed){ + CMatrix mat(GetMatrix()); + bIsStuck = false; + bHasContacted = false; + bIsInSafePosition = false; + bWasPostponed = false; + bHasHitWall = false; + m_fDistanceTravelled = 0.0f; + field_EF = false; + m_phy_flagA80 = false; + ApplyMoveSpeed(); + ApplyTurnSpeed(); + for(i = 0; CheckCollision() && i < 5; i++){ + GetMatrix() = mat; + ApplyMoveSpeed(); + ApplyTurnSpeed(); + } + bIsInSafePosition = true; + bIsStuck = false; + } + + CPhysical::ProcessControl(); + + ProcessBuoyancy(); + + // Rescale spring ratios, i.e. subtract wheel radius + for(i = 0; i < 4; i++){ + // wheel radius in relation to suspension line + float wheelRadius = 1.0f - m_aSuspensionSpringLength[i]/m_aSuspensionLineLength[i]; + // rescale such that 0.0 is fully compressed and 1.0 is fully extended + m_aSuspensionSpringRatio[i] = (m_aSuspensionSpringRatio[i]-wheelRadius)/(1.0f-wheelRadius); + } + + float fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward()); + CVector contactPoints[4]; // relative to model + CVector contactSpeeds[4]; // speed at contact points + CVector springDirections[4]; // normalized, in model space + + for(i = 0; i < 4; i++){ + // Set spring under certain circumstances + if(Damage.GetWheelStatus(i) == WHEEL_STATUS_MISSING) + m_aSuspensionSpringRatio[i] = 1.0f; + else if(Damage.GetWheelStatus(i) == WHEEL_STATUS_BURST){ + // wheel more bumpy the faster we are + if(CGeneral::GetRandomNumberInRange(0, (uint16)(40*fwdSpeed) + 98) < 100){ + m_aSuspensionSpringRatio[i] += 0.3f*(m_aSuspensionLineLength[i]-m_aSuspensionSpringLength[i])/m_aSuspensionSpringLength[i]; + if(m_aSuspensionSpringRatio[i] > 1.0f) + m_aSuspensionSpringRatio[i] = 1.0f; + } + } + + // get points and directions if spring is compressed + if(m_aSuspensionSpringRatio[i] < 1.0f){ + contactPoints[i] = m_aWheelColPoints[i].point - GetPosition(); + springDirections[i] = Multiply3x3(GetMatrix(), colModel->lines[i].p1 - colModel->lines[i].p0); + springDirections[i].Normalise(); + } + } + + // Make springs push up vehicle + for(i = 0; i < 4; i++){ + if(m_aSuspensionSpringRatio[i] < 1.0f){ + float bias = pHandling->fSuspensionBias; + if(i == 1 || i == 3) // rear + bias = 1.0f - bias; + + ApplySpringCollision(pHandling->fSuspensionForceLevel, + springDirections[i], contactPoints[i], + m_aSuspensionSpringRatio[i], bias); + m_aWheelSkidmarkMuddy[i] = + m_aWheelColPoints[i].surfaceB == SURFACE_GRASS || + m_aWheelColPoints[i].surfaceB == SURFACE_DIRTTRACK || + m_aWheelColPoints[i].surfaceB == SURFACE_SAND; + }else{ + contactPoints[i] = Multiply3x3(GetMatrix(), colModel->lines[i].p1); + } + } + + // Get speed at contact points + for(i = 0; i < 4; i++){ + contactSpeeds[i] = GetSpeed(contactPoints[i]); + if(m_aGroundPhysical[i]){ + // subtract movement of physical we're standing on + contactSpeeds[i] -= m_aGroundPhysical[i]->GetSpeed(m_aGroundOffset[i]); +#ifndef FIX_BUGS + // this shouldn't be reset because we still need it below + m_aGroundPhysical[i] = nil; +#endif + } + } + + // dampen springs + for(i = 0; i < 4; i++) + if(m_aSuspensionSpringRatio[i] < 1.0f) + ApplySpringDampening(pHandling->fSuspensionDampingLevel, + springDirections[i], contactPoints[i], contactSpeeds[i]); + + // Get speed at contact points again + for(i = 0; i < 4; i++){ + contactSpeeds[i] = GetSpeed(contactPoints[i]); + if(m_aGroundPhysical[i]){ + // subtract movement of physical we're standing on + contactSpeeds[i] -= m_aGroundPhysical[i]->GetSpeed(m_aGroundOffset[i]); + m_aGroundPhysical[i] = nil; + } + } + + + bool gripCheat = true; + fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward()); + if(!strongGrip1 && !CVehicle::bCheat3) + gripCheat = false; + float acceleration = pHandling->Transmission.CalculateDriveAcceleration(m_fGasPedal, m_nCurrentGear, m_fChangeGearTime, fwdSpeed, gripCheat); + acceleration /= fForceMultiplier; + + // unused + if(GetModelIndex() == MI_MIAMI_RCBARON || + GetModelIndex() == MI_MIAMI_RCRAIDER || + GetModelIndex() == MI_MIAMI_SPARROW) + acceleration = 0.0f; + + brake = m_fBrakePedal * pHandling->fBrakeDeceleration * CTimer::GetTimeStep(); + bool neutralHandling = !!(pHandling->Flags & HANDLING_NEUTRALHANDLING); + float brakeBiasFront = neutralHandling ? 1.0f : 2.0f*pHandling->fBrakeBias; + float brakeBiasRear = neutralHandling ? 1.0f : 2.0f*(1.0f-pHandling->fBrakeBias); + float tractionBiasFront = neutralHandling ? 1.0f : 2.0f*pHandling->fTractionBias; + float tractionBiasRear = neutralHandling ? 1.0f : 2.0f*(1.0f-pHandling->fTractionBias); + + // Count how many wheels are touching the ground + + m_nWheelsOnGround = 0; + m_nDriveWheelsOnGroundPrev = m_nDriveWheelsOnGround; + m_nDriveWheelsOnGround = 0; + + for(i = 0; i < 4; i++){ + if(m_aSuspensionSpringRatio[i] < 1.0f) + m_aWheelTimer[i] = 4.0f; + else + m_aWheelTimer[i] = max(m_aWheelTimer[i]-CTimer::GetTimeStep(), 0.0f); + + if(m_aWheelTimer[i] > 0.0f){ + m_nWheelsOnGround++; + switch(pHandling->Transmission.nDriveType){ + case '4': + m_nDriveWheelsOnGround++; + break; + case 'F': + if(i == CARWHEEL_FRONT_LEFT || i == CARWHEEL_FRONT_RIGHT) + m_nDriveWheelsOnGround++; + break; + case 'R': + if(i == CARWHEEL_REAR_LEFT || i == CARWHEEL_REAR_RIGHT) + m_nDriveWheelsOnGround++; + break; + } + } + } + + float traction; + if(m_status == STATUS_PHYSICS) + traction = 0.004f * m_fTraction; + else + traction = 0.004f; + traction *= pHandling->fTractionMultiplier / 4.0f; + traction /= fForceMultiplier; + if(CVehicle::bCheat3) + traction *= 4.0f; + + if(FindPlayerVehicle() && FindPlayerVehicle() == this){ + if(CPad::GetPad(0)->WeaponJustDown()){ + if(m_bombType == CARBOMB_TIMED){ + m_bombType = CARBOMB_TIMEDACTIVE; + m_nBombTimer = 7000; + m_pBlowUpEntity = FindPlayerPed(); + CGarages::TriggerMessage("GA_12", -1, 3000, -1); + DMAudio.PlayOneShot(m_audioEntityId, SOUND_BOMB_TIMED_ACTIVATED, 1.0f); + }else if(m_bombType == CARBOMB_ONIGNITION){ + m_bombType = CARBOMB_ONIGNITIONACTIVE; + CGarages::TriggerMessage("GA_12", -1, 3000, -1); + DMAudio.PlayOneShot(m_audioEntityId, SOUND_BOMB_ONIGNITION_ACTIVATED, 1.0f); + } + } + }else if(strongGrip1 || CVehicle::bCheat3){ + traction *= 1.2f; + acceleration *= 1.4f; + if(strongGrip2 || CVehicle::bCheat3){ + traction *= 1.3f; + acceleration *= 1.4f; + } + } + + static float fThrust; + static tWheelState WheelState[4]; + + // Process front wheels on ground + + if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] > 0.0f || m_aWheelTimer[CARWHEEL_FRONT_RIGHT] > 0.0f){ + float s = Sin(m_fSteerAngle); + float c = Cos(m_fSteerAngle); + CVector wheelFwd = Multiply3x3(GetMatrix(), CVector(-s, c, 0.0f)); + CVector wheelRight = Multiply3x3(GetMatrix(), CVector(c, s, 0.0f)); + + if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] > 0.0f){ + if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier)) + fThrust = 0.0f; + else + fThrust = acceleration; + + m_aWheelColPoints[CARWHEEL_FRONT_LEFT].surfaceA = SURFACE_RUBBER29; + float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_FRONT_LEFT])*traction; + if(m_status == STATUS_PLAYER) + adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[CARWHEEL_FRONT_LEFT].surfaceB); + WheelState[CARWHEEL_FRONT_LEFT] = m_aWheelState[CARWHEEL_FRONT_LEFT]; + + if(Damage.GetWheelStatus(VEHWHEEL_FRONT_LEFT) == WHEEL_STATUS_BURST) + ProcessWheel(wheelFwd, wheelRight, + contactSpeeds[CARWHEEL_FRONT_LEFT], contactPoints[CARWHEEL_FRONT_LEFT], + m_nWheelsOnGround, fThrust, + brake*brakeBiasFront, + adhesion*tractionBiasFront*Damage.m_fWheelDamageEffect, + CARWHEEL_FRONT_LEFT, + &m_aWheelSpeed[CARWHEEL_FRONT_LEFT], + &WheelState[CARWHEEL_FRONT_LEFT], + WHEEL_STATUS_BURST); + else + ProcessWheel(wheelFwd, wheelRight, + contactSpeeds[CARWHEEL_FRONT_LEFT], contactPoints[CARWHEEL_FRONT_LEFT], + m_nWheelsOnGround, fThrust, + brake*brakeBiasFront, + adhesion*tractionBiasFront, + CARWHEEL_FRONT_LEFT, + &m_aWheelSpeed[CARWHEEL_FRONT_LEFT], + &WheelState[CARWHEEL_FRONT_LEFT], + WHEEL_STATUS_OK); + } + + if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] > 0.0f){ + if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier)) + fThrust = 0.0f; + else + fThrust = acceleration; + + m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].surfaceA = SURFACE_RUBBER29; + float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_FRONT_RIGHT])*traction; + if(m_status == STATUS_PLAYER) + adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].surfaceB); + WheelState[CARWHEEL_FRONT_RIGHT] = m_aWheelState[CARWHEEL_FRONT_RIGHT]; + + if(Damage.GetWheelStatus(VEHWHEEL_FRONT_RIGHT) == WHEEL_STATUS_BURST) + ProcessWheel(wheelFwd, wheelRight, + contactSpeeds[CARWHEEL_FRONT_RIGHT], contactPoints[CARWHEEL_FRONT_RIGHT], + m_nWheelsOnGround, fThrust, + brake*brakeBiasFront, + adhesion*tractionBiasFront*Damage.m_fWheelDamageEffect, + CARWHEEL_FRONT_RIGHT, + &m_aWheelSpeed[CARWHEEL_FRONT_RIGHT], + &WheelState[CARWHEEL_FRONT_RIGHT], + WHEEL_STATUS_BURST); + else + ProcessWheel(wheelFwd, wheelRight, + contactSpeeds[CARWHEEL_FRONT_RIGHT], contactPoints[CARWHEEL_FRONT_RIGHT], + m_nWheelsOnGround, fThrust, + brake*brakeBiasFront, + adhesion*tractionBiasFront, + CARWHEEL_FRONT_RIGHT, + &m_aWheelSpeed[CARWHEEL_FRONT_RIGHT], + &WheelState[CARWHEEL_FRONT_RIGHT], + WHEEL_STATUS_OK); + } + } + + // Process front wheels off ground + + if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] <= 0.0f){ + if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f) + m_aWheelSpeed[CARWHEEL_FRONT_LEFT] *= 0.95f; + else{ + if(acceleration > 0.0f){ + if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] < 2.0f) + m_aWheelSpeed[CARWHEEL_FRONT_LEFT] -= 0.2f; + }else{ + if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] > -2.0f) + m_aWheelSpeed[CARWHEEL_FRONT_LEFT] += 0.1f; + } + } + m_aWheelRotation[CARWHEEL_FRONT_LEFT] += m_aWheelSpeed[CARWHEEL_FRONT_LEFT]; + } + if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] <= 0.0f){ + if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f) + m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] *= 0.95f; + else{ + if(acceleration > 0.0f){ + if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] < 2.0f) + m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] -= 0.2f; + }else{ + if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] > -2.0f) + m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] += 0.1f; + } + } + m_aWheelRotation[CARWHEEL_FRONT_RIGHT] += m_aWheelSpeed[CARWHEEL_FRONT_RIGHT]; + } + + // Process rear wheels + + if(m_aWheelTimer[CARWHEEL_REAR_LEFT] > 0.0f || m_aWheelTimer[CARWHEEL_REAR_RIGHT] > 0.0f){ + CVector wheelFwd = GetForward(); + CVector wheelRight = GetRight(); + + if(bIsHandbrakeOn) + brake = 20000.0f; + + if(m_aWheelTimer[CARWHEEL_REAR_LEFT] > 0.0f){ + if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier)) + fThrust = 0.0f; + else + fThrust = acceleration; + + m_aWheelColPoints[CARWHEEL_REAR_LEFT].surfaceA = SURFACE_RUBBER29; + float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_REAR_LEFT])*traction; + if(m_status == STATUS_PLAYER) + adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[CARWHEEL_REAR_LEFT].surfaceB); + WheelState[CARWHEEL_REAR_LEFT] = m_aWheelState[CARWHEEL_REAR_LEFT]; + + if(Damage.GetWheelStatus(VEHWHEEL_REAR_LEFT) == WHEEL_STATUS_BURST) + ProcessWheel(wheelFwd, wheelRight, + contactSpeeds[CARWHEEL_REAR_LEFT], contactPoints[CARWHEEL_REAR_LEFT], + m_nWheelsOnGround, fThrust, + brake*brakeBiasRear, + adhesion*tractionBiasRear*Damage.m_fWheelDamageEffect, + CARWHEEL_REAR_LEFT, + &m_aWheelSpeed[CARWHEEL_REAR_LEFT], + &WheelState[CARWHEEL_REAR_LEFT], + WHEEL_STATUS_BURST); + else + ProcessWheel(wheelFwd, wheelRight, + contactSpeeds[CARWHEEL_REAR_LEFT], contactPoints[CARWHEEL_REAR_LEFT], + m_nWheelsOnGround, fThrust, + brake*brakeBiasRear, + adhesion*tractionBiasRear, + CARWHEEL_REAR_LEFT, + &m_aWheelSpeed[CARWHEEL_REAR_LEFT], + &WheelState[CARWHEEL_REAR_LEFT], + WHEEL_STATUS_OK); + } + + if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] > 0.0f){ + if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier)) + fThrust = 0.0f; + else + fThrust = acceleration; + + m_aWheelColPoints[CARWHEEL_REAR_RIGHT].surfaceA = SURFACE_RUBBER29; + float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_REAR_RIGHT])*traction; + if(m_status == STATUS_PLAYER) + adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[CARWHEEL_REAR_RIGHT].surfaceB); + WheelState[CARWHEEL_REAR_RIGHT] = m_aWheelState[CARWHEEL_REAR_RIGHT]; + + if(Damage.GetWheelStatus(VEHWHEEL_REAR_RIGHT) == WHEEL_STATUS_BURST) + ProcessWheel(wheelFwd, wheelRight, + contactSpeeds[CARWHEEL_REAR_RIGHT], contactPoints[CARWHEEL_REAR_RIGHT], + m_nWheelsOnGround, fThrust, + brake*brakeBiasRear, + adhesion*tractionBiasRear*Damage.m_fWheelDamageEffect, + CARWHEEL_REAR_RIGHT, + &m_aWheelSpeed[CARWHEEL_REAR_RIGHT], + &WheelState[CARWHEEL_REAR_RIGHT], + WHEEL_STATUS_BURST); + else + ProcessWheel(wheelFwd, wheelRight, + contactSpeeds[CARWHEEL_REAR_RIGHT], contactPoints[CARWHEEL_REAR_RIGHT], + m_nWheelsOnGround, fThrust, + brake*brakeBiasRear, + adhesion*tractionBiasRear, + CARWHEEL_REAR_RIGHT, + &m_aWheelSpeed[CARWHEEL_REAR_RIGHT], + &WheelState[CARWHEEL_REAR_RIGHT], + WHEEL_STATUS_OK); + } + } + + // Process rear wheels off ground + + if(m_aWheelTimer[CARWHEEL_REAR_LEFT] <= 0.0f){ + if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f) + m_aWheelSpeed[CARWHEEL_REAR_LEFT] *= 0.95f; + else{ + if(acceleration > 0.0f){ + if(m_aWheelSpeed[CARWHEEL_REAR_LEFT] < 2.0f) + m_aWheelSpeed[CARWHEEL_REAR_LEFT] -= 0.2f; + }else{ + if(m_aWheelSpeed[CARWHEEL_REAR_LEFT] > -2.0f) + m_aWheelSpeed[CARWHEEL_REAR_LEFT] += 0.1f; + } + } + m_aWheelRotation[CARWHEEL_REAR_LEFT] += m_aWheelSpeed[CARWHEEL_REAR_LEFT]; + } + if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] <= 0.0f){ + if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f) + m_aWheelSpeed[CARWHEEL_REAR_RIGHT] *= 0.95f; + else{ + if(acceleration > 0.0f){ + if(m_aWheelSpeed[CARWHEEL_REAR_RIGHT] < 2.0f) + m_aWheelSpeed[CARWHEEL_REAR_RIGHT] -= 0.2f; + }else{ + if(m_aWheelSpeed[CARWHEEL_REAR_RIGHT] > -2.0f) + m_aWheelSpeed[CARWHEEL_REAR_RIGHT] += 0.1f; + } + } + m_aWheelRotation[CARWHEEL_REAR_RIGHT] += m_aWheelSpeed[CARWHEEL_REAR_RIGHT]; + } + + for(i = 0; i < 4; i++){ + float wheelPos = colModel->lines[i].p0.z; + if(m_aSuspensionSpringRatio[i] > 0.0f) + wheelPos -= m_aSuspensionSpringRatio[i]*m_aSuspensionSpringLength[i]; + m_aWheelPosition[i] += (wheelPos - m_aWheelPosition[i])*0.75f; + } + for(i = 0; i < 4; i++) + m_aWheelState[i] = WheelState[i]; + + // Process horn + + if(m_status != STATUS_PLAYER){ + ReduceHornCounter(); + }else{ + if(GetModelIndex() == MI_MRWHOOP){ + if(Pads[0].bHornHistory[Pads[0].iCurrHornHistory] && + !Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % 5]){ + m_bSirenOrAlarm = !m_bSirenOrAlarm; + printf("m_bSirenOrAlarm toggled to %d\n", m_bSirenOrAlarm); + } + }else if(UsesSiren(GetModelIndex())){ + if(Pads[0].bHornHistory[Pads[0].iCurrHornHistory]){ + if(Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % 5] && + Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+3) % 5]) + m_nCarHornTimer = 1; + else + m_nCarHornTimer = 0; + }else if(Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % 5] && + !Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+1) % 5]){ + m_nCarHornTimer = 0; + m_bSirenOrAlarm = !m_bSirenOrAlarm; + }else + m_nCarHornTimer = 0; + }else if(GetModelIndex() != MI_YARDIE && !CVehicle::bCheat3){ + if(Pads[0].GetHorn()) + m_nCarHornTimer = 1; + else + m_nCarHornTimer = 0; + } + } + + // Flying + + if(m_status != STATUS_PLAYER && m_status != STATUS_PLAYER_REMOTE && m_status != STATUS_PHYSICS){ + if(GetModelIndex() == MI_MIAMI_RCRAIDER || GetModelIndex() == MI_MIAMI_SPARROW) + m_aWheelSpeed[0] = max(m_aWheelSpeed[0]-0.0005f, 0.0f); + }else if((GetModelIndex() == MI_DODO || CVehicle::bAllDodosCheat) && + m_vecMoveSpeed.Magnitude() > 0.0f && CTimer::GetTimeStep() > 0.0f){ + FlyingControl(FLIGHT_MODEL_DODO); + }else if(GetModelIndex() == MI_MIAMI_RCBARON){ + FlyingControl(FLIGHT_MODEL_HELI); + }else if(GetModelIndex() == MI_MIAMI_RCRAIDER || GetModelIndex() == MI_MIAMI_SPARROW || bAllCarCheat){ + if(CPad::GetPad(0)->GetCircleJustDown()) + m_aWheelSpeed[0] = max(m_aWheelSpeed[0]-0.03f, 0.0f); + if(m_aWheelSpeed[0] < 0.22f) + m_aWheelSpeed[0] += 0.0001f; + if(m_aWheelSpeed[0] > 0.15f) + FlyingControl(FLIGHT_MODEL_HELI); + } + } + + + + // Process car on fire + // A similar calculation of damagePos is done elsewhere for smoke + + uint8 engineStatus = Damage.GetEngineStatus(); + CVector damagePos = ((CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()))->m_positions[CAR_POS_HEADLIGHTS]; + + switch(Damage.GetDoorStatus(DOOR_BONNET)){ + case DOOR_STATUS_OK: + case DOOR_STATUS_SMASHED: + // Bonnet is still there, smoke comes out at the edge + damagePos += vecDAMAGE_ENGINE_POS_SMALL; + break; + case DOOR_STATUS_SWINGING: + case DOOR_STATUS_MISSING: + // Bonnet is gone, smoke comes out at the engine + damagePos += vecDAMAGE_ENGINE_POS_BIG; + break; + } + + // move fire forward if in first person + if(this == FindPlayerVehicle() && TheCamera.GetLookingForwardFirstPerson()) + if(m_fHealth < 250.0f && m_status != STATUS_WRECKED){ + if(GetModelIndex() == MI_FIRETRUCK) + damagePos += CVector(0.0f, 3.0f, -0.2f); + else + damagePos += CVector(0.0f, 1.2f, -0.8f); + } + + damagePos = GetMatrix()*damagePos; + damagePos.z += 0.15f; + + if(m_fHealth < 250.0f && m_status != STATUS_WRECKED){ + // Car is on fire + + CParticle::AddParticle(PARTICLE_CARFLAME, damagePos, + CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(0.01125f, 0.09f)), + nil, 0.9f); + + CVector coors = damagePos; + coors.x += CGeneral::GetRandomNumberInRange(-0.5625f, 0.5625f), + coors.y += CGeneral::GetRandomNumberInRange(-0.5625f, 0.5625f), + coors.z += CGeneral::GetRandomNumberInRange(0.5625f, 2.25f); + CParticle::AddParticle(PARTICLE_CARFLAME_SMOKE, coors, CVector(0.0f, 0.0f, 0.0f)); + + CParticle::AddParticle(PARTICLE_ENGINE_SMOKE2, damagePos, CVector(0.0f, 0.0f, 0.0f), nil, 0.5f); + + // Blow up car after 5 seconds + m_fFireBlowUpTimer += CTimer::GetTimeStepInMilliseconds(); + if(m_fFireBlowUpTimer > 5000.0f){ + CWorld::Players[CWorld::PlayerInFocus].AwardMoneyForExplosion(this); + BlowUpCar(m_pSetOnFireEntity); + } + }else + m_fFireBlowUpTimer = 0.0f; + + // Decrease car health if engine is damaged badly + if(engineStatus > ENGINE_STATUS_ON_FIRE && m_fHealth > 250.0f) + m_fHealth -= 2.0f; + + ProcessDelayedExplosion(); + + + if(m_bSirenOrAlarm && (CTimer::GetFrameCounter()&7) == 5 && + UsesSiren(GetModelIndex()) && GetModelIndex() != MI_RCBANDIT) + CCarAI::MakeWayForCarWithSiren(this); + + + // Find out how much to shake the pad depending on suspension and ground surface + + float suspShake = 0.0f; + float surfShake = 0.0f; + for(i = 0; i < 4; i++){ + float suspChange = m_aSuspensionSpringRatioPrev[i] - m_aSuspensionSpringRatio[i]; + if(suspChange > 0.3f){ + DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_JUMP, suspChange); + if(suspChange > suspShake) + suspShake = suspChange; + } + + uint8 surf = m_aWheelColPoints[i].surfaceB; + if(surf == SURFACE_DIRT || surf == SURFACE_PUDDLE || surf == SURFACE_HEDGE){ + if(surfShake < 0.2f) + surfShake = 0.3f; + }else if(surf == SURFACE_DIRTTRACK || surf == SURFACE_SAND){ + if(surfShake < 0.1f) + surfShake = 0.2f; + }else if(surf == SURFACE_GRASS){ + if(surfShake < 0.05f) + surfShake = 0.1f; + } + + m_aSuspensionSpringRatioPrev[i] = m_aSuspensionSpringRatio[i]; + m_aSuspensionSpringRatio[i] = 1.0f; + } + + // Shake pad + + if((suspShake > 0.0f || surfShake > 0.0f) && m_status == STATUS_PLAYER){ + float speed = m_vecMoveSpeed.MagnitudeSqr(); + if(speed > sq(0.1f)){ + speed = Sqrt(speed); + if(suspShake > 0.0f){ + uint8 freq = min(200.0f*suspShake*speed*2000.0f/m_fMass + 100.0f, 250.0f); + CPad::GetPad(0)->StartShake(20000.0f*CTimer::GetTimeStep()/freq, freq); + }else{ + uint8 freq = min(200.0f*surfShake*speed*2000.0f/m_fMass + 40.0f, 145.0f); + CPad::GetPad(0)->StartShake(5000.0f*CTimer::GetTimeStep()/freq, freq); + } + } + } + + bVehicleColProcessed = false; + + if(!bWarnedPeds) + CCarCtrl::ScanForPedDanger(this); + + + // Turn around at the edge of the world + // TODO: make the numbers defines + + float heading; + if(GetPosition().x > 1900.0f){ + if(m_vecMoveSpeed.x > 0.0f) + m_vecMoveSpeed.x *= -1.0f; + heading = GetForward().Heading(); + if(heading > 0.0f) // going west + SetHeading(-heading); + }else if(GetPosition().x < -1900.0f){ + if(m_vecMoveSpeed.x < 0.0f) + m_vecMoveSpeed.x *= -1.0f; + heading = GetForward().Heading(); + if(heading < 0.0f) // going east + SetHeading(-heading); + } + if(GetPosition().y > 1900.0f){ + if(m_vecMoveSpeed.y > 0.0f) + m_vecMoveSpeed.y *= -1.0f; + heading = GetForward().Heading(); + if(heading < HALFPI && heading > 0.0f) + SetHeading(PI-heading); + else if(heading > -HALFPI && heading < 0.0f) + SetHeading(-PI-heading); + }else if(GetPosition().y < -1900.0f){ + if(m_vecMoveSpeed.y < 0.0f) + m_vecMoveSpeed.y *= -1.0f; + heading = GetForward().Heading(); + if(heading > HALFPI) + SetHeading(PI-heading); + else if(heading < -HALFPI) + SetHeading(-PI-heading); + } + + if(bInfiniteMass){ + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); + m_vecMoveFriction = CVector(0.0f, 0.0f, 0.0f); + m_vecTurnFriction = CVector(0.0f, 0.0f, 0.0f); + }else if(!skipPhysics && + (m_fGasPedal == 0.0f && brake == 0.0f || m_status == STATUS_WRECKED)){ + if(Abs(m_vecMoveSpeed.x) < 0.005f && + Abs(m_vecMoveSpeed.y) < 0.005f && + Abs(m_vecMoveSpeed.z) < 0.005f){ + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + m_vecTurnSpeed.z = 0.0f; + } + } + +// TEMP +if(pDriver) + pDriver->m_fHealth = 100.0f; +} void CAutomobile::Teleport(CVector pos) @@ -86,7 +1232,7 @@ CAutomobile::ProcessEntityCollision(CEntity *ent, CColPoint *colpoints) // In ProcessControl these will be re-normalized to ignore the tyre radius. if(field_EF || m_phy_flagA80 || - GetModelIndex() == MI_DODO && (ent->m_status == STATUS_PHYSICS || ent->m_status == STATUS_SIMPLE)){ + GetModelIndex() == MI_DODO && (ent->IsPed() || ent->IsVehicle())){ // don't do line collision for(i = 0; i < 4; i++) m_aSuspensionSpringRatio[i] = prevRatios[i]; @@ -141,8 +1287,613 @@ CAutomobile::ProcessEntityCollision(CEntity *ent, CColPoint *colpoints) return numCollisions; } +static int16 nLastControlInput; +static float fMouseCentreRange = 0.35f; +static float fMouseSteerSens = -0.0035f; +static float fMouseCentreMult = 0.975f; + +void +CAutomobile::ProcessControlInputs(uint8 pad) +{ + float speed = DotProduct(m_vecMoveSpeed, GetForward()); + + if(CPad::GetPad(pad)->GetExitVehicle()) + bIsHandbrakeOn = true; + else + bIsHandbrakeOn = !!CPad::GetPad(pad)->GetHandBrake(); + + // Steer left/right + if(CCamera::m_bUseMouse3rdPerson && !CVehicle::m_bDisableMouseSteering){ + if(CPad::GetPad(pad)->GetMouseX() != 0.0f){ + m_fSteerRatio += fMouseSteerSens*CPad::GetPad(pad)->GetMouseX(); + nLastControlInput = 2; + if(Abs(m_fSteerRatio) < fMouseCentreRange) + m_fSteerRatio *= Pow(fMouseCentreMult, CTimer::GetTimeStep()); + }else if(CPad::GetPad(pad)->GetSteeringLeftRight() || nLastControlInput != 2){ + // mouse hasn't move, steer with pad like below + m_fSteerRatio += (-CPad::GetPad(pad)->GetSteeringLeftRight()/128.0f - m_fSteerRatio)* + 0.2f*CTimer::GetTimeStep(); + nLastControlInput = 0; + } + }else{ + m_fSteerRatio += (-CPad::GetPad(pad)->GetSteeringLeftRight()/128.0f - m_fSteerRatio)* + 0.2f*CTimer::GetTimeStep(); + nLastControlInput = 0; + } + m_fSteerRatio = clamp(m_fSteerRatio, -1.0f, 1.0f); + + // Accelerate/Brake + float acceleration = (CPad::GetPad(pad)->GetAccelerate() - CPad::GetPad(pad)->GetBrake())/255.0f; + if(GetModelIndex() == MI_DODO && acceleration < 0.0f) + acceleration *= 0.3f; + if(Abs(speed) < 0.01f){ + // standing still, go into direction we want + m_fGasPedal = acceleration; + m_fBrakePedal = 0.0f; + }else{ +#if 1 + // simpler than the code below + if(speed * acceleration < 0.0f){ + // if opposite directions, have to brake first + m_fGasPedal = 0.0f; + m_fBrakePedal = Abs(acceleration); + }else{ + // accelerating in same direction we were already going + m_fGasPedal = acceleration; + m_fBrakePedal = 0.0f; + } +#else + if(speed < 0.0f){ + // moving backwards currently + if(acceleration < 0.0f){ + // still go backwards + m_fGasPedal = acceleration; + m_fBrakePedal = 0.0f; + }else{ + // want to go forwards, so brake + m_fGasPedal = 0.0f; + m_fBrakePedal = acceleration; + } + }else{ + // moving forwards currently + if(acceleration < 0.0f){ + // want to go backwards, so brake + m_fGasPedal = 0.0f; + m_fBrakePedal = -acceleration; + }else{ + // still go forwards + m_fGasPedal = acceleration; + m_fBrakePedal = 0.0f; + } + } +#endif + } + + // Actually turn wheels + static float fValue; // why static? + if(m_fSteerRatio < 0.0f) + fValue = -sq(m_fSteerRatio); + else + fValue = sq(m_fSteerRatio); + m_fSteerAngle = DEGTORAD(pHandling->fSteeringLock) * fValue; + + if(bComedyControls){ + int rnd = CGeneral::GetRandomNumber() % 10; + switch(m_comedyControlState){ + case 0: + if(rnd < 2) + m_comedyControlState = 1; + else if(rnd < 4) + m_comedyControlState = 2; + break; + case 1: + m_fSteerAngle += 0.05f; + if(rnd < 2) + m_comedyControlState = 0; + break; + case 2: + m_fSteerAngle -= 0.05f; + if(rnd < 2) + m_comedyControlState = 0; + break; + } + }else + m_comedyControlState = 0; + + // Brake if player isn't in control + // BUG: game always uses pad 0 here + if(CPad::GetPad(pad)->DisablePlayerControls){ + m_fBrakePedal = 1.0f; + bIsHandbrakeOn = true; + m_fGasPedal = 0.0f; + + FindPlayerPed()->KeepAreaAroundPlayerClear(); + + // slow down car immediately + speed = m_vecMoveSpeed.Magnitude(); + if(speed > 0.28f) + m_vecMoveSpeed *= 0.28f/speed; + } +} + +WRAPPER void +CAutomobile::FireTruckControl(void) +{ EAXJMP(0x522590); +} -WRAPPER void CAutomobile::ProcessControlInputs(uint8) { EAXJMP(0x53B660); } +WRAPPER void +CAutomobile::TankControl(void) +{ EAXJMP(0x53D530); +} + +WRAPPER void +CAutomobile::HydraulicControl(void) +{ EAXJMP(0x52D4E0); +} + +WRAPPER void +CAutomobile::ProcessBuoyancy(void) +{ EAXJMP(0x5308D0); +} + +void +CAutomobile::DoDriveByShootings(void) +{ + CAnimBlendAssociation *anim; + CWeapon *weapon = pDriver->GetWeapon(); + if(weapon->m_eWeaponType != WEAPONTYPE_UZI) + return; + + weapon->Update(pDriver->m_audioEntityId); + + bool lookingLeft = false; + bool lookingRight = false; + if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN1){ + if(CPad::GetPad(0)->GetLookLeft()) + lookingLeft = true; + if(CPad::GetPad(0)->GetLookRight()) + lookingRight = true; + }else{ + if(TheCamera.Cams[TheCamera.ActiveCam].LookingLeft) + lookingLeft = true; + if(TheCamera.Cams[TheCamera.ActiveCam].LookingRight) + lookingRight = true; + } + + if(lookingLeft || lookingRight){ + if(lookingLeft){ + anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_R); + if(anim) + anim->blendDelta = -1000.0f; + anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_L); + if(anim == nil || anim->blendDelta < 0.0f) + CAnimManager::AddAnimation(pDriver->GetClump(), ASSOCGRP_STD, ANIM_DRIVEBY_L); + else + anim->SetRun(); + }else if(pDriver->m_pMyVehicle->pPassengers[0] == nil || TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FIRSTPERSON){ + anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_L); + if(anim) + anim->blendDelta = -1000.0f; + anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_R); + if(anim == nil || anim->blendDelta < 0.0f) + CAnimManager::AddAnimation(pDriver->GetClump(), ASSOCGRP_STD, ANIM_DRIVEBY_R); + else + anim->SetRun(); + } + + if(CPad::GetPad(0)->GetCarGunFired() && CTimer::GetTimeInMilliseconds() > weapon->m_nTimer){ + weapon->FireFromCar(this, lookingLeft); + weapon->m_nTimer = CTimer::GetTimeInMilliseconds() + 70; + } + }else{ + weapon->Reload(); + anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_L); + if(anim) + anim->blendDelta = -1000.0f; + anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_R); + if(anim) + anim->blendDelta = -1000.0f; + } + + // TODO: what is this? + if(!lookingLeft && m_weaponDoorTimerLeft > 0.0f){ + m_weaponDoorTimerLeft = max(m_weaponDoorTimerLeft - CTimer::GetTimeStep()*0.1f, 0.0f); + ProcessOpenDoor(CAR_DOOR_LF, NUM_ANIMS, m_weaponDoorTimerLeft); + } + if(!lookingRight && m_weaponDoorTimerRight > 0.0f){ + m_weaponDoorTimerRight = max(m_weaponDoorTimerRight - CTimer::GetTimeStep()*0.1f, 0.0f); + ProcessOpenDoor(CAR_DOOR_RF, NUM_ANIMS, m_weaponDoorTimerRight); + } +} + +int32 +CAutomobile::RcbanditCheckHitWheels(void) +{ + int x, xmin, xmax; + int y, ymin, ymax; + + xmin = CWorld::GetSectorIndexX(GetPosition().x - 2.0f); + if(xmin < 0) xmin = 0; + xmax = CWorld::GetSectorIndexX(GetPosition().x + 2.0f); + if(xmax > NUMSECTORS_X-1) xmax = NUMSECTORS_X-1; + ymin = CWorld::GetSectorIndexX(GetPosition().y - 2.0f); + if(ymin < 0) ymin = 0; + ymax = CWorld::GetSectorIndexX(GetPosition().y + 2.0f); + if(ymax > NUMSECTORS_Y-1) ymax = NUMSECTORS_X-1; + + CWorld::AdvanceCurrentScanCode(); + + for(y = ymin; y <= ymax; y++) + for(x = xmin; x <= xmax; x++){ + CSector *s = CWorld::GetSector(x, y); + if(RcbanditCheck1CarWheels(s->m_lists[ENTITYLIST_VEHICLES]) || + RcbanditCheck1CarWheels(s->m_lists[ENTITYLIST_VEHICLES_OVERLAP])) + return 1; + } + return 0; +} + +int32 +CAutomobile::RcbanditCheck1CarWheels(CPtrList &list) +{ + static CMatrix matW2B; + int i; + CPtrNode *node; + CAutomobile *car; + CColModel *colModel = GetColModel(); + CVehicleModelInfo *mi; + + for(node = list.first; node; node = node->next){ + car = (CAutomobile*)node->item; + if(this != car && car->IsCar() && car->m_scanCode != CWorld::GetCurrentScanCode()){ + car->m_scanCode = CWorld::GetCurrentScanCode(); + + if(Abs(this->GetPosition().x - car->GetPosition().x) < 10.0f && + Abs(this->GetPosition().y - car->GetPosition().y) < 10.0f){ + mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(car->GetModelIndex()); + + for(i = 0; i < 4; i++){ + if(car->m_aSuspensionSpringRatioPrev[i] < 1.0f || car->m_status == STATUS_SIMPLE){ + CVector wheelPos; + CColSphere sph; + mi->GetWheelPosn(i, wheelPos); + matW2B = Invert(GetMatrix()); + sph.center = matW2B * (car->GetMatrix() * wheelPos); + sph.radius = mi->m_wheelScale*0.25f; + if(CCollision::TestSphereBox(sph, colModel->boundingBox)) + return 1; + } + } + } + } + } + return 0; +} + +void +CAutomobile::PlaceOnRoadProperly(void) +{ + CColPoint point; + CEntity *entity; + CColModel *colModel = GetColModel(); + float lenFwd, lenBack; + float frontZ, rearZ; + + lenFwd = colModel->boundingBox.max.y; + lenBack = -colModel->boundingBox.min.y; + + CVector front(GetPosition().x + GetForward().x*lenFwd, + GetPosition().y + GetForward().y*lenFwd, + GetPosition().z + 5.0f); + if(CWorld::ProcessVerticalLine(front, GetPosition().z - 5.0f, point, entity, + true, false, false, false, false, false, nil)){ + frontZ = point.point.z; + m_pCurGroundEntity = entity; + }else{ + frontZ = field_21C; + } + + CVector rear(GetPosition().x - GetForward().x*lenBack, + GetPosition().y - GetForward().y*lenBack, + GetPosition().z + 5.0f); + if(CWorld::ProcessVerticalLine(rear, GetPosition().z - 5.0f, point, entity, + true, false, false, false, false, false, nil)){ + rearZ = point.point.z; + m_pCurGroundEntity = entity; + }else{ + rearZ = field_220; + } + + float len = lenFwd + lenBack; + float angle = Atan((frontZ - rearZ)/len); + float c = Cos(angle); + float s = Sin(angle); + + GetRight() = CVector((front.y - rear.y)/len, -(front.x - rear.x)/len, 0.0f); + GetForward() = CVector(-c*GetRight().y, c*GetRight().x, s); + GetUp() = CrossProduct(GetRight(), GetForward()); + GetPosition() = CVector((front.x + rear.x)/2.0f, (front.y + rear.y)/2.0f, (frontZ + rearZ)/2.0f + GetHeightAboveRoad()); +} + +void +CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece) +{ + int i; + float damageMultiplier = 0.2f; + bool doubleMoney = false; + + if(impulse == 0.0f){ + impulse = m_fDamageImpulse; + damagedPiece = m_nDamagePieceType; + damageMultiplier = 1.0f; + } + + CVector pos(0.0f, 0.0f, 0.0f); + + if(!bCanBeDamaged) + return; + + // damage flipped over car + if(GetUp().z < 0.0f && this != FindPlayerVehicle()){ + if(bNotDamagedUpsideDown || m_status == STATUS_PLAYER_REMOTE || bIsInWater) + return; + m_fHealth -= 4.0f*CTimer::GetTimeStep(); + } + + if(impulse > 25.0f && m_status != STATUS_WRECKED){ + if(bIsLawEnforcer && + FindPlayerVehicle() && FindPlayerVehicle() == m_pDamageEntity && + m_status != STATUS_ABANDONED && + FindPlayerVehicle()->m_vecMoveSpeed.Magnitude() >= m_vecMoveSpeed.Magnitude() && + FindPlayerVehicle()->m_vecMoveSpeed.Magnitude() > 0.1f) + FindPlayerPed()->SetWantedLevelNoDrop(1); + + if(m_status == STATUS_PLAYER && impulse > 50.0f){ + uint8 freq = min(0.4f*impulse*2000.0f/m_fMass + 100.0f, 250.0f); + CPad::GetPad(0)->StartShake(40000/freq, freq); + } + + if(bOnlyDamagedByPlayer){ + if(m_pDamageEntity != FindPlayerPed() && + m_pDamageEntity != FindPlayerVehicle()) + return; + } + + if(bCollisionProof) + return; + + if(m_pDamageEntity){ + if(m_pDamageEntity->IsBuilding() && + DotProduct(m_vecDamageNormal, GetUp()) > 0.6f) + return; + } + + int oldLightStatus[4]; + for(i = 0; i < 4; i++) + oldLightStatus[i] = Damage.GetLightStatus((eLights)i); + + if(GetUp().z > 0.0f || m_vecMoveSpeed.MagnitudeSqr() > 0.1f){ + float impulseMult = bMoreResistantToDamage ? 0.5f : 4.0f; + + switch(damagedPiece){ + case CAR_PIECE_BUMP_FRONT: + GetComponentWorldPosition(CAR_BUMP_FRONT, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if(Damage.ApplyDamage(COMPONENT_BUMPER_FRONT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetBumperDamage(CAR_BUMP_FRONT, VEHBUMPER_FRONT); + doubleMoney = true; + } + if(m_aCarNodes[CAR_BONNET] && Damage.GetPanelStatus(VEHBUMPER_FRONT) == PANEL_STATUS_MISSING){ + case CAR_PIECE_BONNET: + GetComponentWorldPosition(CAR_BONNET, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if(Damage.ApplyDamage(COMPONENT_DOOR_BONNET, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetDoorDamage(CAR_BONNET, DOOR_BONNET); + doubleMoney = true; + } + } + break; + + case CAR_PIECE_BUMP_REAR: + GetComponentWorldPosition(CAR_BUMP_REAR, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if(Damage.ApplyDamage(COMPONENT_BUMPER_FRONT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetBumperDamage(CAR_BUMP_REAR, VEHBUMPER_REAR); + doubleMoney = true; + } + if(m_aCarNodes[CAR_BOOT] && Damage.GetPanelStatus(VEHBUMPER_REAR) == PANEL_STATUS_MISSING){ + case CAR_PIECE_BOOT: + GetComponentWorldPosition(CAR_BOOT, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if(Damage.ApplyDamage(COMPONENT_DOOR_BOOT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetDoorDamage(CAR_BOOT, DOOR_BOOT); + doubleMoney = true; + } + } + break; + + case CAR_PIECE_DOOR_LF: + GetComponentWorldPosition(CAR_DOOR_LF, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if((m_nDoorLock == CARLOCK_NOT_USED || m_nDoorLock == CARLOCK_UNLOCKED) && + Damage.ApplyDamage(COMPONENT_DOOR_FRONT_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetDoorDamage(CAR_DOOR_LF, DOOR_FRONT_LEFT); + doubleMoney = true; + } + break; + case CAR_PIECE_DOOR_RF: + GetComponentWorldPosition(CAR_DOOR_RF, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if((m_nDoorLock == CARLOCK_NOT_USED || m_nDoorLock == CARLOCK_UNLOCKED) && + Damage.ApplyDamage(COMPONENT_DOOR_FRONT_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetDoorDamage(CAR_DOOR_RF, DOOR_FRONT_RIGHT); + doubleMoney = true; + } + break; + case CAR_PIECE_DOOR_LR: + GetComponentWorldPosition(CAR_DOOR_LR, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if((m_nDoorLock == CARLOCK_NOT_USED || m_nDoorLock == CARLOCK_UNLOCKED) && + Damage.ApplyDamage(COMPONENT_DOOR_REAR_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetDoorDamage(CAR_DOOR_LR, DOOR_REAR_LEFT); + doubleMoney = true; + } + break; + case CAR_PIECE_DOOR_RR: + GetComponentWorldPosition(CAR_DOOR_RR, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if((m_nDoorLock == CARLOCK_NOT_USED || m_nDoorLock == CARLOCK_UNLOCKED) && + Damage.ApplyDamage(COMPONENT_DOOR_REAR_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetDoorDamage(CAR_DOOR_RR, DOOR_REAR_RIGHT); + doubleMoney = true; + } + break; + + case CAR_PIECE_WING_LF: + GetComponentWorldPosition(CAR_WING_LF, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if(Damage.ApplyDamage(COMPONENT_PANEL_FRONT_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetPanelDamage(CAR_WING_LF, VEHPANEL_FRONT_LEFT); + doubleMoney = true; + } + break; + case CAR_PIECE_WING_RF: + GetComponentWorldPosition(CAR_WING_RF, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if(Damage.ApplyDamage(COMPONENT_PANEL_FRONT_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetPanelDamage(CAR_WING_RF, VEHPANEL_FRONT_RIGHT); + doubleMoney = true; + } + break; + case CAR_PIECE_WING_LR: + GetComponentWorldPosition(CAR_WING_LR, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if(Damage.ApplyDamage(COMPONENT_PANEL_REAR_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetPanelDamage(CAR_WING_LR, VEHPANEL_REAR_LEFT); + doubleMoney = true; + } + break; + case CAR_PIECE_WING_RR: + GetComponentWorldPosition(CAR_WING_RR, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if(Damage.ApplyDamage(COMPONENT_PANEL_REAR_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetPanelDamage(CAR_WING_RR, VEHPANEL_REAR_RIGHT); + doubleMoney = true; + } + break; + + case CAR_PIECE_WHEEL_LF: + case CAR_PIECE_WHEEL_LR: + case CAR_PIECE_WHEEL_RF: + case CAR_PIECE_WHEEL_RR: + break; + + case CAR_PIECE_WINDSCREEN: + if(Damage.ApplyDamage(COMPONENT_PANEL_WINDSCREEN, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + uint8 oldStatus = Damage.GetPanelStatus(VEHPANEL_WINDSCREEN); + SetPanelDamage(CAR_WINDSCREEN, VEHPANEL_WINDSCREEN); + if(oldStatus != Damage.GetPanelStatus(VEHPANEL_WINDSCREEN)){ + DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_WINDSHIELD_CRACK, 0.0f); + doubleMoney = true; + } + } + break; + } + + if(m_pDamageEntity && m_pDamageEntity == FindPlayerVehicle() && impulse > 10.0f){ + int money = (doubleMoney ? 2 : 1) * impulse*pHandling->nMonetaryValue/1000000.0f; + money = min(money, 40); + if(money > 2){ + sprintf(gString, "$%d", money); + CWorld::Players[CWorld::PlayerInFocus].m_nMoney += money; + } + } + } + + float damage = (impulse-25.0f)*pHandling->fCollisionDamageMultiplier*0.6f*damageMultiplier; + + if(GetModelIndex() == MI_SECURICA && m_pDamageEntity && m_pDamageEntity->m_status == STATUS_PLAYER) + damage *= 7.0f; + + if(damage > 0.0f){ + int oldHealth = m_fHealth; + if(this == FindPlayerVehicle()){ + m_fHealth -= bTakeLessDamage ? damage/6.0f : damage/2.0f; + }else{ + if(damage > 35.0f && pDriver) + pDriver->Say(SOUND_PED_CAR_COLLISION); + m_fHealth -= bTakeLessDamage ? damage/12.0f : damage/4.0f; + } + if(m_fHealth <= 0.0f && oldHealth > 0) + m_fHealth = 1.0f; + } + + // play sound if a light broke + for(i = 0; i < 4; i++) + if(oldLightStatus[i] != 1 && Damage.GetLightStatus((eLights)i) == 1){ + DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_LIGHT_BREAK, i); // BUG? i? + break; + } + } + + if(m_fHealth < 250.0f){ + // Car is on fire + if(Damage.GetEngineStatus() < ENGINE_STATUS_ON_FIRE){ + // Set engine on fire and remember who did this + Damage.SetEngineStatus(ENGINE_STATUS_ON_FIRE); + m_fFireBlowUpTimer = 0.0f; + m_pSetOnFireEntity = m_pDamageEntity; + if(m_pSetOnFireEntity) + m_pSetOnFireEntity->RegisterReference(&m_pSetOnFireEntity); + } + }else{ + if(GetModelIndex() == MI_BFINJECT){ + if(m_fHealth < 400.0f) + Damage.SetEngineStatus(200); + else if(m_fHealth < 600.0f) + Damage.SetEngineStatus(100); + } + } +} + +void +CAutomobile::dmgDrawCarCollidingParticles(const CVector &pos, float amount) +{ + int i, n; + + if(!GetIsOnScreen()) + return; + + // FindPlayerSpeed() unused + + n = (int)amount/20; + + for(i = 0; i < ((n+4)&0x1F); i++) + CParticle::AddParticle(PARTICLE_SPARK_SMALL, pos, + CVector(CGeneral::GetRandomNumberInRange(-0.1f, 0.1f), + CGeneral::GetRandomNumberInRange(-0.1f, 0.1f), + 0.006f)); + + for(i = 0; i < n+2; i++) + CParticle::AddParticle(PARTICLE_CARCOLLISION_DUST, + CVector(CGeneral::GetRandomNumberInRange(-1.2f, 1.2f) + pos.x, + CGeneral::GetRandomNumberInRange(-1.2f, 1.2f) + pos.y, + pos.z), + CVector(0.0f, 0.0f, 0.0f), nil, 0.5f); + + n = (int)amount/50 + 1; + for(i = 0; i < n; i++) + CParticle::AddParticle(PARTICLE_CAR_DEBRIS, pos, + CVector(CGeneral::GetRandomNumberInRange(-0.25f, 0.25f), + CGeneral::GetRandomNumberInRange(-0.25f, 0.25f), + CGeneral::GetRandomNumberInRange(0.1f, 0.25f)), + nil, + CGeneral::GetRandomNumberInRange(0.02f, 0.08f), + CVehicleModelInfo::ms_vehicleColourTable[m_currentColour1], + CGeneral::GetRandomNumberInRange(-40.0f, 40.0f), + 0, + CGeneral::GetRandomNumberInRange(0.0f, 4.0f)); +} void CAutomobile::GetComponentWorldPosition(int32 component, CVector &pos) @@ -390,6 +2141,7 @@ CAutomobile::BlowUpCar(CEntity *culprit) SetDoorDamage(CAR_DOOR_LR, DOOR_REAR_LEFT); SetDoorDamage(CAR_DOOR_RR, DOOR_REAR_RIGHT); SpawnFlyingComponent(CAR_WHEEL_LF, COMPGROUP_WHEEL); + atomic = nil; RwFrameForAllObjects(m_aCarNodes[CAR_WHEEL_LF], GetCurrentAtomicObjectCB, &atomic); if(atomic) RpAtomicSetFlags(atomic, 0); @@ -397,7 +2149,7 @@ CAutomobile::BlowUpCar(CEntity *culprit) m_fHealth = 0.0f; m_nBombTimer = 0; - m_auto_flagA7 = 0; + m_bombType = CARBOMB_NONE; TheCamera.CamShake(0.7f, GetPosition().x, GetPosition().y, GetPosition().z); @@ -533,8 +2285,8 @@ CAutomobile::PlayCarHorn(void) void CAutomobile::PlayHornIfNecessary(void) { - if(m_autoPilot.m_flag2 || - m_autoPilot.m_flag1) + if(AutoPilot.m_flag2 || + AutoPilot.m_flag1) if(!HasCarStoppedBecauseOfLight()) PlayCarHorn(); } @@ -546,9 +2298,9 @@ CAutomobile::ResetSuspension(void) int i; for(i = 0; i < 4; i++){ m_aSuspensionSpringRatio[i] = 1.0f; - m_aWheelSkidThing[i] = 0.0f; + m_aWheelTimer[i] = 0.0f; m_aWheelRotation[i] = 0.0f; - m_aWheelState[i] = 0; // TODO: enum? + m_aWheelState[i] = WHEEL_STATE_0; } } @@ -567,23 +2319,23 @@ CAutomobile::SetupSuspensionLines(void) m_aWheelPosition[i] = posn.z; // uppermost wheel position - posn.z += m_handling->fSuspensionUpperLimit; + posn.z += pHandling->fSuspensionUpperLimit; colModel->lines[i].p0 = posn; // lowermost wheel position - posn.z += m_handling->fSuspensionLowerLimit - m_handling->fSuspensionUpperLimit; + posn.z += pHandling->fSuspensionLowerLimit - pHandling->fSuspensionUpperLimit; // lowest point on tyre posn.z -= mi->m_wheelScale*0.5f; colModel->lines[i].p1 = posn; // this is length of the spring at rest - m_aSuspensionSpringLength[i] = m_handling->fSuspensionUpperLimit - m_handling->fSuspensionLowerLimit; + m_aSuspensionSpringLength[i] = pHandling->fSuspensionUpperLimit - pHandling->fSuspensionLowerLimit; m_aSuspensionLineLength[i] = colModel->lines[i].p0.z - colModel->lines[i].p1.z; } // Compress spring somewhat to get normal height on road m_fHeightAboveRoad = -(colModel->lines[0].p0.z + (colModel->lines[0].p1.z - colModel->lines[0].p0.z)* - (1.0f - 1.0f/(8.0f*m_handling->fSuspensionForceLevel))); + (1.0f - 1.0f/(8.0f*pHandling->fSuspensionForceLevel))); for(i = 0; i < 4; i++) m_aWheelPosition[i] = mi->m_wheelScale*0.5f - m_fHeightAboveRoad; @@ -606,7 +2358,7 @@ void CAutomobile::ScanForCrimes(void) { if(FindPlayerVehicle() && FindPlayerVehicle()->IsCar()) - if(FindPlayerVehicle()->m_nAlarmState != -1) + if(FindPlayerVehicle()->IsAlarmOn()) // if player's alarm is on, increase wanted level if((FindPlayerVehicle()->GetPosition() - GetPosition()).MagnitudeSqr() < sq(20.0f)) CWorld::Players[CWorld::PlayerInFocus].m_pPed->SetWantedLevelNoDrop(1); @@ -634,20 +2386,20 @@ CAutomobile::HasCarStoppedBecauseOfLight(void) if(m_status != STATUS_SIMPLE && m_status != STATUS_PHYSICS) return false; - if(m_autoPilot.m_nCurrentRouteNode && m_autoPilot.m_nNextRouteNode){ - CPathNode *curnode = &ThePaths.m_pathNodes[m_autoPilot.m_nCurrentRouteNode]; + if(AutoPilot.m_nCurrentRouteNode && AutoPilot.m_nNextRouteNode){ + CPathNode *curnode = &ThePaths.m_pathNodes[AutoPilot.m_nCurrentRouteNode]; for(i = 0; i < curnode->numLinks; i++) - if(ThePaths.m_connections[curnode->firstLink + i] == m_autoPilot.m_nNextRouteNode) + if(ThePaths.m_connections[curnode->firstLink + i] == AutoPilot.m_nNextRouteNode) break; if(i < curnode->numLinks && ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[curnode->firstLink + i]].trafficLightType & 3) // TODO return true; } - if(m_autoPilot.m_nCurrentRouteNode && m_autoPilot.m_nPrevRouteNode){ - CPathNode *curnode = &ThePaths.m_pathNodes[m_autoPilot.m_nCurrentRouteNode]; + if(AutoPilot.m_nCurrentRouteNode && AutoPilot.m_nPrevRouteNode){ + CPathNode *curnode = &ThePaths.m_pathNodes[AutoPilot.m_nCurrentRouteNode]; for(i = 0; i < curnode->numLinks; i++) - if(ThePaths.m_connections[curnode->firstLink + i] == m_autoPilot.m_nPrevRouteNode) + if(ThePaths.m_connections[curnode->firstLink + i] == AutoPilot.m_nPrevRouteNode) break; if(i < curnode->numLinks && ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[curnode->firstLink + i]].trafficLightType & 3) // TODO @@ -734,7 +2486,7 @@ CAutomobile::Fix(void) Damage.ResetDamageStatus(); - if(m_handling->Flags & HANDLING_NO_DOORS){ + if(pHandling->Flags & HANDLING_NO_DOORS){ Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_MISSING); Damage.SetDoorStatus(DOOR_FRONT_RIGHT, DOOR_STATUS_MISSING); Damage.SetDoorStatus(DOOR_REAR_LEFT, DOOR_STATUS_MISSING); @@ -860,7 +2612,7 @@ CAutomobile::SpawnFlyingComponent(int32 component, uint32 type) obj->m_fElasticity = 0.1f; obj->m_fBuoyancy = obj->m_fMass*GRAVITY/0.75f; obj->ObjectCreatedBy = TEMP_OBJECT; - obj->bIsStatic = true; + obj->bIsStatic = false; obj->bIsPickup = false; obj->bUseVehicleColours = true; obj->m_colour1 = m_currentColour1; @@ -987,7 +2739,7 @@ CAutomobile::SetDoorDamage(int32 component, eDoors door, bool noFlyingComponents return; } - if(door == DOOR_BOOT && status == DOOR_STATUS_SWINGING && m_handling->Flags & HANDLING_NOSWING_BOOT){ + if(door == DOOR_BOOT && status == DOOR_STATUS_SWINGING && pHandling->Flags & HANDLING_NOSWING_BOOT){ Damage.SetDoorStatus(DOOR_BOOT, DOOR_STATUS_MISSING); status = DOOR_STATUS_MISSING; } @@ -1051,7 +2803,7 @@ CAutomobile::SetTaxiLight(bool light) bool CAutomobile::GetAllWheelsOffGround(void) { - return m_nWheelsOnGround == 0; + return m_nDriveWheelsOnGround == 0; } void @@ -1091,7 +2843,7 @@ public: int32 ProcessEntityCollision_(CEntity *ent, CColPoint *colpoints){ return CAutomobile::ProcessEntityCollision(ent, colpoints); } - void ProcessControlInputs_(uint8 x) { CAutomobile::ProcessControlInputs(x); } + void ProcessControlInputs_(uint8 pad) { CAutomobile::ProcessControlInputs(pad); } void GetComponentWorldPosition_(int32 component, CVector &pos) { CAutomobile::GetComponentWorldPosition(component, pos); } bool IsComponentPresent_(int32 component) { return CAutomobile::IsComponentPresent(component); } void SetComponentRotation_(int32 component, CVector rotation) { CAutomobile::SetComponentRotation(component, rotation); } @@ -1113,8 +2865,10 @@ public: STARTPATCHES InjectHook(0x52D170, &CAutomobile_::dtor, PATCH_JUMP); InjectHook(0x52D190, &CAutomobile_::SetModelIndex_, PATCH_JUMP); + InjectHook(0x531470, &CAutomobile_::ProcessControl_, PATCH_JUMP); InjectHook(0x535180, &CAutomobile_::Teleport_, PATCH_JUMP); InjectHook(0x53B270, &CAutomobile_::ProcessEntityCollision_, PATCH_JUMP); + InjectHook(0x53B660, &CAutomobile_::ProcessControlInputs_, PATCH_JUMP); InjectHook(0x52E5F0, &CAutomobile_::GetComponentWorldPosition_, PATCH_JUMP); InjectHook(0x52E660, &CAutomobile_::IsComponentPresent_, PATCH_JUMP); InjectHook(0x52E680, &CAutomobile_::SetComponentRotation_, PATCH_JUMP); @@ -1129,6 +2883,8 @@ STARTPATCHES InjectHook(0x53C0E0, &CAutomobile_::BurstTyre_, PATCH_JUMP); InjectHook(0x437690, &CAutomobile_::GetHeightAboveRoad_, PATCH_JUMP); InjectHook(0x53C450, &CAutomobile_::PlayCarHorn_, PATCH_JUMP); + InjectHook(0x53E090, &CAutomobile::PlaceOnRoadProperly, PATCH_JUMP); + InjectHook(0x52F030, &CAutomobile::dmgDrawCarCollidingParticles, PATCH_JUMP); InjectHook(0x5353A0, &CAutomobile::ResetSuspension, PATCH_JUMP); InjectHook(0x52D210, &CAutomobile::SetupSuspensionLines, PATCH_JUMP); InjectHook(0x53E000, &CAutomobile::BlowUpCarsInPath, PATCH_JUMP); diff --git a/src/vehicles/Automobile.h b/src/vehicles/Automobile.h index 60e08d0a..1a103777 100644 --- a/src/vehicles/Automobile.h +++ b/src/vehicles/Automobile.h @@ -6,6 +6,25 @@ class CObject; +// These are used for all the wheel arrays +// DON'T confuse with VEHWHEEL, which are vehicle components +enum { + CARWHEEL_FRONT_LEFT, + CARWHEEL_REAR_LEFT, + CARWHEEL_FRONT_RIGHT, + CARWHEEL_REAR_RIGHT +}; + +enum eBombType +{ + CARBOMB_NONE, + CARBOMB_TIMED, + CARBOMB_ONIGNITION, + CARBOMB_REMOTE, + CARBOMB_TIMEDACTIVE, + CARBOMB_ONIGNITIONACTIVE, +}; + class CAutomobile : public CVehicle { public: @@ -16,7 +35,7 @@ public: CColPoint m_aWheelColPoints[4]; float m_aSuspensionSpringRatio[4]; float m_aSuspensionSpringRatioPrev[4]; - float m_aWheelSkidThing[4]; + float m_aWheelTimer[4]; // set to 4.0 when wheel is touching ground, then decremented float field_49C; bool m_aWheelSkidmarkMuddy[4]; bool m_aWheelSkidmarkBloody[4]; @@ -24,39 +43,45 @@ public: float m_aWheelPosition[4]; float m_aWheelSpeed[4]; uint8 field_4D8; - uint8 m_auto_flagA7 : 1; + uint8 m_bombType : 3; uint8 bTaxiLight : 1; - uint8 m_auto_flagA10 : 1; + uint8 bHadDriver : 1; // for bombs uint8 m_auto_flagA20 : 1; uint8 m_auto_flagA40 : 1; uint8 m_auto_flagA80 : 1; - uint8 field_4DA[10]; + uint8 bNotDamagedUpsideDown : 1; + uint8 bMoreResistantToDamage : 1; + uint8 field_4DB; + CEntity *m_pBombRigger; + int16 field_4E0; + int16 field_4E2; uint32 m_nBusDoorTimerEnd; uint32 m_nBusDoorTimerStart; float m_aSuspensionSpringLength[4]; float m_aSuspensionLineLength[4]; float m_fHeightAboveRoad; - float m_fImprovedHandling; - uint8 stuff6[28]; - float field_530; + float m_fTraction; + float m_fVelocityChangeForAudio; + float m_randomValues[6]; // used for what? + float m_fFireBlowUpTimer; CPhysical *m_aGroundPhysical[4]; // physicals touching wheels CVector m_aGroundOffset[4]; // from ground object to colpoint - CEntity *m_pBlowUpEntity; - float m_weaponThingA; // TODO - float m_weaponThingB; // TODO + CEntity *m_pSetOnFireEntity; + float m_weaponDoorTimerLeft; // still don't know what exactly this is + float m_weaponDoorTimerRight; float m_fCarGunLR; float m_fCarGunUD; float m_fWindScreenRotation; uint8 stuff4[4]; - uint8 m_nWheelsOnGround_2; uint8 m_nWheelsOnGround; - uint8 m_nWheelsOnGroundPrev; - uint8 stuff5[5]; - int32 m_aWheelState[4]; + uint8 m_nDriveWheelsOnGround; + uint8 m_nDriveWheelsOnGroundPrev; + int32 field_594; + tWheelState m_aWheelState[4]; static bool &m_sAllTaxiLights; - CAutomobile(int, uint8); + CAutomobile(int32, uint8); // from CEntity void SetModelIndex(uint32 id); @@ -87,6 +112,16 @@ public: float GetHeightAboveRoad(void); void PlayCarHorn(void); + void FireTruckControl(void); + void TankControl(void); + void HydraulicControl(void); + void VehicleDamage(float impulse, uint16 damagedPiece); + void ProcessBuoyancy(void); + void DoDriveByShootings(void); + int32 RcbanditCheckHitWheels(void); + int32 RcbanditCheck1CarWheels(CPtrList &list); + void PlaceOnRoadProperly(void); + void dmgDrawCarCollidingParticles(const CVector &pos, float amount); void PlayHornIfNecessary(void); void ResetSuspension(void); void SetupSuspensionLines(void); @@ -113,7 +148,5 @@ public: void ReduceHornCounter(void); static void SetAllTaxiLights(bool set); - - CAutomobile* ctor(int, uint8); }; static_assert(sizeof(CAutomobile) == 0x5A8, "CAutomobile: error"); diff --git a/src/vehicles/DamageManager.cpp b/src/vehicles/DamageManager.cpp index 380537f2..3a7bd9e9 100644 --- a/src/vehicles/DamageManager.cpp +++ b/src/vehicles/DamageManager.cpp @@ -7,6 +7,13 @@ float G_aComponentDamage[] = { 2.5f, 1.25f, 3.2f, 1.4f, 2.5f, 2.8f, 0.5f }; +CDamageManager::CDamageManager(void) +{ + ResetDamageStatus(); + m_fWheelDamageEffect = 0.75f; + field_24 = 1; +} + void CDamageManager::ResetDamageStatus(void) { @@ -18,15 +25,15 @@ CDamageManager::FuckCarCompletely(void) { int i; - m_wheelStatus[0] = 2; + m_wheelStatus[0] = WHEEL_STATUS_MISSING; // wheels 1-3 not reset? - m_doorStatus[0] = 3; - m_doorStatus[1] = 3; - m_doorStatus[2] = 3; - m_doorStatus[3] = 3; - m_doorStatus[4] = 3; - m_doorStatus[5] = 3; + m_doorStatus[0] = DOOR_STATUS_MISSING; + m_doorStatus[1] = DOOR_STATUS_MISSING; + m_doorStatus[2] = DOOR_STATUS_MISSING; + m_doorStatus[3] = DOOR_STATUS_MISSING; + m_doorStatus[4] = DOOR_STATUS_MISSING; + m_doorStatus[5] = DOOR_STATUS_MISSING; for(i = 0; i < 3; i++){ #ifdef FIX_BUGS @@ -216,8 +223,8 @@ CDamageManager::ProgressEngineDamage(void) { int status = GetEngineStatus(); int newstatus = status + 32 + (CGeneral::GetRandomNumber() & 0x1F); - if(status < 225 && newstatus > 224) - newstatus = 224; + if(status < ENGINE_STATUS_ON_FIRE && newstatus > ENGINE_STATUS_ON_FIRE-1) + newstatus = ENGINE_STATUS_ON_FIRE-1; SetEngineStatus(newstatus); return true; } diff --git a/src/vehicles/DamageManager.h b/src/vehicles/DamageManager.h index b815f724..adcd7430 100644 --- a/src/vehicles/DamageManager.h +++ b/src/vehicles/DamageManager.h @@ -4,6 +4,11 @@ // TODO: move some of this into Vehicle.h +enum eEngineStatus +{ + ENGINE_STATUS_ON_FIRE = 225 +}; + enum eDoorStatus { DOOR_STATUS_OK, @@ -23,7 +28,8 @@ enum ePanelStatus enum eWheelStatus { WHEEL_STATUS_OK, - WHEEL_STATUS_BURST + WHEEL_STATUS_BURST, + WHEEL_STATUS_MISSING }; enum tComponent @@ -65,7 +71,7 @@ class CDamageManager { public: - float field_0; + float m_fWheelDamageEffect; uint8 m_engineStatus; uint8 m_wheelStatus[4]; uint8 m_doorStatus[6]; @@ -73,6 +79,8 @@ public: uint32 m_panelStatus; uint32 field_24; + CDamageManager(void); + void ResetDamageStatus(void); void FuckCarCompletely(void); bool ApplyDamage(tComponent component, float damage, float unused); diff --git a/src/vehicles/Door.h b/src/vehicles/Door.h index fc771a40..7bb7bba3 100644 --- a/src/vehicles/Door.h +++ b/src/vehicles/Door.h @@ -26,6 +26,12 @@ struct CDoor CVector m_vecSpeed; CDoor(void); + void Init(float minAngle, float maxAngle, int8 dir, int8 axis) { + m_fMinAngle = minAngle; + m_fMaxAngle = maxAngle; + m_nDirn = dir; + m_nAxis = axis; + } void Open(float ratio); void Process(CVehicle *veh); float RetAngleWhenClosed(void); diff --git a/src/vehicles/Floater.cpp b/src/vehicles/Floater.cpp new file mode 100644 index 00000000..cabe00c3 --- /dev/null +++ b/src/vehicles/Floater.cpp @@ -0,0 +1,195 @@ +#include "common.h" +#include "patcher.h" +#include "Timer.h" +#include "WaterLevel.h" +#include "ModelIndices.h" +#include "Physical.h" +#include "Vehicle.h" +#include "Floater.h" + +cBuoyancy &mod_Buoyancy = *(cBuoyancy*)0x8F2674; + +//static float fVolMultiplier = 1.0f; +static float &fVolMultiplier = *(float*)0x601394; +// amount of boat volume in bounding box +// 1.0-volume is the empty space in the bbox +static float fBoatVolumeDistribution[9] = { + // rear + 0.75f, 0.9f, 0.75f, + 0.95f, 1.0f, 0.95f, + 0.3f, 0.7f, 0.3f + // bow +}; + +bool +cBuoyancy::ProcessBuoyancy(CPhysical *phys, float buoyancy, CVector *impulse, CVector *point) +{ + m_numSteps = 2.0f; + + if(!CWaterLevel::GetWaterLevel(phys->GetPosition(), &m_waterlevel, phys->m_flagD8)) + return false; + m_matrix = phys->GetMatrix(); + + PreCalcSetup(phys, buoyancy); + SimpleCalcBuoyancy(); + float f = CalcBuoyancyForce(phys, impulse, point); + if(m_isBoat) + return true; + return f != 0.0f; +} + +void +cBuoyancy::PreCalcSetup(CPhysical *phys, float buoyancy) +{ + CColModel *colModel; + + m_isBoat = phys->IsVehicle() && ((CVehicle*)phys)->IsBoat(); + colModel = phys->GetColModel(); + m_dimMin = colModel->boundingBox.min; + m_dimMax = colModel->boundingBox.max; + + if(m_isBoat){ + if(phys->GetModelIndex() == MI_PREDATOR){ + m_dimMax.y *= 0.9f; + m_dimMin.y *= 0.9f; + }else if(phys->GetModelIndex() == MI_SPEEDER){ + m_dimMax.y *= 1.1f; + m_dimMin.y *= 0.9f; + }else if(phys->GetModelIndex() == MI_REEFER){ + m_dimMin.y *= 0.9f; + }else{ + m_dimMax.y *= 0.9f; + m_dimMin.y *= 0.9f; + } + } + + m_step = (m_dimMax - m_dimMin)/m_numSteps; + + if(m_step.z > m_step.x && m_step.z > m_step.y){ + m_stepRatio.x = m_step.x/m_step.z; + m_stepRatio.y = m_step.y/m_step.z; + m_stepRatio.z = 1.0f; + }else if(m_step.y > m_step.x && m_step.y > m_step.z){ + m_stepRatio.x = m_step.x/m_step.y; + m_stepRatio.y = 1.0f; + m_stepRatio.z = m_step.z/m_step.y; + }else{ + m_stepRatio.x = 1.0f; + m_stepRatio.y = m_step.y/m_step.x; + m_stepRatio.z = m_step.z/m_step.x; + } + + m_haveVolume = false; + m_numPartialVolumes = 1.0f; + m_volumeUnderWater = 0.0f; + m_impulse = CVector(0.0f, 0.0f, 0.0f); + m_position = phys->GetPosition(); + m_positionZ = CVector(0.0f, 0.0f, m_position.z); + m_buoyancy = buoyancy; + m_waterlevel += m_waterLevelInc; +} + +void +cBuoyancy::SimpleCalcBuoyancy(void) +{ + float x, y; + int ix, i; + tWaterLevel waterPosition; + + // Floater is divided into 3x3 parts. Process and sum each of them + ix = 0; + for(x = m_dimMin.x; x <= m_dimMax.x; x += m_step.x){ + i = ix; + for(y = m_dimMin.y; y <= m_dimMax.y; y += m_step.y){ + CVector waterLevel(x, y, 0.0f); + FindWaterLevel(m_positionZ, &waterLevel, &waterPosition); + fVolMultiplier = m_isBoat ? fBoatVolumeDistribution[i] : 1.0f; + if(waterPosition != FLOATER_ABOVE_WATER) + SimpleSumBuoyancyData(waterLevel, waterPosition); + i += 3; + } + ix++; + } + + m_volumeUnderWater /= (m_dimMax.z - m_dimMin.z)*sq(m_numSteps+1.0f); +} + +float +cBuoyancy::SimpleSumBuoyancyData(CVector &waterLevel, tWaterLevel waterPosition) +{ + static float fThisVolume; + static CVector AverageOfWaterLevel; + static float fFraction; + static float fRemainingSlice; + + float submerged = Abs(waterLevel.z - m_dimMin.z); + // subtract empty space from submerged volume + fThisVolume = submerged - (1.0f - fVolMultiplier); + if(fThisVolume < 0.0f) + return 0.0f; + + if(m_isBoat){ + fThisVolume *= fVolMultiplier; + if(fThisVolume < 0.5f) + fThisVolume = 2.0f*sq(fThisVolume); + if(fThisVolume < 1.0f) + fThisVolume = sq(fThisVolume); + fThisVolume = sq(fThisVolume); + } + + m_volumeUnderWater += fThisVolume; + + AverageOfWaterLevel.x = waterLevel.x * m_stepRatio.x; + AverageOfWaterLevel.y = waterLevel.y * m_stepRatio.y; + AverageOfWaterLevel.z = (waterLevel.z+m_dimMin.z)/2.0f * m_stepRatio.z; + + if(m_flipAverage) + AverageOfWaterLevel = -AverageOfWaterLevel; + + fFraction = 1.0f/m_numPartialVolumes; + fRemainingSlice = 1.0f - fFraction; + m_impulse = m_impulse*fRemainingSlice + AverageOfWaterLevel*fThisVolume*fFraction; + m_numPartialVolumes += 1.0f; + m_haveVolume = true; + return fThisVolume; +} + +void +cBuoyancy::FindWaterLevel(const CVector &zpos, CVector *waterLevel, tWaterLevel *waterPosition) +{ + *waterPosition = FLOATER_IN_WATER; + // waterLevel is a local x,y point + // m_position is the global position of our floater + // zpos is the global z coordinate of our floater + CVector xWaterLevel = Multiply3x3(m_matrix, *waterLevel); + CWaterLevel::GetWaterLevel(xWaterLevel.x + m_position.x, xWaterLevel.y + m_position.y, m_position.z, + &waterLevel->z, true); + waterLevel->z -= xWaterLevel.z + zpos.z; // make local + if(waterLevel->z > m_dimMax.z){ + waterLevel->z = m_dimMax.z; + *waterPosition = FLOATER_UNDER_WATER; + }else if(waterLevel->z < m_dimMin.z){ + waterLevel->z = m_dimMin.z; + *waterPosition = FLOATER_ABOVE_WATER; + } +} + +bool +cBuoyancy::CalcBuoyancyForce(CPhysical *phys, CVector *impulse, CVector *point) +{ + if(!m_haveVolume) + return false; + + *impulse = Multiply3x3(m_matrix, m_impulse); + *point = CVector(0.0f, 0.0f, m_volumeUnderWater*m_buoyancy*CTimer::GetTimeStep()); + return true; +} + +STARTPATCHES + InjectHook(0x546270, &cBuoyancy::ProcessBuoyancy, PATCH_JUMP); + InjectHook(0x546360, &cBuoyancy::PreCalcSetup, PATCH_JUMP); + InjectHook(0x5466F0, &cBuoyancy::SimpleCalcBuoyancy, PATCH_JUMP); + InjectHook(0x546820, &cBuoyancy::SimpleSumBuoyancyData, PATCH_JUMP); + InjectHook(0x546620, &cBuoyancy::FindWaterLevel, PATCH_JUMP); + InjectHook(0x5465A0, &cBuoyancy::CalcBuoyancyForce, PATCH_JUMP); +ENDPATCHES diff --git a/src/vehicles/Floater.h b/src/vehicles/Floater.h new file mode 100644 index 00000000..ede2b9d0 --- /dev/null +++ b/src/vehicles/Floater.h @@ -0,0 +1,45 @@ +#pragma once + +class Physical; + +enum tWaterLevel +{ + FLOATER_ABOVE_WATER, + FLOATER_IN_WATER, + FLOATER_UNDER_WATER, +}; + +class cBuoyancy +{ +public: + CVector m_position; + CMatrix m_matrix; + int m_field_54; + CVector m_positionZ; + float m_waterlevel; + float m_waterLevelInc; + float m_buoyancy; + CVector m_dimMax; + CVector m_dimMin; + float m_numPartialVolumes; + int m_field_8C; + int m_field_90; + int m_field_94; + bool m_haveVolume; + CVector m_step; + CVector m_stepRatio; + float m_numSteps; + bool m_flipAverage; + char m_field_B9; + bool m_isBoat; + float m_volumeUnderWater; + CVector m_impulse; + + bool ProcessBuoyancy(CPhysical *phys, float buoyancy, CVector *impulse, CVector *point); + void PreCalcSetup(CPhysical *phys, float buoyancy); + void SimpleCalcBuoyancy(void); + float SimpleSumBuoyancyData(CVector &waterLevel, tWaterLevel waterPosition); + void FindWaterLevel(const CVector &zpos, CVector *waterLevel, tWaterLevel *waterPosition); + bool CalcBuoyancyForce(CPhysical *phys, CVector *impulse, CVector *point); +}; +extern cBuoyancy &mod_Buoyancy; diff --git a/src/vehicles/HandlingMgr.cpp b/src/vehicles/HandlingMgr.cpp index 47d0564c..be96ab08 100644 --- a/src/vehicles/HandlingMgr.cpp +++ b/src/vehicles/HandlingMgr.cpp @@ -70,7 +70,7 @@ char VehicleNames[NUMHANDLINGS][14] = { cHandlingDataMgr::cHandlingDataMgr(void) { - memset(this, 0, sizeof(this)); + memset(this, 0, sizeof(*this)); } void @@ -127,7 +127,7 @@ cHandlingDataMgr::LoadHandlingData(void) handlingId = FindExactWord(word, (const char*)VehicleNames, 14, NUMHANDLINGS); assert(handlingId >= 0 && handlingId < NUMHANDLINGS); handling = &HandlingData[handlingId]; - handling->nIdentifier = handlingId; + handling->nIdentifier = (eHandlingId)handlingId; break; case 1: handling->fMass = strtod(word, nil); break; case 2: handling->Dimension.x = strtod(word, nil); break; @@ -140,11 +140,11 @@ cHandlingDataMgr::LoadHandlingData(void) case 9: handling->fTractionMultiplier = strtod(word, nil); break; case 10: handling->fTractionLoss = strtod(word, nil); break; case 11: handling->fTractionBias = strtod(word, nil); break; - case 12: handling->TransmissionData.nNumberOfGears = atoi(word); break; - case 13: handling->TransmissionData.fMaxVelocity = strtod(word, nil); break; - case 14: handling->TransmissionData.fEngineAcceleration = strtod(word, nil) * 0.4f; break; - case 15: handling->TransmissionData.nDriveType = word[0]; break; - case 16: handling->TransmissionData.nEngineType = word[0]; break; + case 12: handling->Transmission.nNumberOfGears = atoi(word); break; + case 13: handling->Transmission.fMaxVelocity = strtod(word, nil); break; + case 14: handling->Transmission.fEngineAcceleration = strtod(word, nil) * 0.4f; break; + case 15: handling->Transmission.nDriveType = word[0]; break; + case 16: handling->Transmission.nEngineType = word[0]; break; case 17: handling->fBrakeDeceleration = strtod(word, nil); break; case 18: handling->fBrakeBias = strtod(word, nil); break; case 19: handling->bABS = !!atoi(word); break; @@ -159,7 +159,7 @@ cHandlingDataMgr::LoadHandlingData(void) case 28: handling->fSuspensionBias = strtod(word, nil); break; case 29: sscanf(word, "%x", &handling->Flags); - handling->TransmissionData.Flags = handling->Flags; + handling->Transmission.Flags = handling->Flags; break; case 30: handling->FrontLights = atoi(word); break; case 31: handling->RearLights = atoi(word); break; @@ -192,8 +192,8 @@ cHandlingDataMgr::ConvertDataToGameUnits(tHandlingData *handling) // TODO: figure out what exactly is being converted here float velocity, a, b, specificVolume; - handling->TransmissionData.fEngineAcceleration /= 2500.0f; - handling->TransmissionData.fMaxVelocity /= 180.0f; + handling->Transmission.fEngineAcceleration /= 2500.0f; + handling->Transmission.fMaxVelocity /= 180.0f; handling->fBrakeDeceleration /= 2500.0f; handling->fTurnMass = (sq(handling->Dimension.x) + sq(handling->Dimension.y)) * handling->fMass / 12.0f; if(handling->fTurnMass < 10.0f) @@ -205,27 +205,27 @@ cHandlingDataMgr::ConvertDataToGameUnits(tHandlingData *handling) specificVolume = handling->Dimension.x*handling->Dimension.z*0.5f / handling->fMass; // ? a = 0.0f; b = 100.0f; - velocity = handling->TransmissionData.fMaxVelocity; + velocity = handling->Transmission.fMaxVelocity; while(a < b && velocity > 0.0f){ velocity -= 0.01; - a = handling->TransmissionData.fEngineAcceleration/6.0f; + a = handling->Transmission.fEngineAcceleration/6.0f; b = -velocity * (1.0f/(specificVolume * sq(velocity) + 1.0f) - 1.0f); } if(handling->nIdentifier == HANDLING_RCBANDIT){ - handling->TransmissionData.fUnkMaxVelocity = handling->TransmissionData.fMaxVelocity; + handling->Transmission.fUnkMaxVelocity = handling->Transmission.fMaxVelocity; }else{ - handling->TransmissionData.fUnkMaxVelocity = velocity; - handling->TransmissionData.fMaxVelocity = velocity * 1.2f; + handling->Transmission.fUnkMaxVelocity = velocity; + handling->Transmission.fMaxVelocity = velocity * 1.2f; } - handling->TransmissionData.fMaxReverseVelocity = -0.2f; + handling->Transmission.fMaxReverseVelocity = -0.2f; - if(handling->TransmissionData.nDriveType == '4') - handling->TransmissionData.fEngineAcceleration /= 4.0f; + if(handling->Transmission.nDriveType == '4') + handling->Transmission.fEngineAcceleration /= 4.0f; else - handling->TransmissionData.fEngineAcceleration /= 2.0f; + handling->Transmission.fEngineAcceleration /= 2.0f; - handling->TransmissionData.InitGearRatios(); + handling->Transmission.InitGearRatios(); } int32 diff --git a/src/vehicles/HandlingMgr.h b/src/vehicles/HandlingMgr.h index 2627fbae..70f1c005 100644 --- a/src/vehicles/HandlingMgr.h +++ b/src/vehicles/HandlingMgr.h @@ -85,7 +85,7 @@ enum struct tHandlingData { - int32 nIdentifier; + eHandlingId nIdentifier; float fMass; float fInvMass; float fTurnMass; @@ -94,7 +94,7 @@ struct tHandlingData int8 nPercentSubmerged; float fBuoyancy; float fTractionMultiplier; - cTransmission TransmissionData; + cTransmission Transmission; float fBrakeDeceleration; float fBrakeBias; int8 bABS; @@ -136,6 +136,8 @@ public: void ConvertDataToGameUnits(tHandlingData *handling); int32 GetHandlingId(const char *name); tHandlingData *GetHandlingData(eHandlingId id) { return &HandlingData[id]; } + bool HasRearWheelDrive(eHandlingId id) { return HandlingData[id].Transmission.nDriveType == 'R'; } + bool HasFrontWheelDrive(eHandlingId id) { return HandlingData[id].Transmission.nDriveType == 'F'; } }; VALIDATE_SIZE(cHandlingDataMgr, 0x3030); extern cHandlingDataMgr &mod_HandlingManager; diff --git a/src/vehicles/Plane.h b/src/vehicles/Plane.h index 1f54e529..e263766e 100644 --- a/src/vehicles/Plane.h +++ b/src/vehicles/Plane.h @@ -7,7 +7,17 @@ class CPlane : public CVehicle { public: // 0x288 - uint8 stuff[20]; + int16 m_wIndex; + int16 field_650; + int16 m_wNextPathNode; + char field_654; + char field_655; + float field_656; + int m_nFrameWhenHit; + char m_bHasBeenHit; + char m_bIsIncomingCesna; + char m_bIsDropoffCesna; + char field_667; CPlane(int, uint8); ~CPlane(void); diff --git a/src/vehicles/Transmission.cpp b/src/vehicles/Transmission.cpp index 2be25cbb..d500d004 100644 --- a/src/vehicles/Transmission.cpp +++ b/src/vehicles/Transmission.cpp @@ -1,5 +1,7 @@ #include "common.h" #include "patcher.h" +#include "Timer.h" +#include "HandlingMgr.h" #include "Transmission.h" void @@ -35,3 +37,107 @@ cTransmission::InitGearRatios(void) Gears[1].fShiftDownVelocity = -0.01f; } + +void +cTransmission::CalculateGearForSimpleCar(float speed, uint8 &gear) +{ + static tGear *pGearRatio; + + pGearRatio = &Gears[gear]; + fCurVelocity = speed; + if(speed > pGearRatio->fShiftUpVelocity) + gear++; + else if(speed < pGearRatio->fShiftDownVelocity){ + if(gear - 1 < 0) + gear = 0; + else + gear--; + } +} + +float +cTransmission::CalculateDriveAcceleration(const float &gasPedal, uint8 &gear, float &time, const float &velocity, bool cheat) +{ + static float fAcceleration = 0.0f; + static float fVelocity; + static float fCheat; + static tGear *pGearRatio; + + fVelocity = velocity; + if(fVelocity < fMaxReverseVelocity){ + fVelocity = fMaxReverseVelocity; + return 0.0f; + } + if(fVelocity > fMaxVelocity){ + fVelocity = fMaxVelocity; + return 0.0f; + } + fCurVelocity = fVelocity; + + assert(gear <= nNumberOfGears); + + pGearRatio = &Gears[gear]; + if(fVelocity > pGearRatio->fShiftUpVelocity){ + if(gear != 0 || gasPedal > 0.0f){ + gear++; + time = 0.0f; + return CalculateDriveAcceleration(gasPedal, gear, time, fVelocity, false); + } + }else if(fVelocity < pGearRatio->fShiftDownVelocity && gear != 0){ + if(gear != 1 || gasPedal < 0.0f){ + gear--; + time = 0.0f; + return CalculateDriveAcceleration(gasPedal, gear, time, fVelocity, false); + } + } + + if(time > 0.0f){ + // changing gears currently, can't accelerate + fAcceleration = 0.0f; + time -= CTimer::GetTimeStepInSeconds(); + }else{ + float speedMul, accelMul; + + if(gear < 1){ + // going reverse + accelMul = (Flags & HANDLING_2G_BOOST) ? 2.0f : 1.0f; + speedMul = -1.0f; + }else if(nNumberOfGears == 1){ + accelMul = 1.0f; + speedMul = 1.0f; + }else{ + // BUG or not? this is 1.0 normally but 0.0 in the highest gear + float f = 1.0f - (gear-1)/(nNumberOfGears-1); + speedMul = 3.0f*sq(f) + 1.0f; + // This is pretty ugly, could be written more clearly + if(Flags & HANDLING_2G_BOOST){ + if(gear == 1) + accelMul = (Flags & HANDLING_1G_BOOST) ? 3.0f : 2.0f; + else if(gear == 2) + accelMul = 1.3f; + else + accelMul = 1.0f; + }else if(Flags & HANDLING_1G_BOOST && gear == 1){ + accelMul = 3.0f; + }else + accelMul = 1.0f; + } + + if(cheat) + fCheat = 1.2f; + else + fCheat = 1.0f; + float targetVelocity = Gears[gear].fMaxVelocity*speedMul*fCheat; + float accel = fEngineAcceleration*accelMul * (targetVelocity - fVelocity)/Abs(targetVelocity); + if(Abs(fVelocity) < Abs(Gears[gear].fMaxVelocity*fCheat)) + fAcceleration = gasPedal * accel * CTimer::GetTimeStep(); + else + fAcceleration = 0.0f; + } + return fAcceleration; +} + +STARTPATCHES + InjectHook(0x550A00, &cTransmission::CalculateGearForSimpleCar, PATCH_JUMP); + InjectHook(0x5506B0, &cTransmission::CalculateDriveAcceleration, PATCH_JUMP); +ENDPATCHES diff --git a/src/vehicles/Transmission.h b/src/vehicles/Transmission.h index 686e0aca..8eeef1e8 100644 --- a/src/vehicles/Transmission.h +++ b/src/vehicles/Transmission.h @@ -20,7 +20,9 @@ public: float fMaxVelocity; float fUnkMaxVelocity; float fMaxReverseVelocity; - float field_5C; + float fCurVelocity; void InitGearRatios(void); + void CalculateGearForSimpleCar(float speed, uint8 &gear); + float CalculateDriveAcceleration(const float &gasPedal, uint8 &gear, float &time, const float &velocity, bool cheat); }; diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index d8ed1a15..cc98bbe9 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -35,7 +35,7 @@ CVehicle::CVehicle(uint8 CreatedBy) int i; m_nCurrentGear = 0; - field_208 = 0; + m_fChangeGearTime = 0; m_fSteerRatio = 0.0f; m_type = ENTITY_TYPE_VEHICLE; VehicleCreatedBy = CreatedBy; @@ -56,16 +56,18 @@ CVehicle::CVehicle(uint8 CreatedBy) for(i = 0; i < m_nNumMaxPassengers; i++) pPassengers[i] = nil; m_nBombTimer = 0; - m_pWhoSetMeOnFire = nil; + m_pBlowUpEntity = nil; field_1FB = 0; - m_veh_flagB10 = false; + bComedyControls = false; m_veh_flagB40 = false; m_veh_flagB80 = false; - m_veh_flagC1 = false; + bTakeLessDamage = false; bIsDamaged = false; - m_veh_flagC8 = false; + bFadeOut = false; m_veh_flagC10 = false; - m_veh_flagC4 = false; + m_nTimeOfDeath = 0; + m_pCarFire = nil; + bHasBeenOwnedByPlayer = false; m_veh_flagC20 = false; bCanBeDamaged = true; m_veh_flagC80 = false; @@ -93,14 +95,14 @@ CVehicle::CVehicle(uint8 CreatedBy) m_pCurGroundEntity = nil; field_22A = 0; field_22B = 0; - field_22F = 0; + m_comedyControlState = 0; m_aCollPolys[0].valid = false; m_aCollPolys[1].valid = false; - m_autoPilot.m_nCarMission = MISSION_NONE; - m_autoPilot.m_nAnimationId = TEMPACT_NONE; - m_autoPilot.m_nTimeToStartMission = CTimer::GetTimeInMilliseconds(); - m_autoPilot.m_flag4 = false; - m_autoPilot.m_flag10 = false; + AutoPilot.m_nCarMission = MISSION_NONE; + AutoPilot.m_nAnimationId = TEMPACT_NONE; + AutoPilot.m_nTimeToStartMission = CTimer::GetTimeInMilliseconds(); + AutoPilot.m_flag4 = false; + AutoPilot.m_flag10 = false; } CVehicle::~CVehicle() @@ -259,7 +261,7 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon adhesion *= CTimer::GetTimeStep(); if(bAlreadySkidding) - adhesion *= m_handling->fTractionLoss; + adhesion *= pHandling->fTractionLoss; // moving sideways if(contactSpeedRight != 0.0f){ @@ -318,7 +320,7 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon } float l = Sqrt(sq(right) + sq(fwd)); - float tractionLoss = bAlreadySkidding ? 1.0f : m_handling->fTractionLoss; + float tractionLoss = bAlreadySkidding ? 1.0f : pHandling->fTractionLoss; right *= adhesion * tractionLoss / l; fwd *= adhesion * tractionLoss / l; } @@ -362,9 +364,9 @@ CVehicle::ExtinguishCarFire(void) m_pCarFire->Extinguish(); if(IsCar()){ CAutomobile *car = (CAutomobile*)this; - if(car->Damage.GetEngineStatus() >= 225) - car->Damage.SetEngineStatus(215); - car->field_530 = 0.0f; + if(car->Damage.GetEngineStatus() >= ENGINE_STATUS_ON_FIRE) + car->Damage.SetEngineStatus(ENGINE_STATUS_ON_FIRE-10); + car->m_fFireBlowUpTimer = 0.0f; } } @@ -374,20 +376,21 @@ CVehicle::ProcessDelayedExplosion(void) if(m_nBombTimer == 0) return; - if(m_nBombTimer == 0){ - int tick = CTimer::GetTimeStep()/60.0f*1000.0f; - if(tick > m_nBombTimer) - m_nBombTimer = 0; - else - m_nBombTimer -= tick; + int tick = CTimer::GetTimeStep()/60.0f*1000.0f; + if(tick > m_nBombTimer) + m_nBombTimer = 0; + else + m_nBombTimer -= tick; - if(IsCar() && ((CAutomobile*)this)->m_auto_flagA7 == 4 && (m_nBombTimer & 0xFE00) != 0xFE00) - DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_BOMB_TICK, 0.0f); + if(IsCar() && ((CAutomobile*)this)->m_bombType == CARBOMB_TIMEDACTIVE && (m_nBombTimer & 0xFE00) != 0xFE00) + DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_BOMB_TICK, 0.0f); - if(FindPlayerVehicle() != this && m_pWhoSetMeOnFire == FindPlayerPed()) - CWorld::Players[CWorld::PlayerInFocus].AwardMoneyForExplosion(this); - BlowUpCar(m_pWhoSetMeOnFire); - } + if (m_nBombTimer != 0) + return; + + if(FindPlayerVehicle() != this && m_pBlowUpEntity == FindPlayerPed()) + CWorld::Players[CWorld::PlayerInFocus].AwardMoneyForExplosion(this); + BlowUpCar(m_pBlowUpEntity); } bool @@ -449,7 +452,7 @@ CVehicle::IsVehicleNormal(void) bool CVehicle::CarHasRoof(void) { - if((m_handling->Flags & HANDLING_HAS_NO_ROOF) == 0) + if((pHandling->Flags & HANDLING_HAS_NO_ROOF) == 0) return true; if(m_aExtras[0] && m_aExtras[1]) return false; @@ -519,7 +522,7 @@ bool CVehicle::CanPedOpenLocks(CPed *ped) { if(m_nDoorLock == CARLOCK_LOCKED || - m_nDoorLock == CARLOCK_COP_CAR || + m_nDoorLock == CARLOCK_LOCKED_INITIALLY || m_nDoorLock == CARLOCK_LOCKED_PLAYER_INSIDE) return false; if(ped->IsPlayer() && m_nDoorLock == CARLOCK_LOCKOUT_PLAYER_ONLY) @@ -602,7 +605,7 @@ CVehicle::SetUpDriver(void) pDriver->bInVehicle = true; pDriver->SetPedState(PED_DRIVING); if(bIsBus) - pDriver->m_ped_flagC4 = false; + pDriver->bRenderPedInCar = false; return pDriver; } @@ -618,7 +621,7 @@ CVehicle::SetupPassenger(int n) pPassengers[n]->bInVehicle = true; pPassengers[n]->SetPedState(PED_DRIVING); if(bIsBus) - pPassengers[n]->m_ped_flagC4 = false; + pPassengers[n]->bRenderPedInCar = false; return pPassengers[n]; } diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h index c293b8a6..38d411cd 100644 --- a/src/vehicles/Vehicle.h +++ b/src/vehicles/Vehicle.h @@ -20,7 +20,7 @@ enum eCarLock { CARLOCK_LOCKED, CARLOCK_LOCKOUT_PLAYER_ONLY, CARLOCK_LOCKED_PLAYER_INSIDE, - CARLOCK_COP_CAR, + CARLOCK_LOCKED_INITIALLY, CARLOCK_FORCE_SHUT_DOORS, CARLOCK_SKIP_SHUT_DOORS }; @@ -98,10 +98,23 @@ enum eWheels enum { - CAR_PIECE_WHEEL_LF = 13, + CAR_PIECE_BONNET = 1, + CAR_PIECE_BOOT, + CAR_PIECE_BUMP_FRONT, + CAR_PIECE_BUMP_REAR, + CAR_PIECE_DOOR_LF, + CAR_PIECE_DOOR_RF, + CAR_PIECE_DOOR_LR, + CAR_PIECE_DOOR_RR, + CAR_PIECE_WING_LF, + CAR_PIECE_WING_RF, + CAR_PIECE_WING_LR, + CAR_PIECE_WING_RR, + CAR_PIECE_WHEEL_LF, CAR_PIECE_WHEEL_LR, CAR_PIECE_WHEEL_RF, CAR_PIECE_WHEEL_RR, + CAR_PIECE_WINDSCREEN, }; enum tWheelState @@ -125,12 +138,12 @@ class CVehicle : public CPhysical { public: // 0x128 - tHandlingData *m_handling; - CAutoPilot m_autoPilot; + tHandlingData *pHandling; + CAutoPilot AutoPilot; uint8 m_currentColour1; uint8 m_currentColour2; uint8 m_aExtras[2]; - int16 m_nAlarmState; // m_nWantedStarsOnEnter on DK22 + int16 m_nAlarmState; int16 m_nMissionValue; CPed *pDriver; CPed *pPassengers[8]; @@ -144,7 +157,7 @@ public: CFire *m_pCarFire; float m_fSteerAngle; float m_fGasPedal; - float m_fBreakPedal; + float m_fBrakePedal; uint8 VehicleCreatedBy; // cf. https://github.com/DK22Pac/plugin-sdk/blob/master/plugin_sa/game_sa/CVehicle.h from R* @@ -161,15 +174,15 @@ public: uint8 bIsBus: 1; // Is this vehicle a bus uint8 bIsBig: 1; // Is this vehicle a bus uint8 bLowVehicle: 1; // Need this for sporty type cars to use low getting-in/out anims - uint8 m_veh_flagB10 : 1; - uint8 m_veh_flagB20 : 1; + uint8 bComedyControls : 1; // Will make the car hard to control (hopefully in a funny way) + uint8 bWarnedPeds : 1; // Has scan and warn peds of danger been processed? uint8 m_veh_flagB40 : 1; uint8 m_veh_flagB80 : 1; - uint8 m_veh_flagC1 : 1; + uint8 bTakeLessDamage : 1; // This vehicle is stronger (takes about 1/4 of damage) uint8 bIsDamaged : 1; // This vehicle has been damaged and is displaying all its components - uint8 m_veh_flagC4 : 1; - uint8 m_veh_flagC8 : 1; + uint8 bHasBeenOwnedByPlayer : 1;// To work out whether stealing it is a crime + uint8 bFadeOut : 1; // Fade vehicle out uint8 m_veh_flagC10 : 1; uint8 m_veh_flagC20 : 1; uint8 bCanBeDamaged : 1; // Set to FALSE during cut scenes to avoid explosions @@ -188,17 +201,17 @@ public: uint8 m_nAmmoInClip; // Used to make the guns on boat do a reload (20 by default) int8 field_1FB; int8 field_1FC[4]; - float m_fHealth; // 1000.0f = full health. 0 -> explode + float m_fHealth; // 1000.0f = full health. 250.0f = fire. 0 -> explode uint8 m_nCurrentGear; int8 field_205[3]; - int field_208; + float m_fChangeGearTime; uint32 m_nGunFiringTime; // last time when gun on vehicle was fired (used on boats) uint32 m_nTimeOfDeath; int16 field_214; int16 m_nBombTimer; // goes down with each frame - CPed *m_pWhoSetMeOnFire; - float field_21C; - float field_220; + CEntity *m_pBlowUpEntity; + float field_21C; // front Z? + float field_220; // rear Z? eCarLock m_nDoorLock; int8 m_nLastWeaponDamage; // see eWeaponType, -1 if no damage int8 m_nRadioStation; @@ -207,7 +220,7 @@ public: uint8 m_nCarHornTimer; int8 field_22D; bool m_bSirenOrAlarm; - int8 field_22F; + int8 m_comedyControlState; CStoredCollPoly m_aCollPolys[2]; // poly which is under front/rear part of car float m_fSteerRatio; eVehicleType m_vehType; @@ -277,6 +290,8 @@ public: void RemoveDriver(void); void ProcessCarAlarm(void); bool IsSphereTouchingVehicle(float sx, float sy, float sz, float radius); + + bool IsAlarmOn(void) { return m_nAlarmState != 0 && m_nAlarmState != -1; } static bool &bWheelsOnlyCheat; static bool &bAllDodosCheat; @@ -305,3 +320,19 @@ inline uint8 GetVehDoorFlag(int32 carnode) { return 0; } } + +class cTransmission; + +class cVehicleParams +{ +public: + char m_bDistanceCalculated; + char gap_1[3]; + float m_fDistance; + CVehicle *m_pVehicle; + cTransmission *m_pTransmission; + int m_nIndex; + float m_fVelocityChange; +}; + +static_assert(sizeof(cVehicleParams) == 0x18, "CVehicle: error"); diff --git a/src/weapons/Weapon.cpp b/src/weapons/Weapon.cpp index 90a6408b..0fc89637 100644 --- a/src/weapons/Weapon.cpp +++ b/src/weapons/Weapon.cpp @@ -5,7 +5,9 @@ #include "WeaponInfo.h" WRAPPER bool CWeapon::Fire(CEntity*, CVector*) { EAXJMP(0x55C380); } +WRAPPER void CWeapon::FireFromCar(CAutomobile *car, bool left) { EAXJMP(0x55C940); } WRAPPER void CWeapon::AddGunshell(CEntity*, CVector const&, CVector2D const&, float) { EAXJMP(0x55F770); } +WRAPPER void CWeapon::Update(int32 audioEntity) { EAXJMP(0x563A10); } void CWeapon::Initialise(eWeaponType type, int ammo) @@ -36,6 +38,12 @@ CWeapon::Reload(void) } bool +CWeapon::IsType2Handed(void) +{ + return m_eWeaponType >= WEAPONTYPE_SHOTGUN && m_eWeaponType <= WEAPONTYPE_FLAMETHROWER && m_eWeaponType != WEAPONTYPE_ROCKETLAUNCHER; +} + +bool CWeapon::IsTypeMelee(void) { return m_eWeaponType == WEAPONTYPE_UNARMED || m_eWeaponType == WEAPONTYPE_BASEBALLBAT; diff --git a/src/weapons/Weapon.h b/src/weapons/Weapon.h index 81516c4e..71fe1f45 100644 --- a/src/weapons/Weapon.h +++ b/src/weapons/Weapon.h @@ -1,5 +1,4 @@ #pragma once -#include "Entity.h" enum eWeaponType { @@ -46,6 +45,9 @@ enum eWeaponState WEAPONSTATE_MELEE_MADECONTACT }; +class CEntity; +class CAutomobile; + class CWeapon { public: @@ -61,9 +63,12 @@ public: } void Initialise(eWeaponType type, int ammo); + void Update(int32 audioEntity); void Reload(void); bool Fire(CEntity*, CVector*); + void FireFromCar(CAutomobile *car, bool left); void AddGunshell(CEntity*, CVector const&, CVector2D const&, float); bool IsTypeMelee(void); + bool IsType2Handed(void); }; static_assert(sizeof(CWeapon) == 0x18, "CWeapon: error"); |