diff options
author | Nikolay Korolev <nickvnuk@gmail.com> | 2020-01-01 00:42:00 +0100 |
---|---|---|
committer | Nikolay Korolev <nickvnuk@gmail.com> | 2020-01-01 00:42:00 +0100 |
commit | 5b0cf80a76e49cee88e796bb8c4b53fd3ca8f3c5 (patch) | |
tree | 2e2bca559ef34473733d63a022c74a711c894830 /src | |
parent | some not fully tested stuff (diff) | |
parent | making particleobject compile on vs2015 (diff) | |
download | re3-5b0cf80a76e49cee88e796bb8c4b53fd3ca8f3c5.tar re3-5b0cf80a76e49cee88e796bb8c4b53fd3ca8f3c5.tar.gz re3-5b0cf80a76e49cee88e796bb8c4b53fd3ca8f3c5.tar.bz2 re3-5b0cf80a76e49cee88e796bb8c4b53fd3ca8f3c5.tar.lz re3-5b0cf80a76e49cee88e796bb8c4b53fd3ca8f3c5.tar.xz re3-5b0cf80a76e49cee88e796bb8c4b53fd3ca8f3c5.tar.zst re3-5b0cf80a76e49cee88e796bb8c4b53fd3ca8f3c5.zip |
Diffstat (limited to 'src')
69 files changed, 4004 insertions, 818 deletions
diff --git a/src/animation/AnimBlendAssocGroup.cpp b/src/animation/AnimBlendAssocGroup.cpp index 72c90233..ecdebd29 100644 --- a/src/animation/AnimBlendAssocGroup.cpp +++ b/src/animation/AnimBlendAssocGroup.cpp @@ -1,5 +1,6 @@ #include "common.h" #include "patcher.h" +#include "General.h" #include "ModelInfo.h" #include "AnimManager.h" #include "RpAnimBlend.h" @@ -38,7 +39,7 @@ CAnimBlendAssocGroup::GetAnimation(const char *name) { int i; for(i = 0; i < numAssociations; i++) - if(strcmpi(assocList[i].hierarchy->name, name) == 0) + if(!CGeneral::faststricmp(assocList[i].hierarchy->name, name)) return &assocList[i]; return nil; } @@ -64,7 +65,7 @@ CAnimBlendAssocGroup::CopyAnimation(const char *name) return new CAnimBlendAssociation(*anim); } -int +bool strcmpIgnoringDigits(const char *s1, const char *s2) { char c1, c2; @@ -75,13 +76,13 @@ strcmpIgnoringDigits(const char *s1, const char *s2) if(c1) s1++; if(c2) s2++; if(c1 == '\0' && c2 == '\0') - return 1; - if(islower(c1)) c1 = toupper(c1); - if(islower(c2)) c2 = toupper(c2); - if(isdigit(c1) && isdigit(c2)) + return true; + if(__ascii_iswdigit(c1) && __ascii_iswdigit(c2)) continue; + c1 = __ascii_toupper(c1); + c2 = __ascii_toupper(c2); if(c1 != c2) - return 0; + return false; } } diff --git a/src/animation/AnimBlendAssociation.h b/src/animation/AnimBlendAssociation.h index 01d862cc..aec28f56 100644 --- a/src/animation/AnimBlendAssociation.h +++ b/src/animation/AnimBlendAssociation.h @@ -16,7 +16,7 @@ enum { ASSOC_FLAG80 = 0x80, // used for footstep sound calculation ASSOC_FLAG100 = 0x100, ASSOC_FLAG200 = 0x200, - ASSOC_FLAG400 = 0x400, // not seen yet + ASSOC_FLAG400 = 0x400, // unused, blending it with move anims makes them stop. 0x800 in VC ASSOC_FLAG800 = 0x800, // anims that we fall to front. 0x1000 in VC ASSOC_HAS_X_TRANSLATION = 0x1000, // 0x2000 is vehicle anims in VC diff --git a/src/animation/AnimManager.cpp b/src/animation/AnimManager.cpp index 444ae93d..e5721bdf 100644 --- a/src/animation/AnimManager.cpp +++ b/src/animation/AnimManager.cpp @@ -1,5 +1,6 @@ #include "common.h" #include "patcher.h" +#include "General.h" #include "ModelInfo.h" #include "ModelIndices.h" #include "FileMgr.h" @@ -605,7 +606,7 @@ CAnimManager::GetAnimationBlock(const char *name) int i; for(i = 0; i < ms_numAnimBlocks; i++) - if(strcmpi(ms_aAnimBlocks[i].name, name) == 0) + if(strcasecmp(ms_aAnimBlocks[i].name, name) == 0) return &ms_aAnimBlocks[i]; return nil; } @@ -617,7 +618,7 @@ CAnimManager::GetAnimation(const char *name, CAnimBlock *animBlock) CAnimBlendHierarchy *hier = &ms_aAnimations[animBlock->firstIndex]; for(i = 0; i < animBlock->numAnims; i++){ - if(strcmpi(hier->name, name) == 0) + if(!CGeneral::faststricmp(hier->name, name)) return hier; hier++; } diff --git a/src/animation/RpAnimBlend.cpp b/src/animation/RpAnimBlend.cpp index 17394743..8108619e 100644 --- a/src/animation/RpAnimBlend.cpp +++ b/src/animation/RpAnimBlend.cpp @@ -1,5 +1,6 @@ #include "common.h" #include "patcher.h" +#include "General.h" #include "NodeName.h" #include "VisibilityPlugins.h" #include "AnimBlendClumpData.h" @@ -320,7 +321,7 @@ void FrameFindCallBack(AnimBlendFrameData *frame, void *arg) { char *nodename = GetFrameNodeName(frame->frame); - if(strcmpi(nodename, (char*)arg) == 0) + if(!CGeneral::faststricmp(nodename, (char*)arg)) pFrameDataFound = frame; } diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp index facf3a4a..abfbde00 100644 --- a/src/audio/AudioManager.cpp +++ b/src/audio/AudioManager.cpp @@ -1,5 +1,6 @@ #include "common.h" #include "patcher.h" +#include "General.h" #include "audio_enums.h" #include "AudioManager.h" @@ -517,11 +518,11 @@ cAudioManager::AgeCrimes() } void -cAudioManager::CalculateDistance(bool *ptr, float dist) +cAudioManager::CalculateDistance(bool &distCalculated, float dist) { - if(*ptr == false) { + if(!distCalculated) { m_sQueueSample.m_fDistance = Sqrt(dist); - *ptr = true; + distCalculated = true; } } @@ -2130,16 +2131,16 @@ uint32 cAudioManager::GetSpecialCharacterTalkSfx(int32 modelIndex, int32 sound) { char *modelName = CModelInfo::GetModelInfo(modelIndex)->GetName(); - if(strcmpi(modelName, "eight") == 0 || strcmpi(modelName, "eight2") == 0) { return GetEightTalkSfx(sound); } - if(strcmpi(modelName, "frankie") == 0) { return GetFrankieTalkSfx(sound); } - if(strcmpi(modelName, "misty") == 0) { return GetMistyTalkSfx(sound); } - if(strcmpi(modelName, "ojg") == 0 || strcmpi(modelName, "ojg_p") == 0) { return GetOJGTalkSfx(sound); } - if(strcmpi(modelName, "cat") == 0) { return GetCatatalinaTalkSfx(sound); } - if(strcmpi(modelName, "bomber") == 0) { return GetBomberTalkSfx(sound); } - if(strcmpi(modelName, "s_guard") == 0) { return GetSecurityGuardTalkSfx(sound); } - if(strcmpi(modelName, "chunky") == 0) { return GetChunkyTalkSfx(sound); } - if(strcmpi(modelName, "asuka") == 0) { return GetGenericFemaleTalkSfx(sound); } - if(strcmpi(modelName, "maria") == 0) { return GetGenericFemaleTalkSfx(sound); } + if(!CGeneral::faststricmp(modelName, "eight") || !CGeneral::faststricmp(modelName, "eight2")) { return GetEightTalkSfx(sound); } + if(!CGeneral::faststricmp(modelName, "frankie")) { return GetFrankieTalkSfx(sound); } + if(!CGeneral::faststricmp(modelName, "misty")) { return GetMistyTalkSfx(sound); } + if(!CGeneral::faststricmp(modelName, "ojg") || !CGeneral::faststricmp(modelName, "ojg_p")) { return GetOJGTalkSfx(sound); } + if(!CGeneral::faststricmp(modelName, "cat")) { return GetCatatalinaTalkSfx(sound); } + if(!CGeneral::faststricmp(modelName, "bomber")) { return GetBomberTalkSfx(sound); } + if(!CGeneral::faststricmp(modelName, "s_guard")) { return GetSecurityGuardTalkSfx(sound); } + if(!CGeneral::faststricmp(modelName, "chunky")) { return GetChunkyTalkSfx(sound); } + if(!CGeneral::faststricmp(modelName, "asuka")) { return GetGenericFemaleTalkSfx(sound); } + if(!CGeneral::faststricmp(modelName, "maria")) { return GetGenericFemaleTalkSfx(sound); } return GetGenericMaleTalkSfx(sound); } @@ -2601,7 +2602,7 @@ cAudioManager::InitialisePoliceRadio() SampleManager.SetChannelReverbFlag(policeChannel, 0); gSpecialSuspectLastSeenReport = 0; - for(int32 i = 0; i < 18; i++) { gMinTimeToNextReport[i] = m_nTimeOfRecentCrime; } + for(int32 i = 0; i < 17; i++) { gMinTimeToNextReport[i] = m_nTimeOfRecentCrime; } } struct tPoliceRadioZone { @@ -3100,7 +3101,7 @@ int32 FindMissionAudioSfx(const char *name) { for(uint32 i = 0; i < ARRAY_SIZE(MissionAudioNameSfxAssoc); ++i) { - if(strcmpi(MissionAudioNameSfxAssoc[i].m_pName, name) == 0) return MissionAudioNameSfxAssoc[i].m_nId; + if(!CGeneral::faststricmp(MissionAudioNameSfxAssoc[i].m_pName, name)) return MissionAudioNameSfxAssoc[i].m_nId; } debug("Can't find mission audio %s", name); return NO_SAMPLE; @@ -3180,7 +3181,7 @@ cAudioManager::ProcessAirBrakes(cVehicleParams *params) (automobile->m_fVelocityChangeForAudio > -0.025f || params->m_fVelocityChange <= 0.025f)) return 1; - CalculateDistance((bool *)params, params->m_fDistance); + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); rand = m_anRandomTable[0] % 10 + 70; m_sQueueSample.m_bVolume = ComputeVolume(rand, 30.0f, m_sQueueSample.m_fDistance); if(m_sQueueSample.m_bVolume) { @@ -3272,7 +3273,7 @@ cAudioManager::ProcessBoatEngine(cVehicleParams *params) if(params->m_fDistance < 2500.f) { boat = (CBoat *)params->m_pVehicle; if(params->m_nIndex == REEFER) { - CalculateDistance((bool *)params, params->m_fDistance); + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); m_sQueueSample.m_bVolume = ComputeVolume(80, 50.f, m_sQueueSample.m_fDistance); if(m_sQueueSample.m_bVolume) { m_sQueueSample.m_counter = 39; @@ -3378,7 +3379,7 @@ cAudioManager::ProcessBoatEngine(cVehicleParams *params) m_sQueueSample.m_nSampleIndex = SFX_POLICE_BOAT_ACCEL; } } - CalculateDistance((bool *)params, params->m_fDistance); + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 50.f, m_sQueueSample.m_fDistance); if(!m_sQueueSample.m_bVolume) return 1; m_sQueueSample.m_nFrequency += (m_sQueueSample.m_nEntityIndex << 16) % 1000; @@ -3417,7 +3418,7 @@ cAudioManager::ProcessBoatMovingOverWater(cVehicleParams *params) velocityChange = min(0.75f, velocityChange); multiplier = (velocityChange - 0.0005f) * 1.3342f; - CalculateDistance((bool *)params, params->m_fDistance); + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); vol = (30.f * multiplier); m_sQueueSample.m_bVolume = ComputeVolume(vol, 50.f, m_sQueueSample.m_fDistance); if(m_sQueueSample.m_bVolume) { @@ -3447,13 +3448,13 @@ void cAudioManager::ProcessBridge() { float dist; - bool something = false; + bool distCalculated = false; if(CBridge::pLiftRoad) { m_sQueueSample.m_vecPos = CBridge::pLiftRoad->GetPosition(); dist = GetDistanceSquared(&m_sQueueSample.m_vecPos); if(dist < 202500.0f) { - CalculateDistance(&something, dist); + CalculateDistance(distCalculated, dist); switch(CBridge::State) { case STATE_BRIDGE_LOCKED: case STATE_LIFT_PART_IS_UP: @@ -3583,7 +3584,7 @@ cAudioManager::ProcessCarBombTick(cVehicleParams *params) if(params->m_fDistance >= 1600.f) return 0; automobile = (CAutomobile *)params->m_pVehicle; if(automobile->bEngineOn && automobile->m_bombType == CARBOMB_TIMEDACTIVE) { - CalculateDistance((bool *)params, params->m_fDistance); + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); m_sQueueSample.m_bVolume = ComputeVolume(60, 40.f, m_sQueueSample.m_fDistance); if(m_sQueueSample.m_bVolume) { m_sQueueSample.m_counter = 35; @@ -3749,7 +3750,7 @@ cAudioManager::ProcessEngineDamage(cVehicleParams *params) m_sQueueSample.field_16 = 7; m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CAR_ON_FIRE); } - CalculateDistance((bool *)params, params->m_fDistance); + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); m_sQueueSample.m_bVolume = ComputeVolume(emittingVolume, 40.f, m_sQueueSample.m_fDistance); if(m_sQueueSample.m_bVolume) { m_sQueueSample.m_counter = 28; @@ -3932,12 +3933,12 @@ void cAudioManager::ProcessFireHydrant() { float distSquared; - bool something = false; + bool distCalculated = 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); + CalculateDistance(distCalculated, distSquared); m_sQueueSample.m_bVolume = ComputeVolume(40, 35.f, m_sQueueSample.m_fDistance); if(m_sQueueSample.m_bVolume) { m_sQueueSample.m_counter = 0; @@ -4154,7 +4155,7 @@ cAudioManager::ProcessHelicopter(cVehicleParams *params) if(gHeliSfxRanges[0].m_fMaxDistance * gHeliSfxRanges[0].m_fMaxDistance <= params->m_fDistance) return 0; - CalculateDistance((bool *)params, params->m_fDistance); + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); heli = (CHeli *)params->m_pVehicle; for(uint32 i = 0; i < 3; i++) { MaxDist = gHeliSfxRanges[i].m_fMaxDistance; @@ -4253,7 +4254,7 @@ cAudioManager::ProcessJumbo(cVehicleParams *params) float position; if(params->m_fDistance < 193600.0f) { - CalculateDistance((bool *)params, params->m_fDistance); + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); plane = (CPlane *)params->m_pVehicle; DoJumboVolOffset(); position = PlanePathPosition[plane->m_nPlaneId]; @@ -5213,7 +5214,7 @@ cAudioManager::ProcessModelCarEngine(cVehicleParams *params) else emittingVol = 90; if(emittingVol) { - CalculateDistance((bool *)params, params->m_fDistance); + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 30.f, m_sQueueSample.m_fDistance); if(m_sQueueSample.m_bVolume) { @@ -5535,12 +5536,12 @@ cAudioManager::ProcessPedHeadphones(cPedParams *params) if(params->m_fDistance < 49.f) { ped = params->m_pPed; - if(!ped->bIsAimingGun || ped->m_bodyPartBleeding != 2) { - CalculateDistance((bool *)params, params->m_fDistance); + if(!ped->bIsAimingGun || ped->m_bodyPartBleeding != PED_HEAD) { + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); if(ped->bInVehicle && ped->m_nPedState == PED_DRIVING) { emittingVol = 10; veh = ped->m_pMyVehicle; - if(veh && veh->m_type == 0) { + if(veh && veh->IsCar()) { for(int32 i = 2; i < 6; i++) { if(!veh->IsDoorClosed((eDoors)i) || veh->IsDoorMissing((eDoors)i)) { emittingVol = 42; @@ -6450,7 +6451,7 @@ cAudioManager::ProcessPhysical(int32 id) { CPhysical *entity = (CPhysical *)m_asAudioEntities[id].m_pEntity; if(entity) { - switch(entity->m_type & 7) { + switch(entity->m_type) { 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; @@ -6491,7 +6492,6 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile * float relativeVelocityChange; float accelerationMultipler; uint8 wheelInUseCounter; - uint8 i; float time; int baseFreq; uint8 vol; @@ -6539,19 +6539,15 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile * velocityChange = params->m_fVelocityChange; relativeVelocityChange = 2.0f * velocityChange / transmission->fMaxVelocity; - accelerationMultipler = 0.0f; - - if(relativeVelocityChange > 1.0f) accelerationMultipler = relativeVelocityChange; - + accelerationMultipler = min(min(1.f, relativeVelocityChange), 0.f); gasPedalAudio = accelerationMultipler; currentGear = params->m_pVehicle->m_nCurrentGear; + if(transmission->nDriveType == '4') { wheelInUseCounter = 0; - i = 0; - do { + for (uint8 i = 0; i < 4; i++){ if(automobile->m_aWheelState[i]) ++wheelInUseCounter; - ++i; - } while(i < 4); + } if(wheelInUseCounter > 2) lostTraction = 1; } else if(transmission->nDriveType == 'F') { if((automobile->m_aWheelState[0] || automobile->m_aWheelState[2]) && @@ -6622,7 +6618,8 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile * if(!nCruising) { if(accelerateState < 150 || !automobile->m_nWheelsOnGround || automobile->bIsHandbrakeOn || lostTraction || - currentGear < 2u && velocityChange - automobile->m_fVelocityChangeForAudio >= 0.01f) { + currentGear < 2 && + velocityChange - automobile->m_fVelocityChangeForAudio < 0.01f) { // here could be used abs if(!automobile->m_nWheelsOnGround || automobile->bIsHandbrakeOn || lostTraction) { if(!automobile->m_nWheelsOnGround && automobile->m_nDriveWheelsOnGround || (automobile->bIsHandbrakeOn && !bHandbrakeOnLastFrame || @@ -6994,7 +6991,7 @@ cAudioManager::ProcessRainOnVehicle(cVehicleParams *params) veh = params->m_pVehicle; if(veh->m_bRainAudioCounter >= 2) { veh->m_bRainAudioCounter = 0; - CalculateDistance((bool *)params, params->m_fDistance); + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); emittingVol = 30.f * CWeather::Rain; m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 22.f, m_sQueueSample.m_fDistance); if(m_sQueueSample.m_bVolume) { @@ -7043,7 +7040,7 @@ cAudioManager::ProcessReverseGear(cVehicleParams *params) if(params->m_fDistance >= 900.f) return 0; veh = params->m_pVehicle; if(veh->bEngineOn && (veh->m_fGasPedal < 0.0f || !veh->m_nCurrentGear)) { - CalculateDistance((bool *)params, params->m_fDistance); + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); automobile = (CAutomobile *)params->m_pVehicle; if(automobile->m_nWheelsOnGround) { modificator = params->m_fVelocityChange / params->m_pTransmission->fMaxReverseVelocity; @@ -7261,7 +7258,7 @@ cAudioManager::ProcessTrainNoise(cVehicleParams *params) if(params->m_fDistance >= 90000.f) return 0; if(params->m_fVelocityChange > 0.0f) { - CalculateDistance((bool *)params, params->m_fDistance); + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); train = (CTrain *)params->m_pVehicle; speedMultipler = min(1.0f, train->m_fSpeed * 250.f / 51.f); emittingVol = (75.f * speedMultipler); @@ -7326,7 +7323,7 @@ cAudioManager::ProcessVehicle(CVehicle *veh) cVehicleParams params; m_sQueueSample.m_vecPos = veh->GetPosition(); - params.m_bDistancECalculated = 0; + params.m_bDistanceCalculated = false; params.m_fDistance = GetDistanceSquared(&m_sQueueSample.m_vecPos); params.m_pVehicle = veh; params.m_pTransmission = nil; @@ -7419,7 +7416,7 @@ cAudioManager::ProcessVehicleDoors(cVehicleParams *params) if(params->m_fDistance >= 1600.f) return 0; automobile = (CAutomobile *)params->m_pVehicle; - CalculateDistance((bool *)params, params->m_fDistance); + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); for(int32 i = 0; i < 6; i++) { if(automobile->Damage.GetDoorStatus(i) == 2) { doorState = automobile->Doors[i].m_nDoorState; @@ -7475,7 +7472,7 @@ cAudioManager::ProcessVehicleHorn(cVehicleParams *params) automobile->m_modelIndex != MI_MRWHOOP) { if(automobile->m_nCarHornTimer) { if(!params->m_pVehicle->m_status) { - CalculateDistance((bool *)params, params->m_fDistance); + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); m_sQueueSample.m_bVolume = ComputeVolume(80, 40.f, m_sQueueSample.m_fDistance); if(m_sQueueSample.m_bVolume) { m_sQueueSample.m_counter = 4; @@ -7507,7 +7504,7 @@ cAudioManager::ProcessVehicleHorn(cVehicleParams *params) automobile->field_22D = (LOBYTE(m_nTimeOfRecentCrime) + LOBYTE(m_sQueueSample.m_nEntityIndex)) & 7; if(hornPatternsArray[automobile->field_22D][44 - automobile->m_nCarHornTimer]) { - CalculateDistance((bool *)params, params->m_fDistance); + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); m_sQueueSample.m_bVolume = ComputeVolume(80, 40.f, m_sQueueSample.m_fDistance); if(m_sQueueSample.m_bVolume) { m_sQueueSample.m_counter = 4; @@ -7553,7 +7550,7 @@ cAudioManager::ProcessVehicleReverseWarning(cVehicleParams *params) if(params->m_fDistance >= 2500.f) return 0; if(veh->bEngineOn && veh->m_fGasPedal < 0.0f) { - CalculateDistance((bool *)params, params->m_fDistance); + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); m_sQueueSample.m_bVolume = ComputeVolume(60, 50.f, m_sQueueSample.m_fDistance); if(m_sQueueSample.m_bVolume) { m_sQueueSample.m_counter = 12; @@ -7595,7 +7592,7 @@ cAudioManager::ProcessVehicleRoadNoise(cVehicleParams *params) if(params->m_pVehicle->m_vecMoveSpeed.z) { velocity = Abs(params->m_fVelocityChange); if(velocity > 0.0f) { - CalculateDistance((bool *)params, params->m_fDistance); + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); emittingVol = 30.f * min(1.f, velocity / (0.5f * params->m_pTransmission->fMaxVelocity)); m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 95.f, m_sQueueSample.m_fDistance); @@ -7635,11 +7632,55 @@ cAudioManager::ProcessVehicleRoadNoise(cVehicleParams *params) return 1; } -WRAPPER void -cAudioManager::ProcessVehicleSirenOrAlarm(void *) +cAudioManager::ProcessVehicleSirenOrAlarm(cVehicleParams *params) { - EAXJMP(0x56C420); + if(params->m_fDistance < 12100.f) { + CVehicle *veh = params->m_pVehicle; + if(veh->m_bSirenOrAlarm == 0 && veh->m_nAlarmState <= 0) return; + + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); + m_sQueueSample.m_bVolume = ComputeVolume(80, 110.f, m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume) { + m_sQueueSample.m_counter = 5; + if(UsesSiren(params->m_nIndex)) { + if(params->m_pVehicle->m_status == STATUS_ABANDONED) return; + if(veh->m_nCarHornTimer && params->m_nIndex != FIRETRUK) { + m_sQueueSample.m_nSampleIndex = SFX_SIREN_FAST; + if(params->m_nIndex == FBICAR) + m_sQueueSample.m_nFrequency = 16113; + else + m_sQueueSample.m_nFrequency = + SampleManager.GetSampleBaseFrequency(SFX_SIREN_FAST); + m_sQueueSample.m_counter = 60; + } else { + m_sQueueSample.m_nSampleIndex = + CarSounds[params->m_nIndex].m_nSirenOrAlarmSample; + m_sQueueSample.m_nFrequency = + CarSounds[params->m_nIndex].m_nSirenOrAlarmFrequency; + } + } else { + m_sQueueSample.m_nSampleIndex = CarSounds[params->m_nIndex].m_nSirenOrAlarmSample; + m_sQueueSample.m_nFrequency = CarSounds[params->m_nIndex].m_nSirenOrAlarmFrequency; + } + m_sQueueSample.m_bBankIndex = 0; + m_sQueueSample.m_bIsDistant = 0; + m_sQueueSample.field_16 = 1; + m_sQueueSample.m_nLoopCount = 0; + m_sQueueSample.m_bEmittingVolume = 80; + m_sQueueSample.m_nLoopStart = + SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex); + m_sQueueSample.field_48 = 7.0f; + m_sQueueSample.m_fSoundIntensity = 110.0f; + m_sQueueSample.field_56 = 0; + m_sQueueSample.field_76 = 5; + m_sQueueSample.m_bReverbFlag = 1; + m_sQueueSample.m_bRequireReflection = 0; + AddSampleToRequestedQueue(); + return; + } + } } void @@ -7654,7 +7695,7 @@ cAudioManager::ProcessVehicleSkidding(cVehicleParams *params) if(params->m_fDistance >= 1600.f) return; automobile = (CAutomobile *)params->m_pVehicle; if(!automobile->m_nWheelsOnGround) return; - CalculateDistance((bool *)params, params->m_fDistance); + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); for(int32 i = 0; i < 4; i++) { if(!automobile->m_aWheelState[i] || automobile->Damage.GetWheelStatus(i) == WHEEL_STATUS_MISSING) continue; @@ -7843,7 +7884,7 @@ cAudioManager::ProcessWetRoadNoise(cVehicleParams *params) if(params->m_pVehicle->m_vecMoveSpeed.z) { velChange = Abs(params->m_fVelocityChange); if(velChange > 0.f) { - CalculateDistance((bool *)params, params->m_fDistance); + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); relativeVelocity = min(1.0f, velChange / (0.5f * params->m_pTransmission->fMaxVelocity)); emittingVol = 23.0f * relativeVelocity * CWeather::WetRoads; @@ -8872,14 +8913,14 @@ cAudioManager::SetupPedComments(cPedParams *params, uint32 sound) soundIntensity = 50.f; if(params->m_fDistance < maxDist) { - CalculateDistance((bool *)params, params->m_fDistance); + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); if(sound != SOUND_PAGER) { switch(sound) { case SOUND_AMMUNATION_WELCOME_1: case SOUND_AMMUNATION_WELCOME_2: case SOUND_AMMUNATION_WELCOME_3: emittingVol = maxVolume; break; default: - if(CWorld::GetIsLineOfSightClear(TheCamera.GetGameCamPosition(), + if(CWorld::GetIsLineOfSightClear(TheCamera.GetPosition(), m_sQueueSample.m_vecPos, 1, 0, 0, 0, 0, 0, 0)) { emittingVol = maxVolume; @@ -8933,14 +8974,14 @@ cAudioManager::SetupPedComments(cPedParams *params, uint32 sound) } if(params->m_fDistance < maxDist) { - CalculateDistance((bool *)params, params->m_fDistance); + CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); if(sound != SOUND_PAGER) { switch(sound) { case SOUND_AMMUNATION_WELCOME_1: case SOUND_AMMUNATION_WELCOME_2: case SOUND_AMMUNATION_WELCOME_3: emittingVol = maxVolume; break; default: - if(CWorld::GetIsLineOfSightClear(TheCamera.GetGameCamPosition(), + if(CWorld::GetIsLineOfSightClear(TheCamera.GetPosition(), m_sQueueSample.m_vecPos, 1, 0, 0, 0, 0, 0, 0)) { emittingVol = maxVolume; @@ -9594,6 +9635,7 @@ InjectHook(0x56C770, &cAudioManager::ProcessVehicleDoors, PATCH_JUMP); InjectHook(0x56C200, &cAudioManager::ProcessVehicleHorn, PATCH_JUMP); InjectHook(0x56C640, &cAudioManager::ProcessVehicleReverseWarning, PATCH_JUMP); InjectHook(0x56A230, &cAudioManager::ProcessVehicleRoadNoise, PATCH_JUMP); +InjectHook(0x56C420, &cAudioManager::ProcessVehicleSirenOrAlarm, PATCH_JUMP); InjectHook(0x56BCB0, &cAudioManager::ProcessVehicleSkidding, PATCH_JUMP); InjectHook(0x575F30, &cAudioManager::ProcessWaterCannon, PATCH_JUMP); InjectHook(0x578370, &cAudioManager::ProcessWeather, PATCH_JUMP); diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h index 19809286..7df6dcbe 100644 --- a/src/audio/AudioManager.h +++ b/src/audio/AudioManager.h @@ -440,11 +440,11 @@ public: void AddSampleToRequestedQueue(); /// ok void AgeCrimes(); /// ok - void CalculateDistance(bool *ptr, float dist); /// ok - bool CheckForAnAudioFileOnCD() const; /// ok - void ClearActiveSamples(); /// ok - void ClearMissionAudio(); /// ok - void ClearRequestedQueue(); /// ok + void CalculateDistance(bool &condition, float dist); /// ok + bool CheckForAnAudioFileOnCD() const; /// ok + void ClearActiveSamples(); /// ok + void ClearMissionAudio(); /// ok + void ClearRequestedQueue(); /// ok int32 ComputeDopplerEffectedFrequency(uint32 oldFreq, float position1, float position2, float speedMultiplier) const; /// ok int32 ComputePan(float, CVector *); /// ok @@ -640,7 +640,7 @@ public: void ProcessVehicleOneShots(void *); // todo bool ProcessVehicleReverseWarning(cVehicleParams *params); /// ok bool ProcessVehicleRoadNoise(cVehicleParams *params); /// ok - void ProcessVehicleSirenOrAlarm(void *); // todo + void ProcessVehicleSirenOrAlarm(cVehicleParams *params); /// ok void ProcessVehicleSkidding(cVehicleParams *params); /// ok void ProcessWaterCannon(int32); /// ok void ProcessWeather(int32 id); /// ok diff --git a/src/audio/sampman.cpp b/src/audio/sampman.cpp index 53b81a36..6edb6028 100644 --- a/src/audio/sampman.cpp +++ b/src/audio/sampman.cpp @@ -35,7 +35,7 @@ int32 _nSampleDataEndOffset; int32 nPedSlotSfx [MAX_PEDSFX]; int32 nPedSlotSfxAddr[MAX_PEDSFX]; -int32 nCurrentPedSlot; +uint8 nCurrentPedSlot; uint8 nChannelVolume[MAXCHANNELS+MAX2DCHANNELS]; @@ -116,7 +116,7 @@ typedef struct provider_stuff static int __cdecl comp(const provider_stuff*s1,const provider_stuff*s2) { - return( _stricmp(s1->name,s2->name) ); + return(strcasecmp(s1->name, s2->name)); } static void @@ -352,7 +352,11 @@ _ResolveLink(char const *path, char *out) OutputDebugString(fd.cFileName); strcpy(out, filepath); - + // FIX: Release the objects. Taken from SA. +#ifdef FIX_BUGS + ppf->Release(); + psl->Release(); +#endif return true; } } @@ -1437,7 +1441,7 @@ cSampleManager::IsSampleBankLoaded(uint8 nBank) bool cSampleManager::IsPedCommentLoaded(uint32 nComment) { - int32 slot; + uint8 slot; for ( int32 i = 0; i < _TODOCONST(3); i++ ) { @@ -1452,7 +1456,7 @@ cSampleManager::IsPedCommentLoaded(uint32 nComment) int32 cSampleManager::_GetPedCommentSlot(uint32 nComment) { - int32 slot; + uint8 slot; for ( int32 i = 0; i < _TODOCONST(3); i++ ) { diff --git a/src/control/AccidentManager.cpp b/src/control/AccidentManager.cpp index 46d254fc..a42280b7 100644 --- a/src/control/AccidentManager.cpp +++ b/src/control/AccidentManager.cpp @@ -8,7 +8,8 @@ CAccidentManager& gAccidentManager = *(CAccidentManager*)0x87FD10; WRAPPER void CAccidentManager::Update(void) { EAXJMP(0x456710); } -uint16 CAccidentManager::CountActiveAccidents() +uint16 +CAccidentManager::CountActiveAccidents() { uint16 accidents = 0; for (int i = 0; i < NUM_ACCIDENTS; i++){ @@ -18,7 +19,8 @@ uint16 CAccidentManager::CountActiveAccidents() return accidents; } -CAccident* CAccidentManager::FindNearestAccident(CVector vecPos, float* pDistance) +CAccident* +CAccidentManager::FindNearestAccident(CVector vecPos, float* pDistance) { for (int i = 0; i < MAX_MEDICS_TO_ATTEND_ACCIDENT; i++){ int accidentId = -1; @@ -44,4 +46,14 @@ CAccident* CAccidentManager::FindNearestAccident(CVector vecPos, float* pDistanc return &m_aAccidents[accidentId]; } return nil; +} + +bool +CAccidentManager::UnattendedAccidents(void) +{ + for (int i = 0; i < NUM_ACCIDENTS; i++) { + if (m_aAccidents[i].m_pVictim && m_aAccidents[i].m_nMedicsAttending == 0) + return true; + } + return false; }
\ No newline at end of file diff --git a/src/control/AccidentManager.h b/src/control/AccidentManager.h index 6d7f25c8..6a3088e7 100644 --- a/src/control/AccidentManager.h +++ b/src/control/AccidentManager.h @@ -21,6 +21,7 @@ class CAccidentManager }; public: uint16 CountActiveAccidents(); + bool UnattendedAccidents(); CAccident* FindNearestAccident(CVector, float*); void Update(void); }; diff --git a/src/control/PathFind.cpp b/src/control/PathFind.cpp index 3c16202b..dad879b1 100644 --- a/src/control/PathFind.cpp +++ b/src/control/PathFind.cpp @@ -309,7 +309,7 @@ CPathFind::CountFloodFillGroups(uint8 type) if(m_pathNodes[l].group == 0){ m_pathNodes[l].group = n; if(m_pathNodes[l].group == 0) - m_pathNodes[l].group = 0x80; // ??? + m_pathNodes[l].group = INT8_MIN; m_pathNodes[l].next = node; node = &m_pathNodes[l]; } diff --git a/src/control/PathFind.h b/src/control/PathFind.h index 0b20ea5a..70b431f6 100644 --- a/src/control/PathFind.h +++ b/src/control/PathFind.h @@ -36,7 +36,7 @@ struct CPathNode uint8 bDisabled : 1; uint8 bBetweenLevels : 1; - uint8 group; + int8 group; /* For reference VC: int16 prevIndex; int16 nextIndex; diff --git a/src/control/Phones.cpp b/src/control/Phones.cpp index ef978868..f3b3a8db 100644 --- a/src/control/Phones.cpp +++ b/src/control/Phones.cpp @@ -6,16 +6,146 @@ #include "Ped.h" #include "Pad.h" #include "Messages.h" +#include "Camera.h" +#include "World.h" +#include "General.h" +#include "AudioScriptObject.h" +#include "RpAnimBlend.h" CPhoneInfo &gPhoneInfo = *(CPhoneInfo*)0x732A20; -bool &CPhoneInfo::isPhonePickedUp = *(bool*)0x6283AC; -uint32 &CPhoneInfo::phoneMessagesTimer = *(uint32*)0x6283A8; -CPhone *&CPhoneInfo::pickedUpPhone = *(CPhone**)0x6283B0; -bool &CPhoneInfo::isPhoneBeingPickedUp = *(bool*)0x6283B4; -CPed *&CPhoneInfo::pedWhoPickingUpPhone = *(CPed**)0x6283B8; +bool &CPhoneInfo::bDisplayingPhoneMessage = *(bool*)0x6283AC; // is phone picked up +uint32 &CPhoneInfo::PhoneEnableControlsTimer = *(uint32*)0x6283A8; +CPhone *&CPhoneInfo::pPhoneDisplayingMessages = *(CPhone**)0x6283B0; +bool &CPhoneInfo::bPickingUpPhone = *(bool*)0x6283B4; +CPed *&CPhoneInfo::pCallBackPed = *(CPed**)0x6283B8; // ped who picking up the phone (reset after pickup cb) -WRAPPER void CPhoneInfo::Update(void) { EAXJMP(0x42F7A0); } +/* + Entering phonebooth cutscene, showing messages and triggering these things + by checking coordinates happens in here - blue mission marker is cosmetic. + + Repeated message means after the script set the messages for a particular phone, + player can pick the phone again with the same messages appearing, + after 60 seconds of last phone pick-up. +*/ + +#ifdef TOGGLEABLE_BETA_FEATURES +CPed* crimeReporters[NUMPHONES] = {}; +bool +isPhoneAvailable(int m_phoneId) +{ + return gPhoneInfo.m_aPhones[m_phoneId].m_nState == PHONE_STATE_FREE && + (crimeReporters[m_phoneId] == nil || !crimeReporters[m_phoneId]->IsPointerValid() || !crimeReporters[m_phoneId]->bRunningToPhone || crimeReporters[m_phoneId]->m_objective > OBJECTIVE_IDLE || + crimeReporters[m_phoneId]->m_nLastPedState != PED_SEEK_POS && + (crimeReporters[m_phoneId]->m_nPedState != PED_MAKE_CALL && crimeReporters[m_phoneId]->m_nPedState != PED_FACE_PHONE && crimeReporters[m_phoneId]->m_nPedState != PED_SEEK_POS)); +} +#endif + +void +CPhoneInfo::Update(void) +{ + CPlayerPed *player = FindPlayerPed(); + CPlayerInfo *playerInfo = &CWorld::Players[CWorld::PlayerInFocus]; + if (bDisplayingPhoneMessage && CTimer::GetTimeInMilliseconds() > PhoneEnableControlsTimer) { + playerInfo->MakePlayerSafe(false); + TheCamera.SetWideScreenOff(); + pPhoneDisplayingMessages = nil; + bDisplayingPhoneMessage = false; + CAnimBlendAssociation *talkAssoc = RpAnimBlendClumpGetAssociation(player->GetClump(), ANIM_PHONE_TALK); + if (talkAssoc && talkAssoc->blendAmount > 0.5f) { + CAnimBlendAssociation *endAssoc = CAnimManager::BlendAnimation(player->GetClump(), ASSOCGRP_STD, ANIM_PHONE_OUT, 8.0f); + endAssoc->flags &= ~ASSOC_DELETEFADEDOUT; + endAssoc->SetFinishCallback(PhonePutDownCB, player); + } else { + CPad::GetPad(0)->DisablePlayerControls &= ~PLAYERCONTROL_DISABLED_40; + if (player->m_nPedState == PED_MAKE_CALL) + player->m_nPedState = PED_IDLE; + } + } + bool notInCar; + CVector playerPos; + if (FindPlayerVehicle()) { + notInCar = false; + playerPos = FindPlayerVehicle()->GetPosition(); + } else { + notInCar = true; + playerPos = player->GetPosition(); + } + bool phoneRings = false; + bool scratchTheCabinet; + for(int phoneId = 0; phoneId < m_nScriptPhonesMax; phoneId++) { + if (m_aPhones[phoneId].m_visibleToCam) { + switch (m_aPhones[phoneId].m_nState) { + case PHONE_STATE_ONETIME_MESSAGE_SET: + case PHONE_STATE_REPEATED_MESSAGE_SET: + case PHONE_STATE_REPEATED_MESSAGE_SHOWN_ONCE: + if (bPickingUpPhone) { + scratchTheCabinet = false; + phoneRings = false; + } else { + scratchTheCabinet = (CTimer::GetTimeInMilliseconds() / 1880) % 2 == 1; + phoneRings = (CTimer::GetPreviousTimeInMilliseconds() / 1880) % 2 == 1; + } + if (scratchTheCabinet) { + m_aPhones[phoneId].m_pEntity->GetUp().z = (CGeneral::GetRandomNumber() % 1024) / 16000.0f + 1.0f; + if (!phoneRings) + PlayOneShotScriptObject(_SCRSOUND_PHONE_RING, m_aPhones[phoneId].m_pEntity->GetPosition()); + } else { + m_aPhones[phoneId].m_pEntity->GetUp().z = 1.0f; + } + m_aPhones[phoneId].m_pEntity->GetMatrix().UpdateRW(); + m_aPhones[phoneId].m_pEntity->UpdateRwFrame(); + if (notInCar && !bPickingUpPhone && player->IsPedInControl()) { + CVector2D distToPhone = playerPos - m_aPhones[phoneId].m_vecPos; + if (Abs(distToPhone.x) < 1.0f && Abs(distToPhone.y) < 1.0f) { + if (DotProduct2D(distToPhone, m_aPhones[phoneId].m_pEntity->GetForward()) / distToPhone.Magnitude() < -0.85f) { + CVector2D distToPhoneObj = playerPos - m_aPhones[phoneId].m_pEntity->GetPosition(); + float angleToFace = CGeneral::GetATanOfXY(distToPhoneObj.x, distToPhoneObj.y) + HALFPI; + if (angleToFace > TWOPI) + angleToFace = angleToFace - TWOPI; + player->m_fRotationCur = angleToFace; + player->m_fRotationDest = angleToFace; + player->SetHeading(angleToFace); + player->m_nPedState = PED_MAKE_CALL; + CPad::GetPad(0)->DisablePlayerControls |= PLAYERCONTROL_DISABLED_40; + TheCamera.SetWideScreenOn(); + playerInfo->MakePlayerSafe(true); + CAnimBlendAssociation *phonePickAssoc = CAnimManager::BlendAnimation(player->GetClump(), ASSOCGRP_STD, ANIM_PHONE_IN, 4.0f); + phonePickAssoc->SetFinishCallback(PhonePickUpCB, &m_aPhones[phoneId]); + bPickingUpPhone = true; + pCallBackPed = player; + } + } + } + break; + case PHONE_STATE_REPEATED_MESSAGE_STARTED: + if (CTimer::GetTimeInMilliseconds() - m_aPhones[phoneId].m_repeatedMessagePickupStart > 60000) + m_aPhones[phoneId].m_nState = PHONE_STATE_REPEATED_MESSAGE_SHOWN_ONCE; + break; + case PHONE_STATE_9: + scratchTheCabinet = (CTimer::GetTimeInMilliseconds() / 1880) % 2 == 1; + phoneRings = (CTimer::GetPreviousTimeInMilliseconds() / 1880) % 2 == 1; + if (scratchTheCabinet) { + m_aPhones[phoneId].m_pEntity->GetUp().z = (CGeneral::GetRandomNumber() % 1024) / 16000.0f + 1.0f; + if (!phoneRings) + PlayOneShotScriptObject(_SCRSOUND_PHONE_RING, m_aPhones[phoneId].m_pEntity->GetPosition()); + } else { + m_aPhones[phoneId].m_pEntity->GetUp().z = 1.0f; + } + m_aPhones[phoneId].m_pEntity->GetMatrix().UpdateRW(); + m_aPhones[phoneId].m_pEntity->UpdateRwFrame(); + break; + default: + break; + } + if (CVector2D(TheCamera.GetPosition() - m_aPhones[phoneId].m_vecPos).MagnitudeSqr() > sq(100.0f)) + m_aPhones[phoneId].m_visibleToCam = false; + } else if (!((CTimer::GetFrameCounter() + m_aPhones[phoneId].m_pEntity->m_randomSeed) % 16)) { + if (CVector2D(TheCamera.GetPosition() - m_aPhones[phoneId].m_vecPos).MagnitudeSqr() < sq(60.0f)) + m_aPhones[phoneId].m_visibleToCam = true; + } + } +} int CPhoneInfo::FindNearestFreePhone(CVector *pos) @@ -25,7 +155,11 @@ CPhoneInfo::FindNearestFreePhone(CVector *pos) for (int phoneId = 0; phoneId < m_nMax; phoneId++) { - if (gPhoneInfo.m_aPhones[phoneId].m_nState == PHONE_STATE_FREE) { + if (gPhoneInfo.m_aPhones[phoneId].m_nState == PHONE_STATE_FREE +#ifdef TOGGLEABLE_BETA_FEATURES + && isPhoneAvailable(phoneId) +#endif + ) { float phoneDist = (m_aPhones[phoneId].m_vecPos - *pos).Magnitude2D(); if (phoneDist < nearestPhoneDist) { @@ -50,20 +184,20 @@ CPhoneInfo::PhoneAtThisPosition(CVector pos) bool CPhoneInfo::HasMessageBeenDisplayed(int phoneId) { - if (isPhonePickedUp) + if (bDisplayingPhoneMessage) return false; int state = m_aPhones[phoneId].m_nState; return state == PHONE_STATE_REPEATED_MESSAGE_SHOWN_ONCE || - state == PHONE_STATE_ONETIME_MESSAGE_SHOWN || - state == PHONE_STATE_REPEATED_MESSAGE_SHOWN; + state == PHONE_STATE_ONETIME_MESSAGE_STARTED || + state == PHONE_STATE_REPEATED_MESSAGE_STARTED; } bool CPhoneInfo::IsMessageBeingDisplayed(int phoneId) { - return pickedUpPhone == &m_aPhones[phoneId]; + return pPhoneDisplayingMessages == &m_aPhones[phoneId]; } void @@ -71,8 +205,8 @@ CPhoneInfo::Load(uint8 *buf, uint32 size) { INITSAVEBUF m_nMax = ReadSaveBuf<int32>(buf); - m_nNum = ReadSaveBuf<int32>(buf); - for (int i = 0; i < 50; i++) { + m_nScriptPhonesMax = ReadSaveBuf<int32>(buf); + for (int i = 0; i < NUMPHONES; i++) { m_aPhones[i] = ReadSaveBuf<CPhone>(buf); // It's saved as building pool index in save file, convert it to true entity if (m_aPhones[i].m_pEntity) { @@ -127,7 +261,7 @@ CPhoneInfo::GrabPhone(float xPos, float yPos) CVector pos(xPos, yPos, 0.0f); float nearestPhoneDist = 100.0f; - for (int phoneId = m_nNum; phoneId < m_nMax; phoneId++) { + for (int phoneId = m_nScriptPhonesMax; phoneId < m_nMax; phoneId++) { float phoneDistance = (m_aPhones[phoneId].m_vecPos - pos).Magnitude2D(); if (phoneDistance < nearestPhoneDist) { nearestPhoneDist = phoneDistance; @@ -136,23 +270,23 @@ CPhoneInfo::GrabPhone(float xPos, float yPos) } m_aPhones[nearestPhoneId].m_nState = PHONE_STATE_MESSAGE_REMOVED; - CPhone oldFirstPhone = m_aPhones[m_nNum]; - m_aPhones[m_nNum] = m_aPhones[nearestPhoneId]; + CPhone oldFirstPhone = m_aPhones[m_nScriptPhonesMax]; + m_aPhones[m_nScriptPhonesMax] = m_aPhones[nearestPhoneId]; m_aPhones[nearestPhoneId] = oldFirstPhone; - m_nNum++; - return m_nNum - 1; + m_nScriptPhonesMax++; + return m_nScriptPhonesMax - 1; } void CPhoneInfo::Initialise(void) { CBuildingPool *pool = CPools::GetBuildingPool(); - pedWhoPickingUpPhone = nil; - isPhonePickedUp = false; - isPhoneBeingPickedUp = false; - pickedUpPhone = nil; + pCallBackPed = nil; + bDisplayingPhoneMessage = false; + bPickingUpPhone = false; + pPhoneDisplayingMessages = nil; m_nMax = 0; - m_nNum = 0; + m_nScriptPhonesMax = 0; for (int i = pool->GetSize() - 1; i >= 0; i--) { CBuilding *building = pool->GetSlot(i); if (building) { @@ -173,8 +307,8 @@ CPhoneInfo::Save(uint8 *buf, uint32 *size) *size = sizeof(CPhoneInfo); INITSAVEBUF WriteSaveBuf(buf, m_nMax); - WriteSaveBuf(buf, m_nNum); - for(int phoneId = 0; phoneId < 50; phoneId++) { + WriteSaveBuf(buf, m_nScriptPhonesMax); + for(int phoneId = 0; phoneId < NUMPHONES; phoneId++) { CPhone* phone = WriteSaveBuf(buf, m_aPhones[phoneId]); // Convert entity pointer to building pool index while saving @@ -189,7 +323,7 @@ void CPhoneInfo::Shutdown(void) { m_nMax = 0; - m_nNum = 0; + m_nScriptPhonesMax = 0; } void @@ -221,26 +355,26 @@ PhonePickUpCB(CAnimBlendAssociation *assoc, void *arg) } } - CPhoneInfo::isPhoneBeingPickedUp = false; - CPhoneInfo::isPhonePickedUp = true; - CPhoneInfo::pickedUpPhone = phone; - CPhoneInfo::phoneMessagesTimer = CTimer::GetTimeInMilliseconds() + messagesDisplayTime; + CPhoneInfo::bPickingUpPhone = false; + CPhoneInfo::bDisplayingPhoneMessage = true; + CPhoneInfo::pPhoneDisplayingMessages = phone; + CPhoneInfo::PhoneEnableControlsTimer = CTimer::GetTimeInMilliseconds() + messagesDisplayTime; if (phone->m_nState == PHONE_STATE_ONETIME_MESSAGE_SET) { - phone->m_nState = PHONE_STATE_ONETIME_MESSAGE_SHOWN; + phone->m_nState = PHONE_STATE_ONETIME_MESSAGE_STARTED; } else { - phone->m_nState = PHONE_STATE_REPEATED_MESSAGE_SHOWN; - phone->m_lastTimeRepeatedMsgShown = CTimer::GetTimeInMilliseconds(); + phone->m_nState = PHONE_STATE_REPEATED_MESSAGE_STARTED; + phone->m_repeatedMessagePickupStart = CTimer::GetTimeInMilliseconds(); } - CPed *ped = CPhoneInfo::pedWhoPickingUpPhone; + CPed *ped = CPhoneInfo::pCallBackPed; ped->m_nMoveState = PEDMOVE_STILL; CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_IDLE_STANCE, 8.0f); if (assoc->blendAmount > 0.5f && ped) CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_PHONE_TALK, 8.0f); - CPhoneInfo::pedWhoPickingUpPhone = nil; + CPhoneInfo::pCallBackPed = nil; } STARTPATCHES @@ -255,6 +389,7 @@ STARTPATCHES InjectHook(0x42F710, &CPhoneInfo::Shutdown, PATCH_JUMP); InjectHook(0x42F640, &CPhoneInfo::Initialise, PATCH_JUMP); InjectHook(0x42FDB0, &CPhoneInfo::GrabPhone, PATCH_JUMP); + InjectHook(0x42F7A0, &CPhoneInfo::Update, 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 99ec520c..e7e3c9a7 100644 --- a/src/control/Phones.h +++ b/src/control/Phones.h @@ -5,42 +5,46 @@ class CPed; class CAnimBlendAssociation; -enum { +enum PhoneState { PHONE_STATE_FREE, - PHONE_STATE_1, + PHONE_STATE_REPORTING_CRIME, // CCivilianPed::ProcessControl sets it but unused PHONE_STATE_2, PHONE_STATE_MESSAGE_REMOVED, PHONE_STATE_ONETIME_MESSAGE_SET, PHONE_STATE_REPEATED_MESSAGE_SET, PHONE_STATE_REPEATED_MESSAGE_SHOWN_ONCE, - PHONE_STATE_ONETIME_MESSAGE_SHOWN, - PHONE_STATE_REPEATED_MESSAGE_SHOWN, - PHONE_STATE_9 + PHONE_STATE_ONETIME_MESSAGE_STARTED, + PHONE_STATE_REPEATED_MESSAGE_STARTED, + PHONE_STATE_9 // just rings, picking being handled via script. most of the time game uses this }; -struct CPhone +class CPhone { +public: CVector m_vecPos; wchar *m_apMessages[6]; - uint32 m_lastTimeRepeatedMsgShown; - CEntity *m_pEntity; // it's building pool index in save files - int32 m_nState; - uint8 field_30; + uint32 m_repeatedMessagePickupStart; + CEntity *m_pEntity; // stored as building pool index in save files + PhoneState m_nState; + bool m_visibleToCam; + + CPhone() { } + ~CPhone() { } }; static_assert(sizeof(CPhone) == 0x34, "CPhone: error"); class CPhoneInfo { public: - static bool &isPhonePickedUp; - static uint32 &phoneMessagesTimer; - static CPhone *&pickedUpPhone; - static bool &isPhoneBeingPickedUp; - static CPed *&pedWhoPickingUpPhone; + static bool &bDisplayingPhoneMessage; + static uint32 &PhoneEnableControlsTimer; + static CPhone *&pPhoneDisplayingMessages; + static bool &bPickingUpPhone; + static CPed *&pCallBackPed; int32 m_nMax; - int32 m_nNum; - CPhone m_aPhones[50]; + int32 m_nScriptPhonesMax; + CPhone m_aPhones[NUMPHONES]; CPhoneInfo() { } ~CPhoneInfo() { } @@ -62,4 +66,9 @@ public: extern CPhoneInfo &gPhoneInfo; void PhonePutDownCB(CAnimBlendAssociation *assoc, void *arg); -void PhonePickUpCB(CAnimBlendAssociation *assoc, void *arg);
\ No newline at end of file +void PhonePickUpCB(CAnimBlendAssociation *assoc, void *arg); + +#ifdef TOGGLEABLE_BETA_FEATURES +extern CPed *crimeReporters[NUMPHONES]; +bool isPhoneAvailable(int); +#endif
\ No newline at end of file diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp index 1bd1bf4b..ea305778 100644 --- a/src/control/Replay.cpp +++ b/src/control/Replay.cpp @@ -346,7 +346,7 @@ void CReplay::StorePedUpdate(CPed *ped, int id) pp->matrix.CompressFromFullMatrix(ped->GetMatrix()); pp->assoc_group_id = ped->m_animGroup; /* Would be more sane to use GetJustIndex(ped->m_pMyVehicle) in following assignment */ - if (ped->bInVehicle && ped->m_pMyVehicle) + if (ped->InVehicle()) pp->vehicle_index = (CPools::GetVehiclePool()->GetIndex(ped->m_pMyVehicle) >> 8) + 1; else pp->vehicle_index = 0; diff --git a/src/control/Script.cpp b/src/control/Script.cpp index 6d0c596d..c08eefe2 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -204,7 +204,7 @@ void CUpsideDownCarCheck::Init() { for (int i = 0; i < MAX_UPSIDEDOWN_CAR_CHECKS; i++){ m_sCars[i].m_nVehicleIndex = -1; - m_sCars[i].m_nVehicleIndex = 0; + m_sCars[i].m_nUpsideDownTimer = 0; } } @@ -220,6 +220,10 @@ void CUpsideDownCarCheck::UpdateTimers() { uint32 timeStep = CTimer::GetTimeStepInMilliseconds(); for (int i = 0; i < MAX_UPSIDEDOWN_CAR_CHECKS; i++){ +#ifdef FIX_BUGS + if (m_sCars[i].m_nVehicleIndex == -1) + continue; +#endif CVehicle* v = CPools::GetVehiclePool()->GetAt(m_sCars[i].m_nVehicleIndex); if (v){ if (IsCarUpsideDown(m_sCars[i].m_nVehicleIndex)) @@ -1744,7 +1748,7 @@ int8 CRunningScript::ProcessCommandsFrom100To199(int32 command) CollectParameters(&m_nIp, 1); CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); if (ped) { - if (ped->bInVehicle && ped->m_pMyVehicle) { + if (ped->InVehicle()) { if (ped->m_pMyVehicle->pDriver == ped) { ped->m_pMyVehicle->RemoveDriver(); ped->m_pMyVehicle->m_status = STATUS_ABANDONED; @@ -2317,17 +2321,23 @@ int8 CRunningScript::ProcessCommandsFrom200To299(int32 command) assert(pCurrent); // GetIndex(0) doesn't look good int handle = CPools::GetVehiclePool()->GetIndex(pCurrent); if (handle != CTheScripts::StoreVehicleIndex && m_bIsMissionScript){ - CVehicle* pOld = CPools::GetVehiclePool()->GetAt(CTheScripts::StoreVehicleIndex); - if (pOld){ - CCarCtrl::RemoveFromInterestingVehicleList(pOld); - if (pOld->VehicleCreatedBy == MISSION_VEHICLE && CTheScripts::StoreVehicleWasRandom){ - pOld->VehicleCreatedBy = RANDOM_VEHICLE; - pOld->bIsLocked = false; - CCarCtrl::NumRandomCars++; - CCarCtrl::NumMissionCars--; - CTheScripts::MissionCleanup.RemoveEntityFromList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR); +#ifdef FIX_BUGS + if (CTheScripts::StoreVehicleIndex != -1) +#endif + { + CVehicle* pOld = CPools::GetVehiclePool()->GetAt(CTheScripts::StoreVehicleIndex); + if (pOld){ + CCarCtrl::RemoveFromInterestingVehicleList(pOld); + if (pOld->VehicleCreatedBy == MISSION_VEHICLE && CTheScripts::StoreVehicleWasRandom){ + pOld->VehicleCreatedBy = RANDOM_VEHICLE; + pOld->bIsLocked = false; + CCarCtrl::NumRandomCars++; + CCarCtrl::NumMissionCars--; + CTheScripts::MissionCleanup.RemoveEntityFromList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR); + } } } + CTheScripts::StoreVehicleIndex = handle; switch (pCurrent->VehicleCreatedBy){ case RANDOM_VEHICLE: @@ -2367,17 +2377,23 @@ int8 CRunningScript::ProcessCommandsFrom200To299(int32 command) assert(pCurrent); // Here pCurrent shouldn't be NULL anyway int handle = CPools::GetVehiclePool()->GetIndex(pCurrent); if (handle != CTheScripts::StoreVehicleIndex && m_bIsMissionScript) { - CVehicle* pOld = CPools::GetVehiclePool()->GetAt(CTheScripts::StoreVehicleIndex); - if (pOld) { - CCarCtrl::RemoveFromInterestingVehicleList(pOld); - if (pOld->VehicleCreatedBy == MISSION_VEHICLE && CTheScripts::StoreVehicleWasRandom) { - pOld->VehicleCreatedBy = RANDOM_VEHICLE; - pOld->bIsLocked = false; - CCarCtrl::NumRandomCars++; - CCarCtrl::NumMissionCars--; - CTheScripts::MissionCleanup.RemoveEntityFromList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR); +#ifdef FIX_BUGS + if (CTheScripts::StoreVehicleIndex != -1) +#endif + { + CVehicle* pOld = CPools::GetVehiclePool()->GetAt(CTheScripts::StoreVehicleIndex); + if (pOld){ + CCarCtrl::RemoveFromInterestingVehicleList(pOld); + if (pOld->VehicleCreatedBy == MISSION_VEHICLE && CTheScripts::StoreVehicleWasRandom){ + pOld->VehicleCreatedBy = RANDOM_VEHICLE; + pOld->bIsLocked = false; + CCarCtrl::NumRandomCars++; + CCarCtrl::NumMissionCars--; + CTheScripts::MissionCleanup.RemoveEntityFromList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR); + } } } + CTheScripts::StoreVehicleIndex = handle; switch (pCurrent->VehicleCreatedBy) { case RANDOM_VEHICLE: @@ -3438,7 +3454,7 @@ int8 CRunningScript::ProcessCommandsFrom300To399(int32 command) assert(pPed); // Useless call. CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - int handle = CRadar::SetEntityBlip(BLIP_CHAR, ScriptParams[0], 0, BLIP_DISPLAY_BOTH); + int handle = CRadar::SetEntityBlip(BLIP_CHAR, ScriptParams[0], 1, BLIP_DISPLAY_BOTH); CRadar::ChangeBlipScale(handle, 3); ScriptParams[0] = handle; StoreParameters(&m_nIp, 1); @@ -3451,7 +3467,7 @@ int8 CRunningScript::ProcessCommandsFrom300To399(int32 command) assert(pObject); // Useless call. CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - int handle = CRadar::SetEntityBlip(BLIP_OBJECT, ScriptParams[0], 0, BLIP_DISPLAY_BOTH); + int handle = CRadar::SetEntityBlip(BLIP_OBJECT, ScriptParams[0], 6, BLIP_DISPLAY_BOTH); CRadar::ChangeBlipScale(handle, 3); ScriptParams[0] = handle; StoreParameters(&m_nIp, 1); @@ -4948,7 +4964,7 @@ int8 CRunningScript::ProcessCommandsFrom500To599(int32 command) assert(pPed); CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[1]); bool isTouching = false; - if (pPed->bInVehicle && pPed->m_pMyVehicle) + if (pPed->InVehicle()) isTouching = false; else if (pPed->GetHasCollidedWith(pObject)) isTouching = true; @@ -5089,7 +5105,7 @@ int8 CRunningScript::ProcessCommandsFrom500To599(int32 command) case COMMAND_HAS_PHONE_DISPLAYED_MESSAGE: { CollectParameters(&m_nIp, 1); - gPhoneInfo.HasMessageBeenDisplayed(ScriptParams[0]); + UpdateCompareFlag(gPhoneInfo.HasMessageBeenDisplayed(ScriptParams[0])); return 0; } case COMMAND_TURN_PHONE_OFF: diff --git a/src/core/ControllerConfig.cpp b/src/core/ControllerConfig.cpp index f0492b0f..26db4e5e 100644 --- a/src/core/ControllerConfig.cpp +++ b/src/core/ControllerConfig.cpp @@ -1443,39 +1443,36 @@ bool CControllerConfigManager::GetIsMouseButtonDown(RsKeyCodes keycode) bool CControllerConfigManager::GetIsMouseButtonUp(RsKeyCodes keycode) { - if (keycode > rsMOUSEX2BUTTON) + switch (keycode) { - switch (keycode) - { - case rsMOUSELEFTBUTTON: - if (CPad::GetPad(PAD1)->GetLeftMouseUp()) - return true; - break; - case rsMOUSMIDDLEBUTTON: - if (CPad::GetPad(PAD1)->GetMiddleMouseUp()) - return true; - break; - case rsMOUSERIGHTBUTTON: - if (CPad::GetPad(PAD1)->GetRightMouseUp()) - return true; - break; - case rsMOUSEWHEELUPBUTTON: - if (CPad::GetPad(PAD1)->GetMouseWheelUpUp()) - return true; - break; - case rsMOUSEWHEELDOWNBUTTON: - if (CPad::GetPad(PAD1)->GetMouseWheelDownUp()) - return true; - break; - case rsMOUSEX1BUTTON: - if (CPad::GetPad(PAD1)->GetMouseX1Up()) - return true; - break; - case rsMOUSEX2BUTTON: - if (CPad::GetPad(PAD1)->GetMouseX2Up()) - return true; - break; - } + case rsMOUSELEFTBUTTON: + if (CPad::GetPad(PAD1)->GetLeftMouseUp()) + return true; + break; + case rsMOUSMIDDLEBUTTON: + if (CPad::GetPad(PAD1)->GetMiddleMouseUp()) + return true; + break; + case rsMOUSERIGHTBUTTON: + if (CPad::GetPad(PAD1)->GetRightMouseUp()) + return true; + break; + case rsMOUSEWHEELUPBUTTON: + if (CPad::GetPad(PAD1)->GetMouseWheelUpUp()) + return true; + break; + case rsMOUSEWHEELDOWNBUTTON: + if (CPad::GetPad(PAD1)->GetMouseWheelDownUp()) + return true; + break; + case rsMOUSEX1BUTTON: + if (CPad::GetPad(PAD1)->GetMouseX1Up()) + return true; + break; + case rsMOUSEX2BUTTON: + if (CPad::GetPad(PAD1)->GetMouseX2Up()) + return true; + break; } return false; @@ -1662,9 +1659,6 @@ void CControllerConfigManager::DeleteMatchingActionInitiators(e_ControllerAction bool CControllerConfigManager::GetIsKeyBlank(int32 key, eControllerType type) { - if (type > JOYSTICK) - return true; - switch (type) { case KEYBOARD: @@ -1755,27 +1749,24 @@ e_ControllerActionType CControllerConfigManager::GetActionType(e_ControllerActio void CControllerConfigManager::ClearSettingsAssociatedWithAction(e_ControllerAction action, eControllerType type) { - if (type <= JOYSTICK) + switch (type) { - switch (type) - { - case KEYBOARD: - m_aSettings[action][type].m_Key = rsNULL; - m_aSettings[action][type].m_ContSetOrder = SETORDER_NONE; - break; - case OPTIONAL_EXTRA: - m_aSettings[action][type].m_Key = rsNULL; - m_aSettings[action][type].m_ContSetOrder = SETORDER_NONE; - break; - case MOUSE: - m_aSettings[action][type].m_Key = 0; - m_aSettings[action][type].m_ContSetOrder = SETORDER_NONE; - break; - case JOYSTICK: - m_aSettings[action][type].m_Key = 0; - m_aSettings[action][type].m_ContSetOrder = SETORDER_NONE; - break; - } + case KEYBOARD: + m_aSettings[action][type].m_Key = rsNULL; + m_aSettings[action][type].m_ContSetOrder = SETORDER_NONE; + break; + case OPTIONAL_EXTRA: + m_aSettings[action][type].m_Key = rsNULL; + m_aSettings[action][type].m_ContSetOrder = SETORDER_NONE; + break; + case MOUSE: + m_aSettings[action][type].m_Key = 0; + m_aSettings[action][type].m_ContSetOrder = SETORDER_NONE; + break; + case JOYSTICK: + m_aSettings[action][type].m_Key = 0; + m_aSettings[action][type].m_ContSetOrder = SETORDER_NONE; + break; } ResetSettingOrder(action); @@ -2257,6 +2248,7 @@ void CControllerConfigManager::UpdateJoyButtonState(int32 padnumber) for (int32 i = 0; i < MAX_BUTTONS; i++) m_aButtonStates[i] = false; +#ifdef __DINPUT_INCLUDED__ for (int32 i = 0; i < MAX_BUTTONS; i++) { if (m_NewState.rgbButtons[i] & 0x80) @@ -2264,6 +2256,7 @@ void CControllerConfigManager::UpdateJoyButtonState(int32 padnumber) else m_aButtonStates[i] = false; } +#endif } bool CControllerConfigManager::GetIsActionAButtonCombo(e_ControllerAction action) @@ -2412,4 +2405,4 @@ STARTPATCHES InjectHook(0x58F740, &CControllerConfigManager::GetMouseButtonAssociatedWithAction, PATCH_JUMP); InjectHook(0x58F760, &CControllerConfigManager::SetMouseButtonAssociatedWithAction, PATCH_JUMP); InjectHook(0x58F790, &CControllerConfigManager::ResetSettingOrder, PATCH_JUMP); -ENDPATCHES
\ No newline at end of file +ENDPATCHES diff --git a/src/core/CutsceneMgr.cpp b/src/core/CutsceneMgr.cpp index fa322242..2fbc5186 100644 --- a/src/core/CutsceneMgr.cpp +++ b/src/core/CutsceneMgr.cpp @@ -1,5 +1,6 @@ #include "common.h" #include "patcher.h" +#include "General.h" #include "CutsceneMgr.h" #include "Directory.h" #include "Camera.h" @@ -107,7 +108,7 @@ int FindCutsceneAudioTrackId(const char *szCutsceneName) { for (int i = 0; musicNameIdAssoc[i].szTrackName; i++) { - if (!strcmpi(musicNameIdAssoc[i].szTrackName, szCutsceneName)) + if (!CGeneral::faststricmp(musicNameIdAssoc[i].szTrackName, szCutsceneName)) return musicNameIdAssoc[i].iTrackId; } return -1; @@ -171,7 +172,7 @@ CCutsceneMgr::LoadCutsceneData(const char *szCutsceneName) CPlayerPed *pPlayerPed;
ms_cutsceneProcessing = true;
- if (!strcmpi(szCutsceneName, "jb"))
+ if (!strcasecmp(szCutsceneName, "jb"))
ms_useLodMultiplier = true;
CTimer::Stop();
@@ -207,7 +208,7 @@ CCutsceneMgr::LoadCutsceneData(const char *szCutsceneName) CFileMgr::CloseFile(file);
- if (strcmpi(ms_cutsceneName, "end")) {
+ if (CGeneral::faststricmp(ms_cutsceneName, "end")) {
DMAudio.ChangeMusicMode(MUSICMODE_CUTSCENE);
int trackId = FindCutsceneAudioTrackId(szCutsceneName);
if (trackId != -1) {
@@ -364,9 +365,9 @@ CCutsceneMgr::DeleteCutsceneData(void) CPad::GetPad(0)->DisablePlayerControls &= ~PLAYERCONTROL_DISABLED_80;
CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(false);
- if (strcmpi(ms_cutsceneName, "end")) {
+ if (CGeneral::faststricmp(ms_cutsceneName, "end")) {
DMAudio.StopCutSceneMusic();
- if (strcmpi(ms_cutsceneName, "bet"))
+ if (CGeneral::faststricmp(ms_cutsceneName, "bet"))
DMAudio.ChangeMusicMode(MUSICMODE_GAME);
}
CTimer::Stop();
@@ -389,7 +390,7 @@ CCutsceneMgr::Update(void) switch (ms_cutsceneLoadStatus) {
case CUTSCENE_LOADING_AUDIO:
SetupCutsceneToStart();
- if (strcmpi(ms_cutsceneName, "end"))
+ if (CGeneral::faststricmp(ms_cutsceneName, "end"))
DMAudio.PlayPreloadedCutSceneMusic();
ms_cutsceneLoadStatus++;
break;
@@ -407,7 +408,7 @@ CCutsceneMgr::Update(void) if (!ms_running) return;
ms_cutsceneTimer += CTimer::GetTimeStepNonClipped() * 0.02f;
- if (strcmpi(ms_cutsceneName, "end") && TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FLYBY && ms_cutsceneLoadStatus == CUTSCENE_LOADING_0) {
+ if (CGeneral::faststricmp(ms_cutsceneName, "end") && TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FLYBY && ms_cutsceneLoadStatus == CUTSCENE_LOADING_0) {
if (CPad::GetPad(0)->GetCrossJustDown()
|| (CGame::playingIntro && CPad::GetPad(0)->GetStartJustDown())
|| CPad::GetPad(0)->GetLeftMouseJustDown()
diff --git a/src/core/Directory.cpp b/src/core/Directory.cpp index 3e0d5382..d4b4279d 100644 --- a/src/core/Directory.cpp +++ b/src/core/Directory.cpp @@ -1,5 +1,6 @@ #include "common.h" #include "patcher.h" +#include "General.h" #include "FileMgr.h" #include "Directory.h" @@ -49,7 +50,7 @@ CDirectory::FindItem(const char *name, uint32 &offset, uint32 &size) int i; for(i = 0; i < numEntries; i++) - if(strcmpi(entries[i].name, name) == 0){ + if(!CGeneral::faststricmp(entries[i].name, name)){ offset = entries[i].offset; size = entries[i].size; return true; diff --git a/src/core/Explosion.cpp b/src/core/Explosion.cpp index 9ccd6e81..30809dc9 100644 --- a/src/core/Explosion.cpp +++ b/src/core/Explosion.cpp @@ -3,6 +3,7 @@ #include "Explosion.h" WRAPPER void CExplosion::AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type, const CVector &pos, uint32) { EAXJMP(0x5591C0); } +WRAPPER void CExplosion::RemoveAllExplosionsInArea(CVector, float) { EAXJMP(0x55AD40); } WRAPPER int8 CExplosion::GetExplosionActiveCounter(uint8 id) diff --git a/src/core/Explosion.h b/src/core/Explosion.h index fde4ad7f..0768bbe4 100644 --- a/src/core/Explosion.h +++ b/src/core/Explosion.h @@ -27,4 +27,5 @@ public: static CVector *GetExplosionPosition(uint8 id); static uint8 GetExplosionType(uint8 id); static void ResetExplosionActiveCounter(uint8 id); + static void RemoveAllExplosionsInArea(CVector, float); }; diff --git a/src/core/Fire.cpp b/src/core/Fire.cpp index 274c06a5..5c777eab 100644 --- a/src/core/Fire.cpp +++ b/src/core/Fire.cpp @@ -5,6 +5,9 @@ CFireManager &gFireManager = *(CFireManager*)0x8F31D0; WRAPPER void CFire::Extinguish(void) { EAXJMP(0x479D40); } +WRAPPER void CFireManager::StartFire(CEntity* entityOnFire, CEntity* culprit, float, uint32) { EAXJMP(0x479590); } +WRAPPER void CFireManager::Update(void) { EAXJMP(0x479310); } +WRAPPER CFire* CFireManager::FindFurthestFire_NeverMindFireMen(CVector coors, float, float) { EAXJMP(0x479430); } uint32 CFireManager::GetTotalActiveFires() const { @@ -38,12 +41,28 @@ CFire* CFireManager::FindNearestFire(CVector vecPos, float* pDistance) return nil; } +void +CFireManager::ExtinguishPoint(CVector point, float range) +{ + for (int i = 0; i < NUM_FIRES; i++) { + if (m_aFires[i].m_bIsOngoing) { + if ((point - m_aFires[i].m_vecPos).MagnitudeSqr() < sq(range)) + m_aFires[i].Extinguish(); + } + } +} + WRAPPER CFire *CFireManager::FindFurthestFire_NeverMindFireMen(CVector coors, float, float) { EAXJMP(0x479430); } WRAPPER void CFireManager::StartFire(CEntity *entityOnFire, CEntity *culprit, float, uint32) { EAXJMP(0x479590); } WRAPPER void CFireManager::StartFire(CVector, float, uint8) { EAXJMP(0x479500); } -WRAPPER void CFireManager::ExtinguishPoint(CVector, float) { EAXJMP(0x479DB0); } WRAPPER int32 CFireManager::StartScriptFire(const CVector& pos, CEntity* culprit, float, uint8) { EAXJMP(0x479E60); } WRAPPER bool CFireManager::IsScriptFireExtinguish(int16) { EAXJMP(0x479FC0); } WRAPPER void CFireManager::RemoveScriptFire(int16) { EAXJMP(0x479FE0); } WRAPPER void CFireManager::RemoveAllScriptFires(void) { EAXJMP(0x47A000); } WRAPPER void CFireManager::SetScriptFireAudio(int16, bool) { EAXJMP(0x47A040); } + +STARTPATCHES + InjectHook(0x479DB0, &CFireManager::ExtinguishPoint, PATCH_JUMP); + InjectHook(0x479340, &CFireManager::FindNearestFire, PATCH_JUMP); +ENDPATCHES + diff --git a/src/core/Fire.h b/src/core/Fire.h index 9d72179e..cd6de90c 100644 --- a/src/core/Fire.h +++ b/src/core/Fire.h @@ -35,12 +35,13 @@ public: void Update(void); CFire *FindFurthestFire_NeverMindFireMen(CVector coors, float, float); CFire *FindNearestFire(CVector, float*); - uint32 GetTotalActiveFires() const; + uint32 GetTotalActiveFires() const { return m_nTotalFires; } void ExtinguishPoint(CVector, float); int32 StartScriptFire(const CVector& pos, CEntity* culprit, float, uint8); bool IsScriptFireExtinguish(int16); void RemoveScriptFire(int16); void RemoveAllScriptFires(void); void SetScriptFireAudio(int16, bool); + void ExtinguishPoint(CVector, float); }; extern CFireManager &gFireManager; diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index 5911433c..05c6b6e8 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -26,6 +26,7 @@ #include "PlayerInfo.h" #include "World.h" #include "Renderer.h" +#include "CdStream.h" #define ALL_ORIGINAL_FRONTEND 1 @@ -58,13 +59,17 @@ char *CMenuManager::m_PrefsSkinFile = (char*)0x5F2E74; //[256] "$$\"\"" int32 &CMenuManager::m_KeyPressedCode = *(int32*)0x5F2E70; // -1 +float &CMenuManager::headingYStart = *(float*)0x5F355C; // don't know the original name +float &CMenuManager::unkX = *(float*)0x5F2E40; +float &CMenuManager::unkY = *(float*)0x5F2E44; + CMenuManager &FrontEndMenuManager = *(CMenuManager*)0x8F59D8; // Move this somewhere else. float &CRenderer::ms_lodDistScale = *(float*)0x5F726C; // 1.2 // Stuff not in CMenuManager: -uint32 &VibrationTime = *(uint32*)0x628CF8; +uint32 &TimeToStopPadShaking = *(uint32*)0x628CF8; char *&pEditString = *(char**)0x628D00; int32 *&pControlEdit = *(int32**)0x628D08; bool &DisplayComboButtonErrMsg = *(bool*)0x628D14; @@ -94,87 +99,108 @@ bool GetMouseMoveRight(); bool GetPadInput(); bool GetMouseInput(); -const char *FrontendFilenames[] = { - "fe2_mainpanel_ul", - "fe2_mainpanel_ur", - "fe2_mainpanel_dl", - "fe2_mainpanel_dr", - "fe2_mainpanel_dr2", - "fe2_tabactive", - "fe_iconbrief", - "fe_iconstats", - "fe_iconcontrols", - "fe_iconsave", - "fe_iconaudio", - "fe_icondisplay", - "fe_iconlanguage", - "fe_controller", - "fe_controllersh", - "fe_arrows1", - "fe_arrows2", - "fe_arrows3", - "fe_arrows4", - "fe_radio1", // HEAD_RADIO - "fe_radio2", // DOUBLE_CLEF - "fe_radio5", // JAH_RADIO - "fe_radio7", // RISE_FM - "fe_radio8", // LIPS_106 - "fe_radio3", // GAME_FM - "fe_radio4", // MSX_FM - "fe_radio6", // FLASHBACK - "fe_radio9", // CHATTERBOX +// 0x5F311C +const char* FrontendFilenames[][2] = { + {"fe2_mainpanel_ul", "" }, + {"fe2_mainpanel_ur", "" }, + {"fe2_mainpanel_dl", "" }, + {"fe2_mainpanel_dr", "" }, + {"fe2_mainpanel_dr2", "" }, + {"fe2_tabactive", "" }, + {"fe_iconbrief", "" }, + {"fe_iconstats", "" }, + {"fe_iconcontrols", "" }, + {"fe_iconsave", "" }, + {"fe_iconaudio", "" }, + {"fe_icondisplay", "" }, + {"fe_iconlanguage", "" }, + {"fe_controller", "" }, + {"fe_controllersh", "" }, + {"fe_arrows1", "" }, + {"fe_arrows2", "" }, + {"fe_arrows3", "" }, + {"fe_arrows4", "" }, + {"fe_radio1", "" }, // HEAD_RADIO + {"fe_radio2", "" }, // DOUBLE_CLEF + {"fe_radio3", "" }, // JAH_RADIO + {"fe_radio4", "" }, // RISE_FM + {"fe_radio5", "" }, // LIPS_106 + {"fe_radio6", "" }, // GAME_FM + {"fe_radio7", "" }, // MSX_FM + {"fe_radio8", "" }, // FLASHBACK + {"fe_radio9", "" }, // CHATTERBOX }; -const char *MenuFilenames[] = { - "connection24", "", - "findgame24", "", - "hostgame24", "", - "mainmenu24", "", - "Playersetup24", "", - "singleplayer24", "", - "multiplayer24", "", - "dmalogo128", "dmalogo128m", - "gtaLogo128", "gtaLogo128", - "rockstarLogo128", "rockstarlogo128m", - "gamespy256", "gamespy256a", - "mouse", "mousetimera", - "mousetimer", "mousetimera", - "mp3logo", "mp3logoA", - "downOFF", "buttonA", - "downON", "buttonA", - "upOFF", "buttonA", - "upON", "buttonA", - "gta3logo256", "gta3logo256m", - nil, nil +// 0x5F3344 +const char* MenuFilenames[][2] = { + {"connection24", ""}, + {"findgame24", ""}, + {"hostgame24", ""}, + {"mainmenu24", ""}, + {"Playersetup24", ""}, + {"singleplayer24", ""}, + {"multiplayer24", ""}, + {"dmalogo128", "dmalogo128m"}, + {"gtaLogo128", "gtaLogo128"}, + {"rockstarLogo128", "rockstarlogo128m"}, + {"gamespy256", "gamespy256a"}, + {"mouse", "mousetimera"}, + {"mousetimer", "mousetimera"}, + {"mp3logo", "mp3logoA"}, + {"downOFF", "buttonA"}, + {"downON", "buttonA"}, + {"upOff", "buttonA"}, + {"upON", "buttonA"}, + {"gta3logo256", "gta3logo256m"}, + { nil, nil } }; -#if 0 -WRAPPER void CMenuManager::BuildStatLine(char *text, float *stat, bool aFloat, float* stat2) { EAXJMP(0x483870); } +#ifdef ASPECT_RATIO_SCALE +// All of these defines replaces the StretchX function. Otherwise use SCREEN_SCALE_X. +#define MENU_X_LEFT_ALIGNED(x) ScaleAndCenterX(x) +#define MENU_X(x) SCREEN_SCALE_X(x) +#define MENU_Y(y) SCREEN_SCALE_Y(y) +float +ScaleAndCenterX(float x) +{ + if (SCREEN_WIDTH == DEFAULT_SCREEN_WIDTH) + return x; + else { + if (x > DEFAULT_SCREEN_WIDTH / 2) { + return SCREEN_WIDTH / 2 + SCREEN_SCALE_X(x - DEFAULT_SCREEN_WIDTH / 2); + } else { + return SCREEN_WIDTH / 2 - SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH / 2 - x); + } + } +} #else -void CMenuManager::BuildStatLine(char *text, float *stat, bool aFloat, float* stat2) +#define MENU_X_LEFT_ALIGNED(x) StretchX(x) +#define MENU_X(x) StretchX(x) +#define MENU_Y(y) StretchY(y) +#endif + +void +CMenuManager::BuildStatLine(char *text, void *stat, uint8 aFloat, void *stat2) { if (!text) return; if (stat2) { if (aFloat) - sprintf(gString2, " %.2f %s %.2f", *stat, UnicodeToAscii(TheText.Get("FEST_OO")), *stat2); + sprintf(gString2, " %.2f %s %.2f", *(float*)stat, UnicodeToAscii(TheText.Get("FEST_OO")), *(float*)stat2); else sprintf(gString2, " %d %s %d", *(int*)stat, UnicodeToAscii(TheText.Get("FEST_OO")), *(int*)stat2); - } - else if (stat) { + } else if (stat) { if (aFloat) - sprintf(gString2, " %.2f", *stat); + sprintf(gString2, " %.2f", *(float*)stat); else sprintf(gString2, " %d", *(int*)stat); - } - else + } else gString2[0] = '\0'; UnicodeStrcpy(gUString, TheText.Get(text)); AsciiToUnicode(gString2, gUString2); } -#endif #if 0 WRAPPER void CMenuManager::CentreMousePointer() { EAXJMP(0x48ACE0); } @@ -359,6 +385,7 @@ void CMenuManager::DoSettingsBeforeStartingAGame() } #endif +// WIP - has broken, duplicate and missing codes #if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::Draw() { EAXJMP(0x47AE00); } #else @@ -370,29 +397,27 @@ void CMenuManager::Draw() CFont::SetJustifyOn(); CFont::SetBackGroundOnlyTextOn(); CFont::SetWrapx(SCREEN_SCALE_FROM_RIGHT(40.0f)); - CFont::SetRightJustifyWrap(0.0f); - CFont::SetDropColor(CRGBA(0, 0, 0, FadeIn(MENUDROP_COLOR_A))); + CFont::SetRightJustifyWrap(SCREEN_SCALE_X(38.0f)); +// CFont::SetDropColor(CRGBA(0, 0, 0, FadeIn(MENUDROP_COLOR_A))); switch (m_nCurrScreen) { - case MENUPAGE_STATS: - PrintStats(); - break; - case MENUPAGE_BRIEFS: - PrintBriefs(); - break; - case MENUPAGE_CONTROLLER_DEBUG: - DrawControllerScreenExtraText(0, 350, 20); - break; + case MENUPAGE_STATS: + PrintStats(); + break; + case MENUPAGE_BRIEFS: + PrintBriefs(); + break; } // Header. + headingYStart = 40.0f; if (aScreens[m_nCurrScreen].m_ScreenName[0]) { - CFont::SetDropShadowPosition(0); CFont::SetColor(CRGBA(0, 0, 0, FadeIn(255))); CFont::SetRightJustifyOn(); CFont::SetFontStyle(FONT_HEADING); - CFont::SetScale(SCREEN_SCALE_X(MENUHEADER_WIDTH), SCREEN_SCALE_Y(MENUHEADER_HEIGHT)); + CFont::SetScale(MENU_X(MENUHEADER_WIDTH), MENU_Y(MENUHEADER_HEIGHT)); CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(MENUHEADER_POS_X), SCREEN_SCALE_FROM_BOTTOM(MENUHEADER_POS_Y), TheText.Get(aScreens[m_nCurrScreen].m_ScreenName)); + headingYStart += 24.0f + 10.0f; } // Action text. @@ -422,13 +447,109 @@ void CMenuManager::Draw() break; } - CFont::SetDropShadowPosition(MENUDROP_COLOR_SIZE); - CFont::SetDropColor(CRGBA(0, 0, 0, FadeIn(MENUDROP_COLOR_A))); +// CFont::SetDropShadowPosition(MENUDROP_COLOR_SIZE); +// CFont::SetDropColor(CRGBA(0, 0, 0, FadeIn(MENUDROP_COLOR_A))); CFont::SetFontStyle(FONT_BANK); - CFont::SetScale(SCREEN_SCALE_X(MENUACTION_WIDTH), SCREEN_SCALE_Y(MENUACTION_HEIGHT)); - CFont::SetAlignment(ALIGN_LEFT); + CFont::SetScale(MENU_X(MENUACTION_WIDTH), MENU_Y(MENUACTION_HEIGHT)); + CFont::SetAlignment(ALIGN_LEFT); // AG's extra. III uses SetRightJustifyOff. CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255))); - CFont::PrintString(SCREEN_SCALE_X(MENUACTION_POS_X), SCREEN_SCALE_Y(MENUACTION_POS_Y), str); + CFont::PrintString(MENU_X_LEFT_ALIGNED(MENUACTION_POS_X), MENU_Y(headingYStart), str); + } + + CFont::SetCentreSize(SCREEN_WIDTH); + + bool v360 = false; + int v361; + int v362; + int v20; + switch (m_nCurrScreen) { + case MENUPAGE_STATS: + case MENUPAGE_BRIEFS: + v20 = 320; + v362 = 240; + v361 = 24; + CFont::SetFontStyle(FONT_HEADING); + CFont::SetScale(StretchX(unkX = 0.75f), StretchY(unkY = 0.9f)); + CFont::SetCentreOn(); + break; + case MENUPAGE_SOUND_SETTINGS: + case MENUPAGE_GRAPHICS_SETTINGS: + case MENUPAGE_MULTIPLAYER_CREATE: + case MENUPAGE_SKIN_SELECT_OLD: + case MENUPAGE_CONTROLLER_PC_OLD1: + case MENUPAGE_CONTROLLER_PC_OLD2: + case MENUPAGE_CONTROLLER_PC_OLD3: + case MENUPAGE_CONTROLLER_PC_OLD4: + case MENUPAGE_CONTROLLER_DEBUG: + case MENUPAGE_MOUSE_CONTROLS: + v20 = 50; + v362 = 0; + v361 = 20; + CFont::SetFontStyle(FONT_HEADING); + CFont::SetScale(StretchX(unkX = 0.8f), StretchY(unkY = 0.55f)); + CFont::SetRightJustifyOff(); + break; + case MENUPAGE_CHOOSE_LOAD_SLOT: + case MENUPAGE_CHOOSE_DELETE_SLOT: + case MENUPAGE_CHOOSE_SAVE_SLOT: + v20 = 120; + v362 = 38; + v361 = 20; + CFont::SetFontStyle(FONT_BANK); + CFont::SetScale(StretchX(unkX = 0.7f), StretchY(unkY = 0.45f)); + CFont::SetRightJustifyOff(); + break; + case MENUPAGE_NEW_GAME_RELOAD: + case MENUPAGE_LOAD_SLOT_CONFIRM: + case MENUPAGE_DELETE_SLOT_CONFIRM: + case MENUPAGE_SAVE_OVERWRITE_CONFIRM: + case MENUPAGE_EXIT: + v20 = 320; + v362 = 60; + v361 = 24; + CFont::SetFontStyle(FONT_HEADING); + CFont::SetScale(StretchX(unkX = 0.75f), StretchY(unkY = 0.9f)); + CFont::SetCentreOn(); + break; + case MENUPAGE_START_MENU: + v20 = 320; + v362 = 140; + v361 = 24; + CFont::SetFontStyle(FONT_HEADING); + CFont::SetScale(StretchX(unkX = 0.75f), StretchY(unkY = 0.9f)); + CFont::SetCentreOn(); + break; + case MENUPAGE_PAUSE_MENU: + v20 = 320; + v362 = 117; + v361 = 24; + CFont::SetFontStyle(FONT_HEADING); + CFont::SetScale(StretchX(unkX = 0.75f), StretchY(unkY = 0.9f)); + CFont::SetCentreOn(); + break; + default: + v20 = 320; + v362 = 40; + v361 = 24; + CFont::SetFontStyle(FONT_HEADING); + CFont::SetScale(StretchX(unkX = 0.75f), StretchY(unkY = 0.9f)); + CFont::SetCentreOn(); + break; + } + + switch (m_nCurrScreen) { + case MENUPAGE_CONTROLLER_PC_OLD1: + case MENUPAGE_CONTROLLER_PC_OLD2: + case MENUPAGE_CONTROLLER_PC_OLD3: + case MENUPAGE_CONTROLLER_PC_OLD4: + case MENUPAGE_CONTROLLER_DEBUG: + if (field_113) + v360 = 0; + + CMenuManager::DrawControllerScreenExtraText(headingYStart - 8.0f, 350, v361); + break; + default: + break; } for (int i = 0; i < NUM_MENUROWS; ++i) { @@ -437,27 +558,38 @@ void CMenuManager::Draw() bool Locked = false; if (aScreens[m_nCurrScreen].m_aEntries[i].m_SaveSlot >= SAVESLOT_1 && aScreens[m_nCurrScreen].m_aEntries[i].m_SaveSlot <= SAVESLOT_8) { + CFont::SetRightJustifyOff(); textToPrint[MENUCOLUMN_LEFT] = GetNameOfSavedGame(i - 1); - textToPrint[MENUCOLUMN_RIGHT] = GetSavedGameDateAndTime(i - 1); - if (!textToPrint[MENUCOLUMN_LEFT][0]) { + if (Slots[i-1] != 1) + textToPrint[MENUCOLUMN_RIGHT] = GetSavedGameDateAndTime(i - 1); + + if (!textToPrint[MENUCOLUMN_LEFT]) { sprintf(gString, "FEM_SL%d", i); textToPrint[MENUCOLUMN_LEFT] = TheText.Get(gString); } } else { textToPrint[MENUCOLUMN_LEFT] = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[i].m_EntryName); - + /* if (aScreens[m_nCurrScreen].m_aEntries[i].m_Action == MENUACTION_SCREENRES) { if (m_bGameNotLoaded) Locked = false; else Locked = true; } + */ } switch (aScreens[m_nCurrScreen].m_aEntries[i].m_Action) { + case MENUACTION_CHANGEMENU: + assert(0 && "Not implemented"); + break; case MENUACTION_CTRLVIBRATION: + if (CMenuManager::m_PrefsUseVibration) + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEM_ON"); + else + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEM_OFF"); break; case MENUACTION_CTRLCONFIG: switch (CPad::GetPad(0)->Mode) { @@ -476,6 +608,10 @@ void CMenuManager::Draw() } break; case MENUACTION_CTRLDISPLAY: + if (m_DisplayControllerOnFoot) + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEC_ONF"); + else + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEC_INC"); break; case MENUACTION_FRAMESYNC: textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_PrefsVsyncDisp ? "FEM_ON" : "FEM_OFF"); @@ -507,6 +643,9 @@ void CMenuManager::Draw() #endif break; case MENUACTION_RADIO: + if (m_PrefsRadioStation > 9) + break; + sprintf(gString, "FEA_FM%d", m_PrefsRadioStation); textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(gString); break; @@ -514,29 +653,42 @@ void CMenuManager::Draw() textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(CTheScripts::DbgFlag ? "FEM_ON" : "FEM_OFF"); break; case MENUACTION_SWITCHBIGWHITEDEBUGLIGHT: - textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(CTheScripts::DbgFlag ? "FEM_ON" : "FEM_OFF"); + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(gbBigWhiteDebugLightSwitchedOn ? "FEM_ON" : "FEM_OFF"); + break; + case MENUACTION_PEDROADGROUPS: + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(gbShowPedRoadGroups ? "FEM_ON" : "FEM_OFF"); + break; + case MENUACTION_CARROADGROUPS: + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(gbShowCarRoadGroups ? "FEM_ON" : "FEM_OFF"); + break; + case MENUACTION_COLLISIONPOLYS: + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(gbShowCollisionPolys ? "FEM_ON" : "FEM_OFF"); + break; + case MENUACTION_SHOWCULL: + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(gbShowCullZoneDebugStuff ? "FEM_ON" : "FEM_OFF"); + break; + case MENUACTION_SHOWHEADBOB: + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(TheCamera.m_bHeadBob ? "FEM_ON" : "FEM_OFF"); break; case MENUACTION_INVVERT: textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(MousePointerStateHelper.bInvertVertically ? "FEM_ON" : "FEM_OFF"); break; case MENUACTION_SCREENRES: - { char *res = _psGetVideoModeList()[m_nDisplayVideoMode]; - - if (!res) - res = ""; - - AsciiToUnicode(res, gUString); - textToPrint[MENUCOLUMN_RIGHT] = gUString; - } - break; + AsciiToUnicode(res, textToPrint[MENUCOLUMN_RIGHT]); + break; case MENUACTION_AUDIOHW: if (m_nPrefsAudio3DProviderIndex == -1) textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEA_NAH"); else { char *provider = DMAudio.Get3DProviderName(m_nPrefsAudio3DProviderIndex); - AsciiToUnicode(provider, gUString); - textToPrint[MENUCOLUMN_RIGHT] = gUString; + + if (!strcmp(strupr(provider), "DIRECTSOUND3D HARDWARE SUPPORT")) { + strcpy(provider, "DSOUND3D HARDWARE SUPPORT"); + } else if (!strcmp(strupr(provider), "DIRECTSOUND3D SOFTWARE EMULATION")) { + strcpy(provider, "DSOUND3D SOFTWARE EMULATION"); + } + AsciiToUnicode(provider, textToPrint[MENUCOLUMN_RIGHT]); } break; case MENUACTION_SPEAKERCONF: @@ -580,6 +732,7 @@ void CMenuManager::Draw() CFont::SetWrapx(SCREEN_WIDTH); CFont::SetRightJustifyWrap(-SCREEN_WIDTH); + // !! Most of these are now duplicate(see before the loop) and needs to be deleted. // Set alignment. CVector2D vecPositions = { 0.0f, 0.0f }; float fVerticalSpacing; @@ -768,19 +921,27 @@ void CMenuManager::Draw() SetHelperText(3); } } - - switch (m_nCurrScreen) { - case MENUPAGE_CONTROLLER_SETTINGS: - case MENUPAGE_SOUND_SETTINGS: - case MENUPAGE_GRAPHICS_SETTINGS: - case MENUPAGE_SKIN_SELECT: - case MENUPAGE_CONTROLLER_PC: - case MENUPAGE_MOUSE_CONTROLS: - DisplayHelperText(); - break; - } } } + + switch (m_nCurrScreen) { + case MENUPAGE_CONTROLLER_SETTINGS: + case MENUPAGE_SOUND_SETTINGS: + case MENUPAGE_GRAPHICS_SETTINGS: + case MENUPAGE_SKIN_SELECT: + case MENUPAGE_CONTROLLER_PC: + case MENUPAGE_MOUSE_CONTROLS: + DisplayHelperText(); + break; + } +/* + if (m_nCurrScreen == MENUPAGE_CONTROLLER_SETTINGS) { + PrintController(); + } else if (m_nCurrScreen == MENUPAGE_SKIN_SELECT_OLD) { + CSprite2d::DrawRect(CRect(StretchX(180), StretchY(98), StretchX(230), StretchY(123)), CRGBA(255, 255, 255, FadeIn(255))); + CSprite2d::DrawRect(CRect(StretchX(181), StretchY(99), StretchX(229), StretchY(233)), CRGBA(Player color from PickNewPlayerColour, FadeIn(255))); + } +*/ } #endif @@ -811,9 +972,6 @@ void CMenuManager::DrawControllerSetupScreen() } #endif -#if 0 -WRAPPER void CMenuManager::DrawFrontEnd(void) { EAXJMP(0x47A540); } -#else void CMenuManager::DrawFrontEnd() { CFont::SetAlphaFade(255.0f); @@ -833,27 +991,73 @@ void CMenuManager::DrawFrontEnd() CMenuManager::DrawFrontEndNormal(); CMenuManager::PrintErrorMessage(); } -#endif -#if 0 -WRAPPER void CMenuManager::DrawFrontEndNormal(void) { EAXJMP(0x47A5B0); } -#else void CMenuManager::DrawFrontEndNormal() { - RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); - CSprite2d::InitPerFrame(); CFont::InitPerFrame(); + RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); LoadSplash(nil); - eMenuSprites previousSprite = MENUSPRITE_MAINMENU; // actually uninitialized + eMenuSprites previousSprite; if (m_nMenuFadeAlpha < 255) { switch (m_nPrevScreen) { + case MENUPAGE_STATS: + case MENUPAGE_START_MENU: + case MENUPAGE_PAUSE_MENU: + previousSprite = MENUSPRITE_MAINMENU; + break; + case MENUPAGE_NEW_GAME: + case MENUPAGE_CHOOSE_LOAD_SLOT: + case MENUPAGE_CHOOSE_DELETE_SLOT: + case MENUPAGE_NEW_GAME_RELOAD: + case MENUPAGE_LOAD_SLOT_CONFIRM: + case MENUPAGE_DELETE_SLOT_CONFIRM: + case MENUPAGE_EXIT: + previousSprite = MENUSPRITE_SINGLEPLAYER; + break; + case MENUPAGE_MULTIPLAYER_MAIN: + previousSprite = MENUSPRITE_MULTIPLAYER; + break; + case MENUPAGE_MULTIPLAYER_MAP: + case MENUPAGE_MULTIPLAYER_FIND_GAME: + case MENUPAGE_SKIN_SELECT: + case MENUPAGE_KEYBOARD_CONTROLS: + case MENUPAGE_MOUSE_CONTROLS: + previousSprite = MENUSPRITE_FINDGAME; + break; + case MENUPAGE_MULTIPLAYER_CONNECTION: + case MENUPAGE_MULTIPLAYER_MODE: + previousSprite = MENUSPRITE_CONNECTION; + break; + case MENUPAGE_MULTIPLAYER_CREATE: + previousSprite = MENUSPRITE_HOSTGAME; + break; + case MENUPAGE_SKIN_SELECT_OLD: + case MENUPAGE_OPTIONS: + previousSprite = MENUSPRITE_PLAYERSET; + break; + default: + previousSprite = MENUSPRITE_MAINMENU; + break; + } + + 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_nMenuFadeAlpha)); + } + + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); + + eMenuSprites currentSprite = MENUSPRITE_MAINMENU; // actually uninitialized + switch (m_nCurrScreen) { case MENUPAGE_STATS: case MENUPAGE_START_MENU: case MENUPAGE_PAUSE_MENU: - previousSprite = MENUSPRITE_MAINMENU; + currentSprite = MENUSPRITE_MAINMENU; break; case MENUPAGE_NEW_GAME: case MENUPAGE_CHOOSE_LOAD_SLOT: @@ -862,77 +1066,29 @@ void CMenuManager::DrawFrontEndNormal() case MENUPAGE_LOAD_SLOT_CONFIRM: case MENUPAGE_DELETE_SLOT_CONFIRM: case MENUPAGE_EXIT: - previousSprite = MENUSPRITE_SINGLEPLAYER; + currentSprite = MENUSPRITE_SINGLEPLAYER; break; case MENUPAGE_MULTIPLAYER_MAIN: - previousSprite = MENUSPRITE_MULTIPLAYER; + currentSprite = MENUSPRITE_MULTIPLAYER; break; case MENUPAGE_MULTIPLAYER_MAP: case MENUPAGE_MULTIPLAYER_FIND_GAME: case MENUPAGE_SKIN_SELECT: case MENUPAGE_KEYBOARD_CONTROLS: case MENUPAGE_MOUSE_CONTROLS: - previousSprite = MENUSPRITE_FINDGAME; + currentSprite = MENUSPRITE_FINDGAME; break; case MENUPAGE_MULTIPLAYER_CONNECTION: case MENUPAGE_MULTIPLAYER_MODE: - previousSprite = MENUSPRITE_CONNECTION; + currentSprite = MENUSPRITE_CONNECTION; break; case MENUPAGE_MULTIPLAYER_CREATE: - previousSprite = MENUSPRITE_HOSTGAME; + currentSprite = MENUSPRITE_HOSTGAME; break; case MENUPAGE_SKIN_SELECT_OLD: case MENUPAGE_OPTIONS: - previousSprite = MENUSPRITE_PLAYERSET; + currentSprite = MENUSPRITE_PLAYERSET; break; - } - - 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_nMenuFadeAlpha)); - } - - RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); - RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); - - eMenuSprites currentSprite = MENUSPRITE_MAINMENU; // actually uninitialized - switch (m_nCurrScreen) { - case MENUPAGE_STATS: - case MENUPAGE_START_MENU: - case MENUPAGE_PAUSE_MENU: - currentSprite = MENUSPRITE_MAINMENU; - break; - case MENUPAGE_NEW_GAME: - case MENUPAGE_CHOOSE_LOAD_SLOT: - case MENUPAGE_CHOOSE_DELETE_SLOT: - case MENUPAGE_NEW_GAME_RELOAD: - case MENUPAGE_LOAD_SLOT_CONFIRM: - case MENUPAGE_DELETE_SLOT_CONFIRM: - case MENUPAGE_EXIT: - currentSprite = MENUSPRITE_SINGLEPLAYER; - break; - case MENUPAGE_MULTIPLAYER_MAIN: - currentSprite = MENUSPRITE_MULTIPLAYER; - break; - case MENUPAGE_MULTIPLAYER_MAP: - case MENUPAGE_MULTIPLAYER_FIND_GAME: - case MENUPAGE_SKIN_SELECT: - case MENUPAGE_KEYBOARD_CONTROLS: - case MENUPAGE_MOUSE_CONTROLS: - currentSprite = MENUSPRITE_FINDGAME; - break; - case MENUPAGE_MULTIPLAYER_CONNECTION: - case MENUPAGE_MULTIPLAYER_MODE: - currentSprite = MENUSPRITE_CONNECTION; - break; - case MENUPAGE_MULTIPLAYER_CREATE: - currentSprite = MENUSPRITE_HOSTGAME; - break; - case MENUPAGE_SKIN_SELECT_OLD: - case MENUPAGE_OPTIONS: - currentSprite = MENUSPRITE_PLAYERSET; - break; } if (m_nMenuFadeAlpha < 255) { @@ -954,7 +1110,9 @@ void CMenuManager::DrawFrontEndNormal() 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) + if(m_nHoverOption == HOVEROPTION_3 || m_nHoverOption == HOVEROPTION_4 || + m_nHoverOption == HOVEROPTION_5 || m_nHoverOption == HOVEROPTION_6 || m_nHoverOption == HOVEROPTION_7) + field_518 = 2; else field_518 = 1; @@ -966,24 +1124,24 @@ void CMenuManager::DrawFrontEndNormal() 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))); + m_aMenuSprites[MENUSPRITE_GTA3LOGO].Draw(CRect(MENU_X_LEFT_ALIGNED(205.0f), StretchY(70.0f), MENU_X_LEFT_ALIGNED(435.0f), StretchY(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))); + m_aMenuSprites[MENUSPRITE_GTALOGO].Draw(CRect(MENU_X_LEFT_ALIGNED(225.0f), StretchY(40.0f), MENU_X_LEFT_ALIGNED(415.0f), StretchY(210.0f)), CRGBA(255, 255, 255, FadeIn(255))); } RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERNEAREST); RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP); RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); switch (m_nCurrScreen) { - case MENUPAGE_SKIN_SELECT: - CMenuManager::DrawPlayerSetupScreen(); - break; - case MENUPAGE_KEYBOARD_CONTROLS: - CMenuManager::DrawControllerSetupScreen(); - break; - default: - CMenuManager::Draw(); - break; + case MENUPAGE_SKIN_SELECT: + CMenuManager::DrawPlayerSetupScreen(); + break; + case MENUPAGE_KEYBOARD_CONTROLS: + CMenuManager::DrawControllerSetupScreen(); + break; + default: + CMenuManager::Draw(); + break; } CFont::DrawFonts(); @@ -996,20 +1154,22 @@ void CMenuManager::DrawFrontEndNormal() RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); - CRect mouse(0.0f, 0.0f, SCREEN_SCALE_X(75.0f), SCREEN_SCALE_Y(75.0f)); + CRect mouse(0.0f, 0.0f, MENU_X(75.0f), MENU_Y(75.0f)); + CRect shad(MENU_X(10.0f), MENU_Y(3.0f), MENU_X(85.0f), MENU_Y(78.0f)); + mouse.Translate(m_nMousePosX, m_nMousePosY); - CRect shad = mouse; - shad.Translate(SCREEN_SCALE_X(10.0f), SCREEN_SCALE_Y(3.0f)); + shad.Translate(m_nMousePosX, m_nMousePosY); if(field_518 == 4){ m_aMenuSprites[MENUSPRITE_MOUSET].Draw(shad, CRGBA(100, 100, 100, 50)); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); m_aMenuSprites[MENUSPRITE_MOUSET].Draw(mouse, CRGBA(255, 255, 255, 255)); }else{ m_aMenuSprites[MENUSPRITE_MOUSE].Draw(shad, CRGBA(100, 100, 100, 50)); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); m_aMenuSprites[MENUSPRITE_MOUSE].Draw(mouse, CRGBA(255, 255, 255, 255)); } } } -#endif #if 1 WRAPPER void CMenuManager::DrawPlayerSetupScreen() { EAXJMP(0x47F2B0); } @@ -1078,78 +1238,80 @@ void CMenuManager::InitialiseChangedLanguageSettings() } #endif -#if ALL_ORIGINAL_FRONTEND -WRAPPER void CMenuManager::LoadAllTextures() { EAXJMP(0x47A230); } -#else void CMenuManager::LoadAllTextures() { - if (!m_bSpritesLoaded) { - CMenuManager::CentreMousePointer(); - DMAudio.ChangeMusicMode(MUSICMODE_FRONTEND); - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_STARTING, 0); - m_nCurrOption = 0; - m_PrefsRadioStation = DMAudio.GetRadioInCar(); + if (m_bSpritesLoaded) + return; - if (DMAudio.IsMP3RadioChannelAvailable()) { - if (CMenuManager::m_PrefsRadioStation > USERTRACK) - CMenuManager::m_PrefsRadioStation = CGeneral::GetRandomNumber() % 10; - } - else if (CMenuManager::m_PrefsRadioStation > CHATTERBOX) - CMenuManager::m_PrefsRadioStation = CGeneral::GetRandomNumber() % 9; + CMenuManager::CentreMousePointer(); + DMAudio.ChangeMusicMode(MUSICMODE_FRONTEND); + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_STARTING, 0); + m_nCurrOption = 0; + m_PrefsRadioStation = DMAudio.GetRadioInCar(); + + if (DMAudio.IsMP3RadioChannelAvailable()) { + if (CMenuManager::m_PrefsRadioStation > USERTRACK) + CMenuManager::m_PrefsRadioStation = CGeneral::GetRandomNumber() % 10; + } else if (CMenuManager::m_PrefsRadioStation > CHATTERBOX) + CMenuManager::m_PrefsRadioStation = CGeneral::GetRandomNumber() % 9; - CFileMgr::SetDir(""); - CTimer::Stop(); - CStreaming::MakeSpaceFor(700 * 1024); - CStreaming::ImGonnaUseStreamingMemory(); - CTxdStore::PushCurrentTxd(); - - int frontend = CTxdStore::AddTxdSlot("frontend"); - CTxdStore::LoadTxd(frontend, "MODELS/FRONTEND.TXD"); - CTxdStore::AddRef(frontend); - CTxdStore::SetCurrentTxd(frontend); - CStreaming::IHaveUsedStreamingMemory(); - CTimer::Update(); - - debug("LOAD frontend\n"); - for (int i = 0; i < ARRAY_SIZE(FrontendFilenames); i++) { - m_aFrontEndSprites[i].SetTexture(FrontendFilenames[i]); - m_aFrontEndSprites[i].SetAddressing(rwTEXTUREADDRESSBORDER); - } - - CTxdStore::PopCurrentTxd(); + CFileMgr::SetDir(""); + //CFileMgr::SetDir(""); + CTimer::Stop(); + CStreaming::MakeSpaceFor(350 * CDSTREAM_SECTOR_SIZE); // twice of it in mobile + CStreaming::ImGonnaUseStreamingMemory(); + CGame::TidyUpMemory(false, true); + CTxdStore::PushCurrentTxd(); + int frontendTxdSlot = CTxdStore::FindTxdSlot("frontend"); + + if(frontendTxdSlot == -1) + frontendTxdSlot = CTxdStore::AddTxdSlot("frontend"); + + printf("LOAD frontend\n"); + CTxdStore::LoadTxd(frontendTxdSlot, "MODELS/FRONTEND.TXD"); + CTxdStore::AddRef(frontendTxdSlot); + CTxdStore::SetCurrentTxd(frontendTxdSlot); + CStreaming::IHaveUsedStreamingMemory(); + CTimer::Update(); + + for (int i = 0; i < ARRAY_SIZE(FrontendFilenames); i++) { + m_aFrontEndSprites[i].SetTexture(FrontendFilenames[i][0], FrontendFilenames[i][1]); + m_aFrontEndSprites[i].SetAddressing(rwTEXTUREADDRESSBORDER); + } - int menu = CTxdStore::AddTxdSlot("menu"); - CTxdStore::LoadTxd(menu, "MODELS/MENU.TXD"); - CTxdStore::AddRef(menu); - CTxdStore::SetCurrentTxd(menu); + int menuTxdSlot = CTxdStore::FindTxdSlot("menu"); - debug("LOAD sprite\n"); - for (int i = 0; i < ARRAY_SIZE(MenuFilenames)/2; i++) { - m_aMenuSprites[i].SetTexture(MenuFilenames[i*2], MenuFilenames[i*2+1]); - m_aMenuSprites[i].SetAddressing(rwTEXTUREADDRESSBORDER); - } + if (menuTxdSlot == -1) + menuTxdSlot = CTxdStore::AddTxdSlot("menu"); - CTxdStore::PopCurrentTxd(); + printf("LOAD sprite\n"); + CTxdStore::LoadTxd(menuTxdSlot, "MODELS/MENU.TXD"); + CTxdStore::AddRef(menuTxdSlot); + CTxdStore::SetCurrentTxd(menuTxdSlot); - m_bSpritesLoaded = true; + for (int i = 0; i < ARRAY_SIZE(MenuFilenames); i++) { + m_aMenuSprites[i].SetTexture(MenuFilenames[i][0], MenuFilenames[i][1]); + m_aMenuSprites[i].SetAddressing(rwTEXTUREADDRESSBORDER); } -} -#endif + m_bSpritesLoaded = true; + CTxdStore::PopCurrentTxd(); +} #if 0 WRAPPER void CMenuManager::LoadSettings() { EAXJMP(0x488EE0); } #else void CMenuManager::LoadSettings() { - CFileMgr::SetDirMyDocuments(); + int fileHandle = CFileMgr::OpenFile("gta3.set", "r"); int32 prevLang = m_PrefsLanguage; CMBlur::BlurOn = true; MousePointerStateHelper.bInvertVertically = true; + // 50 is silly char Ver[50]; - int fileHandle = CFileMgr::OpenFile("gta3.set", "r"); + if (fileHandle) { CFileMgr::Read(fileHandle, Ver, 29); @@ -1206,14 +1368,14 @@ void CMenuManager::LoadSettings() m_bFrontEnd_ReloadObrTxtGxt = true; InitialiseChangedLanguageSettings(); - debug("The previously saved language is now in use"); + OutputDebugString("The previously saved language is now in use"); } - struct _WIN32_FIND_DATAA FindFileData; - char skinfile[256+16]; // ?? + 16? + WIN32_FIND_DATA FindFileData; + char skinfile[256+16]; // Stack analysis shows 16 bits gap, but I don't trust it. It may very well be MAX_PATH(260). bool SkinFound = false; - HANDLE handle = FindFirstFileA("skins\\*.bmp", &FindFileData); - for (int i = 1; handle != (HANDLE)-1 && i; i = FindNextFileA(handle, &FindFileData)) { + HANDLE handle = FindFirstFile("skins\\*.bmp", &FindFileData); + for (int i = 1; handle != INVALID_HANDLE_VALUE && i; i = FindNextFile(handle, &FindFileData)) { strcpy(skinfile, m_PrefsSkinFile); strcat(skinfile, ".bmp"); if (strcmp(FindFileData.cFileName, skinfile) == 0) @@ -1222,7 +1384,7 @@ void CMenuManager::LoadSettings() FindClose(handle); if (!SkinFound) { - debug("Default skin set as no other skins are available OR saved skin not found!"); + OutputDebugString("Default skin set as no other skins are available OR saved skin not found!"); strcpy(m_PrefsSkinFile, "$$\"\""); strcpy(m_aSkinName, "$$\"\""); } @@ -1238,9 +1400,8 @@ void CMenuManager::SaveSettings() CFileMgr::SetDirMyDocuments(); - int fileHandle = CFileMgr::OpenFile("gta3.set", "w"); + int fileHandle = CFileMgr::OpenFile("gta3.set", "w+"); if (fileHandle) { - ControlsManager.SaveSettings(fileHandle); CFileMgr::Write(fileHandle, RubbishString, 20); CFileMgr::Write(fileHandle, RubbishString, 20); @@ -1266,7 +1427,7 @@ void CMenuManager::SaveSettings() 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*)&m_nPrefsVideoMode, 1); CFileMgr::Write(fileHandle, (char*)&CMBlur::BlurOn, 1); CFileMgr::Write(fileHandle, m_PrefsSkinFile, 256); CFileMgr::Write(fileHandle, (char*)&m_ControlMethod, 1); @@ -1398,10 +1559,10 @@ void CMenuManager::Process(void) if (m_PrefsVsyncDisp != m_PrefsVsync) m_PrefsVsync = m_PrefsVsyncDisp; DMAudio.Service(); - m_bStartGameLoading = 1; + m_bStartGameLoading = true; RequestFrontEndShutdown(); - m_bLoadingSavedGame = 1; - b_FoundRecentSavedGameWantToLoad = 1; + m_bLoadingSavedGame = true; + b_FoundRecentSavedGameWantToLoad = true; DMAudio.SetEffectsFadeVol(0); DMAudio.SetMusicFadeVol(0); DMAudio.ResetTimers(CTimer::GetTimeInMilliseconds()); @@ -1483,9 +1644,9 @@ void CMenuManager::Process(void) } // Reset pad shaking. - if (VibrationTime && CTimer::GetTimeInMillisecondsPauseMode() > VibrationTime) { + if (TimeToStopPadShaking && TimeToStopPadShaking < CTimer::GetTimeInMillisecondsPauseMode()) { CPad::StopPadsShaking(); - VibrationTime = 0; + TimeToStopPadShaking = 0; } } else { @@ -1780,7 +1941,7 @@ void CMenuManager::ProcessOnOffMenuOptions() if (m_PrefsUseVibration) { CPad::GetPad(0)->StartShake(350, 150); - VibrationTime = CTimer::GetTimeInMillisecondsPauseMode() + 500; + TimeToStopPadShaking = CTimer::GetTimeInMillisecondsPauseMode() + 500; } SaveSettings(); break; @@ -2155,40 +2316,44 @@ void CMenuManager::ResetHelperText() } #endif -#if ALL_ORIGINAL_FRONTEND -WRAPPER void CMenuManager::SaveLoadFileError_SetUpErrorScreen() { EAXJMP(0x488930); } -#else void CMenuManager::SaveLoadFileError_SetUpErrorScreen() { + // TO-DO: Enum switch (PcSaveHelper.m_nHelper) { - case 1: - case 2: - case 3: - SwitchToNewScreen(MENUPAGE_SAVE_FAILED); - m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); - break; - break; - case 4: - case 5: - case 6: - SwitchToNewScreen(MENUPAGE_LOAD_FAILED); - m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); - break; - case 7: - SwitchToNewScreen(MENUPAGE_LOAD_FAILED_2); - m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); - break; - case 8: - case 9: - case 10: - SwitchToNewScreen(MENUPAGE_DELETE_FAILED); - m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); - break; - default: - return; + case 1: + case 2: + case 3: + m_nPrevScreen = m_nCurrScreen; + m_nCurrScreen = MENUPAGE_SAVE_FAILED; + m_nCurrOption = 0; + m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); + break; + case 4: + case 5: + case 6: + m_nPrevScreen = m_nCurrScreen; + m_nCurrScreen = MENUPAGE_LOAD_FAILED; + m_nCurrOption = 0; + m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); + break; + case 7: + m_nPrevScreen = m_nCurrScreen; + m_nCurrScreen = MENUPAGE_LOAD_FAILED_2; + m_nCurrOption = 0; + m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); + break; + case 8: + case 9: + case 10: + m_nPrevScreen = m_nCurrScreen; + m_nCurrScreen = MENUPAGE_DELETE_FAILED; + m_nCurrOption = 0; + m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); + break; + default: + return; } } -#endif #if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::SetHelperText(int text) { EAXJMP(0x48B450); } @@ -2210,33 +2375,23 @@ void CMenuManager::ShutdownJustMenu() } #endif -#if ALL_ORIGINAL_FRONTEND -WRAPPER float CMenuManager::StretchX(float) { EAXJMP(0x48ABE0); } -#else float CMenuManager::StretchX(float x) { - if (SCREEN_WIDTH == 640) + if (SCREEN_WIDTH == DEFAULT_SCREEN_WIDTH) return x; else -#ifndef ASPECT_RATIO_SCALE - return SCREEN_WIDTH * x * 0.0015625f; -#else - return SCREEN_SCALE_X(x); -#endif + // We won't make this SCREEN_SCALE, because many cases relies on stretching and we want the code to be portable. + // Instead we will use MENU_X_LEFT_ALIGNED or SCREEN_SCALE_X when needed. + return SCREEN_STRETCH_X(x); } -#endif -#if ALL_ORIGINAL_FRONTEND -WRAPPER float CMenuManager::StretchY(float) { EAXJMP(0x48AC20); } -#else float CMenuManager::StretchY(float y) { - if (SCREEN_HEIGHT == 448) + if (SCREEN_HEIGHT == DEFAULT_SCREEN_HEIGHT) return y; else - return SCREEN_HEIGHT * y * 0.002232143f; + return SCREEN_STRETCH_Y(y); } -#endif #if ALL_ORIGINAL_FRONTEND WRAPPER void CMenuManager::SwitchMenuOnAndOff() { EAXJMP(0x488790); } @@ -2580,20 +2735,19 @@ bool GetMouseInput() STARTPATCHES #if ALL_ORIGINAL_FRONTEND #else - InjectHook(0x47A230, &CMenuManager::LoadAllTextures, PATCH_JUMP); InjectHook(0x47A440, &CMenuManager::UnloadTextures, PATCH_JUMP); - InjectHook(0x485100, &CMenuManager::Process, PATCH_JUMP); InjectHook(0x4856F0, &CMenuManager::ProcessButtonPresses, PATCH_JUMP); 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(0x485100, &CMenuManager::Process, PATCH_JUMP); + InjectHook(0x47A230, &CMenuManager::LoadAllTextures, PATCH_JUMP); + InjectHook(0x47A540, &CMenuManager::DrawFrontEnd, PATCH_JUMP); + InjectHook(0x48ABE0, &CMenuManager::StretchX, PATCH_JUMP); + InjectHook(0x48AC20, &CMenuManager::StretchY, PATCH_JUMP); 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 e1ee5b31..ed7cd2c3 100644 --- a/src/core/Frontend.h +++ b/src/core/Frontend.h @@ -7,10 +7,10 @@ #define MENUHEADER_WIDTH 0.84f #define MENUHEADER_HEIGHT 1.6f -#define MENUACTION_POS_X 20.0f +#define MENUACTION_POS_X 40.0f #define MENUACTION_POS_Y 37.5f -#define MENUACTION_WIDTH 0.675f -#define MENUACTION_HEIGHT 0.81f +#define MENUACTION_WIDTH 0.405f +#define MENUACTION_HEIGHT 0.63f #define MENUCOLUMN_POS_X MENUHEADER_POS_X + 16.0f #define MENUCOLUMN_MAX_Y 149.0f @@ -466,9 +466,13 @@ public: static bool &m_bStartUpFrontEndRequested; static bool &m_bShutDownFrontEndRequested; static bool &m_PrefsAllowNastyGame; + + static float &headingYStart; + static float &unkX; + static float &unkY; public: - void BuildStatLine(char *text, float *stat, bool aFloat, float* stat2); + static void BuildStatLine(char *text, void *stat, uint8 aFloat, void *stat2); static void CentreMousePointer(); int CheckCodesForControls(int32); bool CheckHover(int x1, int x2, int y1, int y2); diff --git a/src/core/General.h b/src/core/General.h index d73cf36f..a7b240c2 100644 --- a/src/core/General.h +++ b/src/core/General.h @@ -104,6 +104,29 @@ public: return (int)floorf(angle / DEGTORAD(45.0f)); } + // Unlike usual string comparison functions, these don't care about greater or lesser + static bool faststrcmp(const char *str1, const char *str2) + { + for (; *str1; str1++, str2++) { + if (*str1 != *str2) + return true; + } + return *str2 != '\0'; + } + + static bool faststricmp(const char *str1, const char *str2) + { + for (; *str1; str1++, str2++) { +#if MUCH_SLOWER + if (toupper(*str1) != toupper(*str2)) +#else + if (__ascii_toupper(*str1) != __ascii_toupper(*str2)) +#endif + return true; + } + return *str2 != '\0'; + } + // not too sure about all these... static uint16 GetRandomNumber(void) { return myrand() & MYRAND_MAX; } diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp index e5178ef3..51102c7b 100644 --- a/src/core/Pad.cpp +++ b/src/core/Pad.cpp @@ -36,7 +36,7 @@ CKeyboardState &CPad::OldKeyState = *(CKeyboardState*)0x6F1E70; CKeyboardState &CPad::NewKeyState = *(CKeyboardState*)0x6E60D0; CKeyboardState &CPad::TempKeyState = *(CKeyboardState*)0x774DE8; -char CPad::KeyBoardCheatString[18]; +char CPad::KeyBoardCheatString[20]; CMouseControllerState &CPad::OldMouseControllerState = *(CMouseControllerState*)0x8472A0; CMouseControllerState &CPad::NewMouseControllerState = *(CMouseControllerState*)0x8809F0; @@ -427,7 +427,7 @@ void CPad::StartShake_Train(float fX, float fY) void CPad::AddToPCCheatString(char c) { - for ( int32 i = ARRAY_SIZE(KeyBoardCheatString); i >= 0; i-- ) + for ( int32 i = ARRAY_SIZE(KeyBoardCheatString) - 2; i >= 0; i-- ) KeyBoardCheatString[i + 1] = KeyBoardCheatString[i]; KeyBoardCheatString[0] = c; diff --git a/src/core/Pad.h b/src/core/Pad.h index 89ec4aa2..03b734cb 100644 --- a/src/core/Pad.h +++ b/src/core/Pad.h @@ -7,7 +7,7 @@ enum { PLAYERCONTROL_DISABLED_4 = 4, PLAYERCONTROL_DISABLED_8 = 8, PLAYERCONTROL_DISABLED_10 = 16, - PLAYERCONTROL_DISABLED_20 = 32, + PLAYERCONTROL_DISABLED_20 = 32, // used on CPlayerInfo::MakePlayerSafe PLAYERCONTROL_DISABLED_40 = 64, // used on phone calls PLAYERCONTROL_DISABLED_80 = 128, }; @@ -166,7 +166,7 @@ public: static CKeyboardState &OldKeyState; static CKeyboardState &NewKeyState; static CKeyboardState &TempKeyState; - static char KeyBoardCheatString[18]; + static char KeyBoardCheatString[20]; static CMouseControllerState &OldMouseControllerState; static CMouseControllerState &NewMouseControllerState; static CMouseControllerState &PCTempMouseControllerState; diff --git a/src/core/PlayerInfo.cpp b/src/core/PlayerInfo.cpp index f0b7d444..fcdd60da 100644 --- a/src/core/PlayerInfo.cpp +++ b/src/core/PlayerInfo.cpp @@ -1,18 +1,32 @@ #include "common.h" #include "patcher.h" +#include "main.h" #include "PlayerPed.h" #include "PlayerInfo.h" #include "Frontend.h" -#include "Vehicle.h" #include "PlayerSkin.h" #include "Darkel.h" #include "Messages.h" #include "Text.h" #include "Stats.h" - -WRAPPER void CPlayerInfo::MakePlayerSafe(bool) { EAXJMP(0x4A1400); } -WRAPPER void CPlayerInfo::AwardMoneyForExplosion(CVehicle *vehicle) { EAXJMP(0x4A15F0); } -WRAPPER void CPlayerInfo::Process(void) { EAXJMP(0x49FD30); } +#include "Remote.h" +#include "World.h" +#include "Replay.h" +#include "Pad.h" +#include "ProjectileInfo.h" +#include "Explosion.h" +#include "Script.h" +#include "Automobile.h" +#include "HandlingMgr.h" +#include "General.h" +#include "SpecialFX.h" +#include "Cranes.h" +#include "Bridge.h" +#include "WaterLevel.h" +#include "PathFind.h" +#include "ZoneCull.h" +#include "Renderer.h" +#include "Streaming.h" void CPlayerInfo::SetPlayerSkin(char *skin) @@ -24,7 +38,7 @@ CPlayerInfo::SetPlayerSkin(char *skin) CVector& CPlayerInfo::GetPos() { - if (m_pPed->bInVehicle && m_pPed->m_pMyVehicle) + if (m_pPed->InVehicle()) return m_pPed->m_pMyVehicle->GetPosition(); return m_pPed->GetPosition(); } @@ -44,7 +58,7 @@ CPlayerInfo::DeletePlayerSkin() {
if (m_pSkinTexture) {
RwTextureDestroy(m_pSkinTexture);
- m_pSkinTexture = NULL;
+ m_pSkinTexture = nil;
} } @@ -88,9 +102,473 @@ CPlayerInfo::PlayerFailedCriticalMission() CDarkel::ResetOnPlayerDeath(); } +void
+CPlayerInfo::Clear(void)
+{
+ m_pPed = nil;
+ m_pRemoteVehicle = nil;
+ if (m_pVehicleEx) {
+ m_pVehicleEx->bUsingSpecialColModel = false;
+ m_pVehicleEx = nil;
+ }
+ m_nVisibleMoney = 0;
+ m_nMoney = m_nVisibleMoney;
+ m_WBState = WBSTATE_PLAYING;
+ m_nWBTime = 0;
+ m_nTrafficMultiplier = 0;
+ m_fRoadDensity = 1.0f;
+ m_bInRemoteMode = false;
+ m_bUnusedTaxiThing = false;
+ m_nUnusedTaxiTimer = 0;
+ m_nCollectedPackages = 0;
+ m_nTotalPackages = 3;
+ m_nTimeLastHealthLoss = 0;
+ m_nTimeLastArmourLoss = 0;
+ m_nNextSexFrequencyUpdateTime = 0;
+ m_nNextSexMoneyUpdateTime = 0;
+ m_nSexFrequency = 0;
+ m_pHooker = nil;
+ m_nTimeTankShotGun = 0;
+ field_248 = 0;
+ m_nUpsideDownCounter = 0;
+ m_bInfiniteSprint = false;
+ m_bFastReload = false;
+ m_bGetOutOfJailFree = false;
+ m_bGetOutOfHospitalFree = false;
+ m_nPreviousTimeRewardedForExplosion = 0;
+ m_nExplosionsSinceLastReward = 0;
+} + +void
+CPlayerInfo::BlowUpRCBuggy(void)
+{
+ if (!m_pRemoteVehicle || m_pRemoteVehicle->bRemoveFromWorld)
+ return;
+
+ CRemote::TakeRemoteControlledCarFromPlayer();
+ m_pRemoteVehicle->BlowUpCar(FindPlayerPed());
+} +
+void
+CPlayerInfo::CancelPlayerEnteringCars(CVehicle *car)
+{
+ if (!car || car == m_pPed->m_pMyVehicle) {
+ if (m_pPed->m_nPedState == PED_CARJACK || m_pPed->m_nPedState == PED_ENTER_CAR)
+ m_pPed->QuitEnteringCar();
+ }
+ if (m_pPed->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER || m_pPed->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER)
+ m_pPed->ClearObjective();
+} + +void
+CPlayerInfo::MakePlayerSafe(bool toggle)
+{
+ if (toggle) {
+ CTheScripts::CountdownToMakePlayerUnsafe = 0;
+ m_pPed->m_pWanted->m_bIgnoredByEveryone = true;
+ CWorld::StopAllLawEnforcersInTheirTracks();
+ CPad::GetPad(0)->DisablePlayerControls |= PLAYERCONTROL_DISABLED_20;
+ CPad::StopPadsShaking();
+ m_pPed->bBulletProof = true;
+ m_pPed->bFireProof = true;
+ m_pPed->bCollisionProof = true;
+ m_pPed->bMeleeProof = true;
+ m_pPed->bOnlyDamagedByPlayer = true;
+ m_pPed->bExplosionProof = true;
+ m_pPed->m_bCanBeDamaged = false;
+ ((CPlayerPed*)m_pPed)->ClearAdrenaline();
+ CancelPlayerEnteringCars(false);
+ gFireManager.ExtinguishPoint(GetPos(), 4000.0f);
+ CExplosion::RemoveAllExplosionsInArea(GetPos(), 4000.0f);
+ CProjectileInfo::RemoveAllProjectiles();
+ CWorld::SetAllCarsCanBeDamaged(false);
+ CWorld::ExtinguishAllCarFiresInArea(GetPos(), 4000.0f);
+ CReplay::DisableReplays();
+
+ } else if (!CGame::playingIntro && !CTheScripts::CountdownToMakePlayerUnsafe) {
+ m_pPed->m_pWanted->m_bIgnoredByEveryone = false;
+ CPad::GetPad(0)->DisablePlayerControls &= ~PLAYERCONTROL_DISABLED_20;
+ m_pPed->bBulletProof = false;
+ m_pPed->bFireProof = false;
+ m_pPed->bCollisionProof = false;
+ m_pPed->bMeleeProof = false;
+ m_pPed->bOnlyDamagedByPlayer = false;
+ m_pPed->bExplosionProof = false;
+ m_pPed->m_bCanBeDamaged = true;
+ CWorld::SetAllCarsCanBeDamaged(true);
+ CReplay::EnableReplays();
+ }
+} + +bool +CPlayerInfo::IsRestartingAfterDeath() +{ + return m_WBState == WBSTATE_WASTED; +} + +bool +CPlayerInfo::IsRestartingAfterArrest() +{ + return m_WBState == WBSTATE_BUSTED; +} + +// lastClosestness is passed to other calls of this function +void
+CPlayerInfo::EvaluateCarPosition(CEntity *carToTest, CPed *player, float carBoundCentrePedDist, float *lastClosestness, CVehicle **closestCarOutput)
+{
+ // This dist used for determining the angle to face
+ CVector2D dist(carToTest->GetPosition() - player->GetPosition());
+ float neededTurn = CGeneral::GetATanOfXY(player->GetForward().x, player->GetForward().y) - CGeneral::GetATanOfXY(dist.x, dist.y);
+ while (neededTurn >= PI) {
+ neededTurn -= 2 * PI;
+ }
+
+ while (neededTurn < -PI) {
+ neededTurn += 2 * PI;
+ }
+
+ // This dist used for evaluating cars' distances, weird...
+ // Accounts inverted needed turn (or needed turn in long way) and car dist.
+ float closestness = (1.0f - Abs(neededTurn) / TWOPI) * (10.0f - carBoundCentrePedDist);
+ if (closestness > *lastClosestness) {
+ *lastClosestness = closestness;
+ *closestCarOutput = (CVehicle*)carToTest;
+ }
+} + +// There is something unfinished in here... Sadly all IDBs we have have it unfinished. +void
+CPlayerInfo::AwardMoneyForExplosion(CVehicle *wreckedCar)
+{
+ if (CTimer::GetTimeInMilliseconds() - m_nPreviousTimeRewardedForExplosion < 6000)
+ ++m_nExplosionsSinceLastReward;
+ else
+ m_nExplosionsSinceLastReward = 1;
+
+ m_nPreviousTimeRewardedForExplosion = CTimer::GetTimeInMilliseconds();
+ int award = wreckedCar->pHandling->nMonetaryValue * 0.002f;
+ sprintf(gString, "$%d", award);
+#ifdef MONEY_MESSAGES
+ // This line is a leftover from PS2, I don't know what it was meant to be.
+ // CVector sth(TheCamera.GetPosition() * 4.0f);
+
+ CMoneyMessages::RegisterOne(wreckedCar->GetPosition() + CVector(0.0f, 0.0f, 2.0f), gString, 0, 255, 0, 2.0f, 0.5f);
+#endif
+ CWorld::Players[CWorld::PlayerInFocus].m_nMoney += award;
+
+ for (int i = m_nExplosionsSinceLastReward; i > 1; --i) {
+ CGeneral::GetRandomNumber();
+ CWorld::Players[CWorld::PlayerInFocus].m_nMoney += award;
+ }
+} + +void
+CPlayerInfo::SavePlayerInfo(uint8 *buf, uint32 *size)
+{
+ // Interesting
+ *size = sizeof(CPlayerInfo);
+
+INITSAVEBUF
+ WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nMoney);
+ WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_WBState);
+ WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nWBTime);
+ WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nTrafficMultiplier);
+ WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_fRoadDensity);
+ WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nVisibleMoney);
+ WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages);
+ WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nTotalPackages);
+ WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_bInfiniteSprint);
+ WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_bFastReload);
+ WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_bGetOutOfJailFree);
+ WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_bGetOutOfHospitalFree);
+ for (int i = 0; i < sizeof(CWorld::Players[CWorld::PlayerInFocus].m_aPlayerName); i++) {
+ WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_aPlayerName[i]);
+ }
+// Save struct is different
+// VALIDATESAVEBUF(*size)
+} + +void
+CPlayerInfo::LoadPlayerInfo(uint8 *buf, uint32 size)
+{
+INITSAVEBUF
+ CWorld::Players[CWorld::PlayerInFocus].m_nMoney = ReadSaveBuf<uint32>(buf);
+ CWorld::Players[CWorld::PlayerInFocus].m_WBState = ReadSaveBuf<int8>(buf);
+ CWorld::Players[CWorld::PlayerInFocus].m_nWBTime = ReadSaveBuf<uint32>(buf);
+ CWorld::Players[CWorld::PlayerInFocus].m_nTrafficMultiplier = ReadSaveBuf<int16>(buf);
+ CWorld::Players[CWorld::PlayerInFocus].m_fRoadDensity = ReadSaveBuf<float>(buf);
+ CWorld::Players[CWorld::PlayerInFocus].m_nVisibleMoney = ReadSaveBuf<int32>(buf);
+ CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages = ReadSaveBuf<int32>(buf);
+ CWorld::Players[CWorld::PlayerInFocus].m_nTotalPackages = ReadSaveBuf<int32>(buf);
+ CWorld::Players[CWorld::PlayerInFocus].m_bInfiniteSprint = ReadSaveBuf<bool>(buf);
+ CWorld::Players[CWorld::PlayerInFocus].m_bFastReload = ReadSaveBuf<bool>(buf);
+ CWorld::Players[CWorld::PlayerInFocus].m_bGetOutOfJailFree = ReadSaveBuf<bool>(buf);
+ CWorld::Players[CWorld::PlayerInFocus].m_bGetOutOfHospitalFree = ReadSaveBuf<bool>(buf);
+ for (int i = 0; i < sizeof(CWorld::Players[CWorld::PlayerInFocus].m_aPlayerName); i++) {
+ CWorld::Players[CWorld::PlayerInFocus].m_aPlayerName[i] = ReadSaveBuf<char>(buf);
+ }
+// Save struct is different
+// VALIDATESAVEBUF(size)
+} + +void
+CPlayerInfo::FindClosestCarSectorList(CPtrList& carList, CPed* ped, float unk1, float unk2, float unk3, float unk4, float* lastClosestness, CVehicle** closestCarOutput)
+{
+ for (CPtrNode* node = carList.first; node; node = node->next) {
+ CVehicle *car = (CVehicle*)node->item;
+ if(car->m_scanCode != CWorld::GetCurrentScanCode()) {
+ if (!car->bUsesCollision || !car->IsVehicle())
+ continue;
+
+ car->m_scanCode = CWorld::GetCurrentScanCode();
+ if (car->m_status != STATUS_WRECKED && car->m_status != STATUS_TRAIN_MOVING
+ && (car->GetUp().z > 0.3f || (car->IsVehicle() && ((CVehicle*)car)->m_vehType == VEHICLE_TYPE_BIKE))) {
+ CVector carCentre = car->GetBoundCentre();
+
+ if (Abs(ped->GetPosition().z - carCentre.z) < 2.0f) {
+ float dist = (ped->GetPosition() - carCentre).Magnitude2D();
+ if (dist <= 10.0f && !CCranes::IsThisCarBeingCarriedByAnyCrane(car)) {
+ EvaluateCarPosition(car, ped, dist, lastClosestness, closestCarOutput);
+ }
+ }
+ }
+ }
+ }
+} + +void
+CPlayerInfo::Process(void)
+{
+ // Unused taxi feature. Gives you a dollar for every second with a passenger. Can be toggled via 0x29A opcode.
+ bool startTaxiTimer = true;
+ if (m_bUnusedTaxiThing && m_pPed->bInVehicle) {
+ CVehicle *veh = m_pPed->m_pMyVehicle;
+ if ((veh->m_modelIndex == MI_TAXI || veh->m_modelIndex == MI_CABBIE || veh->m_modelIndex == MI_BORGNINE)
+ && veh->pDriver == m_pPed && veh->m_nNumPassengers != 0) {
+ for (uint32 timePassed = CTimer::GetTimeInMilliseconds() - m_nUnusedTaxiTimer; timePassed >= 1000; m_nUnusedTaxiTimer += 1000) {
+ timePassed -= 1000;
+ ++m_nMoney;
+ }
+ startTaxiTimer = false;
+ }
+ }
+ if (startTaxiTimer)
+ m_nUnusedTaxiTimer = CTimer::GetTimeInMilliseconds();
+
+ // The effect that makes money counter does while earning/losing money
+ if (m_nVisibleMoney != m_nMoney) {
+ int diff = m_nMoney - m_nVisibleMoney;
+ int diffAbs = Abs(diff);
+ int changeBy;
+
+ if (diffAbs > 100000)
+ changeBy = 12345;
+ else if (diffAbs > 10000)
+ changeBy = 1234;
+ else if (diffAbs > 1000)
+ changeBy = 123;
+ else if (diffAbs > 50)
+ changeBy = 42;
+ else
+ changeBy = 1;
+
+ if (diff < 0)
+ m_nVisibleMoney -= changeBy;
+ else
+ m_nVisibleMoney += changeBy;
+ }
+
+ if (!(CTimer::GetFrameCounter() & 15)) {
+ CVector2D playerPos = m_pPed->bInVehicle ? m_pPed->m_pMyVehicle->GetPosition() : m_pPed->GetPosition();
+ m_fRoadDensity = ThePaths.CalcRoadDensity(playerPos.x, playerPos.y);
+ }
+
+ m_fRoadDensity = clamp(m_fRoadDensity, 0.4f, 1.45f);
+
+ // Because vehicle enter/exit use same key binding.
+ bool enterOrExitVeh;
+ if (m_pPed->m_ped_flagI4 && m_pPed->bInVehicle)
+ enterOrExitVeh = CPad::GetPad(0)->ExitVehicleJustDown();
+ else
+ enterOrExitVeh = CPad::GetPad(0)->GetExitVehicle();
+
+ if (enterOrExitVeh && m_pPed->m_nPedState != PED_SNIPER_MODE && m_pPed->m_nPedState != PED_ROCKET_ODE) {
+ if (m_pPed->bInVehicle) {
+ if (!m_pRemoteVehicle) {
+ CEntity *surfaceBelowVeh = m_pPed->m_pMyVehicle->m_pCurGroundEntity;
+ if (!surfaceBelowVeh || !CBridge::ThisIsABridgeObjectMovingUp(surfaceBelowVeh->m_modelIndex)) {
+ CVehicle *veh = m_pPed->m_pMyVehicle;
+ if (!veh->IsBoat() || veh->m_nDoorLock == CARLOCK_LOCKED_PLAYER_INSIDE) {
+
+ // This condition will always return true, else block was probably WIP Miami code.
+ if (veh->m_vehType != VEHICLE_TYPE_BIKE || veh->m_nDoorLock == CARLOCK_LOCKED_PLAYER_INSIDE) {
+ if (veh->m_status != STATUS_WRECKED && veh->m_status != STATUS_TRAIN_MOVING && veh->m_nDoorLock != CARLOCK_LOCKED_PLAYER_INSIDE) {
+ if (veh->m_vecMoveSpeed.Magnitude() < 0.17f && CTimer::GetTimeScale() >= 0.5f && !veh->bIsInWater) {
+ m_pPed->SetObjective(OBJECTIVE_LEAVE_VEHICLE, veh);
+ }
+ }
+ } else {
+ CVector sth = 0.7f * veh->GetRight() + veh->GetPosition();
+ bool found = false;
+ float groundZ = CWorld::FindGroundZFor3DCoord(sth.x, sth.y, 2.0f + sth.z, &found);
+
+ if (found)
+ sth.z = 1.0f + groundZ;
+ m_pPed->m_nPedState = PED_IDLE;
+ m_pPed->SetMoveState(PEDMOVE_STILL);
+ CPed::PedSetOutCarCB(0, m_pPed);
+ CAnimManager::BlendAnimation(m_pPed->GetClump(), m_pPed->m_animGroup, ANIM_IDLE_STANCE, 100.0f);
+ CAnimManager::BlendAnimation(m_pPed->GetClump(), ASSOCGRP_STD, ANIM_FALL_LAND, 100.0f);
+ m_pPed->GetPosition() = sth;
+ m_pPed->SetMoveState(PEDMOVE_STILL);
+ m_pPed->m_vecMoveSpeed = veh->m_vecMoveSpeed;
+ }
+ } else {
+ // The code in here was under CPed::SetExitBoat in VC, did the same for here.
+ m_pPed->SetExitBoat(veh);
+ m_pPed->bTryingToReachDryLand = true;
+ }
+ }
+ }
+ } else {
+ // Enter vehicle
+ if (CPad::GetPad(0)->ExitVehicleJustDown()) {
+ bool weAreOnBoat = false;
+ float lastClosestness = 0.0f;
+ CVehicle *carBelow;
+ CEntity *surfaceBelow = m_pPed->m_pCurrentPhysSurface;
+ if (surfaceBelow && surfaceBelow->IsVehicle()) {
+ carBelow = (CVehicle*)surfaceBelow;
+ if (carBelow->IsBoat()) {
+ weAreOnBoat = true;
+ m_pPed->bOnBoat = true;
+#ifdef VC_PED_PORTS
+ if (carBelow->m_status != STATUS_WRECKED && carBelow->GetUp().z > 0.3f)
+#else
+ if (carBelow->m_status != STATUS_WRECKED)
+#endif
+ m_pPed->SetSeekBoatPosition(carBelow);
+ }
+ }
+ // Find closest car
+ if (!weAreOnBoat) {
+ float minX = m_pPed->GetPosition().x - 10.0f;
+ float maxX = 10.0f + m_pPed->GetPosition().x;
+ float minY = m_pPed->GetPosition().y - 10.0f;
+ float maxY = 10.0f + m_pPed->GetPosition().y;
+
+ int minXSector = CWorld::GetSectorIndexX(minX);
+ if (minXSector < 0) minXSector = 0;
+ int minYSector = CWorld::GetSectorIndexY(minY);
+ if (minYSector < 0) minYSector = 0;
+ int maxXSector = CWorld::GetSectorIndexX(maxX);
+ if (maxXSector > NUMSECTORS_X - 1) maxXSector = NUMSECTORS_X - 1;
+ int maxYSector = CWorld::GetSectorIndexY(maxY);
+ if (maxYSector > NUMSECTORS_Y - 1) maxYSector = NUMSECTORS_Y - 1;
+
+ CWorld::AdvanceCurrentScanCode();
+
+ for (int curY = minYSector; curY <= maxYSector; curY++) {
+ for (int curX = minXSector; curX <= maxXSector; curX++) {
+ CSector *sector = CWorld::GetSector(curX, curY);
+ FindClosestCarSectorList(sector->m_lists[ENTITYLIST_VEHICLES], m_pPed,
+ minX, minY, maxX, maxY, &lastClosestness, &carBelow);
+ FindClosestCarSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], m_pPed,
+ minX, minY, maxX, maxY, &lastClosestness, &carBelow);
+ }
+ }
+ }
+ // carBelow is now closest vehicle
+ if (carBelow && !weAreOnBoat) {
+ if (carBelow->m_status == STATUS_TRAIN_NOT_MOVING) {
+ m_pPed->SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, carBelow);
+ } else if (carBelow->IsBoat()) {
+ if (!carBelow->pDriver) {
+ m_pPed->m_vehEnterType = 0;
+ m_pPed->SetEnterCar(carBelow, m_pPed->m_vehEnterType);
+ }
+ } else {
+ m_pPed->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, carBelow);
+ }
+ }
+ }
+ }
+ }
+ if (m_bInRemoteMode) {
+ uint32 timeWithoutRemoteCar = CTimer::GetTimeInMilliseconds() - m_nTimeLostRemoteCar;
+ if (CTimer::GetPreviousTimeInMilliseconds() - m_nTimeLostRemoteCar < 1000 && timeWithoutRemoteCar >= 1000 && m_WBState == WBSTATE_PLAYING) {
+ TheCamera.SetFadeColour(0, 0, 0);
+ TheCamera.Fade(1.0f, 0);
+ }
+ if (timeWithoutRemoteCar > 2000) {
+ if (m_WBState == WBSTATE_PLAYING) {
+ TheCamera.RestoreWithJumpCut();
+ TheCamera.SetFadeColour(0, 0, 0);
+ TheCamera.Fade(1.0f, 1);
+ TheCamera.Process();
+ CTimer::Stop();
+ CCullZones::ForceCullZoneCoors(TheCamera.GetPosition());
+ CRenderer::RequestObjectsInFrustum();
+ CStreaming::LoadAllRequestedModels(false);
+ CTimer::Update();
+ }
+ m_bInRemoteMode = false;
+ CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle = nil;
+ if (FindPlayerVehicle()) {
+ FindPlayerVehicle()->m_status = STATUS_PLAYER;
+ }
+ }
+ }
+ if (!(CTimer::GetFrameCounter() & 31)) {
+ CVehicle *veh = FindPlayerVehicle();
+ if (veh && m_pPed->bInVehicle && veh->GetUp().z < 0.0f
+ && veh->m_vecMoveSpeed.Magnitude() < 0.05f && veh->IsCar() && !veh->bIsInWater) {
+
+ if (veh->GetUp().z < -0.5f) {
+ m_nUpsideDownCounter += 2;
+
+ } else {
+ m_nUpsideDownCounter++;
+ }
+ } else {
+ m_nUpsideDownCounter = 0;
+ }
+
+ if (m_nUpsideDownCounter > 6 && veh->bCanBeDamaged) {
+ veh->m_fHealth = 249.0f < veh->m_fHealth ? 249.0f : veh->m_fHealth;
+ if (veh->IsCar()) {
+ CAutomobile* car = (CAutomobile*)veh;
+ car->Damage.SetEngineStatus(225);
+ car->m_pSetOnFireEntity = nil;
+ }
+ }
+ }
+ if (FindPlayerVehicle()) {
+ CVehicle *veh = FindPlayerVehicle();
+ veh->m_nZoneLevel = -1;
+ for (int i = 0; i < ARRAY_SIZE(veh->pPassengers); i++) {
+ if (veh->pPassengers[i])
+ veh->pPassengers[i]->m_nZoneLevel = 0;
+ }
+ CStats::DistanceTravelledInVehicle += veh->m_fDistanceTravelled;
+ } else {
+ CStats::DistanceTravelledOnFoot += FindPlayerPed()->m_fDistanceTravelled;
+ }
+} + STARTPATCHES -InjectHook(0x4A1700, &CPlayerInfo::LoadPlayerSkin, PATCH_JUMP); -InjectHook(0x4A1750, &CPlayerInfo::DeletePlayerSkin, PATCH_JUMP); -InjectHook(0x4A12E0, &CPlayerInfo::KillPlayer, PATCH_JUMP); -InjectHook(0x4A1330, &CPlayerInfo::ArrestPlayer, PATCH_JUMP); + InjectHook(0x4B5DC0, &CPlayerInfo::dtor, PATCH_JUMP); + InjectHook(0x4A1700, &CPlayerInfo::LoadPlayerSkin, PATCH_JUMP); + InjectHook(0x4A1750, &CPlayerInfo::DeletePlayerSkin, PATCH_JUMP); + InjectHook(0x4A12E0, &CPlayerInfo::KillPlayer, PATCH_JUMP); + InjectHook(0x4A1330, &CPlayerInfo::ArrestPlayer, PATCH_JUMP); + InjectHook(0x49FC10, &CPlayerInfo::Clear, PATCH_JUMP); + InjectHook(0x4A15C0, &CPlayerInfo::BlowUpRCBuggy, PATCH_JUMP); + InjectHook(0x4A13B0, &CPlayerInfo::CancelPlayerEnteringCars, PATCH_JUMP); + InjectHook(0x4A1400, &CPlayerInfo::MakePlayerSafe, PATCH_JUMP); + InjectHook(0x4A0EC0, &CPlayerInfo::EvaluateCarPosition, PATCH_JUMP); + InjectHook(0x4A15F0, &CPlayerInfo::AwardMoneyForExplosion, PATCH_JUMP); + InjectHook(0x4A0B20, &CPlayerInfo::LoadPlayerInfo, PATCH_JUMP); + InjectHook(0x4A0960, &CPlayerInfo::SavePlayerInfo, PATCH_JUMP); + InjectHook(0x49FD30, &CPlayerInfo::Process, PATCH_JUMP); ENDPATCHES diff --git a/src/core/PlayerInfo.h b/src/core/PlayerInfo.h index ef21fb52..19c5ce23 100644 --- a/src/core/PlayerInfo.h +++ b/src/core/PlayerInfo.h @@ -10,6 +10,8 @@ enum eWastedBustedState WBSTATE_FAILED_CRITICAL_MISSION, }; +class CEntity; +class CPed; class CVehicle; class CPlayerPed; class CCivilianPed; @@ -27,20 +29,20 @@ public: int32 m_nCollectedPackages; int32 m_nTotalPackages; uint32 m_nLastBumpPlayerCarTimer; - int32 m_nSwitchTaxiTime; - bool m_bSwitchTaxi; + uint32 m_nUnusedTaxiTimer; + bool m_bUnusedTaxiThing; int8 field_197; int8 field_198; int8 field_199; - int32 m_nNextSexFrequencyUpdateTime; - int32 m_nNextSexMoneyUpdateTime; + uint32 m_nNextSexFrequencyUpdateTime; + uint32 m_nNextSexMoneyUpdateTime; int32 m_nSexFrequency; CCivilianPed *m_pHooker; int8 m_WBState; // eWastedBustedState int8 field_217; int8 field_218; int8 field_219; - int32 m_nWBTime; + uint32 m_nWBTime; bool m_bInRemoteMode; int8 field_225; int8 field_226; @@ -55,7 +57,7 @@ public: int8 field_254; int8 field_255; float m_fRoadDensity; - int32 m_nPreviousTimeRewardedForExplosion; + uint32 m_nPreviousTimeRewardedForExplosion; int32 m_nExplosionsSinceLastReward; int32 field_268; int32 field_272; @@ -77,6 +79,18 @@ public: void ArrestPlayer(void); bool IsPlayerInRemoteMode(void); void PlayerFailedCriticalMission(void); + void Clear(void); + void BlowUpRCBuggy(void); + void CancelPlayerEnteringCars(CVehicle*); + bool IsRestartingAfterDeath(void); + bool IsRestartingAfterArrest(void); + void EvaluateCarPosition(CEntity*, CPed*, float, float*, CVehicle**); + void LoadPlayerInfo(uint8 *buf, uint32 size); + void SavePlayerInfo(uint8 *buf, uint32* size); + void FindClosestCarSectorList(CPtrList&, CPed*, float, float, float, float, float*, CVehicle**); + + ~CPlayerInfo() { }; + void dtor(void) { this->CPlayerInfo::~CPlayerInfo(); } }; static_assert(sizeof(CPlayerInfo) == 0x13C, "CPlayerInfo: error"); diff --git a/src/core/PlayerSkin.cpp b/src/core/PlayerSkin.cpp index 82427491..4d2c31df 100644 --- a/src/core/PlayerSkin.cpp +++ b/src/core/PlayerSkin.cpp @@ -28,7 +28,7 @@ FindPlayerDff(uint32 &offset, uint32 &size) do {
if (!CFileMgr::Read(file, (char*)&info, sizeof(CDirectory::DirectoryInfo)))
return;
- } while (strcmpi("player.dff", info.name));
+ } while (strcasecmp("player.dff", info.name) != 0);
offset = info.offset;
size = info.size;
@@ -94,7 +94,7 @@ CPlayerSkin::GetSkinTexture(const char *texName) CTxdStore::PopCurrentTxd();
if (tex) return tex;
- if (!strcmp(DEFAULT_SKIN_NAME, texName))
+ if (strcmp(DEFAULT_SKIN_NAME, texName) == 0)
sprintf(gString, "models\\generic\\player.bmp");
else
sprintf(gString, "skins\\%s.bmp", texName);
diff --git a/src/core/Radar.cpp b/src/core/Radar.cpp index f06e5317..ab7de13e 100644 --- a/src/core/Radar.cpp +++ b/src/core/Radar.cpp @@ -312,7 +312,7 @@ void CRadar::DrawBlips() break; case BLIP_CHAR: blipEntity = CPools::GetPedPool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle); - if (blipEntity && ((CPed*)blipEntity)->bInVehicle && ((CPed*)blipEntity)->m_pMyVehicle) { + if (blipEntity && ((CPed*)blipEntity)->InVehicle()) { blipEntity = ((CPed*)blipEntity)->m_pMyVehicle; } break; @@ -415,7 +415,7 @@ void CRadar::DrawBlips() break; case BLIP_CHAR: blipEntity = CPools::GetPedPool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle); - if (blipEntity && ((CPed*)blipEntity)->bInVehicle && ((CPed*)blipEntity)->m_pMyVehicle) { + if (blipEntity && ((CPed*)blipEntity)->InVehicle()) { blipEntity = ((CPed*)blipEntity)->m_pMyVehicle; } break; diff --git a/src/core/Stats.cpp b/src/core/Stats.cpp index 5d2401ed..17c3d9d7 100644 --- a/src/core/Stats.cpp +++ b/src/core/Stats.cpp @@ -12,6 +12,8 @@ int32 *CStats::PedsKilledOfThisType = (int32*)0x880DBC; int32 &CStats::TimesDied = *(int32*)0x8E2BDC; int32 &CStats::TimesArrested = *(int32*)0x8E2BEC; int32 &CStats::KillsSinceLastCheckpoint = *(int32*)0x8F2C8C; +int32& CStats::DistanceTravelledInVehicle = *(int32*)0x940574; +int32& CStats::DistanceTravelledOnFoot = *(int32*)0x941518; int32 &CStats::ProgressMade = *(int32*)0x8F6224; int32 &CStats::TotalProgressInGame = *(int32*)0x885B2C; float &CStats::MaximumJumpDistance = *(float*)0x8F2BDC; diff --git a/src/core/Stats.h b/src/core/Stats.h index 22f0c68a..add4320b 100644 --- a/src/core/Stats.h +++ b/src/core/Stats.h @@ -14,6 +14,8 @@ public: static int32 &TimesDied; static int32 &TimesArrested; static int32 &KillsSinceLastCheckpoint; + static int32 &DistanceTravelledInVehicle; + static int32 &DistanceTravelledOnFoot; static int32 &ProgressMade; static int32 &TotalProgressInGame; static float &MaximumJumpDistance; diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp index 69e14869..b0933063 100644 --- a/src/core/Streaming.cpp +++ b/src/core/Streaming.cpp @@ -1,5 +1,6 @@ #include "common.h" #include "patcher.h" +#include "General.h" #include "Pad.h" #include "Hud.h" #include "Text.h" @@ -347,7 +348,7 @@ CStreaming::LoadCdDirectory(const char *dirname, int n) if(direntry.size > (uint32)ms_streamingBufferSize) ms_streamingBufferSize = direntry.size; - if(strcmp(dot+1, "DFF") == 0 || strcmp(dot+1, "dff") == 0){ + if(!CGeneral::faststrcmp(dot+1, "DFF") || !CGeneral::faststrcmp(dot+1, "dff")){ if(CModelInfo::GetModelInfo(direntry.name, &modelId)){ if(ms_aInfoForModel[modelId].GetCdPosnAndSize(posn, size)){ debug("%s appears more than once in %s\n", direntry.name, dirname); @@ -364,20 +365,20 @@ CStreaming::LoadCdDirectory(const char *dirname, int n) ms_pExtraObjectsDir->AddItem(direntry); lastID = -1; } - }else if(strcmp(dot+1, "TXD") == 0 || strcmp(dot+1, "txd") == 0){ + }else if(!CGeneral::faststrcmp(dot+1, "TXD") || !CGeneral::faststrcmp(dot+1, "txd")){ txdId = CTxdStore::FindTxdSlot(direntry.name); if(txdId == -1) txdId = CTxdStore::AddTxdSlot(direntry.name); - if(ms_aInfoForModel[txdId + STREAM_OFFSET_TXD].GetCdPosnAndSize(posn, size)){ - debug("%s appears more than once in %s\n", direntry.name, dirname); - lastID = -1; - }else{ - direntry.offset |= imgSelector; - ms_aInfoForModel[txdId + STREAM_OFFSET_TXD].SetCdPosnAndSize(direntry.offset, direntry.size); - if(lastID != -1) - ms_aInfoForModel[lastID].m_nextID = txdId + STREAM_OFFSET_TXD; - lastID = txdId + STREAM_OFFSET_TXD; - } + if(ms_aInfoForModel[txdId + STREAM_OFFSET_TXD].GetCdPosnAndSize(posn, size)){ + debug("%s appears more than once in %s\n", direntry.name, dirname); + lastID = -1; + }else{ + direntry.offset |= imgSelector; + ms_aInfoForModel[txdId + STREAM_OFFSET_TXD].SetCdPosnAndSize(direntry.offset, direntry.size); + if(lastID != -1) + ms_aInfoForModel[lastID].m_nextID = txdId + STREAM_OFFSET_TXD; + lastID = txdId + STREAM_OFFSET_TXD; + } }else lastID = -1; } @@ -720,7 +721,7 @@ CStreaming::RequestSpecialModel(int32 modelId, const char *modelName, int32 flag uint32 pos, size; mi = CModelInfo::GetModelInfo(modelId); - if(strcmp(mi->GetName(), modelName) == 0){ + if(!CGeneral::faststrcmp(mi->GetName(), modelName)){ // Already have the correct name, just request it RequestModel(modelId, flags); return; diff --git a/src/core/TempColModels.cpp b/src/core/TempColModels.cpp index d2d3f5fb..f7cf035e 100644 --- a/src/core/TempColModels.cpp +++ b/src/core/TempColModels.cpp @@ -1,6 +1,7 @@ #include "common.h" #include "patcher.h" #include "TempColModels.h" +#include "SurfaceTable.h" CColModel &CTempColModels::ms_colModelPed1 = *(CColModel*)0x726CB0; CColModel &CTempColModels::ms_colModelPed2 = *(CColModel*)0x726D08; @@ -16,4 +17,277 @@ CColModel &CTempColModels::ms_colModelBoot1 = *(CColModel*)0x880670; CColModel &CTempColModels::ms_colModelDoor1 = *(CColModel*)0x880850; CColModel &CTempColModels::ms_colModelBonnet1 = *(CColModel*)0x8808A8; -WRAPPER void CTempColModels::Initialise(void) { EAXJMP(0x412160); } + +CColSphere s_aPedSpheres[3]; +CColSphere s_aPed2Spheres[3]; +CColSphere s_aPedGSpheres[4]; +CColSphere s_aDoorSpheres[4]; +CColSphere s_aBumperSpheres[4]; +CColSphere s_aPanelSpheres[4]; +CColSphere s_aBonnetSpheres[4]; +CColSphere s_aBootSpheres[4]; +CColSphere s_aWheelSpheres[2]; +CColSphere s_aBodyPartSpheres1[2]; +CColSphere s_aBodyPartSpheres2[2]; + +void +CTempColModels::Initialise(void) +{ +#define SET_COLMODEL_SPHERES(colmodel, sphrs)\ + colmodel.numSpheres = ARRAYSIZE(sphrs);\ + colmodel.spheres = sphrs;\ + colmodel.level = LEVEL_NONE;\ + colmodel.ownsCollisionVolumes = false;\ + + int i; + + ms_colModelBBox.boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); + ms_colModelBBox.boundingBox.Set(CVector(-2.0f, -2.0f, -2.0f), CVector(2.0f, 2.0f, 2.0f), SURFACE_DEFAULT, 0); + ms_colModelBBox.level = LEVEL_NONE; + + for (i = 0; i < ARRAYSIZE(ms_colModelCutObj); i++) { + ms_colModelCutObj[i].boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); + ms_colModelCutObj[i].boundingBox.Set(CVector(-2.0f, -2.0f, -2.0f), CVector(2.0f, 2.0f, 2.0f), SURFACE_DEFAULT, 0); + ms_colModelCutObj[i].level = LEVEL_NONE; + } + + // Ped Spheres + + for (i = 0; i < ARRAYSIZE(s_aPedSpheres); i++) + s_aPedSpheres[i].radius = 0.35f; + + s_aPedSpheres[0].center = CVector(0.0f, 0.0f, -0.25f); + s_aPedSpheres[1].center = CVector(0.0f, 0.0f, 0.15f); + s_aPedSpheres[2].center = CVector(0.0f, 0.0f, 0.55f); + +#ifdef FIX_BUGS + for (i = 0; i < ARRAYSIZE(s_aPedSpheres); i++) { +#else + for (i = 0; i < ARRAYSIZE(s_aPedGSpheres); i++) { +#endif + s_aPedSpheres[i].surface = SURFACE_FLESH; + s_aPedSpheres[i].piece = 0; + } + + ms_colModelPed1.boundingSphere.Set(1.25f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); + ms_colModelPed1.boundingBox.Set(CVector(-0.35f, -0.35f, -1.0f), CVector(0.35f, 0.35f, 0.9f), SURFACE_DEFAULT, 0); + SET_COLMODEL_SPHERES(ms_colModelPed1, s_aPedSpheres); + + // Ped 2 Spheres + + s_aPed2Spheres[0].radius = 0.3f; + s_aPed2Spheres[1].radius = 0.4f; + s_aPed2Spheres[2].radius = 0.3f; + + s_aPed2Spheres[0].center = CVector(0.0f, 0.35f, -0.9f); + s_aPed2Spheres[1].center = CVector(0.0f, 0.0f, -0.9f); + s_aPed2Spheres[2].center = CVector(0.0f, -0.35f, -0.9f); + + for (i = 0; i < ARRAYSIZE(s_aPed2Spheres); i++) { + s_aPed2Spheres[i].surface = SURFACE_FLESH; + s_aPed2Spheres[i].piece = 0; + } + + ms_colModelPed2.boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); + ms_colModelPed2.boundingBox.Set(CVector(-0.7f, -0.7f, -1.2f), CVector(0.7f, 0.7f, 0.0f), SURFACE_DEFAULT, 0); + + SET_COLMODEL_SPHERES(ms_colModelPed2, s_aPed2Spheres); + + // Ped ground collision + + s_aPedGSpheres[0].radius = 0.35f; + s_aPedGSpheres[1].radius = 0.35f; + s_aPedGSpheres[2].radius = 0.35f; + s_aPedGSpheres[3].radius = 0.3f; + + s_aPedGSpheres[0].center = CVector(0.0f, -0.4f, -0.9f); + s_aPedGSpheres[1].center = CVector(0.0f, -0.1f, -0.9f); + s_aPedGSpheres[2].center = CVector(0.0f, 0.25f, -0.9f); + s_aPedGSpheres[3].center = CVector(0.0f, 0.65f, -0.9f); + + s_aPedGSpheres[0].surface = SURFACE_FLESH; + s_aPedGSpheres[1].surface = SURFACE_FLESH; + s_aPedGSpheres[2].surface = SURFACE_FLESH; + s_aPedGSpheres[3].surface = SURFACE_FLESH; + s_aPedGSpheres[0].piece = 4; + s_aPedGSpheres[1].piece = 1; + s_aPedGSpheres[2].piece = 0; + s_aPedGSpheres[3].piece = 6; + + ms_colModelPedGroundHit.boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); + ms_colModelPedGroundHit.boundingBox.Set(CVector(-0.4f, -1.0f, -1.25f), CVector(0.4f, 1.2f, -0.5f), SURFACE_DEFAULT, 0); + + SET_COLMODEL_SPHERES(ms_colModelPedGroundHit, s_aPedGSpheres); + + // Door Spheres + + s_aDoorSpheres[0].radius = 0.15f; + s_aDoorSpheres[1].radius = 0.15f; + s_aDoorSpheres[2].radius = 0.25f; + + s_aDoorSpheres[0].center = CVector(0.0f, -0.25f, -0.35f); + s_aDoorSpheres[1].center = CVector(0.0f, -0.95f, -0.35f); + s_aDoorSpheres[2].center = CVector(0.0f, -0.6f, 0.25f); + + for (i = 0; i < ARRAYSIZE(s_aDoorSpheres); i++) { + s_aDoorSpheres[i].surface = SURFACE_BILLBOARD; + s_aDoorSpheres[i].piece = 0; + } + + ms_colModelDoor1.boundingSphere.Set(1.5f, CVector(0.0f, -0.6f, 0.0f), SURFACE_DEFAULT, 0); + ms_colModelDoor1.boundingBox.Set(CVector(-0.3f, 0.0f, -0.6f), CVector(0.3f, -1.2f, 0.6f), SURFACE_DEFAULT, 0); + + SET_COLMODEL_SPHERES(ms_colModelDoor1, s_aDoorSpheres); + + // Bumper Spheres + + for (i = 0; i < ARRAYSIZE(s_aBumperSpheres); i++) + s_aBumperSpheres[i].radius = 0.15f; + + s_aBumperSpheres[0].center = CVector(0.85f, -0.05f, 0.0f); + s_aBumperSpheres[1].center = CVector(0.4f, 0.05f, 0.0f); + s_aBumperSpheres[2].center = CVector(-0.4f, 0.05f, 0.0f); + s_aBumperSpheres[3].center = CVector(-0.85f, -0.05f, 0.0f); + + for (i = 0; i < ARRAYSIZE(s_aBumperSpheres); i++) { + s_aBumperSpheres[i].surface = SURFACE_BILLBOARD; + s_aBumperSpheres[i].piece = 0; + } + + ms_colModelBumper1.boundingSphere.Set(2.2f, CVector(0.0f, -0.6f, 0.0f), SURFACE_DEFAULT, 0); + ms_colModelBumper1.boundingBox.Set(CVector(-1.2f, -0.3f, -0.2f), CVector(1.2f, 0.3f, -0.2f), SURFACE_DEFAULT, 0); + + SET_COLMODEL_SPHERES(ms_colModelBumper1, s_aBumperSpheres); + + // Panel Spheres + + for (i = 0; i < ARRAYSIZE(s_aPanelSpheres); i++) + s_aPanelSpheres[i].radius = 0.15f; + + s_aPanelSpheres[0].center = CVector(0.15f, 0.45f, 0.0f); + s_aPanelSpheres[1].center = CVector(0.15f, -0.45f, 0.0f); + s_aPanelSpheres[2].center = CVector(-0.15f, -0.45f, 0.0f); + s_aPanelSpheres[3].center = CVector(-0.15f, 0.45f, 0.0f); + + for (i = 0; i < ARRAYSIZE(s_aPanelSpheres); i++) { + s_aPanelSpheres[i].surface = SURFACE_BILLBOARD; + s_aPanelSpheres[i].piece = 0; + } + + ms_colModelPanel1.boundingSphere.Set(1.4f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); + ms_colModelPanel1.boundingBox.Set(CVector(-0.3f, -0.6f, -0.15f), CVector(0.3f, 0.6f, 0.15f), SURFACE_DEFAULT, 0); + + SET_COLMODEL_SPHERES(ms_colModelPanel1, s_aPanelSpheres); + + // Bonnet Spheres + + for (i = 0; i < ARRAYSIZE(s_aBonnetSpheres); i++) + s_aBonnetSpheres[i].radius = 0.2f; + + s_aBonnetSpheres[0].center = CVector(-0.4f, 0.1f, 0.0f); + s_aBonnetSpheres[1].center = CVector(-0.4f, 0.9f, 0.0f); + s_aBonnetSpheres[2].center = CVector(0.4f, 0.1f, 0.0f); + s_aBonnetSpheres[3].center = CVector(0.4f, 0.9f, 0.0f); + + for (i = 0; i < ARRAYSIZE(s_aBonnetSpheres); i++) { + s_aBonnetSpheres[i].surface = SURFACE_BILLBOARD; + s_aBonnetSpheres[i].piece = 0; + } + + ms_colModelBonnet1.boundingSphere.Set(1.7f, CVector(0.0f, 0.5f, 0.0f), SURFACE_DEFAULT, 0); + ms_colModelBonnet1.boundingBox.Set(CVector(-0.7f, -0.2f, -0.3f), CVector(0.7f, 1.2f, 0.3f), SURFACE_DEFAULT, 0); + + SET_COLMODEL_SPHERES(ms_colModelBonnet1, s_aBonnetSpheres); + + // Boot Spheres + + for (i = 0; i < ARRAYSIZE(s_aBootSpheres); i++) + s_aBootSpheres[i].radius = 0.2f; + + s_aBootSpheres[0].center = CVector(-0.4f, -0.1f, 0.0f); + s_aBootSpheres[1].center = CVector(-0.4f, -0.6f, 0.0f); + s_aBootSpheres[2].center = CVector(0.4f, -0.1f, 0.0f); + s_aBootSpheres[3].center = CVector(0.4f, -0.6f, 0.0f); + + for (i = 0; i < ARRAYSIZE(s_aBootSpheres); i++) { + s_aBootSpheres[i].surface = SURFACE_BILLBOARD; + s_aBootSpheres[i].piece = 0; + } + + ms_colModelBoot1.boundingSphere.Set(1.4f, CVector(0.0f, -0.4f, 0.0f), SURFACE_DEFAULT, 0); + ms_colModelBoot1.boundingBox.Set(CVector(-0.7f, -0.9f, -0.3f), CVector(0.7f, 0.2f, 0.3f), SURFACE_DEFAULT, 0); + + SET_COLMODEL_SPHERES(ms_colModelBoot1, s_aBootSpheres); + + // Wheel Spheres + + s_aWheelSpheres[0].radius = 0.35f; + s_aWheelSpheres[1].radius = 0.35f; + + s_aWheelSpheres[0].center = CVector(-0.3f, 0.0f, 0.0f); + s_aWheelSpheres[1].center = CVector(0.3f, 0.0f, 0.0f); + +#ifdef FIX_BUGS + for (i = 0; i < ARRAYSIZE(s_aWheelSpheres); i++) { +#else + for (i = 0; i < ARRAYSIZE(s_aBootSpheres); i++) { +#endif + s_aWheelSpheres[i].surface = SURFACE_RUBBER29; + s_aWheelSpheres[i].piece = 0; + } + + ms_colModelWheel1.boundingSphere.Set(1.4f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); + ms_colModelWheel1.boundingBox.Set(CVector(-0.7f, -0.4f, -0.4f), CVector(0.7f, 0.4f, 0.4f), SURFACE_DEFAULT, 0); + + SET_COLMODEL_SPHERES(ms_colModelWheel1, s_aWheelSpheres); + + // Body Part Spheres 1 + + s_aBodyPartSpheres1[0].radius = 0.2f; + s_aBodyPartSpheres1[1].radius = 0.2f; + + s_aBodyPartSpheres1[0].center = CVector(0.0f, 0.0f, 0.0f); + s_aBodyPartSpheres1[1].center = CVector(0.8f, 0.0f, 0.0f); + +#ifdef FIX_BUGS + for (i = 0; i < ARRAYSIZE(s_aBodyPartSpheres1); i++) { +#else + for (i = 0; i < ARRAYSIZE(s_aBootSpheres); i++) { +#endif + s_aBodyPartSpheres1[i].surface = SURFACE_FLESH; + s_aBodyPartSpheres1[i].piece = 0; + } + + ms_colModelBodyPart1.boundingSphere.Set(0.7f, CVector(0.4f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); + ms_colModelBodyPart1.boundingBox.Set(CVector(-0.3f, -0.3f, -0.3f), CVector(1.1f, 0.3f, 0.3f), SURFACE_DEFAULT, 0); + + SET_COLMODEL_SPHERES(ms_colModelBodyPart1, s_aBodyPartSpheres1); + + // Body Part Spheres 2 + + s_aBodyPartSpheres2[0].radius = 0.15f; + s_aBodyPartSpheres2[1].radius = 0.15f; + + s_aBodyPartSpheres2[0].center = CVector(0.0f, 0.0f, 0.0f); + s_aBodyPartSpheres2[1].center = CVector(0.5f, 0.0f, 0.0f); + +#ifdef FIX_BUGS + for (i = 0; i < ARRAYSIZE(s_aBodyPartSpheres2); i++) { +#else + for (i = 0; i < ARRAYSIZE(s_aBootSpheres); i++) { +#endif + s_aBodyPartSpheres2[i].surface = SURFACE_FLESH; + s_aBodyPartSpheres2[i].piece = 0; + } + + ms_colModelBodyPart2.boundingSphere.Set(0.5f, CVector(0.25f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); + ms_colModelBodyPart2.boundingBox.Set(CVector(-0.2f, -0.2f, -0.2f), CVector(0.7f, 0.2f, 0.2f), SURFACE_DEFAULT, 0); + + SET_COLMODEL_SPHERES(ms_colModelBodyPart2, s_aBodyPartSpheres2); + +#undef SET_COLMODEL_SPHERES +} + +STARTPATCHES + InjectHook(0x412160, CTempColModels::Initialise, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/TxdStore.cpp b/src/core/TxdStore.cpp index 5085c7e4..ab970b99 100644 --- a/src/core/TxdStore.cpp +++ b/src/core/TxdStore.cpp @@ -1,6 +1,7 @@ #include "common.h" #include "patcher.h" #include "templates.h" +#include "General.h" #include "Streaming.h" #include "RwHelper.h" #include "TxdStore.h" @@ -61,7 +62,7 @@ CTxdStore::FindTxdSlot(const char *name) int size = ms_pTxdPool->GetSize(); for(int i = 0; i < size; i++){ defname = GetTxdName(i); - if(defname && _strcmpi(defname, name) == 0) + if(defname && !CGeneral::faststricmp(defname, name)) return i; } return -1; diff --git a/src/core/User.cpp b/src/core/User.cpp index 600fa443..488d64be 100644 --- a/src/core/User.cpp +++ b/src/core/User.cpp @@ -140,7 +140,7 @@ bool COnscreenTimerEntry::ProcessForDisplay() { if(m_nTimerOffset != 0) { m_bTimerProcessed = true; - ProcessForDisplayTimer(); + ProcessForDisplayClock(); } if(m_nCounterOffset != 0) { @@ -150,21 +150,21 @@ bool COnscreenTimerEntry::ProcessForDisplay() { return true; } -int COnscreenTimerEntry::ProcessForDisplayTimer() { +void COnscreenTimerEntry::ProcessForDisplayClock() { uint32 time = *(uint32*)&CTheScripts::ScriptSpace[m_nTimerOffset]; - return sprintf(m_bTimerBuffer, "%02d:%02d", time / 1000 / 60, + sprintf(m_bTimerBuffer, "%02d:%02d", time / 1000 / 60, time / 1000 % 60); } -int COnscreenTimerEntry::ProcessForDisplayCounter() { +void COnscreenTimerEntry::ProcessForDisplayCounter() { uint32 counter = *(uint32*)&CTheScripts::ScriptSpace[m_nCounterOffset]; - return sprintf(m_bCounterBuffer, "%d", counter); + sprintf(m_bCounterBuffer, "%d", counter); } STARTPATCHES InjectHook(0x429160, &COnscreenTimerEntry::Process, PATCH_JUMP); InjectHook(0x429110, &COnscreenTimerEntry::ProcessForDisplay, PATCH_JUMP); - InjectHook(0x429080, &COnscreenTimerEntry::ProcessForDisplayTimer, PATCH_JUMP); + InjectHook(0x429080, &COnscreenTimerEntry::ProcessForDisplayClock, PATCH_JUMP); InjectHook(0x4290F0, &COnscreenTimerEntry::ProcessForDisplayCounter, PATCH_JUMP); InjectHook(0x429220, &COnscreenTimer::Init, PATCH_JUMP); diff --git a/src/core/User.h b/src/core/User.h index 90b2da55..03ba1bab 100644 --- a/src/core/User.h +++ b/src/core/User.h @@ -18,8 +18,8 @@ public: void Process(); bool ProcessForDisplay(); - int ProcessForDisplayTimer(); - int ProcessForDisplayCounter(); + void ProcessForDisplayClock(); + void ProcessForDisplayCounter(); }; static_assert(sizeof(COnscreenTimerEntry) == 0x74, "COnscreenTimerEntry: error"); diff --git a/src/core/World.cpp b/src/core/World.cpp index ae0d67cc..dac64970 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -859,8 +859,8 @@ FindPlayerPed(void) CVehicle* FindPlayerVehicle(void) { - CPlayerPed *ped = CWorld::Players[CWorld::PlayerInFocus].m_pPed; - if(ped->bInVehicle && ped->m_pMyVehicle) + CPlayerPed *ped = FindPlayerPed(); + if(ped->InVehicle()) return ped->m_pMyVehicle; else return nil; @@ -878,8 +878,8 @@ FindPlayerTrain(void) CEntity* FindPlayerEntity(void) { - CPlayerPed *ped = CWorld::Players[CWorld::PlayerInFocus].m_pPed; - if(ped->bInVehicle && ped->m_pMyVehicle) + CPlayerPed *ped = FindPlayerPed(); + if(ped->InVehicle()) return ped->m_pMyVehicle; else return ped; @@ -888,8 +888,8 @@ FindPlayerEntity(void) CVector FindPlayerCoors(void) { - CPlayerPed *ped = CWorld::Players[CWorld::PlayerInFocus].m_pPed; - if(ped->bInVehicle && ped->m_pMyVehicle) + CPlayerPed *ped = FindPlayerPed(); + if(ped->InVehicle()) return ped->m_pMyVehicle->GetPosition(); else return ped->GetPosition(); @@ -898,8 +898,8 @@ FindPlayerCoors(void) CVector& FindPlayerSpeed(void) { - CPlayerPed *ped = CWorld::Players[CWorld::PlayerInFocus].m_pPed; - if(ped->bInVehicle && ped->m_pMyVehicle) + CPlayerPed *ped = FindPlayerPed(); + if(ped->InVehicle()) return ped->m_pMyVehicle->m_vecMoveSpeed; else return ped->m_vecMoveSpeed; @@ -926,7 +926,7 @@ FindPlayerCentreOfWorld_NoSniperShift(void) return CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle->GetPosition(); if(FindPlayerVehicle()) return FindPlayerVehicle()->GetPosition(); - return CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetPosition(); + return FindPlayerPed()->GetPosition(); } float @@ -936,7 +936,7 @@ FindPlayerHeading(void) return CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle->GetForward().Heading(); if(FindPlayerVehicle()) return FindPlayerVehicle()->GetForward().Heading(); - return CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetForward().Heading(); + return FindPlayerPed()->GetForward().Heading(); } void @@ -1012,6 +1012,30 @@ CWorld::StopAllLawEnforcersInTheirTracks(void) } void +CWorld::SetAllCarsCanBeDamaged(bool toggle) +{ + int poolSize = CPools::GetVehiclePool()->GetSize(); + for (int poolIndex = 0; poolIndex < poolSize; poolIndex++) { + CVehicle *veh = CPools::GetVehiclePool()->GetSlot(poolIndex); + if (veh) + veh->bCanBeDamaged = toggle; + } +} + +void +CWorld::ExtinguishAllCarFiresInArea(CVector point, float range) +{ + int poolSize = CPools::GetVehiclePool()->GetSize(); + for (int poolIndex = 0; poolIndex < poolSize; poolIndex++) { + CVehicle* veh = CPools::GetVehiclePool()->GetSlot(poolIndex); + if (veh) { + if ((point - veh->GetPosition()).MagnitudeSqr() < sq(range)) + veh->ExtinguishCarFire(); + } + } +} + +void CWorld::Process(void) { if (!(CTimer::GetFrameCounter() & 63)) @@ -1212,5 +1236,9 @@ STARTPATCHES InjectHook(0x4B3AE0, CWorld::FindGroundZFor3DCoord, PATCH_JUMP); InjectHook(0x4B3B50, CWorld::FindRoofZFor3DCoord, PATCH_JUMP); + InjectHook(0x4B5BC0, CWorld::StopAllLawEnforcersInTheirTracks, PATCH_JUMP); + InjectHook(0x4B53F0, CWorld::SetAllCarsCanBeDamaged, PATCH_JUMP); + InjectHook(0x4B5460, CWorld::ExtinguishAllCarFiresInArea, PATCH_JUMP); + InjectHook(0x4B1A60, CWorld::Process, PATCH_JUMP); ENDPATCHES diff --git a/src/core/World.h b/src/core/World.h index 3b04403e..119c6324 100644 --- a/src/core/World.h +++ b/src/core/World.h @@ -121,6 +121,8 @@ public: static void RemoveFallenCars(); static void StopAllLawEnforcersInTheirTracks(); + static void SetAllCarsCanBeDamaged(bool); + static void ExtinguishAllCarFiresInArea(CVector, float); static void Initialise(); static void ShutDown(); diff --git a/src/core/common.h b/src/core/common.h index fd5f35b0..cadcac1d 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -153,6 +153,10 @@ public: #endif }; +#if (defined(_MSC_VER)) +extern int strcasecmp(const char *str1, const char *str2); +#endif + #define clamp(v, low, high) ((v)<(low) ? (low) : (v)>(high) ? (high) : (v)) inline float sq(float x) { return x*x; } diff --git a/src/core/config.h b/src/core/config.h index 175a5f61..166c2a68 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -87,6 +87,7 @@ enum Config { NUM_FIRES = 40, NUMPEDROUTES = 200, + NUMPHONES = 50, NUMVISIBLEENTITIES = 2000, NUMINVISIBLEENTITIES = 150, @@ -145,6 +146,7 @@ enum Config { #endif #define FIX_BUGS // fixes bugs that we've came across during reversing, TODO: use this more +#define TOGGLEABLE_BETA_FEATURES // toggleable from debug menu. doesn't have too many things // Pad #define KANGAROO_CHEAT diff --git a/src/core/re3.cpp b/src/core/re3.cpp index d6bc8148..d3b8200d 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -29,12 +29,10 @@ void **rwengine = *(void***)0x5A10E1; DebugMenuAPI gDebugMenuAPI; -WRAPPER void *gtanew(uint32 sz) { EAXJMP(0x5A0690); } -WRAPPER void gtadelete(void *p) { EAXJMP(0x5A07E0); } - -// overload our own new/delete with GTA's functions -void *operator new(size_t sz) { return gtanew(sz); } -void operator delete(void *ptr) noexcept { gtadelete(ptr); } +STARTPATCHES + InjectHook(0x5A07E0, (void (*)(void*)) &operator delete, PATCH_JUMP); + InjectHook(0x5A0690, (void* (*)(size_t)) &operator new, PATCH_JUMP); +ENDPATCHES #ifdef USE_PS2_RAND unsigned __int64 myrand_seed = 1; @@ -351,10 +349,11 @@ DebugMenuPopulate(void) DebugMenuAddVarBool8("Debug", "Don't render Objects", (int8*)&gbDontRenderObjects, nil); DebugMenuAddCmd("Debug", "Make peds follow you in formation", LetThemFollowYou); -#ifndef MASTER +#ifdef TOGGLEABLE_BETA_FEATURES DebugMenuAddVarBool8("Debug", "Toggle unused fight feature", (int8*)&CPed::bUnusedFightThingOnPlayer, nil); DebugMenuAddVarBool8("Debug", "Toggle banned particles", (int8*)&CParticle::bEnableBannedParticles, nil); DebugMenuAddVarBool8("Debug", "Toggle popping heads on headshot", (int8*)&CPed::bPopHeadsOnHeadshot, nil); + DebugMenuAddVarBool8("Debug", "Toggle peds running to phones to report crimes", (int8*)&CPed::bMakePedsRunToPhonesToReportCrimes, nil); #endif DebugMenuAddCmd("Debug", "Start Credits", CCredits::Start); diff --git a/src/entities/Entity.h b/src/entities/Entity.h index 11d3e8cd..99cc7f17 100644 --- a/src/entities/Entity.h +++ b/src/entities/Entity.h @@ -84,7 +84,7 @@ public: uint32 m_flagE2 : 1; uint16 m_scanCode; - int16 m_randomSeed; + uint16 m_randomSeed; int16 m_modelIndex; uint16 m_level; // int16 CReference *m_pFirstReference; diff --git a/src/modelinfo/ClumpModelInfo.cpp b/src/modelinfo/ClumpModelInfo.cpp index d666313b..c6a6d5d0 100644 --- a/src/modelinfo/ClumpModelInfo.cpp +++ b/src/modelinfo/ClumpModelInfo.cpp @@ -1,5 +1,6 @@ #include "common.h" #include "patcher.h" +#include "General.h" #include "NodeName.h" #include "VisibilityPlugins.h" #include "ModelInfo.h" @@ -86,7 +87,7 @@ CClumpModelInfo::FindFrameFromNameCB(RwFrame *frame, void *data) { RwObjectNameAssociation *assoc = (RwObjectNameAssociation*)data; - if(_strcmpi(GetFrameNodeName(frame), assoc->name) != 0){ + if(CGeneral::faststricmp(GetFrameNodeName(frame), assoc->name)){ RwFrameForAllChildren(frame, FindFrameFromNameCB, assoc); return assoc->frame ? nil : frame; }else{ @@ -101,7 +102,7 @@ CClumpModelInfo::FindFrameFromNameWithoutIdCB(RwFrame *frame, void *data) RwObjectNameAssociation *assoc = (RwObjectNameAssociation*)data; if(CVisibilityPlugins::GetFrameHierarchyId(frame) || - _strcmpi(GetFrameNodeName(frame), assoc->name) != 0){ + CGeneral::faststricmp(GetFrameNodeName(frame), assoc->name)){ RwFrameForAllChildren(frame, FindFrameFromNameWithoutIdCB, assoc); return assoc->frame ? nil : frame; }else{ diff --git a/src/modelinfo/ModelIndices.cpp b/src/modelinfo/ModelIndices.cpp index bf6b3905..ec039a0b 100644 --- a/src/modelinfo/ModelIndices.cpp +++ b/src/modelinfo/ModelIndices.cpp @@ -1,5 +1,6 @@ #include "common.h" #include "patcher.h" +#include "General.h" #include "ModelIndices.h" #define X(name, var, addr) int16 &var = *(int16*)addr; @@ -18,7 +19,7 @@ void MatchModelString(const char *modelname, int16 id) { #define X(name, var, addr) \ - if(strcmp(name, modelname) == 0){ \ + if(!CGeneral::faststrcmp(name, modelname)){ \ var = id; \ return; \ } diff --git a/src/modelinfo/ModelInfo.cpp b/src/modelinfo/ModelInfo.cpp index 0c3ec76a..c7e18e5f 100644 --- a/src/modelinfo/ModelInfo.cpp +++ b/src/modelinfo/ModelInfo.cpp @@ -1,5 +1,6 @@ #include "common.h" #include "patcher.h" +#include "General.h" #include "TempColModels.h" #include "ModelIndices.h" #include "ModelInfo.h" @@ -159,7 +160,7 @@ CModelInfo::GetModelInfo(const char *name, int *id) CBaseModelInfo *modelinfo; for(int i = 0; i < MODELINFOSIZE; i++){ modelinfo = CModelInfo::ms_modelInfoPtrs[i]; - if(modelinfo && _strcmpi(modelinfo->GetName(), name) == 0){ + if(modelinfo && !CGeneral::faststricmp(modelinfo->GetName(), name)){ if(id) *id = i; return modelinfo; diff --git a/src/modelinfo/PedModelInfo.cpp b/src/modelinfo/PedModelInfo.cpp index afe177c2..7b087fbd 100644 --- a/src/modelinfo/PedModelInfo.cpp +++ b/src/modelinfo/PedModelInfo.cpp @@ -1,5 +1,6 @@ #include "common.h" #include "patcher.h" +#include "General.h" #include "Ped.h" #include "NodeName.h" #include "VisibilityPlugins.h" @@ -60,7 +61,7 @@ FindPedFrameFromNameCB(RwFrame *frame, void *data) { RwObjectNameAssociation *assoc = (RwObjectNameAssociation*)data; - if(_strcmpi(GetFrameNodeName(frame)+1, assoc->name+1) != 0){ + if(CGeneral::faststricmp(GetFrameNodeName(frame)+1, assoc->name+1)){ RwFrameForAllChildren(frame, FindPedFrameFromNameCB, assoc); return assoc->frame ? nil : frame; }else{ diff --git a/src/modelinfo/SimpleModelInfo.cpp b/src/modelinfo/SimpleModelInfo.cpp index dd5010fa..f8742f1e 100644 --- a/src/modelinfo/SimpleModelInfo.cpp +++ b/src/modelinfo/SimpleModelInfo.cpp @@ -1,5 +1,6 @@ #include "common.h" #include "patcher.h" +#include "General.h" #include "Camera.h" #include "ModelInfo.h" @@ -131,7 +132,7 @@ CSimpleModelInfo::FindRelatedModel(void) for(i = 0; i < MODELINFOSIZE; i++){ mi = CModelInfo::GetModelInfo(i); if(mi && mi != this && - strcmp(GetName()+3, mi->GetName()+3) == 0){ + !CGeneral::faststrcmp(GetName()+3, mi->GetName()+3)){ assert(mi->IsSimple()); this->SetRelatedModel((CSimpleModelInfo*)mi); return; diff --git a/src/objects/CutsceneHead.cpp b/src/objects/CutsceneHead.cpp index c423d0b8..8c417973 100644 --- a/src/objects/CutsceneHead.cpp +++ b/src/objects/CutsceneHead.cpp @@ -9,6 +9,7 @@ #include "CutsceneMgr.h" #include "Streaming.h" #include "CutsceneHead.h" +#include "CdStream.h" CCutsceneHead::CCutsceneHead(CObject *obj) @@ -94,7 +95,7 @@ CCutsceneHead::PlayAnimation(const char *animName) stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, "ANIM\\CUTS.IMG"); assert(stream); - CStreaming::MakeSpaceFor(size*2048); + CStreaming::MakeSpaceFor(size * CDSTREAM_SECTOR_SIZE); CStreaming::ImGonnaUseStreamingMemory(); RwStreamSkip(stream, offset*2048); diff --git a/src/objects/ParticleObject.cpp b/src/objects/ParticleObject.cpp index 35811289..881510e8 100644 --- a/src/objects/ParticleObject.cpp +++ b/src/objects/ParticleObject.cpp @@ -9,7 +9,7 @@ #include "Game.h" -CParticleObject (&gPObjectArray)[MAX_PARTICLEOBJECTS] = *(CParticleObject(*)[MAX_PARTICLEOBJECTS])int(0x62A58C); +CParticleObject (&gPObjectArray)[MAX_PARTICLEOBJECTS] = *(CParticleObject(*)[MAX_PARTICLEOBJECTS])*(uintptr*)0x62A58C; CParticleObject *&CParticleObject::pCloseListHead = *(CParticleObject **)int(0x8F4340); CParticleObject *&CParticleObject::pFarListHead = *(CParticleObject **)int(0x942F78); diff --git a/src/peds/CivilianPed.cpp b/src/peds/CivilianPed.cpp index 93cdcb3d..6fce25e8 100644 --- a/src/peds/CivilianPed.cpp +++ b/src/peds/CivilianPed.cpp @@ -2,25 +2,415 @@ #include "patcher.h" #include "CivilianPed.h" #include "Phones.h" - -WRAPPER void CCivilianPed::ProcessControl(void) { EAXJMP(0x4BFFE0); } +#include "General.h" +#include "PlayerPed.h" +#include "World.h" +#include "Vehicle.h" +#include "SurfaceTable.h" CCivilianPed::CCivilianPed(int pedtype, int mi) : CPed(pedtype) { SetModelIndex(mi); - for (int i = 0; i < 10; i++) { + for (int i = 0; i < ARRAY_SIZE(m_nearPeds); i++) { m_nearPeds[i] = nil; } } +void +CCivilianPed::CivilianAI(void) +{ + if (CTimer::GetTimeInMilliseconds() <= m_fleeTimer || m_objective != OBJECTIVE_NONE && !bRespondsToThreats + || !IsPedInControl()) { + + if (m_objective == OBJECTIVE_GUARD_SPOT) + return; + + if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS) { + if (m_pedInObjective) { + if (m_pedInObjective->IsPlayer()) + return; + } + } + if (CTimer::GetTimeInMilliseconds() <= m_lookTimer) + return; + + uint32 closestThreatFlag = ScanForThreats(); + if (closestThreatFlag == PED_FLAG_EXPLOSION) { + float angleToFace = CGeneral::GetRadianAngleBetweenPoints( + m_eventOrThreat.x, m_eventOrThreat.y, + GetPosition().x, GetPosition().y); + SetLookFlag(angleToFace, true); + SetLookTimer(500); + + } else if (closestThreatFlag == PED_FLAG_GUN) { + SetLookFlag(m_threatEntity, true); + SetLookTimer(500); + } + return; + } + uint32 closestThreatFlag = ScanForThreats(); + if (closestThreatFlag == PED_FLAG_GUN) { + if (!m_threatEntity || !m_threatEntity->IsPed()) + return; + + CPed *threatPed = (CPed*)m_threatEntity; + float threatDistSqr = (m_threatEntity->GetPosition() - GetPosition()).MagnitudeSqr2D(); + if (m_pedStats->m_fear <= m_pedStats->m_lawfulness) { + if (m_pedStats->m_temper <= m_pedStats->m_fear) { + if (!threatPed->IsPlayer() || !RunToReportCrime(CRIME_POSSESSION_GUN)) { + if (threatDistSqr < sq(10.0f)) { + Say(SOUND_PED_FLEE_SPRINT); + SetFlee(m_threatEntity, 10000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + } else { + SetFlee(m_threatEntity->GetPosition(), 5000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + SetMoveState(PEDMOVE_WALK); + } + } + } else if (m_objective != OBJECTIVE_NONE || GetWeapon()->IsTypeMelee()) { + SetFlee(m_threatEntity, 5000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + if (threatDistSqr < sq(20.0f)) { + SetMoveState(PEDMOVE_RUN); + Say(SOUND_PED_FLEE_SPRINT); + } else { + SetMoveState(PEDMOVE_WALK); + } + } else if (threatPed->IsPlayer() && FindPlayerPed()->m_pWanted->m_CurrentCops) { + SetFlee(m_threatEntity, 5000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + if (threatDistSqr < sq(10.0f)) { + SetMoveState(PEDMOVE_RUN); + } else { + SetMoveState(PEDMOVE_WALK); + } + } else { + SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, m_threatEntity); + } + } else { + if (threatDistSqr < sq(10.0f)) { + Say(SOUND_PED_FLEE_SPRINT); + SetFlee(m_threatEntity, 10000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + SetMoveState(PEDMOVE_SPRINT); + } else { + Say(SOUND_PED_FLEE_SPRINT); + SetFlee(m_threatEntity, 5000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + SetMoveState(PEDMOVE_RUN); + } + } + SetLookFlag(m_threatEntity, false); + SetLookTimer(500); + } else if (closestThreatFlag == PED_FLAG_DEADPEDS) { + float eventDistSqr = (m_pEventEntity->GetPosition() - GetPosition()).MagnitudeSqr2D(); + if (IsGangMember() && m_nPedType == ((CPed*)m_pEventEntity)->m_nPedType) { + if (eventDistSqr < sq(5.0f)) { + SetFlee(m_pEventEntity, 2000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + SetMoveState(PEDMOVE_RUN); + } + } else if (IsGangMember() || eventDistSqr > sq(5.0f)) { + bool investigateDeadPed = true; + CEntity *killerOfDeadPed = ((CPed*)m_pEventEntity)->m_threatEntity; + if (killerOfDeadPed && killerOfDeadPed->IsPed()) { + CVector killerPos = killerOfDeadPed->GetPosition(); + CVector deadPedPos = m_pEventEntity->GetPosition(); + if (CVector2D(killerPos - deadPedPos).MagnitudeSqr() < sq(10.0f)) + investigateDeadPed = false; + } + +#ifdef TOGGLEABLE_BETA_FEATURES + eCrimeType crime = (((CPed*)m_pEventEntity)->m_ped_flagI40 ? + (((CPed*)m_pEventEntity)->m_nPedType == PEDTYPE_COP ? CRIME_RUNOVER_COP : CRIME_RUNOVER_PED) : + (((CPed*)m_pEventEntity)->m_nPedType == PEDTYPE_COP ? CRIME_SHOOT_COP : CRIME_SHOOT_PED)); + bool eligibleToReport = bMakePedsRunToPhonesToReportCrimes && killerOfDeadPed && killerOfDeadPed->IsPed() && ((CPed*)killerOfDeadPed)->IsPlayer() && + m_pedStats->m_fear <= m_pedStats->m_lawfulness && m_pedStats->m_temper <= m_pedStats->m_fear; + if (IsGangMember() || !eligibleToReport || !RunToReportCrime(crime)) +#endif + if (investigateDeadPed) + SetInvestigateEvent(EVENT_DEAD_PED, CVector2D(m_pEventEntity->GetPosition()), 1.0f, 20000, 0.0f); + + } else { +#ifdef TOGGLEABLE_BETA_FEATURES + CEntity* killerOfDeadPed = ((CPed*)m_pEventEntity)->m_threatEntity; + eCrimeType crime = (((CPed*)m_pEventEntity)->m_ped_flagI40 ? + (((CPed*)m_pEventEntity)->m_nPedType == PEDTYPE_COP ? CRIME_RUNOVER_COP : CRIME_RUNOVER_PED) : + (((CPed*)m_pEventEntity)->m_nPedType == PEDTYPE_COP ? CRIME_SHOOT_COP : CRIME_SHOOT_PED)); + bool eligibleToReport = bMakePedsRunToPhonesToReportCrimes && killerOfDeadPed && killerOfDeadPed->IsPed() && ((CPed*)killerOfDeadPed)->IsPlayer() && + m_pedStats->m_fear <= m_pedStats->m_lawfulness && m_pedStats->m_temper <= m_pedStats->m_fear; + if(!eligibleToReport || !RunToReportCrime(crime)) +#endif + { + SetFlee(m_pEventEntity, 5000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + SetMoveState(PEDMOVE_RUN); + } + } + } else if (closestThreatFlag == PED_FLAG_EXPLOSION) { + CVector2D eventDistVec = m_eventOrThreat - GetPosition(); + float eventDistSqr = eventDistVec.MagnitudeSqr(); + if (eventDistSqr < sq(20.0f)) { + Say(SOUND_PED_FLEE_SPRINT); + SetFlee(m_eventOrThreat, 2000); + float angleToFace = CGeneral::GetRadianAngleBetweenPoints( + m_eventOrThreat.x, m_eventOrThreat.y, + GetPosition().x, GetPosition().y); + SetLookFlag(angleToFace, true); + SetLookTimer(500); + } else if (eventDistSqr < sq(40.0f)) { + if (m_ped_flagD2) { + if (CharCreatedBy != MISSION_CHAR && !IsGangMember()) + SetInvestigateEvent(EVENT_EXPLOSION, m_eventOrThreat, 6.0f, 30000, 0.0f); + + } else { + float eventHeading = CGeneral::GetRadianAngleBetweenPoints(eventDistVec.x, eventDistVec.y, 0.0f, 0.0f); + eventHeading = CGeneral::LimitRadianAngle(eventHeading); + if (eventHeading < 0.0f) + eventHeading = eventHeading + TWOPI; + + SetWanderPath(eventHeading / 8.0f); + } + } + } else { + if (m_threatEntity && m_threatEntity->IsPed()) { + CPed *threatPed = (CPed*)m_threatEntity; + if (m_pedStats->m_fear <= 100 - threatPed->m_pedStats->m_temper && threatPed->m_nPedType != PEDTYPE_COP) { + if (threatPed->GetWeapon()->IsTypeMelee() || !GetWeapon()->IsTypeMelee()) { + if (threatPed->IsPlayer() && FindPlayerPed()->m_pWanted->m_CurrentCops) { + if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS) { + SetFlee(m_threatEntity, 10000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + } + } else { + SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, m_threatEntity); + } + } + } else { + SetFlee(m_threatEntity, 10000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + SetMoveState(PEDMOVE_WALK); + } + } + } +} + +void +CCivilianPed::ProcessControl(void) +{ + if (m_nZoneLevel > LEVEL_NONE && m_nZoneLevel != CCollision::ms_collisionInMemory) + return; + + CPed::ProcessControl(); + + if (bWasPostponed) + return; + + if (DyingOrDead()) + return; + + GetWeapon()->Update(m_audioEntityId); + switch (m_nPedState) { + case PED_WANDER_RANGE: + case PED_WANDER_PATH: + if (IsVisible()) + ScanForInterestingStuff(); + break; + case PED_SEEK_ENTITY: + if (!m_pSeekTarget) { + RestorePreviousState(); + break; + } + m_vecSeekPos = m_pSeekTarget->GetPosition(); + + // fall through + case PED_SEEK_POS: + if (Seek()) { + if ((m_objective == OBJECTIVE_GOTO_AREA_ON_FOOT || m_objective == OBJECTIVE_RUN_TO_AREA) && m_pNextPathNode) { + m_pNextPathNode = nil; +#ifdef TOGGLEABLE_BETA_FEATURES + } else if (bRunningToPhone && m_objective < OBJECTIVE_FLEE_TILL_SAFE) { + if (!isPhoneAvailable(m_phoneId)) { + RestorePreviousState(); + crimeReporters[m_phoneId] = nil; + m_phoneId = -1; + bRunningToPhone = false; + } else { + crimeReporters[m_phoneId] = this; + m_nPedState = PED_FACE_PHONE; + } +#else + } else if (bRunningToPhone) { + if (gPhoneInfo.m_aPhones[m_phoneId].m_nState != PHONE_STATE_FREE) { + RestorePreviousState(); + m_phoneId = -1; + } else { + gPhoneInfo.m_aPhones[m_phoneId].m_nState = PHONE_STATE_REPORTING_CRIME; + m_nPedState = PED_FACE_PHONE; + } +#endif + } else if (m_objective != OBJECTIVE_KILL_CHAR_ANY_MEANS && m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT) { + if (m_objective == OBJECTIVE_FOLLOW_PED_IN_FORMATION) { + if (m_moved.Magnitude() == 0.0f) { + if (m_pedInObjective->m_nMoveState == PEDMOVE_STILL) + m_fRotationDest = m_pedInObjective->m_fRotationCur; + } + } else if (m_objective == OBJECTIVE_GOTO_CHAR_ON_FOOT + && m_pedInObjective && m_pedInObjective->m_nMoveState != PEDMOVE_STILL) { + SetMoveState(m_pedInObjective->m_nMoveState); + } else if (m_objective == OBJECTIVE_GOTO_AREA_ON_FOOT || m_objective == OBJECTIVE_RUN_TO_AREA) { + SetIdle(); + } else { + RestorePreviousState(); + } + } + } + break; + case PED_FACE_PHONE: + if (FacePhone()) + m_nPedState = PED_MAKE_CALL; + break; + case PED_MAKE_CALL: + if (MakePhonecall()) + SetWanderPath(CGeneral::GetRandomNumber() & 7); + break; + case PED_MUG: + Mug(); + break; + case PED_SOLICIT: + Solicit(); + break; + case PED_UNKNOWN: + { + int pedsInSameState = 0; + Idle(); + for (int i = 0; i < m_numNearPeds; ++i) { + CPed *nearPed = m_nearPeds[i]; + if (nearPed->m_nPedType == m_nPedType && nearPed->m_nPedState == PED_UNKNOWN) { + ++pedsInSameState; + } + } + if (pedsInSameState < 5) { + for (int j = 0; j < m_numNearPeds; ++j) { + CPed *nearPed = m_nearPeds[j]; + if (nearPed->m_nPedType == m_nPedType && nearPed->m_nPedState == PED_WANDER_PATH) { + nearPed->m_nPedState = PED_UNKNOWN; + } + } + } + break; + } + case PED_DRIVING: + if (m_nPedType != PEDTYPE_PROSTITUTE) + break; + + if (CWorld::Players[CWorld::PlayerInFocus].m_pHooker != this) + break; + + if (CTimer::GetTimeInMilliseconds() > CWorld::Players[CWorld::PlayerInFocus].m_nNextSexFrequencyUpdateTime) { + if (m_nPedState == PED_DRIVING + && m_pMyVehicle->pDriver && m_pMyVehicle->pDriver->IsPlayer() && m_pMyVehicle->pDriver->m_nPedState == PED_DRIVING) { + CColPoint foundCol; + CEntity* foundEnt; + + CWorld::ProcessVerticalLine(m_pMyVehicle->GetPosition(), -100.0f, + foundCol, foundEnt, true, false, false, false, false, false, nil); + + if (m_pMyVehicle->m_vecMoveSpeed.MagnitudeSqr() < sq(0.01f) + && foundCol.surfaceB != SURFACE_DEFAULT && foundCol.surfaceB != SURFACE_TARMAC && foundCol.surfaceB != SURFACE_PAVEMENT) { + + if (m_pMyVehicle->CarHasRoof()) { + m_pMyVehicle->ApplyTurnForce(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(-0.8f, -1.2f) * m_fMass, + GetPosition().x - m_pMyVehicle->GetPosition().x, GetPosition().y - m_pMyVehicle->GetPosition().y, 0.0f); + + DMAudio.PlayOneShot(m_pMyVehicle->m_audioEntityId, SOUND_CAR_JERK, 0.0f); + + int playerSexFrequency = CWorld::Players[CWorld::PlayerInFocus].m_nSexFrequency; + if (CWorld::Players[CWorld::PlayerInFocus].m_nMoney >= 10 && playerSexFrequency > 250) { + CWorld::Players[CWorld::PlayerInFocus].m_nNextSexFrequencyUpdateTime = CTimer::GetTimeInMilliseconds() + playerSexFrequency; + if (playerSexFrequency >= 350) { + CWorld::Players[CWorld::PlayerInFocus].m_nSexFrequency = max(250, playerSexFrequency - 30); + } else { + CWorld::Players[CWorld::PlayerInFocus].m_nSexFrequency = max(250, playerSexFrequency - 10); + } + + m_pMyVehicle->pDriver->m_fHealth = min(125.0f, 1.0f + m_pMyVehicle->pDriver->m_fHealth); + if (CWorld::Players[CWorld::PlayerInFocus].m_nSexFrequency == 250) + CWorld::Players[CWorld::PlayerInFocus].m_nNextSexFrequencyUpdateTime = CTimer::GetTimeInMilliseconds() + 3000; + } else { + bWanderPathAfterExitingCar = true; + CWorld::Players[CWorld::PlayerInFocus].m_pHooker = nil; + SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); + } + } else { + bWanderPathAfterExitingCar = true; + CWorld::Players[CWorld::PlayerInFocus].m_pHooker = nil; + m_pMyVehicle->pDriver->m_fHealth = 125.0f; + SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); + } + } else { + CWorld::Players[CWorld::PlayerInFocus].m_nNextSexFrequencyUpdateTime = CTimer::GetTimeInMilliseconds() + 3000; + int playerSexFrequency = CWorld::Players[CWorld::PlayerInFocus].m_nSexFrequency; + if (playerSexFrequency >= 1000 || playerSexFrequency <= 250) + CWorld::Players[CWorld::PlayerInFocus].m_nSexFrequency = 1200; + else + CWorld::Players[CWorld::PlayerInFocus].m_nSexFrequency = 250; + } + } else { + bWanderPathAfterExitingCar = true; + CWorld::Players[CWorld::PlayerInFocus].m_pHooker = nil; + SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); + } + } + + if (CTimer::GetTimeInMilliseconds() > CWorld::Players[CWorld::PlayerInFocus].m_nNextSexMoneyUpdateTime) { + int playerMoney = CWorld::Players[CWorld::PlayerInFocus].m_nMoney; + if (playerMoney <= 1) { + CWorld::Players[CWorld::PlayerInFocus].m_nSexFrequency = 250; + } else { + CWorld::Players[CWorld::PlayerInFocus].m_nMoney = max(0, playerMoney - 1); + } + CWorld::Players[CWorld::PlayerInFocus].m_nNextSexMoneyUpdateTime = CTimer::GetTimeInMilliseconds() + 1000; + } + break; + default: + break; + } + if (IsPedInControl()) + CivilianAI(); + + if (CTimer::GetTimeInMilliseconds() > m_timerUnused) { + m_stateUnused = 0; + m_timerUnused = 0; + } + + if (m_moved.Magnitude() > 0.0f) + Avoid(); +} + class CCivilianPed_ : public CCivilianPed { public: CCivilianPed *ctor(int pedtype, int mi) { return ::new (this) CCivilianPed(pedtype, mi); }; void dtor(void) { CCivilianPed::~CCivilianPed(); } + void ProcessControl_(void) { CCivilianPed::ProcessControl(); } }; STARTPATCHES InjectHook(0x4BFF30, &CCivilianPed_::ctor, PATCH_JUMP); InjectHook(0x4BFFC0, &CCivilianPed_::dtor, PATCH_JUMP); + InjectHook(0x4BFFE0, &CCivilianPed_::ProcessControl_, PATCH_JUMP); + + InjectHook(0x4C07A0, &CCivilianPed::CivilianAI, PATCH_JUMP); ENDPATCHES diff --git a/src/peds/CivilianPed.h b/src/peds/CivilianPed.h index 14859a5c..80845e62 100644 --- a/src/peds/CivilianPed.h +++ b/src/peds/CivilianPed.h @@ -8,6 +8,7 @@ public: CCivilianPed(int, int); ~CCivilianPed(void) { } + void CivilianAI(void); void ProcessControl(void); }; static_assert(sizeof(CCivilianPed) == 0x53C, "CCivilianPed: error"); diff --git a/src/peds/EmergencyPed.cpp b/src/peds/EmergencyPed.cpp index cbcfb403..16468270 100644 --- a/src/peds/EmergencyPed.cpp +++ b/src/peds/EmergencyPed.cpp @@ -2,37 +2,428 @@ #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); } +#include "Vehicle.h" +#include "Fire.h" +#include "General.h" +#include "CarCtrl.h" +#include "AccidentManager.h" 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; + 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_nEmergencyPedState = EMERGENCY_PED_READY; m_pAttendedAccident = nil; - field_1356 = 0; + m_bStartedToCPR = false; +} + +bool +CEmergencyPed::InRange(CPed *victim) +{ + if (!m_pMyVehicle) + return true; + + if ((m_pMyVehicle->GetPosition() - victim->GetPosition()).Magnitude() > 30.0f) + return false; + + return true; } +void +CEmergencyPed::ProcessControl(void) +{ + if (m_nZoneLevel > LEVEL_NONE && m_nZoneLevel != CCollision::ms_collisionInMemory) + return; + + CPed::ProcessControl(); + if (bWasPostponed) + return; + + if(!DyingOrDead()) { + GetWeapon()->Update(m_audioEntityId); + + if (IsPedInControl() && m_moved.Magnitude() > 0.0f) + Avoid(); + + switch (m_nPedState) { + case PED_SEEK_POS: + Seek(); + break; + case PED_SEEK_ENTITY: + if (m_pSeekTarget) { + m_vecSeekPos = m_pSeekTarget->GetPosition(); + Seek(); + } else { + ClearSeek(); + } + break; + default: + break; + } + + switch (m_nPedType) { + case PEDTYPE_EMERGENCY: + if (IsPedInControl() || m_nPedState == PED_DRIVING) + MedicAI(); + break; + case PEDTYPE_FIREMAN: + if (IsPedInControl()) + FiremanAI(); + break; + default: + return; + } + } +} + +// This function was buggy and incomplete in both III and VC, firemen had to be in 5.0m range of fire etc. etc. +// Copied some code from MedicAI to make it work. +void +CEmergencyPed::FiremanAI(void) +{ + float fireDist; + CFire *nearestFire; + + switch (m_nEmergencyPedState) { + case EMERGENCY_PED_READY: + nearestFire = gFireManager.FindNearestFire(GetPosition(), &fireDist); + if (nearestFire) { + m_nPedState = PED_NONE; + SetSeek(nearestFire->m_vecPos, 1.0f); + SetMoveState(PEDMOVE_RUN); + m_nEmergencyPedState = EMERGENCY_PED_DETERMINE_NEXT_STATE; + m_pAttendedFire = nearestFire; +#ifdef FIX_BUGS + bIsRunning = true; + ++nearestFire->m_nFiremenPuttingOut; +#endif + } + break; + case EMERGENCY_PED_DETERMINE_NEXT_STATE: + nearestFire = gFireManager.FindNearestFire(GetPosition(), &fireDist); + if (nearestFire && nearestFire != m_pAttendedFire) { + m_nPedState = PED_NONE; + SetSeek(nearestFire->m_vecPos, 1.0f); + SetMoveState(PEDMOVE_RUN); +#ifdef FIX_BUGS + bIsRunning = true; + if (m_pAttendedFire) { + --m_pAttendedFire->m_nFiremenPuttingOut; + } + ++nearestFire->m_nFiremenPuttingOut; + m_pAttendedFire = nearestFire; + } else if (!nearestFire) { +#else + m_pAttendedFire = nearestFire; + } else { +#endif + m_nEmergencyPedState = EMERGENCY_PED_STOP; + } + + // "Extinguish" the fire (Will overwrite the stop decision above if the attended and nearest fires are same) + if (fireDist < 5.0f) { + SetIdle(); + m_nEmergencyPedState = EMERGENCY_PED_STAND_STILL; + } + break; + case EMERGENCY_PED_STAND_STILL: + if (!m_pAttendedFire->m_bIsOngoing) + m_nEmergencyPedState = EMERGENCY_PED_STOP; + + // Leftover + // fireDist = 30.0f; + nearestFire = gFireManager.FindNearestFire(GetPosition(), &fireDist); + if (nearestFire) { +#ifdef FIX_BUGS + if(nearestFire != m_pAttendedFire && (nearestFire->m_vecPos - GetPosition()).Magnitude() < 30.0f) +#endif + m_nEmergencyPedState = EMERGENCY_PED_DETERMINE_NEXT_STATE; + } + Say(SOUND_PED_EXTINGUISHING_FIRE); + break; + case EMERGENCY_PED_STOP: +#ifdef FIX_BUGS + bIsRunning = false; + if (m_pAttendedFire) +#endif + --m_pAttendedFire->m_nFiremenPuttingOut; + + m_nPedState = PED_NONE; + SetWanderPath(CGeneral::GetRandomNumber() & 7); + m_pAttendedFire = nil; + m_nEmergencyPedState = EMERGENCY_PED_READY; + SetMoveState(PEDMOVE_WALK); + break; + } +} + +void +CEmergencyPed::MedicAI(void) +{ + float distToEmergency; + if (!bInVehicle && IsPedInControl()) { + ScanForThreats(); + if (m_threatEntity && m_threatEntity->IsPed() && ((CPed*)m_threatEntity)->IsPlayer()) { + if (((CPed*)m_threatEntity)->GetWeapon()->IsTypeMelee()) { + SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, m_threatEntity); + } else { + SetFlee(m_threatEntity, 6000); + Say(SOUND_PED_FLEE_SPRINT); + } + return; + } + } + + if (InVehicle()) { + if (m_pMyVehicle->IsCar() && m_objective != OBJECTIVE_LEAVE_VEHICLE) { + if (gAccidentManager.FindNearestAccident(m_pMyVehicle->GetPosition(), &distToEmergency) + && distToEmergency < 25.0f && m_pMyVehicle->m_vecMoveSpeed.Magnitude() < 0.01f) { + + m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_NONE; + SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); + Say(SOUND_PED_LEAVE_VEHICLE); + } else if (m_pMyVehicle->pDriver == this && m_nPedState == PED_DRIVING + && m_pMyVehicle->AutoPilot.m_nCarMission == MISSION_NONE && !(CGeneral::GetRandomNumber() & 31)) { + + bool waitUntilMedicEntersCar = false; + for (int i = 0; i < m_numNearPeds; ++i) { + CPed *nearPed = m_nearPeds[i]; + if (nearPed->m_nPedType == PEDTYPE_EMERGENCY) { + if ((nearPed->m_nPedState == PED_SEEK_CAR || nearPed->m_nPedState == PED_ENTER_CAR) + && nearPed->m_pMyVehicle == m_pMyVehicle) { + waitUntilMedicEntersCar = true; + break; + } + } + } + if (!waitUntilMedicEntersCar) { + CCarCtrl::JoinCarWithRoadSystem(m_pMyVehicle); + m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE; + m_pMyVehicle->m_bSirenOrAlarm = 0; + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 12; + m_pMyVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_SLOW_DOWN_FOR_CARS; + if (m_pMyVehicle->bIsAmbulanceOnDuty) { + m_pMyVehicle->bIsAmbulanceOnDuty = false; + --CCarCtrl::NumAmbulancesOnDuty; + } + } + } + } + } + + CVector headPos, midPos; + CAccident *nearestAccident; + if (IsPedInControl()) { + switch (m_nEmergencyPedState) { + case EMERGENCY_PED_READY: + nearestAccident = gAccidentManager.FindNearestAccident(GetPosition(), &distToEmergency); + field_1360 = 0; + if (nearestAccident) { + m_pRevivedPed = nearestAccident->m_pVictim; + m_pRevivedPed->RegisterReference((CEntity**)&m_pRevivedPed); + m_pRevivedPed->m_pedIK.GetComponentPosition((RwV3d*)&midPos, PED_MID); + m_pRevivedPed->m_pedIK.GetComponentPosition((RwV3d*)&headPos, PED_HEAD); + SetSeek((headPos + midPos) * 0.5f, 1.0f); + SetObjective(OBJECTIVE_NONE); + bIsRunning = true; + m_nEmergencyPedState = EMERGENCY_PED_DETERMINE_NEXT_STATE; + m_pAttendedAccident = nearestAccident; + ++m_pAttendedAccident->m_nMedicsAttending; + } else { + if (m_pMyVehicle) { + if (!bInVehicle) { + if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || m_pMyVehicle->pDriver || m_pMyVehicle->m_nGettingInFlags) { + + CPed* driver = m_pMyVehicle->pDriver; + if (driver && driver->m_nPedType != PEDTYPE_EMERGENCY && m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT) { + SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, driver); + } else if (m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER + && m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER + && m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT) { + SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_pMyVehicle); + } + } else { + SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle); + } + } + } else if (m_nPedState != PED_WANDER_PATH) { + SetWanderPath(CGeneral::GetRandomNumber() & 7); + } + } + break; + case EMERGENCY_PED_DETERMINE_NEXT_STATE: + nearestAccident = gAccidentManager.FindNearestAccident(GetPosition(), &distToEmergency); + if (nearestAccident) { + if (nearestAccident != m_pAttendedAccident || m_nPedState != PED_SEEK_POS) { + m_pRevivedPed = nearestAccident->m_pVictim; + m_pRevivedPed->RegisterReference((CEntity**)&m_pRevivedPed); + if (!InRange(m_pRevivedPed)) { + m_nEmergencyPedState = EMERGENCY_PED_STOP; + break; + } + m_pRevivedPed->m_pedIK.GetComponentPosition((RwV3d*)&midPos, PED_MID); + m_pRevivedPed->m_pedIK.GetComponentPosition((RwV3d*)&headPos, PED_HEAD); + SetSeek((headPos + midPos) * 0.5f, nearestAccident->m_nMedicsPerformingCPR * 0.5f + 1.0f); + SetObjective(OBJECTIVE_NONE); + bIsRunning = true; + --m_pAttendedAccident->m_nMedicsAttending; + ++nearestAccident->m_nMedicsAttending; + m_pAttendedAccident = nearestAccident; + } + } else { + m_nEmergencyPedState = EMERGENCY_PED_STOP; + bIsRunning = false; + } + if (distToEmergency < 5.0f) { + if (m_pRevivedPed->m_pFire) { + bIsRunning = false; + SetMoveState(PEDMOVE_STILL); + } else if (distToEmergency < 4.5f) { + bIsRunning = false; + SetMoveState(PEDMOVE_WALK); + if (distToEmergency < 1.0f + || distToEmergency < 4.5f && m_pAttendedAccident->m_nMedicsPerformingCPR) { + m_nEmergencyPedState = EMERGENCY_PED_START_CPR; + } + } + } + break; + case EMERGENCY_PED_START_CPR: + if (!m_pRevivedPed || m_pRevivedPed->m_fHealth > 0.0f || m_pRevivedPed->bFadeOut) { + m_nEmergencyPedState = EMERGENCY_PED_DETERMINE_NEXT_STATE; + } else { + m_pRevivedPed->m_bloodyFootprintCount = CTimer::GetTimeInMilliseconds(); + SetMoveState(PEDMOVE_STILL); + m_nPedState = PED_CPR; + m_nLastPedState = PED_CPR; + SetLookFlag(m_pRevivedPed, 0); + SetLookTimer(500); + Say(SOUND_PED_HEALING); + if (m_pAttendedAccident->m_nMedicsPerformingCPR) { + SetIdle(); + m_nEmergencyPedState = EMERGENCY_PED_STAND_STILL; + } else { + m_nEmergencyPedState = EMERGENCY_PED_FACE_TO_PATIENT; + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CPR, 4.0f); + bIsDucking = true; + } + SetLookTimer(2000); + ++m_pAttendedAccident->m_nMedicsPerformingCPR; + m_bStartedToCPR = true; + } + break; + case EMERGENCY_PED_FACE_TO_PATIENT: + if (!m_pRevivedPed || m_pRevivedPed->m_fHealth > 0.0f) + m_nEmergencyPedState = EMERGENCY_PED_DETERMINE_NEXT_STATE; + else { + m_pRevivedPed->m_pedIK.GetComponentPosition((RwV3d*)&midPos, PED_MID); + m_pRevivedPed->m_pedIK.GetComponentPosition((RwV3d*)&headPos, PED_HEAD); + midPos = (headPos + midPos) * 0.5f; + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( + midPos.x, midPos.y, + GetPosition().x, GetPosition().y); + m_fRotationDest = CGeneral::LimitAngle(m_fRotationDest); + m_pLookTarget = m_pRevivedPed; + m_pLookTarget->RegisterReference((CEntity**)&m_pLookTarget); + TurnBody(); + + if (Abs(m_fRotationCur - m_fRotationDest) < DEGTORAD(45.0f)) + m_nEmergencyPedState = EMERGENCY_PED_PERFORM_CPR; + else + m_fRotationCur = (m_fRotationCur + m_fRotationDest) * 0.5f; + } + break; + case EMERGENCY_PED_PERFORM_CPR: + if (!m_pRevivedPed || m_pRevivedPed->m_fHealth > 0.0f) { + m_nEmergencyPedState = EMERGENCY_PED_DETERMINE_NEXT_STATE; + break; + } + m_pRevivedPed->m_pedIK.GetComponentPosition((RwV3d*)&midPos, PED_MID); + m_pRevivedPed->m_pedIK.GetComponentPosition((RwV3d*)&headPos, PED_HEAD); + midPos = (headPos + midPos) * 0.5f; + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( + midPos.x, midPos.y, + GetPosition().x, GetPosition().y); + m_fRotationDest = CGeneral::LimitAngle(m_fRotationDest); + m_pLookTarget = m_pRevivedPed; + m_pLookTarget->RegisterReference((CEntity**)&m_pLookTarget); + TurnBody(); + if (CTimer::GetTimeInMilliseconds() <= m_lookTimer) { + SetMoveState(PEDMOVE_STILL); + break; + } + m_nEmergencyPedState = EMERGENCY_PED_STOP_CPR; + m_nPedState = PED_NONE; + SetMoveState(PEDMOVE_WALK); + m_pVehicleAnim = nil; + if (!m_pRevivedPed->bBodyPartJustCameOff) { + m_pRevivedPed->m_fHealth = 100.0f; + m_pRevivedPed->m_nPedState = PED_NONE; + m_pRevivedPed->m_nLastPedState = PED_WANDER_PATH; + m_pRevivedPed->SetGetUp(); + m_pRevivedPed->bUsesCollision = true; + m_pRevivedPed->SetMoveState(PEDMOVE_WALK); + m_pRevivedPed->RestartNonPartialAnims(); + m_pRevivedPed->bIsPedDieAnimPlaying = false; + m_pRevivedPed->m_ped_flagH1 = false; + m_pRevivedPed->m_pCollidingEntity = nil; + } + break; + case EMERGENCY_PED_STOP_CPR: + m_nEmergencyPedState = EMERGENCY_PED_STOP; + bIsDucking = true; + break; + case EMERGENCY_PED_STAND_STILL: + if (!m_pRevivedPed || m_pRevivedPed->m_fHealth > 0.0f) + m_nEmergencyPedState = EMERGENCY_PED_DETERMINE_NEXT_STATE; + else { + if (!m_pAttendedAccident->m_pVictim) + m_nEmergencyPedState = EMERGENCY_PED_DETERMINE_NEXT_STATE; + if (!m_pAttendedAccident->m_nMedicsPerformingCPR) + m_nEmergencyPedState = EMERGENCY_PED_DETERMINE_NEXT_STATE; + if (gAccidentManager.UnattendedAccidents()) + m_nEmergencyPedState = EMERGENCY_PED_DETERMINE_NEXT_STATE; + } + break; + case EMERGENCY_PED_STOP: + m_bStartedToCPR = false; + m_nPedState = PED_NONE; + if (m_pAttendedAccident) { + m_pAttendedAccident->m_pVictim = nil; + --m_pAttendedAccident->m_nMedicsAttending; + m_pAttendedAccident = nil; + } + SetWanderPath(CGeneral::GetRandomNumber() & 7); + m_pRevivedPed = nil; + m_nEmergencyPedState = EMERGENCY_PED_READY; + SetMoveState(PEDMOVE_WALK); + break; + } + } +} + +class CEmergencyPed_ : public CEmergencyPed +{ +public: + CEmergencyPed* ctor(int pedtype) { return ::new (this) CEmergencyPed(pedtype); }; + void dtor(void) { CEmergencyPed::~CEmergencyPed(); } + void ProcessControl_(void) { CEmergencyPed::ProcessControl(); } +}; + STARTPATCHES InjectHook(0x4C2E40, &CEmergencyPed_::ctor, PATCH_JUMP); InjectHook(0x4C2EF0, &CEmergencyPed_::dtor, PATCH_JUMP); + InjectHook(0x4C2F10, &CEmergencyPed_::ProcessControl_, PATCH_JUMP); + InjectHook(0x4C3EC0, &CEmergencyPed::InRange, PATCH_JUMP); ENDPATCHES diff --git a/src/peds/EmergencyPed.h b/src/peds/EmergencyPed.h index f55fa4e2..5693e908 100644 --- a/src/peds/EmergencyPed.h +++ b/src/peds/EmergencyPed.h @@ -1,20 +1,40 @@ #pragma once -#include "Fire.h" #include "Ped.h" +class CAccident; +class CFire; + +enum EmergencyPedState +{ + EMERGENCY_PED_READY = 0x0, + EMERGENCY_PED_DETERMINE_NEXT_STATE = 0x1, // you can set that anytime you want + EMERGENCY_PED_START_CPR = 0x2, + EMERGENCY_PED_FLAG_4 = 0x4, // unused + EMERGENCY_PED_FLAG_8 = 0x8, // unused + EMERGENCY_PED_FACE_TO_PATIENT = 0x10, // for CPR + EMERGENCY_PED_PERFORM_CPR = 0x20, + EMERGENCY_PED_STOP_CPR = 0x40, + EMERGENCY_PED_STAND_STILL = 0x80, // waiting colleagues for medics, "extinguishing" fire for firemen + EMERGENCY_PED_STOP = 0x100, +}; + class CEmergencyPed : public CPed { public: // 0x53C - CPed* m_pRevivedPed; - int32 m_nEmergencyPedState; // looks like flags - void* m_pAttendedAccident; //TODO: CAccident* - CFire* m_pAttendedFire; - int8 field_1356; - int32 field_1360; + CPed *m_pRevivedPed; + EmergencyPedState m_nEmergencyPedState; + CAccident *m_pAttendedAccident; + CFire *m_pAttendedFire; + bool m_bStartedToCPR; // set but unused(?) + int32 field_1360; // also something for medics, unused(?) CEmergencyPed(uint32); + ~CEmergencyPed() { } + bool InRange(CPed*); void ProcessControl(void); + void FiremanAI(void); + void MedicAI(void); }; static_assert(sizeof(CEmergencyPed) == 0x554, "CEmergencyPed: error"); diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index 11aa480b..5d235507 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -49,15 +49,6 @@ #include "ParticleObject.h" #include "Floater.h" -WRAPPER void CPed::SetMoveAnim(void) { EAXJMP(0x4C5A40); } -WRAPPER void CPed::WanderPath(void) { EAXJMP(0x4D28D0); } -WRAPPER void CPed::SetEnterCar_AllClear(CVehicle*, uint32, uint32) { EAXJMP(0x4E0A40); } -WRAPPER bool CPed::WarpPedToNearEntityOffScreen(CEntity*) { EAXJMP(0x4E5570); } -WRAPPER void CPed::SetObjective(eObjective, CVector) { EAXJMP(0x4D8A90); } -WRAPPER void CPed::SetObjective(eObjective, CVector, float) { EAXJMP(0x4D8770); } -WRAPPER void CPed::SetCarJack(CVehicle*) { EAXJMP(0x4E0220); } -WRAPPER void CPed::WarpPedToNearLeaderOffScreen(void) { EAXJMP(0x4E52A0); } - #define FEET_OFFSET 1.04f CPed *gapTempPedList[50]; @@ -281,10 +272,14 @@ static char WaitStateText[][16] = { "Finish Flee", }; -#ifndef MASTER -int nDisplayDebugInfo = 0; +#ifdef TOGGLEABLE_BETA_FEATURES bool CPed::bUnusedFightThingOnPlayer = false; bool CPed::bPopHeadsOnHeadshot = false; +bool CPed::bMakePedsRunToPhonesToReportCrimes = false; +#endif + +#ifndef MASTER +int nDisplayDebugInfo = 0; void CPed::SwitchDebugDisplay(void) @@ -295,7 +290,7 @@ CPed::SwitchDebugDisplay(void) void CPed::DebugRenderOnePedText(void) { - if ((GetPosition() - TheCamera.GetPosition()).MagnitudeSqr() < 900.0f) { + if ((GetPosition() - TheCamera.GetPosition()).MagnitudeSqr() < sq(30.0f)) { float width, height; RwV3d screenCoords; CVector bitAbove = GetPosition(); @@ -309,7 +304,7 @@ CPed::DebugRenderOnePedText(void) CFont::SetBackgroundOn(); // Originally both of them were being divided by 60.0f. - float xScale = min(width / 190.0f, 0.7f); + float xScale = min(width / 240.0f, 0.7f); float yScale = min(height / 80.0f, 0.7f); CFont::SetScale(SCREEN_SCALE_X(xScale), SCREEN_SCALE_Y(yScale)); @@ -342,7 +337,7 @@ CPed::~CPed(void) { CWorld::Remove(this); CRadar::ClearBlipForEntity(BLIP_CHAR, CPools::GetPedPool()->GetIndex(this)); - if (bInVehicle && m_pMyVehicle){ + if (InVehicle()){ uint8 door_flag = GetCarDoorFlag(m_vehEnterType); if (m_pMyVehicle->pDriver == this) m_pMyVehicle->pDriver = nil; @@ -367,7 +362,7 @@ void CPed::FlagToDestroyWhenNextProcessed(void) { bRemoveFromWorld = true; - if (!bInVehicle || !m_pMyVehicle) + if (!InVehicle()) return; if (m_pMyVehicle->pDriver == this){ m_pMyVehicle->pDriver = nil; @@ -464,7 +459,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) m_wanderRangeBounds = nil; m_nPathNodes = 0; m_nCurPathNode = 0; - m_nPathState = 0; + m_nPathDir = 0; m_pLastPathNode = nil; m_pNextPathNode = nil; m_routeLastPoint = -1; @@ -574,9 +569,9 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) m_fAngleToEvent = 0.0f; m_numNearPeds = 0; - for (int i = 0; i < 10; i++) { + for (int i = 0; i < ARRAY_SIZE(m_nearPeds); i++) { m_nearPeds[i] = nil; - if (i < 8) { + if (i < ARRAY_SIZE(m_pPathNodesStates)) { m_pPathNodesStates[i] = nil; } } @@ -790,9 +785,7 @@ CPed::AimGun(void) if (m_pSeekTarget) { if (m_pSeekTarget->IsPed()) { ((CPed*)m_pSeekTarget)->m_pedIK.GetComponentPosition(&pos, PED_MID); - vector.x = pos.x; - vector.y = pos.y; - vector.z = pos.z; + vector = pos; } else { vector = m_pSeekTarget->GetPosition(); } @@ -877,7 +870,7 @@ CPed::RemoveBodyPart(PedNode nodeId, int8 direction) frame = GetNodeFrame(nodeId); if (frame) { if (CGame::nastyGame) { -#ifndef MASTER +#ifdef TOGGLEABLE_BETA_FEATURES if (bPopHeadsOnHeadshot || nodeId != PED_HEAD) #else if (nodeId != PED_HEAD) @@ -1448,8 +1441,15 @@ CPed::ClearPointGunAt(void) ClearLookFlag(); ClearAimFlag(); bIsPointingGunAt = false; +#ifndef VC_PED_PORTS if (m_nPedState == PED_AIM_GUN) { RestorePreviousState(); +#else + if (m_nPedState == PED_AIM_GUN || m_nPedState == PED_ATTACK) { + m_nPedState = PED_IDLE; + RestorePreviousState(); + } +#endif weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weaponInfo->m_AnimToPlay); if (!animAssoc || animAssoc->blendDelta < 0.0f) { @@ -1459,7 +1459,9 @@ CPed::ClearPointGunAt(void) animAssoc->flags |= ASSOC_DELETEFADEDOUT; animAssoc->blendDelta = -4.0f; } +#ifndef VC_PED_PORTS } +#endif } void @@ -1924,7 +1926,7 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) if (!stillGettingInOut) { m_fRotationCur = m_fRotationDest; } else { - float limitedAngle = CGeneral::LimitRadianAngle(m_fRotationDest); + float limitedDest = CGeneral::LimitRadianAngle(m_fRotationDest); float timeUntilStateChange = (m_nPedStateTimer - CTimer::GetTimeInMilliseconds())/600.0f; m_vecOffsetSeek.z = 0.0f; @@ -1935,12 +1937,12 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) neededPos -= timeUntilStateChange * m_vecOffsetSeek; } - if (PI + m_fRotationCur < limitedAngle) { - limitedAngle -= 2 * PI; - } else if (m_fRotationCur - PI > limitedAngle) { - limitedAngle += 2 * PI; + if (PI + m_fRotationCur < limitedDest) { + limitedDest -= 2 * PI; + } else if (m_fRotationCur - PI > limitedDest) { + limitedDest += 2 * PI; } - m_fRotationCur -= (m_fRotationCur - limitedAngle) * (1.0f - timeUntilStateChange); + m_fRotationCur -= (m_fRotationCur - limitedDest) * (1.0f - timeUntilStateChange); } if (seatPosMult > 0.2f || vehIsUpsideDown) { @@ -2148,7 +2150,7 @@ CPed::BuildPedLists(void) { if ((CTimer::GetFrameCounter() + (m_randomSeed % 256)) % 16) { - for(int i = 0; i < 10; ) { + for(int i = 0; i < ARRAY_SIZE(m_nearPeds); ) { if (m_nearPeds[i]) { if (m_nearPeds[i]->IsPointerValid()) { float distSqr = (GetPosition() - m_nearPeds[i]->GetPosition()).MagnitudeSqr2D(); @@ -2159,7 +2161,7 @@ CPed::BuildPedLists(void) } // If we arrive here, the ped we're checking isn't "near", so we should remove it. - for (int j = i; j < 9; j++) { + for (int j = i; j < ARRAY_SIZE(m_nearPeds) - 1; j++) { m_nearPeds[j] = m_nearPeds[j + 1]; m_nearPeds[j + 1] = nil; } @@ -2194,14 +2196,14 @@ CPed::BuildPedLists(void) } gapTempPedList[gnNumTempPedList] = nil; SortPeds(gapTempPedList, 0, gnNumTempPedList - 1); - for (m_numNearPeds = 0; m_numNearPeds < 10; m_numNearPeds++) { + for (m_numNearPeds = 0; m_numNearPeds < ARRAY_SIZE(m_nearPeds); m_numNearPeds++) { CPed *ped = gapTempPedList[m_numNearPeds]; if (!ped) break; m_nearPeds[m_numNearPeds] = ped; } - for (int pedToClear = m_numNearPeds; pedToClear < 10; pedToClear++) + for (int pedToClear = m_numNearPeds; pedToClear < ARRAY_SIZE(m_nearPeds); pedToClear++) m_nearPeds[pedToClear] = nil; } } @@ -2395,7 +2397,7 @@ CPed::CalculateNewVelocity(void) bool CPed::CanBeDeleted(void) { - if (this->bInVehicle) + if (bInVehicle) return false; switch (CharCreatedBy) { @@ -2775,6 +2777,12 @@ void CPed::SetIdle(void) { if (m_nPedState != PED_IDLE && m_nPedState != PED_MUG && m_nPedState != PED_FLEE_ENTITY) { +#ifdef VC_PED_PORTS + if (m_nPedState == PED_AIM_GUN) + ClearPointGunAt(); + + m_nLastPedState = PED_NONE; +#endif m_nPedState = PED_IDLE; SetMoveState(PEDMOVE_STILL); } @@ -2985,7 +2993,7 @@ CPed::ReactToAttack(CEntity *attacker) } #ifdef VC_PED_PORTS - if (m_nPedState == PED_DRIVING && bInVehicle && m_pMyVehicle + if (m_nPedState == PED_DRIVING && InVehicle() && (m_pMyVehicle->pDriver == this || m_pMyVehicle->pDriver && m_pMyVehicle->pDriver->m_nPedState == PED_DRIVING)) { if (m_pMyVehicle->VehicleCreatedBy == RANDOM_VEHICLE @@ -2994,7 +3002,7 @@ CPed::ReactToAttack(CEntity *attacker) CCarCtrl::SwitchVehicleToRealPhysics(m_pMyVehicle); m_pMyVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 60.0f * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity; + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity; m_pMyVehicle->m_status = STATUS_PHYSICS; } } else @@ -3042,7 +3050,7 @@ bool CPed::TurnBody(void) { float lookDir; - bool doneSmoothly = true; + bool turnDone = true; if (m_pLookTarget) { CVector &lookPos = m_pLookTarget->GetPosition(); @@ -3067,18 +3075,19 @@ CPed::TurnBody(void) m_fRotationDest = limitedLookDir; if (Abs(neededTurn) > 0.05f) { - doneSmoothly = false; + turnDone = false; currentRot -= neededTurn * 0.2f; } m_fRotationCur = currentRot; m_fLookDirection = limitedLookDir; - return doneSmoothly; + return turnDone; } void CPed::Chat(void) { + // We're already looking to our partner if (bIsLooking && TurnBody()) ClearLookFlag(); @@ -3153,7 +3162,7 @@ CPed::CheckAroundForPossibleCollisions(void) if (radius > 4.5f || radius < 1.0f) radius = 1.0f; - // According to code, developers gave up calculating Z diff. later. + // Developers gave up calculating Z diff. later according to asm. float diff = CVector(ourCentre - objCentre).MagnitudeSqr2D(); if (sq(radius + 1.0f) > diff) @@ -3164,11 +3173,23 @@ CPed::CheckAroundForPossibleCollisions(void) bool CPed::MakePhonecall(void) { +#ifdef TOGGLEABLE_BETA_FEATURES + if (bMakePedsRunToPhonesToReportCrimes) + if (!IsPlayer() && CTimer::GetTimeInMilliseconds() > m_phoneTalkTimer - 7000 && bRunningToPhone) { + + FindPlayerPed()->m_pWanted->RegisterCrime_Immediately(m_crimeToReportOnPhone, GetPosition(), + (m_crimeToReportOnPhone == CRIME_POSSESSION_GUN ? (int)m_threatEntity : (int)((CPed*)m_pEventEntity)->m_threatEntity), false); + bRunningToPhone = false; + } +#endif if (CTimer::GetTimeInMilliseconds() <= m_phoneTalkTimer) return false; SetIdle(); gPhoneInfo.m_aPhones[m_phoneId].m_nState = PHONE_STATE_FREE; +#ifdef TOGGLEABLE_BETA_FEATURES + crimeReporters[m_phoneId] = nil; +#endif m_phoneId = -1; return true; } @@ -3176,8 +3197,22 @@ CPed::MakePhonecall(void) 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; + // FIX: This function was broken since it's left unused early in development. +#ifdef FIX_BUGS + 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, false); + bool turnDone = TurnBody(); + if (turnDone) { + SetIdle(); + ClearLookFlag(); + m_phoneTalkTimer = CTimer::GetTimeInMilliseconds() + 10000; + } + return turnDone; +#else + float currentRot = RADTODEG(m_fRotationCur); float phoneDir = CGeneral::GetRadianAngleBetweenPoints( gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.x, gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.y, @@ -3185,14 +3220,13 @@ CPed::FacePhone(void) GetPosition().y); SetLookFlag(phoneDir, false); - - phoneDir = CGeneral::LimitRadianAngle(phoneDir); + phoneDir = CGeneral::LimitAngle(phoneDir); m_moved = CVector2D(0.0f, 0.0f); - if (currentRot - PI > phoneDir) - phoneDir += 2 * PI; - else if (PI + currentRot < phoneDir) - phoneDir -= 2 * PI; + if (currentRot - 180.0f > phoneDir) + phoneDir += 2 * 180.0f; + else if (180.0f + currentRot < phoneDir) + phoneDir -= 2 * 180.0f; float neededTurn = currentRot - phoneDir; @@ -3202,9 +3236,10 @@ CPed::FacePhone(void) m_phoneTalkTimer = CTimer::GetTimeInMilliseconds() + 10000; return true; } else { - m_fRotationCur -= neededTurn * 0.2f; + m_fRotationCur = DEGTORAD(currentRot - neededTurn * 0.2f); return false; } +#endif } CPed * @@ -3946,7 +3981,7 @@ CPed::InflictDamage(CEntity *damagedBy, eWeaponType method, float damage, ePedPi } */ } - for (int i = 0; i < 8; i++) { + for (int i = 0; i < ARRAY_SIZE(m_pMyVehicle->pPassengers); i++) { CPed* passenger = m_pMyVehicle->pPassengers[i]; if (passenger && passenger != this && damagedBy) passenger->ReactToAttack(damagedBy); @@ -4174,39 +4209,36 @@ CPed::SetWanderPath(int8 pathStateDest) SetIdle(); return false; } else { - - // m_nPathState is pure direction for values 1,2,3 and 5,6,7 - - m_nPathState = pathStateDest; + m_nPathDir = pathStateDest; if (pathStateDest == 0) pathStateDest = CGeneral::GetRandomNumberInRange(1, 7); ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, - m_nPathState, &nextPathState); + m_nPathDir, &nextPathState); - // Circular loop until we find a node for current m_nPathState + // Circular loop until we find a node for current m_nPathDir while (!m_pNextPathNode) { - m_nPathState = (m_nPathState+1) % 8; + m_nPathDir = (m_nPathDir+1) % 8; // We're at where we started and couldn't find any node - if (m_nPathState == pathStateDest) { + if (m_nPathDir == pathStateDest) { ClearAll(); SetIdle(); return false; } ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, - m_nPathState, &nextPathState); + m_nPathDir, &nextPathState); } // We did it, save next path state and return true - m_nPathState = nextPathState; + m_nPathDir = nextPathState; m_nPedState = PED_WANDER_PATH; SetMoveState(PEDMOVE_WALK); bIsRunning = false; return true; } } else { - m_nPathState = pathStateDest; + m_nPathDir = pathStateDest; bStartWanderPathOnFoot = true; return false; } @@ -4268,7 +4300,7 @@ CPed::RestorePreviousState(void) if (m_nPedState == PED_GETUP && !bGetUpAnimStarted) return; - if (bInVehicle && m_pMyVehicle) { + if (InVehicle()) { m_nPedState = PED_DRIVING; m_nLastPedState = PED_NONE; } else { @@ -4291,7 +4323,7 @@ CPed::RestorePreviousState(void) if (!bFindNewNodeAfterStateRestore) { if (m_pNextPathNode) { CVector diff = m_pNextPathNode->pos - GetPosition(); - if (diff.MagnitudeSqr() < 49.0f) { + if (diff.MagnitudeSqr() < sq(7.0f)) { SetMoveState(PEDMOVE_WALK); break; } @@ -4341,6 +4373,9 @@ CPed::SetPointGunAt(CEntity *to) if (to) { SetLookFlag(to, true); SetAimFlag(to); +#ifdef VC_PED_PORTS + SetLookTimer(INT_MAX); +#endif } if (m_nPedState == PED_AIM_GUN || bIsDucking || m_nWaitState == WAITSTATE_PLAYANIM_DUCK) @@ -4577,7 +4612,7 @@ CPed::SetEvasiveDive(CPhysical *reason, uint8 onlyRandomJump) if (reason->IsVehicle() && m_nPedType == PEDTYPE_COP) { if (veh->pDriver && veh->pDriver->IsPlayer()) { - CWanted *wanted = CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted; + CWanted *wanted = FindPlayerPed()->m_pWanted; wanted->RegisterCrime_Immediately(CRIME_RECKLESS_DRIVING, GetPosition(), (int)this, false); wanted->RegisterCrime_Immediately(CRIME_SPEEDING, GetPosition(), (int)this, false); } @@ -4792,7 +4827,7 @@ CPed::StartFightAttack(uint8 buttonPressure) animAssoc->SetFinishCallback(FinishFightMoveCB, this); m_fightState = FIGHTSTATE_NO_MOVE; m_takeAStepAfterAttack = false; -#ifndef MASTER +#ifdef TOGGLEABLE_BETA_FEATURES m_takeAStepAfterAttack = IsPlayer() && bUnusedFightThingOnPlayer; #endif @@ -5499,7 +5534,7 @@ CPed::CollideWithPed(CPed *collideWith) int colliderIsAtPlayerSafePosID = -1; int weAreAtPlayerSafePosID = -1; - for (int i = 0; i < 6; i++) { + for (int i = 0; i < ARRAY_SIZE(((CPlayerPed*)m_pedInObjective)->m_pPedAtSafePos); i++) { CPed *pedAtSafePos = ((CPlayerPed*)m_pedInObjective)->m_pPedAtSafePos[i]; if (pedAtSafePos == this) { weAreAtPlayerSafePosID = i; @@ -7422,7 +7457,7 @@ CPed::Flee(void) if (CTimer::GetTimeInMilliseconds() > m_fleeTimer && m_fleeTimer) { bool mayFinishFleeing = true; if (m_nPedState == PED_FLEE_ENTITY) { - if ((CVector2D(GetPosition()) - ms_vec2DFleePosition).MagnitudeSqr() < 900.0f) + if ((CVector2D(GetPosition()) - ms_vec2DFleePosition).MagnitudeSqr() < sq(30.0f)) mayFinishFleeing = false; } @@ -7452,10 +7487,10 @@ CPed::Flee(void) if (m_pNextPathNode && CTimer::GetTimeInMilliseconds() > m_standardTimer) { curDirectionShouldBe = CGeneral::GetNodeHeadingFromVector(GetPosition().x - ms_vec2DFleePosition.x, GetPosition().y - ms_vec2DFleePosition.y); - if (m_nPathState < curDirectionShouldBe) - m_nPathState += 8; + if (m_nPathDir < curDirectionShouldBe) + m_nPathDir += 8; - int dirDiff = m_nPathState - curDirectionShouldBe; + int dirDiff = m_nPathDir - curDirectionShouldBe; if (dirDiff > 2 && dirDiff < 6) { realLastNode = nil; m_pLastPathNode = m_pNextPathNode; @@ -7491,7 +7526,7 @@ CPed::Flee(void) curDirectionShouldBe += 8; if (m_pNextPathNode && m_pNextPathNode != realLastNode && m_pNextPathNode != m_pLastPathNode && curDirectionShouldBe - nextDirection != 4) { - m_nPathState = nextDirection; + m_nPathDir = nextDirection; m_standardTimer = CTimer::GetTimeInMilliseconds() + 2000; } else { bUsePedNodeSeek = false; @@ -7942,7 +7977,7 @@ CPed::Idle(void) CVector doorPos = GetPositionToOpenCarDoor(veh, m_vehEnterType); CVector doorDist = GetPosition() - doorPos; - if (doorDist.MagnitudeSqr() < 0.25f) { + if (doorDist.MagnitudeSqr() < sq(0.5f)) { SetMoveState(PEDMOVE_WALK); return; } @@ -8320,7 +8355,7 @@ CPed::InvestigateEvent(void) } for (int i = 0; i < m_numNearPeds; i++) { - if ((m_eventOrThreat - m_nearPeds[i]->GetPosition()).MagnitudeSqr() < 0.16f) { + if ((m_eventOrThreat - m_nearPeds[i]->GetPosition()).MagnitudeSqr() < sq(0.4f)) { SetMoveState(PEDMOVE_STILL); return; } @@ -8527,6 +8562,10 @@ CPed::KillPedWithCar(CVehicle *car, float impulse) if (car->pDriver) { CEventList::RegisterEvent((m_nPedType == PEDTYPE_COP ? EVENT_HIT_AND_RUN_COP : EVENT_HIT_AND_RUN), EVENT_ENTITY_PED, this, car->pDriver, 1000); +#ifdef TOGGLEABLE_BETA_FEATURES + if (bMakePedsRunToPhonesToReportCrimes) + m_ped_flagI40 = true; +#endif } ePedPieceTypes pieceToDamage; @@ -8655,7 +8694,7 @@ CPed::LookForInterestingNodes(void) objMat = &veh->GetMatrix(); effectPos = veh->GetMatrix() * effect->pos; effectDist = effectPos - GetPosition(); - if (effectDist.MagnitudeSqr() < 64.0f) { + if (effectDist.MagnitudeSqr() < sq(8.0f)) { found = true; break; } @@ -8673,7 +8712,7 @@ CPed::LookForInterestingNodes(void) objMat = &obj->GetMatrix(); effectPos = obj->GetMatrix() * effect->pos; effectDist = effectPos - GetPosition(); - if (effectDist.MagnitudeSqr() < 64.0f) { + if (effectDist.MagnitudeSqr() < sq(8.0f)) { found = true; break; } @@ -8691,7 +8730,7 @@ CPed::LookForInterestingNodes(void) objMat = &building->GetMatrix(); effectPos = building->GetMatrix() * effect->pos; effectDist = effectPos - GetPosition(); - if (effectDist.MagnitudeSqr() < 64.0f) { + if (effectDist.MagnitudeSqr() < sq(8.0f)) { found = true; break; } @@ -8709,7 +8748,7 @@ CPed::LookForInterestingNodes(void) objMat = &building->GetMatrix(); effectPos = building->GetMatrix() * effect->pos; effectDist = effectPos - GetPosition(); - if (effectDist.MagnitudeSqr() < 64.0f) { + if (effectDist.MagnitudeSqr() < sq(8.0f)) { found = true; break; } @@ -9201,7 +9240,7 @@ CPed::ProcessControl(void) float timeDependentDist; if (remainingBloodyFpTime >= 2000) { if (remainingBloodyFpTime <= 7000) - timeDependentDist = (remainingBloodyFpTime - 2000) / 5000 * 0.75f; + timeDependentDist = (remainingBloodyFpTime - 2000) / 5000.0f * 0.75f; else timeDependentDist = 0.75f; } else { @@ -9245,8 +9284,8 @@ CPed::ProcessControl(void) } else { CShadows::StoreStaticShadow( (uintptr)this + 17, SHADOWTYPE_DARK, gpBloodPoolTex, &bloodPos, - (remainingBloodyFpTime - 2000) / 5000 * 0.75f, 0.0f, - 0.0f, (remainingBloodyFpTime - 2000) / 5000 * -0.75f, + (remainingBloodyFpTime - 2000) / 5000.0f * 0.75f, 0.0f, + 0.0f, (remainingBloodyFpTime - 2000) / 5000.0f * -0.75f, 255, 255, 0, 0, 4.0f, 1.0f, 40.0f, false, 0.0f); } } @@ -10070,7 +10109,7 @@ CPed::ProcessControl(void) if (bStartWanderPathOnFoot) { if (IsPedInControl()) { ClearAll(); - SetWanderPath(m_nPathState); + SetWanderPath(m_nPathDir); bStartWanderPathOnFoot = false; } else if (m_nPedState == PED_DRIVING) { bWanderPathAfterExitingCar = true; @@ -10334,6 +10373,34 @@ CPed::ProcessControl(void) break; } + CPad* pad = CPad::GetPad(0); + +#ifdef CAR_AIRBREAK + if (!pad->ArePlayerControlsDisabled()) { + if (pad->GetHorn()) { + float c = Cos(m_fRotationCur); + float s = Sin(m_fRotationCur); + m_pMyVehicle->GetRight() = CVector(1.0f, 0.0f, 0.0f); + m_pMyVehicle->GetForward() = CVector(0.0f, 1.0f, 0.0f); + m_pMyVehicle->GetUp() = CVector(0.0f, 0.0f, 1.0f); + if (pad->GetAccelerate()) { + m_pMyVehicle->ApplyMoveForce(GetForward() * 30.0f); + } else if (pad->GetBrake()) { + m_pMyVehicle->ApplyMoveForce(-GetForward() * 30.0f); + } else { + int16 lr = pad->GetSteeringLeftRight(); + if (lr < 0) { + //m_pMyVehicle->ApplyTurnForce(20.0f * -GetRight(), GetForward()); + m_pMyVehicle->ApplyMoveForce(-GetRight() * 30.0f); + } else if (lr > 0) { + m_pMyVehicle->ApplyMoveForce(GetRight() * 30.0f); + } else { + m_pMyVehicle->ApplyMoveForce(0.0f, 0.0f, 50.0f); + } + } + } + } +#endif float steerAngle = m_pMyVehicle->m_fSteerAngle; CAnimBlendAssociation *lDriveAssoc; CAnimBlendAssociation *rDriveAssoc; @@ -10434,7 +10501,7 @@ CPed::ProcessControl(void) if (CGame::nastyGame) { if (!(CTimer::GetFrameCounter() & 3)) { CVector cameraDist = GetPosition() - TheCamera.GetPosition(); - if (cameraDist.MagnitudeSqr() < 2500.0f) { + if (cameraDist.MagnitudeSqr() < sq(50.0f)) { float length = (CGeneral::GetRandomNumber() & 127) * 0.0015f + 0.15f; CVector bloodPos( @@ -10835,6 +10902,12 @@ CPed::RemoveInCarAnims(void) animAssoc->blendDelta = -1000.0f; } +#ifdef VC_PED_PORTS + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_BOAT); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; +#endif + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LB); if (animAssoc) animAssoc->blendDelta = -1000.0f; @@ -11369,7 +11442,11 @@ CPed::PedSetInCarCB(CAnimBlendAssociation *animAssoc, void *arg) } } } - if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER +#ifdef VC_PED_PORTS + || ped->m_nPedState == PED_CARJACK +#endif + ) veh->bIsBeingCarJacked = false; if (veh->m_nNumGettingIn) @@ -11380,6 +11457,9 @@ CPed::PedSetInCarCB(CAnimBlendAssociation *animAssoc, void *arg) if (veh->IsBoat()) { if (ped->IsPlayer()) { +#ifdef VC_PED_PORTS + CCarCtrl::RegisterVehicleOfInterest(veh); +#endif if (veh->m_status == STATUS_SIMPLE) { veh->m_vecMoveSpeed = CVector(0.0f, 0.0f, -0.00001f); veh->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); @@ -11423,8 +11503,12 @@ CPed::PedSetInCarCB(CAnimBlendAssociation *animAssoc, void *arg) if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { for (int i = 0; i < veh->m_nNumMaxPassengers; ++i) { CPed *passenger = veh->pPassengers[i]; - if (passenger && passenger->CharCreatedBy == RANDOM_CHAR) + if (passenger && passenger->CharCreatedBy == RANDOM_CHAR) { passenger->SetObjective(OBJECTIVE_LEAVE_VEHICLE, veh); +#ifdef VC_PED_PORTS + passenger->m_leaveCarTimer = CTimer::GetTimeInMilliseconds(); +#endif + } } } else if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) { if (ped->m_nPedState == PED_CARJACK) { @@ -11579,12 +11663,20 @@ CPed::PedStaggerCB(CAnimBlendAssociation* animAssoc, void* arg) } // It's "CPhoneInfo::ProcessNearestFreePhone" in PC IDB, but it's not true, someone made it up. -// TO-DO: No peds run to phones to report crimes. Make this work. bool CPed::RunToReportCrime(eCrimeType crimeToReport) { +#ifdef TOGGLEABLE_BETA_FEATURES + if (!bMakePedsRunToPhonesToReportCrimes) + return false; + + if (bRunningToPhone) + return true; +#else + // They changed true into false to make this function unusable. So running to phone actually starts but first frame after that cancels it. if (m_nPedState == PED_SEEK_POS) return false; +#endif CVector pos = GetPosition(); int phoneId = gPhoneInfo.FindNearestFreePhone(&pos); @@ -11592,12 +11684,14 @@ CPed::RunToReportCrime(eCrimeType crimeToReport) if (phoneId == -1) return false; - if (gPhoneInfo.m_aPhones[phoneId].m_nState != PHONE_STATE_FREE) + CPhone *phone = &gPhoneInfo.m_aPhones[phoneId]; + if (phone->m_nState != PHONE_STATE_FREE) return false; bRunningToPhone = true; + SetSeek(phone->m_pEntity->GetPosition() - phone->m_pEntity->GetForward(), 1.3f); // original: phone.m_vecPos, 0.3f SetMoveState(PEDMOVE_RUN); - SetSeek(gPhoneInfo.m_aPhones[phoneId].m_vecPos, 0.3f); + bIsRunning = true; // not there in original m_phoneId = phoneId; m_crimeToReportOnPhone = crimeToReport; return true; @@ -11650,7 +11744,7 @@ CPed::RegisterThreatWithGangPeds(CEntity *attacker) if (nearVehDriver && nearVehDriver != this && nearVehDriver->m_nPedType == m_nPedType) { if (nearVeh->IsVehicleNormal() && nearVeh->IsCar()) { - nearVeh->AutoPilot.m_nCruiseSpeed = 60.0f * nearVeh->pHandling->Transmission.fUnkMaxVelocity * 0.8f; + nearVeh->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * nearVeh->pHandling->Transmission.fUnkMaxVelocity * 0.8f; nearVeh->AutoPilot.m_nCarMission = MISSION_RAMPLAYER_FARAWAY; nearVeh->m_status = STATUS_PHYSICS; nearVeh->AutoPilot.m_nTempAction = TEMPACT_NONE; @@ -11926,6 +12020,20 @@ CPed::ReplaceWeaponWhenExitingVehicle(void) } } +// Same, it's inlined in III. +inline void +CPed::RemoveWeaponWhenEnteringVehicle(void) +{ + if (IsPlayer() && HasWeapon(WEAPONTYPE_UZI) && GetWeapon(WEAPONTYPE_UZI).m_nAmmoTotal > 0) { + if (m_storedWeapon == WEAPONTYPE_UNIDENTIFIED) + m_storedWeapon = GetWeapon()->m_eWeaponType; + SetCurrentWeapon(WEAPONTYPE_UZI); + } else { + CWeaponInfo *ourWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + RemoveWeaponModel(ourWeapon->m_nModelId); + } +} + void CPed::PedSetOutTrainCB(CAnimBlendAssociation *animAssoc, void *arg) { @@ -12286,7 +12394,7 @@ CPed::PossiblyFindBetterPosToSeekCar(CVector *pos, CVehicle *veh) helperPos = GetPosition() - foundPos; helperPos.z = 0.0f; - if (helperPos.MagnitudeSqr() <= 0.25f) + if (helperPos.MagnitudeSqr() <= sq(0.5f)) return false; pos->x = foundPos.x; @@ -12297,11 +12405,8 @@ CPed::PossiblyFindBetterPosToSeekCar(CVector *pos, CVehicle *veh) void CPed::Render(void) { - if (!bInVehicle - || m_nPedState == PED_EXIT_CAR - || m_nPedState == PED_DRAG_FROM_CAR - || bRenderPedInCar && - sq(25.0f * TheCamera.LODDistMultiplier) >= (TheCamera.GetPosition() - GetPosition()).MagnitudeSqr()) { + if (!bInVehicle || m_nPedState == PED_EXIT_CAR || m_nPedState == PED_DRAG_FROM_CAR || + bRenderPedInCar && sq(25.0f * TheCamera.LODDistMultiplier) >= (TheCamera.GetPosition() - GetPosition()).MagnitudeSqr()) { CEntity::Render(); } } @@ -12331,7 +12436,7 @@ CPed::ProcessObjective(void) } if (m_pedInObjective) { - if (m_pedInObjective->bInVehicle && m_pedInObjective->m_nPedState != PED_DRAG_FROM_CAR && m_pedInObjective->m_pMyVehicle) { + if (m_pedInObjective->InVehicle() && m_pedInObjective->m_nPedState != PED_DRAG_FROM_CAR) { targetCarOrHisPos = m_pedInObjective->m_pMyVehicle->GetPosition(); } else { targetCarOrHisPos = m_pedInObjective->GetPosition(); @@ -12358,7 +12463,7 @@ CPed::ProcessObjective(void) SetMoveState(PEDMOVE_STILL); break; case OBJECTIVE_FLEE_TILL_SAFE: - if (bInVehicle && m_pMyVehicle) { + if (InVehicle()) { SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); bFleeAfterExitingCar = true; } else if (m_nPedState != PED_FLEE_POS) { @@ -12414,18 +12519,18 @@ CPed::ProcessObjective(void) SetObjective(OBJECTIVE_FLEE_TILL_SAFE); break; } - if (bInVehicle && m_pMyVehicle) { + if (InVehicle()) { if (distWithTarget.Magnitude() >= 20.0f - || m_pMyVehicle->m_vecMoveSpeed.MagnitudeSqr() >= 0.0004f) { + || m_pMyVehicle->m_vecMoveSpeed.MagnitudeSqr() >= sq(0.02f)) { if (m_pMyVehicle->pDriver == this && !m_pMyVehicle->m_nGettingInFlags) { m_pMyVehicle->m_status = STATUS_PHYSICS; m_pMyVehicle->AutoPilot.m_nPrevRouteNode = 0; if (m_nPedType == PEDTYPE_COP) { - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->m_nWantedLevel * 0.1f + 0.6f) * (60.0f * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity); + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = (FindPlayerPed()->m_pWanted->m_nWantedLevel * 0.1f + 0.6f) * (GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity); m_pMyVehicle->AutoPilot.m_nCarMission = CCarAI::FindPoliceCarMissionForWantedLevel(); } else { - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 60.0f * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity * 0.8f; + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity * 0.8f; m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_RAMPLAYER_FARAWAY; } m_pMyVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; @@ -12512,7 +12617,7 @@ CPed::ProcessObjective(void) case OBJECTIVE_KILL_CHAR_ON_FOOT: { bool killPlayerInNoPoliceZone = false; - if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT && bInVehicle && m_pMyVehicle) { + if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT && InVehicle()) { SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); break; } @@ -12867,7 +12972,7 @@ CPed::ProcessObjective(void) case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: { - if (bInVehicle && m_pMyVehicle) { + if (InVehicle()) { if (m_nPedState == PED_DRIVING) SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); } else if (m_nPedState != PED_FLEE_ENTITY) { @@ -13166,12 +13271,12 @@ CPed::ProcessObjective(void) { distWithTarget = m_nextRoutePointPos - GetPosition(); distWithTarget.z = 0.0f; - if (bInVehicle && m_pMyVehicle) { + if (InVehicle()) { CCarAI::GetCarToGoToCoors(m_pMyVehicle, &m_nextRoutePointPos); CCarCtrl::RegisterVehicleOfInterest(m_pMyVehicle); - if (distWithTarget.MagnitudeSqr() < 400.0f) { + if (distWithTarget.MagnitudeSqr() < sq(20.0f)) { m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; - CPed::ForceStoredObjective(OBJECTIVE_GOTO_AREA_ANY_MEANS); + ForceStoredObjective(OBJECTIVE_GOTO_AREA_ANY_MEANS); SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); } break; @@ -13215,7 +13320,7 @@ CPed::ProcessObjective(void) case OBJECTIVE_RUN_TO_AREA: { if ((m_objective == OBJECTIVE_GOTO_AREA_ON_FOOT || m_objective == OBJECTIVE_RUN_TO_AREA) - && bInVehicle && m_pMyVehicle) { + && InVehicle()) { SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); } else { distWithTarget = m_nextRoutePointPos - GetPosition(); @@ -13408,8 +13513,8 @@ CPed::ProcessObjective(void) return; } float distWithTargetScSqr = distWithTarget.MagnitudeSqr(); - if (distWithTargetScSqr <= 100.0f) { - if (distWithTargetScSqr <= 1.96f) { + if (distWithTargetScSqr <= sq(10.0f)) { + if (distWithTargetScSqr <= sq(1.4f)) { CAnimBlendAssociation *reloadAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_AK_RELOAD); m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( m_pedInObjective->GetPosition().x, m_pedInObjective->GetPosition().y, @@ -13476,12 +13581,16 @@ CPed::ProcessObjective(void) // fall through case OBJECTIVE_LEAVE_VEHICLE: if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) { - if (bInVehicle && m_pMyVehicle) { + if (InVehicle()) { if (m_nPedState != PED_EXIT_CAR && m_nPedState != PED_DRAG_FROM_CAR && m_nPedState != PED_EXIT_TRAIN && (m_nPedType != PEDTYPE_COP || m_pMyVehicle->m_vecMoveSpeed.MagnitudeSqr2D() < 0.000025f)) { if (m_pMyVehicle->IsTrain()) SetExitTrain(m_pMyVehicle); +#ifdef VC_PED_PORTS + else if (m_pMyVehicle->IsBoat()) + SetExitBoat(m_pMyVehicle); +#endif else SetExitCar(m_pMyVehicle, 0); } @@ -13494,14 +13603,11 @@ CPed::ProcessObjective(void) case OBJECTIVE_LEAVE_CAR_AND_DIE: { if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) { - if (bInVehicle && m_pMyVehicle) { - if (m_nPedState != PED_EXIT_CAR && m_nPedState != PED_DRAG_FROM_CAR - && m_nPedState != PED_EXIT_TRAIN) { - // VC calls SetExitBoat for boats, which is not seperate func. in III but housed in CPlayerInfo::Process. - // This obj. will probably break/crash game if ped was in boat. - if (m_pMyVehicle->IsTrain()) - SetExitTrain(m_pMyVehicle); - else if (m_pMyVehicle->bIsBus || m_pMyVehicle->IsBoat()) + if (InVehicle()) { + if (m_nPedState != PED_EXIT_CAR && m_nPedState != PED_DRAG_FROM_CAR && m_nPedState != PED_EXIT_TRAIN) { + if (m_pMyVehicle->IsBoat()) + SetExitBoat(m_pMyVehicle); + else if (m_pMyVehicle->bIsBus) SetExitCar(m_pMyVehicle, 0); else { eCarNodes doorNode = CAR_DOOR_LF; @@ -13672,15 +13778,19 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) if (m_nMoveState == PEDMOVE_NONE || m_nMoveState == PEDMOVE_STILL) return; - if (CharCreatedBy != MISSION_CHAR && obj->m_modelIndex == MI_PHONEBOOTH1) { - bool isRunning = m_nMoveState == PEDMOVE_RUN || m_nMoveState == PEDMOVE_SPRINT; - SetFlee(obj, 5000); - bUsePedNodeSeek = true; - m_pNextPathNode = nil; - if (!isRunning) - SetMoveState(PEDMOVE_WALK); - return; - } +#ifdef TOGGLEABLE_BETA_FEATURES + if (!bMakePedsRunToPhonesToReportCrimes) +#endif + if (CharCreatedBy != MISSION_CHAR && obj->m_modelIndex == MI_PHONEBOOTH1) { + bool isRunning = m_nMoveState == PEDMOVE_RUN || m_nMoveState == PEDMOVE_SPRINT; + SetFlee(obj, 5000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + if (!isRunning) + SetMoveState(PEDMOVE_WALK); + return; + } + CVector2D adjustedColMin(objColMin.x - 0.35f, objColMin.y - 0.35f); CVector2D adjustedColMax(objColMax.x + 0.35f, objColMax.y + 0.35f); @@ -14375,7 +14485,7 @@ CPed::ProcessEntityCollision(CEntity *collidingEnt, CColPoint *collidingPoints) #else float speedSqr = 0.0f; if (!m_ped_flagA2) { - if (m_vecMoveSpeed.z >= -0.25f && (speedSqr = m_vecMoveSpeed.MagnitudeSqr()) <= 0.25f) { + if (m_vecMoveSpeed.z >= -0.25f && (speedSqr = m_vecMoveSpeed.MagnitudeSqr()) <= sq(0.5f)) { if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL) && -0.016f * CTimer::GetTimeStep() > m_vecMoveSpeed.z) { InflictDamage(collidingEnt, WEAPONTYPE_FALL_DAMAGE, 15.0f, PEDPIECE_TORSO, 2); @@ -14691,7 +14801,7 @@ CPed::SetRadioStation(void) } } -bool +inline bool CPed::IsNotInWreckedVehicle() { return m_pMyVehicle != nil && m_pMyVehicle->m_status != STATUS_WRECKED; @@ -15302,7 +15412,7 @@ CPed::ScanForInterestingStuff(void) for (int i = 0; i < m_numNearPeds; ++i) { CPed *nearPed = m_nearPeds[i]; - if ((nearPed->GetPosition() - GetPosition()).MagnitudeSqr() > 49.0f) + if ((nearPed->GetPosition() - GetPosition()).MagnitudeSqr() > sq(7.0f)) break; if ((nearPed->m_nPedType == PEDTYPE_CIVFEMALE || nearPed->m_nPedType == PEDTYPE_CIVMALE @@ -15468,7 +15578,7 @@ CPed::ScanForThreats(void) CPed *deadPed = nil; if (fearFlags & PED_FLAG_DEADPEDS && CharCreatedBy != MISSION_CHAR - && (deadPed = CheckForDeadPeds()) != nil && (deadPed->GetPosition() - ourPos).MagnitudeSqr() < 400.0f) { + && (deadPed = CheckForDeadPeds()) != nil && (deadPed->GetPosition() - ourPos).MagnitudeSqr() < sq(20.0f)) { m_pEventEntity = deadPed; m_pEventEntity->RegisterReference((CEntity **) &m_pEventEntity); return PED_FLAG_DEADPEDS; @@ -15695,21 +15805,21 @@ CPed::SeekCar(void) } bool foundBetterPosToSeek = PossiblyFindBetterPosToSeekCar(&dest, vehToSeek); m_vecSeekPos = dest; - float distToDest = (m_vecSeekPos - GetPosition()).MagnitudeSqr(); + float distToDestSqr = (m_vecSeekPos - GetPosition()).MagnitudeSqr(); #ifndef VC_PED_PORTS if (bIsRunning) SetMoveState(PEDMOVE_RUN); #else if (bIsRunning || - vehToSeek->pDriver && distToDest > 4.0f && (Abs(vehToSeek->m_vecMoveSpeed.x) > 0.01f || Abs(vehToSeek->m_vecMoveSpeed.y) > 0.01f)) + vehToSeek->pDriver && distToDestSqr > sq(2.0f) && (Abs(vehToSeek->m_vecMoveSpeed.x) > 0.01f || Abs(vehToSeek->m_vecMoveSpeed.y) > 0.01f)) SetMoveState(PEDMOVE_RUN); #endif - else if (distToDest < 4.0f) + else if (distToDestSqr < sq(2.0f)) SetMoveState(PEDMOVE_WALK); - if (distToDest >= 1.0f) + if (distToDestSqr >= 1.0f) bCanPedEnterSeekedCar = false; - else if (2.0f * vehToSeek->GetColModel()->boundingBox.max.x > distToDest) + else if (2.0f * vehToSeek->GetColModel()->boundingBox.max.x > distToDestSqr) bCanPedEnterSeekedCar = true; if (vehToSeek->m_nGettingInFlags & GetCarDoorFlag(m_vehEnterType)) @@ -15717,6 +15827,7 @@ CPed::SeekCar(void) else bVehEnterDoorIsBlocked = false; + // Arrived to the car if (Seek()) { if (!foundBetterPosToSeek) { if (1.5f + GetPosition().z > dest.z && GetPosition().z - 0.5f < dest.z) { @@ -16066,7 +16177,7 @@ CPed::UpdateFromLeader(void) return; CVector leaderDist; - if (m_leader->bInVehicle && m_leader->m_pMyVehicle) + if (m_leader->InVehicle()) leaderDist = m_leader->m_pMyVehicle->GetPosition() - GetPosition(); else leaderDist = m_leader->GetPosition() - GetPosition(); @@ -16530,17 +16641,8 @@ CPed::WarpPedIntoCar(CVehicle *car) CWeaponInfo *ourWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); RemoveWeaponModel(ourWeapon->m_nModelId); } else { - // Because we can use Uzi for drive by - // RemoveWeaponWhenEnteringVehicle in VC - if (IsPlayer() && HasWeapon(WEAPONTYPE_UZI) && GetWeapon(WEAPONTYPE_UZI).m_nAmmoTotal > 0) { - if (m_storedWeapon == WEAPONTYPE_UNIDENTIFIED) - m_storedWeapon = GetWeapon()->m_eWeaponType; - SetCurrentWeapon(WEAPONTYPE_UZI); - } else { - CWeaponInfo *ourWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - RemoveWeaponModel(ourWeapon->m_nModelId); - } + RemoveWeaponWhenEnteringVehicle(); if (car->bLowVehicle) m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_LSIT, 100.0f); @@ -16554,6 +16656,676 @@ CPed::WarpPedIntoCar(CVehicle *car) bChangedSeat = true; } +void +CPed::SetObjective(eObjective newObj, CVector dest) +{ + if (DyingOrDead()) + return; + + if (m_prevObjective != OBJECTIVE_NONE && m_prevObjective == newObj) + return; + + SetObjectiveTimer(0); + if (m_objective == newObj) { + if (newObj == OBJECTIVE_GOTO_AREA_ANY_MEANS || newObj == OBJECTIVE_GOTO_AREA_ON_FOOT || newObj == OBJECTIVE_RUN_TO_AREA) { + if (m_nextRoutePointPos == dest) + return; + } else if (newObj == OBJECTIVE_GUARD_SPOT) { + if (m_vecSeekPosEx == dest) + return; + } + } + +#ifdef VC_PED_PORTS + ClearPointGunAt(); +#endif + bObjectiveCompleted = false; + switch (newObj) { + case OBJECTIVE_GUARD_SPOT: + m_vecSeekPosEx = dest; + m_distanceToCountSeekDoneEx = 5.0f; + SetMoveState(PEDMOVE_STILL); + break; + case OBJECTIVE_GUARD_AREA: + case OBJECTIVE_WAIT_IN_CAR: + case OBJECTIVE_WAIT_IN_CAR_THEN_GETOUT: + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + case OBJECTIVE_FOLLOW_PED_IN_FORMATION: + case OBJECTIVE_LEAVE_VEHICLE: + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + case OBJECTIVE_FOLLOW_CAR_IN_CAR: + case OBJECTIVE_FIRE_AT_OBJ_FROM_VEHICLE: + case OBJECTIVE_DESTROY_OBJ: + case OBJECTIVE_DESTROY_CAR: + break; + case OBJECTIVE_GOTO_AREA_ANY_MEANS: + case OBJECTIVE_GOTO_AREA_ON_FOOT: + bIsRunning = false; + m_pNextPathNode = nil; + m_nextRoutePointPos = dest; + m_vecSeekPos = m_nextRoutePointPos; + m_distanceToCountSeekDone = 0.5f; + bUsePedNodeSeek = true; + if (sq(m_distanceToCountSeekDone) > (m_nextRoutePointPos - GetPosition()).MagnitudeSqr2D()) + return; + break; + case OBJECTIVE_RUN_TO_AREA: + bIsRunning = true; + m_pNextPathNode = nil; + m_nextRoutePointPos = dest; + m_vecSeekPos = m_nextRoutePointPos; + m_distanceToCountSeekDone = 0.5f; + bUsePedNodeSeek = true; + if (sq(m_distanceToCountSeekDone) > (m_nextRoutePointPos - GetPosition()).MagnitudeSqr2D()) + return; + break; + } + + if (IsTemporaryObjective(m_objective)) { + m_prevObjective = newObj; + } else { + if (m_objective != newObj) + SetStoredObjective(); + + m_objective = newObj; + } +} + +void +CPed::SetMoveAnim(void) +{ + if (m_nStoredMoveState == m_nMoveState || !IsPedInControl()) + return; + + if (m_nMoveState == PEDMOVE_NONE) { + m_nStoredMoveState = PEDMOVE_NONE; + return; + } + + AssocGroupId animGroupToUse; + if (m_leader && m_leader->IsPlayer()) + animGroupToUse = ASSOCGRP_PLAYER; + else + animGroupToUse = m_animGroup; + + CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FLAG400); + if (!animAssoc) { + CAnimBlendAssociation *fightIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE); + animAssoc = fightIdleAssoc; + if (fightIdleAssoc && m_nPedState == PED_FIGHT) + return; + + if (fightIdleAssoc) { + CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); + if (!idleAssoc || idleAssoc->blendDelta <= 0.0f) { + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_IDLE_STANCE, 8.0f); + } + } + } + if (!animAssoc) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED); + if (animAssoc) + if (m_nWaitState == WAITSTATE_STUCK || m_nWaitState == WAITSTATE_FINISH_FLEE) + return; + + if (animAssoc) { + CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); + if (!idleAssoc || idleAssoc->blendDelta <= 0.0f) { + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_IDLE_STANCE, 4.0f); + } + } + } + if (!animAssoc) { + m_nStoredMoveState = m_nMoveState; + if (m_nMoveState == PEDMOVE_WALK || m_nMoveState == PEDMOVE_RUN || m_nMoveState == PEDMOVE_SPRINT) { + for (CAnimBlendAssociation *assoc = RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_PARTIAL); + assoc; assoc = RpAnimBlendGetNextAssociation(assoc, ASSOC_PARTIAL)) { + + if (!(assoc->flags & ASSOC_FADEOUTWHENDONE)) { + assoc->blendDelta = -2.0f; + assoc->flags |= ASSOC_DELETEFADEDOUT; + } + } + + ClearAimFlag(); + ClearLookFlag(); + } + + switch (m_nMoveState) { + case PEDMOVE_STILL: + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_IDLE_STANCE, 4.0f); + break; + case PEDMOVE_WALK: + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_WALK, 1.0f); + break; + case PEDMOVE_RUN: + if (m_nPedState == PED_FLEE_ENTITY) { + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_RUN, 3.0f); + } else { + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_RUN, 1.0f); + } + break; + case PEDMOVE_SPRINT: + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_SPRINT, 1.0f); + break; + default: + break; + } + + if (animAssoc) { + if (m_leader) { + CAnimBlendAssociation *walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_WALK); + if (!walkAssoc) + walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_RUN); + + if (!walkAssoc) + walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_SPRINT); + + if (walkAssoc) { + animAssoc->speed = walkAssoc->speed; + } else { + if (CharCreatedBy == MISSION_CHAR) + animAssoc->speed = 1.0f; + else + animAssoc->speed = 1.2f - m_randomSeed * 0.4f / MYRAND_MAX; + + } + } else { + if (CharCreatedBy == MISSION_CHAR) + animAssoc->speed = 1.0f; + else + animAssoc->speed = 1.2f - m_randomSeed * 0.4f / MYRAND_MAX; + } + } + } +} + +void +CPed::SetEnterCar_AllClear(CVehicle *car, uint32 doorNode, uint32 doorFlag) +{ + float zDiff = 0.0f; + RemoveWeaponWhenEnteringVehicle(); + car->m_nGettingInFlags |= doorFlag; + bVehEnterDoorIsBlocked = false; + if (m_nPedState != PED_SEEK_CAR && m_nPedState != PED_SEEK_IN_BOAT) + SetStoredState(); + + m_pSeekTarget = car; + m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); + m_vehEnterType = doorNode; + m_nPedState = PED_ENTER_CAR; + if (m_vehEnterType == CAR_DOOR_RF && m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && car->m_vehType != VEHICLE_TYPE_BIKE) { + car->bIsBeingCarJacked = true; + } + + m_pMyVehicle = (CVehicle*)m_pSeekTarget; + m_pMyVehicle->RegisterReference((CEntity**) &m_pMyVehicle); + ((CVehicle*)m_pSeekTarget)->m_nNumGettingIn++; + bUsesCollision = false; + CVector doorOpenPos = GetPositionToOpenCarDoor(car, m_vehEnterType); + + // Because buses have stairs + if (!m_pMyVehicle->bIsBus) + zDiff = max(0.0f, doorOpenPos.z - GetPosition().z); + + m_vecOffsetSeek = doorOpenPos - GetPosition(); + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 600; + if (car->IsBoat()) { + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DRIVE_BOAT, 100.0f); +#ifdef VC_PED_PORTS + PedSetInCarCB(nil, this); + m_ped_flagI4 = true; +#else + m_pVehicleAnim->SetFinishCallback(PedSetInCarCB, this); +#endif + if (IsPlayer()) + CWaterLevel::AllocateBoatWakeArray(); + } else { + if (zDiff > 4.4f) { + if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGNHI_RHS, 4.0f); + else + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGNHI_LHS, 4.0f); + + } else { + if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGN_RHS, 4.0f); + else + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGN_LHS, 4.0f); + } + m_pVehicleAnim->SetFinishCallback(PedAnimAlignCB, this); + car->AutoPilot.m_nCruiseSpeed = 0; + } +} + +void +CPed::WanderPath(void) +{ + if (!m_pNextPathNode) { + printf("THIS SHOULDN@T HAPPEN TOO OFTEN\n"); + SetIdle(); + return; + } + if (m_nWaitState == WAITSTATE_FALSE) { + if (m_nMoveState == PEDMOVE_STILL || m_nMoveState == PEDMOVE_NONE) + SetMoveState(PEDMOVE_WALK); + } + m_vecSeekPos = m_pNextPathNode->pos; + m_vecSeekPos.z += 1.0f; + + // Only returns true when ped is stuck(not stopped) I think, then we should assign new direction or wait state to him. + if (!Seek()) + return; + + CPathNode *previousLastNode = m_pLastPathNode; + uint8 randVal = (m_randomSeed + 3 * CTimer::GetFrameCounter()) % 100; + + // We don't prefer 180-degree turns in normal situations + uint8 dirWeWouldntPrefer = m_nPathDir; + if (dirWeWouldntPrefer <= 3) + dirWeWouldntPrefer += 4; + else + dirWeWouldntPrefer -= 4; + + CPathNode *nodeWeWouldntPrefer = nil; + uint8 dirToSet = 9; // means undefined + uint8 dirWeWouldntPrefer2 = 9; // means undefined + if (randVal <= 90) { + if (randVal > 80) { + m_nPathDir += 2; + m_nPathDir %= 8; + } + } else { + m_nPathDir -= 2; + if (m_nPathDir < 0) + m_nPathDir += 8; + } + + m_pLastPathNode = m_pNextPathNode; + ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, + m_nPathDir, &dirToSet); + + uint8 tryCount = 0; + + // NB: SetWanderPath checks for m_nPathDir == dirToStartWith, this one checks for tryCount > 7 + while (!m_pNextPathNode) { + tryCount++; + m_nPathDir = (m_nPathDir + 1) % 8; + + // We're at where we started and couldn't find any node + if (tryCount > 7) { + if (!nodeWeWouldntPrefer) { + ClearAll(); + SetIdle(); + // Probably this text carried over here after copy-pasting this loop from early version of SetWanderPath. + Error("Can't find valid path node, SetWanderPath, Ped.cpp"); + return; + } + m_pNextPathNode = nodeWeWouldntPrefer; + dirToSet = dirWeWouldntPrefer2; + } else { + ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, + m_nPathDir, &dirToSet); + if (m_pNextPathNode) { + if (dirToSet == dirWeWouldntPrefer) { + nodeWeWouldntPrefer = m_pNextPathNode; + dirWeWouldntPrefer2 = dirToSet; + m_pNextPathNode = nil; + } + } + } + } + + m_nPathDir = dirToSet; + if (m_pLastPathNode == m_pNextPathNode) { + m_pNextPathNode = previousLastNode; + SetWaitState(WAITSTATE_DOUBLEBACK, nil); + Say(SOUND_PED_WAIT_DOUBLEBACK); + } else if (ThePaths.TestForPedTrafficLight(m_pLastPathNode, m_pNextPathNode)) { + SetWaitState(WAITSTATE_TRAFFIC_LIGHTS, nil); + } else if (ThePaths.TestCrossesRoad(m_pLastPathNode, m_pNextPathNode)) { + SetWaitState(WAITSTATE_CROSS_ROAD, nil); + } else if (m_pNextPathNode == previousLastNode) { + SetWaitState(WAITSTATE_DOUBLEBACK, nil); + Say(SOUND_PED_WAIT_DOUBLEBACK); + } +} + +bool +CPed::WarpPedToNearEntityOffScreen(CEntity *warpTo) +{ + bool teleported = false; + if (GetIsOnScreen() || m_leaveCarTimer > CTimer::GetTimeInMilliseconds()) + return false; + + CVector warpToPos = warpTo->GetPosition(); + CVector distVec = warpToPos - GetPosition(); + float halfOfDist = distVec.Magnitude() * 0.5f; + CVector halfNormalizedDist = distVec / halfOfDist; + + CVector appropriatePos = GetPosition(); + CVector zCorrectedPos = appropriatePos; + int tryCount = min(10, halfOfDist); + for (int i = 0; i < tryCount; ++i) { + appropriatePos += halfNormalizedDist; + CPedPlacement::FindZCoorForPed(&zCorrectedPos); + + if (Abs(zCorrectedPos.z - warpToPos.z) >= 3.0f && Abs(zCorrectedPos.z - appropriatePos.z) >= 3.0f) + continue; + + appropriatePos.z = zCorrectedPos.z; + if (!TheCamera.IsSphereVisible(appropriatePos, 0.6f, &TheCamera.GetCameraMatrix()) + && CWorld::GetIsLineOfSightClear(appropriatePos, warpToPos, true, true, false, true, false, false, false) + && !CWorld::TestSphereAgainstWorld(appropriatePos, 0.6f, this, true, true, false, true, false, false)) { + teleported = true; + Teleport(appropriatePos); + } + } + m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 3000; + return teleported; +} + +bool +CPed::WarpPedToNearLeaderOffScreen(void) +{ + bool teleported = false; + if (GetIsOnScreen() || m_leaveCarTimer > CTimer::GetTimeInMilliseconds()) + return false; + + CVector warpToPos = m_leader->GetPosition(); + CVector distVec = warpToPos - GetPosition(); + float halfOfDist = distVec.Magnitude() * 0.5f; + CVector halfNormalizedDist = distVec / halfOfDist; + + CVector appropriatePos = GetPosition(); + CVector zCorrectedPos = appropriatePos; + int tryCount = min(10, halfOfDist); + for (int i = 0; i < tryCount; ++i) { + appropriatePos += halfNormalizedDist; + CPedPlacement::FindZCoorForPed(&zCorrectedPos); + + if (Abs(zCorrectedPos.z - warpToPos.z) >= 3.0f && Abs(zCorrectedPos.z - appropriatePos.z) >= 3.0f) + continue; + + appropriatePos.z = zCorrectedPos.z; + if (!TheCamera.IsSphereVisible(appropriatePos, 0.6f, &TheCamera.GetCameraMatrix()) + && CWorld::GetIsLineOfSightClear(appropriatePos, warpToPos, true, true, false, true, false, false, false) + && !CWorld::TestSphereAgainstWorld(appropriatePos, 0.6f, this, true, true, false, true, false, false)) { + teleported = true; + Teleport(appropriatePos); + } + } + m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 3000; + return teleported; +} + +void +CPed::SetCarJack_AllClear(CVehicle *car, uint32 doorNode, uint32 doorFlag) +{ + RemoveWeaponWhenEnteringVehicle(); + if (m_nPedState != PED_SEEK_CAR) + SetStoredState(); + + m_pSeekTarget = car; + m_pSeekTarget->RegisterReference((CEntity**)&m_pSeekTarget); + m_nPedState = PED_CARJACK; + car->bIsBeingCarJacked = true; + m_pMyVehicle = (CVehicle*)m_pSeekTarget; + m_pMyVehicle->RegisterReference((CEntity**)&m_pMyVehicle); + ((CVehicle*)m_pSeekTarget)->m_nNumGettingIn++; + + Say(m_nPedType == PEDTYPE_COP ? SOUND_PED_ARREST_COP : SOUND_PED_CAR_JACKING); + CVector carEnterPos; + carEnterPos = GetPositionToOpenCarDoor(car, m_vehEnterType); + + car->m_nGettingInFlags |= doorFlag; + m_vecOffsetSeek = carEnterPos - GetPosition(); + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 600; + float zDiff = max(0.0f, carEnterPos.z - GetPosition().z); + bUsesCollision = false; + + if (zDiff > 4.4f) { + if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGNHI_RHS, 4.0f); + else + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGNHI_LHS, 4.0f); + + } else { + if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGN_RHS, 4.0f); + else + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGN_LHS, 4.0f); + } + + m_pVehicleAnim->SetFinishCallback(PedAnimAlignCB, this); +} + +void +CPed::SetObjective(eObjective newObj, CVector dest, float safeDist) +{ + if (DyingOrDead()) + return; + + if (m_prevObjective != OBJECTIVE_NONE && m_prevObjective == newObj) + return; + + SetObjectiveTimer(0); + if (m_objective == newObj) { + if (newObj == OBJECTIVE_GOTO_AREA_ANY_MEANS || newObj == OBJECTIVE_GOTO_AREA_ON_FOOT || newObj == OBJECTIVE_RUN_TO_AREA) { + if (m_nextRoutePointPos == dest && m_distanceToCountSeekDone == safeDist) + return; + } else if (newObj == OBJECTIVE_GUARD_SPOT) { + if (m_vecSeekPosEx == dest && m_distanceToCountSeekDoneEx == safeDist) + return; + } + } + +#ifdef VC_PED_PORTS + ClearPointGunAt(); +#endif + bObjectiveCompleted = false; + if (IsTemporaryObjective(m_objective)) { + m_prevObjective = newObj; + } else { + if (m_objective != newObj) + SetStoredObjective(); + + m_objective = newObj; + } + + if (newObj == OBJECTIVE_GUARD_SPOT) { + m_vecSeekPosEx = dest; + m_distanceToCountSeekDoneEx = safeDist; + } else if (newObj == OBJECTIVE_GOTO_AREA_ANY_MEANS || newObj == OBJECTIVE_GOTO_AREA_ON_FOOT || newObj == OBJECTIVE_RUN_TO_AREA) { + m_pNextPathNode = nil; + m_nextRoutePointPos = dest; + m_vecSeekPos = m_nextRoutePointPos; + bUsePedNodeSeek = true; + } +} + +void +CPed::SetCarJack(CVehicle* car) +{ + uint8 doorFlag; + eDoors door; + CPed *pedInSeat = nil; + + if (car->IsBoat()) + return; + + switch (m_vehEnterType) { + case CAR_DOOR_RF: + doorFlag = CAR_DOOR_FLAG_RF; + door = DOOR_FRONT_RIGHT; + if (car->pPassengers[0]) { + pedInSeat = car->pPassengers[0]; + } else if (m_nPedType == PEDTYPE_COP) { + pedInSeat = car->pDriver; + } + break; + case CAR_DOOR_RR: + doorFlag = CAR_DOOR_FLAG_RR; + door = DOOR_REAR_RIGHT; + pedInSeat = car->pPassengers[2]; + break; + case CAR_DOOR_LF: + doorFlag = CAR_DOOR_FLAG_LF; + door = DOOR_FRONT_LEFT; + pedInSeat = car->pDriver; + break; + case CAR_DOOR_LR: + doorFlag = CAR_DOOR_FLAG_LR; + door = DOOR_REAR_LEFT; + pedInSeat = car->pPassengers[1]; + break; + default: + doorFlag = CAR_DOOR_FLAG_UNKNOWN; + break; + } + + if(car->bIsBus) + pedInSeat = car->pDriver; + + if (m_fHealth > 0.0f && (IsPlayer() || m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS || + (car->VehicleCreatedBy != MISSION_VEHICLE && car->m_modelIndex != MI_DODO))) + if (pedInSeat && !pedInSeat->IsPedDoingDriveByShooting() && pedInSeat->m_nPedState == PED_DRIVING) + if (m_nPedState != PED_CARJACK && !m_pVehicleAnim) + if ((car->IsDoorReady(door) || car->IsDoorFullyOpen(door))) + if (!car->bIsBeingCarJacked && !(doorFlag & car->m_nGettingInFlags) && !(doorFlag & car->m_nGettingOutFlags)) + SetCarJack_AllClear(car, m_vehEnterType, doorFlag); +} + +void +CPed::Solicit(void) +{ + if (m_standardTimer >= CTimer::GetTimeInMilliseconds() && m_carInObjective) { + CVector doorPos = GetPositionToOpenCarDoor(m_carInObjective, m_vehEnterType, 0.0f); + SetMoveState(PEDMOVE_STILL); + + // Game uses GetAngleBetweenPoints and converts it to radian + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( + doorPos.x, doorPos.y, + GetPosition().x, GetPosition().y); + + if (m_fRotationDest < 0.0f) { + m_fRotationDest = m_fRotationDest + TWOPI; + } else if (m_fRotationDest > TWOPI) { + m_fRotationDest = m_fRotationDest - TWOPI; + } + + if ((GetPosition() - doorPos).MagnitudeSqr() <= 1.0f) + return; + CAnimBlendAssociation *talkAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_HOOKERTALK); + if (talkAssoc) { + talkAssoc->blendDelta = -1000.0f; + talkAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + RestorePreviousState(); + RestorePreviousObjective(); + SetObjectiveTimer(10000); + } else if (!m_carInObjective) { + RestorePreviousState(); + RestorePreviousObjective(); + SetObjectiveTimer(10000); + } else if (CWorld::Players[CWorld::PlayerInFocus].m_nMoney <= 100) { + m_carInObjective = nil; + } else { + m_pVehicleAnim = nil; + SetLeader(m_carInObjective->pDriver); + } +} + +// Seperate function in VC, more logical. Not sure is it inlined in III. +void +CPed::SetExitBoat(CVehicle *boat) +{ +#ifndef VC_PED_PORTS + m_nPedState = PED_IDLE; + CVector firstPos = GetPosition(); + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 100.0f); + if (boat->m_modelIndex == MI_SPEEDER && boat->IsUpsideDown()) { + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_CRAWLOUT_RHS, 8.0f); + m_pVehicleAnim->SetFinishCallback(CPed::PedSetOutCarCB, this); + m_vehEnterType = CAR_DOOR_RF; + m_nPedState = PED_EXIT_CAR; + } else { + m_vehEnterType = CAR_DOOR_RF; + CPed::PedSetOutCarCB(nil, this); + bIsStanding = true; + m_pCurSurface = boat; + m_pCurSurface->RegisterReference((CEntity**)&m_pCurSurface); + } + GetPosition() = firstPos; + SetMoveState(PEDMOVE_STILL); + m_vecMoveSpeed = boat->m_vecMoveSpeed; + bTryingToReachDryLand = true; +#else + m_nPedState = PED_IDLE; + CVector newPos = GetPosition(); + RemoveInCarAnims(); + CColModel* boatCol = boat->GetColModel(); + if (boat->IsUpsideDown()) { + newPos = { 0.0f, 0.0f, boatCol->boundingBox.min.z }; + newPos = boat->GetMatrix() * newPos; + newPos.z += 1.0f; + m_vehEnterType = CAR_DOOR_RF; + PedSetOutCarCB(nil, this); + bIsStanding = true; + m_pCurSurface = boat; + m_pCurSurface->RegisterReference((CEntity**)&m_pCurSurface); + m_pCurrentPhysSurface = boat; + } else { +/* if (boat->m_modelIndex != MI_SKIMMER || boat->bIsInWater) { + if (boat->m_modelIndex == MI_SKIMMER) + newPos.z += 2.0f +*/ + m_vehEnterType = CAR_DOOR_RF; + PedSetOutCarCB(nil, this); + bIsStanding = true; + m_pCurSurface = boat; + m_pCurSurface->RegisterReference((CEntity**)&m_pCurSurface); + m_pCurrentPhysSurface = boat; + CColPoint foundCol; + CEntity *foundEnt = nil; + if (CWorld::ProcessVerticalLine(newPos, newPos.z - 1.4f, foundCol, foundEnt, false, true, false, false, false, false, nil)) + newPos.z = FEET_OFFSET + foundCol.point.z; +/* // VC specific + } else { + m_vehEnterType = CAR_DOOR_RF; + PedSetOutCarCB(nil, this); + bIsStanding = true; + SetMoveState(PEDMOVE_STILL); + bTryingToReachDryLand = true; + float upMult = 1.04f + boatCol->boundingBox.min.z; + float rightMult = 0.6f * boatCol->boundingBox.max.x; + newPos = upMult * boat->GetUp() + rightMult * boat->GetRight() + boat->GetPosition(); + GetPosition() = newPos; + if (m_pMyVehicle) { + PositionPedOutOfCollision(); + } else { + m_pMyVehicle = boat; + PositionPedOutOfCollision(); + m_pMyVehicle = nil; + } + return; + } +*/ } + GetPosition() = newPos; + SetMoveState(PEDMOVE_STILL); + m_vecMoveSpeed = boat->m_vecMoveSpeed; +#endif + // Not there in VC. + CWaterLevel::FreeBoatWakeArray(); +} + class CPed_ : public CPed { public: @@ -16569,6 +17341,7 @@ public: void Render_(void) { CPed::Render(); } void PreRender_(void) { CPed::PreRender(); } int32 ProcessEntityCollision_(CEntity *collidingEnt, CColPoint *collidingPoints) { return CPed::ProcessEntityCollision(collidingEnt, collidingPoints); } + void SetMoveAnim_(void) { CPed::SetMoveAnim(); } }; STARTPATCHES @@ -16583,6 +17356,7 @@ STARTPATCHES InjectHook(0x4D03F0, &CPed_::Render_, PATCH_JUMP); InjectHook(0x4CBB30, &CPed_::ProcessEntityCollision_, PATCH_JUMP); InjectHook(0x4CFDD0, &CPed_::PreRender_, PATCH_JUMP); + InjectHook(0x4C5A40, &CPed_::SetMoveAnim_, PATCH_JUMP); InjectHook(0x4CF8F0, &CPed::AddWeaponModel, PATCH_JUMP); InjectHook(0x4C6AA0, &CPed::AimGun, PATCH_JUMP); @@ -16622,6 +17396,8 @@ STARTPATCHES InjectHook(0x4D82C0, (void (CPed::*)(eObjective)) &CPed::SetObjective, PATCH_JUMP); InjectHook(0x4D83E0, (void (CPed::*)(eObjective, void*)) &CPed::SetObjective, PATCH_JUMP); InjectHook(0x4D89A0, (void (CPed::*)(eObjective, int16, int16)) &CPed::SetObjective, PATCH_JUMP); + InjectHook(0x4D8A90, (void (CPed::*)(eObjective, CVector)) &CPed::SetObjective, PATCH_JUMP); + InjectHook(0x4D8770, (void (CPed::*)(eObjective, CVector, float)) &CPed::SetObjective, PATCH_JUMP); InjectHook(0x4DDEC0, &CPed::ReactToAttack, PATCH_JUMP); InjectHook(0x4D0600, &CPed::SetIdle, PATCH_JUMP); InjectHook(0x4E0E00, &CPed::QuitEnteringCar, PATCH_JUMP); @@ -16777,4 +17553,10 @@ STARTPATCHES InjectHook(0x4D8F30, &CPed::UpdateFromLeader, PATCH_JUMP); InjectHook(0x4D4970, &CPed::SetPedPositionInCar, PATCH_JUMP); InjectHook(0x4D7D20, &CPed::WarpPedIntoCar, PATCH_JUMP); + InjectHook(0x4E0A40, &CPed::SetEnterCar_AllClear, PATCH_JUMP); + InjectHook(0x4D28D0, &CPed::WanderPath, PATCH_JUMP); + InjectHook(0x4E5570, &CPed::WarpPedToNearEntityOffScreen, PATCH_JUMP); + InjectHook(0x4E52A0, &CPed::WarpPedToNearLeaderOffScreen, PATCH_JUMP); + InjectHook(0x4E0220, &CPed::SetCarJack, PATCH_JUMP); + InjectHook(0x4D6780, &CPed::Solicit, PATCH_JUMP); ENDPATCHES
\ No newline at end of file diff --git a/src/peds/Ped.h b/src/peds/Ped.h index 446aab4b..49803418 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -243,9 +243,11 @@ enum PedState PED_STEP_AWAY, PED_ON_FIRE, - PED_UNKNOWN, // HANG_OUT in Fire_Head's idb + PED_UNKNOWN, // Same with IDLE, but also infects up to 5 peds with same pedType and WANDER_PATH, so they become stone too. HANG_OUT in Fire_Head's idb PED_STATES_NO_AI, + + // One of these states isn't on PS2 - start PED_JUMP, PED_FALL, PED_GETUP, @@ -256,6 +258,8 @@ enum PedState PED_ENTER_TRAIN, PED_EXIT_TRAIN, PED_ARREST_PLAYER, + // One of these states isn't on PS2 - end + PED_DRIVING, PED_PASSENGER, PED_TAXI_PASSENGER, @@ -363,7 +367,7 @@ public: uint8 bShakeFist : 1; // test shake hand at look entity uint8 bNoCriticalHits : 1; // if set, limbs won't came off - uint8 m_ped_flagI4 : 1; // we've been put to car by script? - related with cars + uint8 m_ped_flagI4 : 1; // we've been put to car by script or without align phase? - related with cars uint8 bHasAlreadyBeenRecorded : 1; uint8 bFallenDown : 1; #ifdef VC_PED_PORTS @@ -371,8 +375,8 @@ public: #else uint8 m_ped_flagI20 : 1; #endif - uint8 m_ped_flagI40 : 1; - uint8 m_ped_flagI80 : 1; + uint8 m_ped_flagI40 : 1; // bMakePedsRunToPhonesToReportCrimes makes use of this as runover by car indicator + uint8 m_ped_flagI80 : 1; // KANGAROO_CHEAT define makes use of this as cheat toggle uint8 stuff10[3]; uint8 CharCreatedBy; @@ -407,11 +411,11 @@ public: int32 m_nPrevMoveState; eWaitState m_nWaitState; uint32 m_nWaitTimer; - void *m_pPathNodesStates[8]; // seems unused, probably leftover from VC + void *m_pPathNodesStates[8]; // unused, probably leftover from VC CVector2D m_stPathNodeStates[10]; uint16 m_nPathNodes; int16 m_nCurPathNode; - int8 m_nPathState; + int8 m_nPathDir; private: int8 _pad2B5[3]; public: @@ -499,8 +503,8 @@ public: uint32 m_soundStart; uint16 m_lastQueuedSound; uint16 m_queuedSound; - CVector m_vecSeekPosEx; // used in objectives - float m_distanceToCountSeekDoneEx; // used in objectives + CVector m_vecSeekPosEx; // used for OBJECTIVE_GUARD_SPOT + float m_distanceToCountSeekDoneEx; // used for OBJECTIVE_GUARD_SPOT static void *operator new(size_t); static void *operator new(size_t, int); @@ -690,7 +694,9 @@ public: void ScanForInterestingStuff(void); void WarpPedIntoCar(CVehicle*); void SetCarJack(CVehicle*); - void WarpPedToNearLeaderOffScreen(void); + bool WarpPedToNearLeaderOffScreen(void); + void Solicit(void); + void SetExitBoat(CVehicle*); // Static methods static CVector GetLocalPositionToOpenCarDoor(CVehicle *veh, uint32 component, float offset); @@ -768,6 +774,7 @@ public: void SeekBoatPosition(void); void UpdatePosition(void); CObject *SpawnFlyingComponent(int, int8); + void SetCarJack_AllClear(CVehicle*, uint32, uint32); #ifdef VC_PED_PORTS bool CanPedJumpThis(CEntity*, CVector*); #else @@ -781,7 +788,9 @@ public: PedState GetPedState(void) { return m_nPedState; } void SetPedState(PedState state) { m_nPedState = state; } bool DyingOrDead(void) { return m_nPedState == PED_DIE || m_nPedState == PED_DEAD; } + bool InVehicle(void) { return bInVehicle && m_pMyVehicle; } // True when ped is sitting/standing in vehicle, not in enter/exit state. void ReplaceWeaponWhenExitingVehicle(void); + void RemoveWeaponWhenEnteringVehicle(void); bool IsNotInWreckedVehicle(); // set by 0482:set_threat_reaction_range_multiplier opcode @@ -796,10 +805,13 @@ public: static CVector2D ms_vec2DFleePosition; static CPedAudioData (&CommentWaitTime)[38]; -#ifndef MASTER +#ifdef TOGGLEABLE_BETA_FEATURES static bool bUnusedFightThingOnPlayer; static bool bPopHeadsOnHeadshot; + static bool bMakePedsRunToPhonesToReportCrimes; +#endif +#ifndef MASTER // Mobile things static void SwitchDebugDisplay(void); void DebugRenderOnePedText(void); @@ -809,7 +821,7 @@ public: class cPedParams { public: - char m_bDistanceCalculated; + bool m_bDistanceCalculated; char gap_1[3]; float m_fDistance; CPed *m_pPed; diff --git a/src/peds/PedStats.cpp b/src/peds/PedStats.cpp index f6508580..c393fddc 100644 --- a/src/peds/PedStats.cpp +++ b/src/peds/PedStats.cpp @@ -1,5 +1,6 @@ #include "common.h" #include "patcher.h" +#include "General.h" #include "FileMgr.h" #include "PedStats.h" @@ -112,7 +113,7 @@ CPedStats::GetPedStatType(char *name) int type; for(type = 0; type < NUM_PEDSTATS; type++) - if(strcmp(ms_apPedStats[type]->m_name, name) == 0) + if(!CGeneral::faststrcmp(ms_apPedStats[type]->m_name, name)) return type; return NUM_PEDSTATS; } diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp index 69cc316a..7c946dda 100644 --- a/src/peds/PlayerPed.cpp +++ b/src/peds/PlayerPed.cpp @@ -5,20 +5,15 @@ #include "WeaponEffects.h" #include "ModelIndices.h" #include "World.h" +#include "RpAnimBlend.h" +#include "General.h" CPlayerPed::~CPlayerPed() { delete m_pWanted; } -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); } -WRAPPER void CPlayerPed::MakeChangesForNewWeapon(int8) { EAXJMP(0x4F2560); } -WRAPPER void CPlayerPed::SetInitialState(void) { EAXJMP(0x4EFC40); } -WRAPPER void CPlayerPed::SetMoveAnim(void) { EAXJMP(0x4F3760); } WRAPPER void CPlayerPed::ProcessControl(void) { EAXJMP(0x4EFD90); } CPlayerPed::CPlayerPed(void) : CPed(PEDTYPE_PLAYER1) @@ -31,7 +26,7 @@ CPlayerPed::CPlayerPed(void) : CPed(PEDTYPE_PLAYER1) m_pWanted->Initialise(); m_pArrestingCop = nil; m_currentWeapon = WEAPONTYPE_UNARMED; - m_nSelectedWepSlot = 0; + m_nSelectedWepSlot = WEAPONTYPE_UNARMED; m_nSpeedTimer = 0; m_bSpeedTimerFlag = 0; m_pPointGunAt = nil; @@ -113,17 +108,364 @@ CPlayerPed::GetPlayerInfoForThisPlayerPed() return nil;
} +void
+CPlayerPed::SetupPlayerPed(int32 index)
+{
+ CPlayerPed *player = new CPlayerPed();
+ CWorld::Players[index].m_pPed = player;
+
+ player->SetOrientation(0.0f, 0.0f, 0.0f);
+
+ CWorld::Add(player);
+ player->m_wepAccuracy = 100; +} + +void
+CPlayerPed::DeactivatePlayerPed(int32 index)
+{
+ CWorld::Remove(CWorld::Players[index].m_pPed); +} + +void
+CPlayerPed::ReactivatePlayerPed(int32 index)
+{
+ CWorld::Add(CWorld::Players[index].m_pPed); +} + +void
+CPlayerPed::UseSprintEnergy(void)
+{
+ if (m_fCurrentStamina > -150.0f && !CWorld::Players[CWorld::PlayerInFocus].m_bInfiniteSprint
+ && !m_bAdrenalineActive) {
+ m_fCurrentStamina = m_fCurrentStamina - CTimer::GetTimeStep();
+ m_fStaminaProgress = m_fStaminaProgress + CTimer::GetTimeStep();
+ }
+
+ if (m_fStaminaProgress >= 500.0f) {
+ m_fStaminaProgress = 0;
+ if (m_fMaxStamina < 1000.0f)
+ m_fMaxStamina += 10.0f;
+ }
+} + +void
+CPlayerPed::MakeChangesForNewWeapon(int8 weapon)
+{
+ if (m_nPedState == PED_SNIPER_MODE) {
+ RestorePreviousState();
+ TheCamera.ClearPlayerWeaponMode();
+ }
+ SetCurrentWeapon(weapon);
+
+ GetWeapon()->m_nAmmoInClip = min(GetWeapon()->m_nAmmoTotal, CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_nAmountofAmmunition);
+
+ if (!(CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bCanAim))
+ ClearWeaponTarget();
+
+ CAnimBlendAssociation *weaponAnim = RpAnimBlendClumpGetAssociation(GetClump(), CWeaponInfo::GetWeaponInfo(WEAPONTYPE_SNIPERRIFLE)->m_AnimToPlay);
+ if (weaponAnim) {
+ weaponAnim->SetRun();
+ weaponAnim->flags |= ASSOC_FADEOUTWHENDONE;
+ }
+ TheCamera.ClearPlayerWeaponMode(); +} + +void
+CPlayerPed::ReApplyMoveAnims(void)
+{
+ static AnimationId moveAnims[] = { ANIM_WALK, ANIM_RUN, ANIM_SPRINT, ANIM_IDLE_STANCE, ANIM_WALK_START };
+
+ for(int i = 0; i < ARRAY_SIZE(moveAnims); i++) {
+ CAnimBlendAssociation *curMoveAssoc = RpAnimBlendClumpGetAssociation(GetClump(), moveAnims[i]);
+ if (curMoveAssoc) {
+ if (strcmp(CAnimManager::GetAnimAssociation(m_animGroup, moveAnims[i])->hierarchy->name, curMoveAssoc->hierarchy->name) != 0) {
+ CAnimBlendAssociation *newMoveAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, moveAnims[i]);
+ newMoveAssoc->blendDelta = curMoveAssoc->blendDelta;
+ newMoveAssoc->blendAmount = curMoveAssoc->blendAmount;
+ curMoveAssoc->blendDelta = -1000.0f;
+ curMoveAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ }
+ }
+ }
+} + +void
+CPlayerPed::SetInitialState(void)
+{
+ m_bAdrenalineActive = false;
+ m_nAdrenalineTime = 0;
+ CTimer::SetTimeStep(1.0f);
+ m_pSeekTarget = nil;
+ m_vecSeekPos = { 0.0f, 0.0f, 0.0f };
+ m_fleeFromPosX = 0.0f;
+ m_fleeFromPosY = 0.0f;
+ m_fleeFrom = nil;
+ m_fleeTimer = 0;
+ m_objective = OBJECTIVE_NONE;
+ m_prevObjective = OBJECTIVE_NONE;
+ bUsesCollision = true;
+ ClearAimFlag();
+ ClearLookFlag();
+ bIsPointingGunAt = false;
+ bRenderPedInCar = true;
+ if (m_pFire)
+ m_pFire->Extinguish();
+ RpAnimBlendClumpRemoveAllAssociations(GetClump());
+ m_nPedState = PED_IDLE;
+ SetMoveState(PEDMOVE_STILL);
+ m_nLastPedState = PED_NONE;
+ m_animGroup = ASSOCGRP_PLAYER;
+ m_fMoveSpeed = 0.0f;
+ m_nSelectedWepSlot = WEAPONTYPE_UNARMED;
+ m_bShouldEvade = false;
+ m_pEvadingFrom = nil;
+ bIsPedDieAnimPlaying = false;
+ SetRealMoveAnim();
+ m_bCanBeDamaged = true;
+ m_pedStats->m_temper = 50;
+ m_fWalkAngle = 0.0f;
+} + +void
+CPlayerPed::SetRealMoveAnim(void)
+{
+ CAnimBlendAssociation *curWalkAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK);
+ CAnimBlendAssociation *curRunAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN);
+ CAnimBlendAssociation *curSprintAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_SPRINT);
+ CAnimBlendAssociation *curWalkStartAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK_START);
+ CAnimBlendAssociation *curIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE);
+ CAnimBlendAssociation *curRunStopAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP);
+ CAnimBlendAssociation *curRunStopRAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP_R);
+ if (bResetWalkAnims) {
+ if (curWalkAssoc)
+ curWalkAssoc->SetCurrentTime(0.0f);
+ if (curRunAssoc)
+ curRunAssoc->SetCurrentTime(0.0f);
+ if (curSprintAssoc)
+ curSprintAssoc->SetCurrentTime(0.0f);
+ bResetWalkAnims = false;
+ }
+
+ if (!curIdleAssoc)
+ curIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED);
+ if (!curIdleAssoc)
+ curIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE);
+
+ if ((!curRunStopAssoc || !(curRunStopAssoc->IsRunning())) && (!curRunStopRAssoc || !(curRunStopRAssoc->IsRunning()))) {
+
+ if (curRunStopAssoc && curRunStopAssoc->blendDelta >= 0.0f || curRunStopRAssoc && curRunStopRAssoc->blendDelta >= 0.0f) {
+ if (curRunStopAssoc) {
+ curRunStopAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ curRunStopAssoc->blendAmount = 1.0f;
+ curRunStopAssoc->blendDelta = -8.0f;
+ } else if (curRunStopRAssoc) {
+ curRunStopRAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ curRunStopRAssoc->blendAmount = 1.0f;
+ curRunStopRAssoc->blendDelta = -8.0f;
+ }
+
+ RestoreHeadingRate();
+ if (!curIdleAssoc) {
+ if (m_fCurrentStamina < 0.0f && !CWorld::TestSphereAgainstWorld(GetPosition(), 0.0f,
+ nil, true, false, false, false, false, false)) {
+ curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 8.0f);
+
+ } else {
+ curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 8.0f);
+ }
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2500, 4000);
+ }
+ curIdleAssoc->blendAmount = 0.0f;
+ curIdleAssoc->blendDelta = 8.0f;
+
+ } else if (m_fMoveSpeed == 0.0f && !curSprintAssoc) {
+ if (!curIdleAssoc) {
+ if (m_fCurrentStamina < 0.0f && !CWorld::TestSphereAgainstWorld(GetPosition(), 0.0f,
+ nil, true, false, false, false, false, false)) {
+ curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 4.0f);
+
+ } else {
+ curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f);
+ }
+
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2500, 4000);
+ }
+
+ if (m_fCurrentStamina > 0.0f && curIdleAssoc->animId == ANIM_IDLE_TIRED) {
+ CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f);
+
+ } else if (m_nPedState != PED_FIGHT) {
+ if (m_fCurrentStamina < 0.0f && curIdleAssoc->animId != ANIM_IDLE_TIRED
+ && !CWorld::TestSphereAgainstWorld(GetPosition(), 0.0f, nil, true, false, false, false, false, false)) {
+ CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 4.0f);
+
+ } else if (curIdleAssoc->animId != ANIM_IDLE_STANCE) {
+ CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f);
+ }
+ }
+
+ m_nMoveState = PEDMOVE_STILL;
+ } else {
+ if (curIdleAssoc) {
+ if (curWalkStartAssoc) {
+ curWalkStartAssoc->blendAmount = 1.0f;
+ curWalkStartAssoc->blendDelta = 0.0f;
+ } else {
+ curWalkStartAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_WALK_START);
+ }
+ if (curWalkAssoc)
+ curWalkAssoc->SetCurrentTime(0.0f);
+ if (curRunAssoc)
+ curRunAssoc->SetCurrentTime(0.0f);
+
+ delete curIdleAssoc;
+ delete RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED);
+ delete RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE);
+ delete curSprintAssoc;
+
+ curSprintAssoc = nil;
+ m_nMoveState = PEDMOVE_WALK;
+ }
+ if (curRunStopAssoc) {
+ delete curRunStopAssoc;
+ RestoreHeadingRate();
+ }
+ if (curRunStopRAssoc) {
+ delete curRunStopRAssoc;
+ RestoreHeadingRate();
+ }
+ if (!curWalkAssoc) {
+ curWalkAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_WALK);
+ curWalkAssoc->blendAmount = 0.0f;
+ }
+ if (!curRunAssoc) {
+ curRunAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_RUN);
+ curRunAssoc->blendAmount = 0.0f;
+ }
+ if (curWalkStartAssoc && !(curWalkStartAssoc->IsRunning())) {
+ delete curWalkStartAssoc;
+ curWalkStartAssoc = nil;
+ curWalkAssoc->SetRun();
+ curRunAssoc->SetRun();
+ }
+ if (m_nMoveState == PEDMOVE_SPRINT) {
+ if (m_fCurrentStamina < 0.0f && (m_fCurrentStamina <= -150.0f || !curSprintAssoc || curSprintAssoc->blendDelta < 0.0f))
+ m_nMoveState = PEDMOVE_STILL;
+
+ if (curWalkStartAssoc)
+ m_nMoveState = PEDMOVE_STILL;
+ }
+
+ if (curSprintAssoc && (m_nMoveState != PEDMOVE_SPRINT || m_fMoveSpeed < 0.4f)) {
+ if (curSprintAssoc->blendAmount == 0.0f) {
+ curSprintAssoc->blendDelta = -1000.0f;
+ curSprintAssoc->flags |= ASSOC_DELETEFADEDOUT;
+
+ } else if (curSprintAssoc->blendDelta >= 0.0f || curSprintAssoc->blendAmount >= 0.8f) {
+ if (m_fMoveSpeed < 0.4f) {
+ AnimationId runStopAnim;
+ if (curSprintAssoc->currentTime / curSprintAssoc->hierarchy->totalLength < 0.5) // double
+ runStopAnim = ANIM_RUN_STOP;
+ else
+ runStopAnim = ANIM_RUN_STOP_R;
+ CAnimBlendAssociation* newRunStopAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, runStopAnim);
+ newRunStopAssoc->blendAmount = 1.0f;
+ newRunStopAssoc->SetDeleteCallback(RestoreHeadingRateCB, this);
+ m_headingRate = 0.0f;
+ curSprintAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ curSprintAssoc->blendDelta = -1000.0f;
+ curWalkAssoc->flags &= ~ASSOC_RUNNING;
+ curWalkAssoc->blendAmount = 0.0f;
+ curWalkAssoc->blendDelta = 0.0f;
+ curRunAssoc->flags &= ~ASSOC_RUNNING;
+ curRunAssoc->blendAmount = 0.0f;
+ curRunAssoc->blendDelta = 0.0f;
+ } else if (curSprintAssoc->blendDelta < 0.0f) {
+ curSprintAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ curSprintAssoc->blendDelta = -1.0f;
+ curRunAssoc->blendDelta = 1.0f;
+ }
+ } else if (m_fMoveSpeed < 1.0f) {
+ curSprintAssoc->blendDelta = -8.0f;
+ curRunAssoc->blendDelta = 8.0f;
+ }
+ } else if (curWalkStartAssoc) {
+ curWalkAssoc->flags &= ~ASSOC_RUNNING;
+ curRunAssoc->flags &= ~ASSOC_RUNNING;
+ curWalkAssoc->blendAmount = 0.0f;
+ curRunAssoc->blendAmount = 0.0f;
+
+ } else if (m_nMoveState == PEDMOVE_SPRINT) {
+ if (curSprintAssoc) {
+ if (curSprintAssoc->blendDelta < 0.0f) {
+ curSprintAssoc->blendDelta = 2.0f;
+ curRunAssoc->blendDelta = -2.0f;
+ }
+ } else {
+ curWalkAssoc->blendAmount = 0.0f;
+ curRunAssoc->blendAmount = 1.0f;
+ curSprintAssoc = CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_SPRINT, 2.0f);
+ }
+ UseSprintEnergy();
+ } else {
+ if (m_fMoveSpeed < 1.0f) {
+ curWalkAssoc->blendAmount = 1.0f;
+ curRunAssoc->blendAmount = 0.0f;
+ m_nMoveState = PEDMOVE_WALK;
+ } else if (m_fMoveSpeed < 2.0f) {
+ curWalkAssoc->blendAmount = 2.0f - m_fMoveSpeed;
+ curRunAssoc->blendAmount = m_fMoveSpeed - 1.0f;
+ m_nMoveState = PEDMOVE_RUN;
+ } else {
+ curWalkAssoc->blendAmount = 0.0f;
+ curRunAssoc->blendAmount = 1.0f;
+ m_nMoveState = PEDMOVE_RUN;
+ }
+ }
+ }
+ }
+ if (m_bAdrenalineActive) {
+ if (CTimer::GetTimeInMilliseconds() > m_nAdrenalineTime) {
+ m_bAdrenalineActive = false;
+ CTimer::SetTimeScale(1.0f);
+ if (curWalkStartAssoc)
+ curWalkStartAssoc->speed = 1.0f;
+ if (curWalkAssoc)
+ curWalkAssoc->speed = 1.0f;
+ if (curRunAssoc)
+ curRunAssoc->speed = 1.0f;
+ if (curSprintAssoc)
+ curSprintAssoc->speed = 1.0f;
+ } else {
+ CTimer::SetTimeScale(1.0f / 3);
+ if (curWalkStartAssoc)
+ curWalkStartAssoc->speed = 2.0f;
+ if (curWalkAssoc)
+ curWalkAssoc->speed = 2.0f;
+ if (curRunAssoc)
+ curRunAssoc->speed = 2.0f;
+ if (curSprintAssoc)
+ curSprintAssoc->speed = 2.0f;
+ }
+ }
+} + class CPlayerPed_ : public CPlayerPed { public: CPlayerPed* ctor(void) { return ::new (this) CPlayerPed(); } void dtor(void) { CPlayerPed::~CPlayerPed(); } + void SetMoveAnim_(void) { CPlayerPed::SetMoveAnim(); } }; STARTPATCHES InjectHook(0x4EF7E0, &CPlayerPed_::ctor, PATCH_JUMP); InjectHook(0x4EFB30, &CPlayerPed_::dtor, PATCH_JUMP); + InjectHook(0x4F3760, &CPlayerPed_::SetMoveAnim_, PATCH_JUMP); InjectHook(0x4F28A0, &CPlayerPed::ClearWeaponTarget, PATCH_JUMP); InjectHook(0x4F3700, &CPlayerPed::AnnoyPlayerPed, PATCH_JUMP); InjectHook(0x4F36C0, &CPlayerPed::GetPlayerInfoForThisPlayerPed, PATCH_JUMP); + InjectHook(0x4F2560, &CPlayerPed::MakeChangesForNewWeapon, PATCH_JUMP); + InjectHook(0x4F07C0, &CPlayerPed::ReApplyMoveAnims, PATCH_JUMP); + InjectHook(0x4F0880, &CPlayerPed::SetRealMoveAnim, PATCH_JUMP); ENDPATCHES diff --git a/src/peds/PlayerPed.h b/src/peds/PlayerPed.h index bd24ecd0..1de1b442 100644 --- a/src/peds/PlayerPed.h +++ b/src/peds/PlayerPed.h @@ -41,6 +41,7 @@ public: CPlayerPed(); ~CPlayerPed(); + void SetMoveAnim() { }; void ReApplyMoveAnims(void); void ClearWeaponTarget(void); @@ -50,10 +51,11 @@ public: void AnnoyPlayerPed(bool); void MakeChangesForNewWeapon(int8); void SetInitialState(void); - void SetMoveAnim(void); void ProcessControl(void); void ClearAdrenaline(void); + void UseSprintEnergy(void); class CPlayerInfo *GetPlayerInfoForThisPlayerPed(); + void SetRealMoveAnim(void); static void SetupPlayerPed(int32); static void DeactivatePlayerPed(int32); diff --git a/src/render/Particle.cpp b/src/render/Particle.cpp index 56ac9512..6956a887 100644 --- a/src/render/Particle.cpp +++ b/src/render/Particle.cpp @@ -12,7 +12,7 @@ #include "ParticleObject.h" #include "Particle.h" -#ifndef MASTER +#ifdef TOGGLEABLE_BETA_FEATURES bool CParticle::bEnableBannedParticles = false; #endif @@ -772,7 +772,7 @@ CParticle *CParticle::AddParticle(tParticleType type, CVector const &vecPos, CVe { if ( CTimer::GetIsPaused() ) return NULL; -#ifndef MASTER +#ifdef TOGGLEABLE_BETA_FEATURES if(!bEnableBannedParticles) #endif if ( ( type == PARTICLE_ENGINE_SMOKE @@ -1462,7 +1462,7 @@ void CParticle::Render() tParticleType type = psystem->m_Type; -#ifndef MASTER +#ifdef TOGGLEABLE_BETA_FEATURES if (!bEnableBannedParticles) #endif if ( type == PARTICLE_ENGINE_SMOKE diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 8322c22a..78a4e5b4 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -24,6 +24,8 @@ bool gbShowPedRoadGroups; bool gbShowCarRoadGroups; bool gbShowCollisionPolys; bool gbShowCollisionLines; +bool gbShowCullZoneDebugStuff; +bool gbBigWhiteDebugLightSwitchedOn; bool gbDontRenderBuildings; bool gbDontRenderBigBuildings; diff --git a/src/render/Renderer.h b/src/render/Renderer.h index ea49ed4e..89fc23cb 100644 --- a/src/render/Renderer.h +++ b/src/render/Renderer.h @@ -6,6 +6,8 @@ extern bool gbShowPedRoadGroups; extern bool gbShowCarRoadGroups; extern bool gbShowCollisionPolys; extern bool gbShowCollisionLines; +extern bool gbShowCullZoneDebugStuff; +extern bool gbBigWhiteDebugLightSwitchedOn; extern bool gbDontRenderBuildings; extern bool gbDontRenderBigBuildings; diff --git a/src/render/Shadows.cpp b/src/render/Shadows.cpp index 5b6bb976..1d100d4d 100644 --- a/src/render/Shadows.cpp +++ b/src/render/Shadows.cpp @@ -1516,11 +1516,11 @@ CShadows::UpdatePermanentShadows(void) aPermanentShadows[i].m_nType = SHADOWTYPE_NONE; else { - if ( timePassed >= (aPermanentShadows[i].m_nLifeTime*(1-(1/4))) ) + if ( timePassed >= (aPermanentShadows[i].m_nLifeTime * 3 / 4) ) { // timePassed == 0 -> 4 // timePassed == aPermanentShadows[i].m_nLifeTime -> 0 - float fMult = 1.0f - (timePassed - (aPermanentShadows[i].m_nLifeTime*(1-(1/4)))) / (aPermanentShadows[i].m_nLifeTime / 4); + float fMult = 1.0f - float(timePassed - (aPermanentShadows[i].m_nLifeTime * 3 / 4)) / (aPermanentShadows[i].m_nLifeTime / 4); StoreStaticShadow((uint32)&aPermanentShadows[i], aPermanentShadows[i].m_nType, diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp index 5b328d03..2492c2de 100644 --- a/src/skel/win/win.cpp +++ b/src/skel/win/win.cpp @@ -3004,6 +3004,13 @@ BOOL _InputIsExtended(INT flag) return (flag & 0x1000000) != 0; } +#if (defined(_MSC_VER)) +int strcasecmp(const char *str1, const char *str2) +{ + return _strcmpi(str1, str2); +} +#endif + STARTPATCHES //InjectHook(0x580B30, &CJoySticks::CJoySticks, PATCH_JUMP); diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 0f5ff811..cfcfcf65 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -1014,7 +1014,7 @@ CAutomobile::ProcessControl(void) m_vecMoveSpeed.Magnitude() > 0.0f && CTimer::GetTimeStep() > 0.0f){ FlyingControl(FLIGHT_MODEL_DODO); }else if(GetModelIndex() == MI_MIAMI_RCBARON){ - FlyingControl(FLIGHT_MODEL_HELI); + FlyingControl(FLIGHT_MODEL_RCPLANE); }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); @@ -1918,7 +1918,7 @@ CAutomobile::Render(void) CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()); if(GetModelIndex() == MI_RHINO && m_aCarNodes[CAR_BONNET]){ - // Rhino has no bonnet...what are we doing here? + // Rotate Rhino turret CMatrix m; CVector p; m.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BONNET])); diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h index de05a738..7e99258c 100644 --- a/src/vehicles/Vehicle.h +++ b/src/vehicles/Vehicle.h @@ -288,7 +288,7 @@ class cTransmission; class cVehicleParams { public: - uint8 m_bDistancECalculated; + bool m_bDistanceCalculated; char gap_1[3]; float m_fDistance; CVehicle *m_pVehicle; @@ -297,4 +297,4 @@ public: float m_fVelocityChange; }; -static_assert(sizeof(cVehicleParams) == 0x18, "CVehicle: error"); +static_assert(sizeof(cVehicleParams) == 0x18, "cVehicleParams: error"); diff --git a/src/weapons/ProjectileInfo.cpp b/src/weapons/ProjectileInfo.cpp index a915504d..7919b8ab 100644 --- a/src/weapons/ProjectileInfo.cpp +++ b/src/weapons/ProjectileInfo.cpp @@ -3,6 +3,6 @@ #include "ProjectileInfo.h" #include "Projectile.h" - +WRAPPER void CProjectileInfo::RemoveAllProjectiles(void) { EAXJMP(0x55BB80); } WRAPPER bool CProjectileInfo::RemoveIfThisIsAProjectile(CObject *pObject) { EAXJMP(0x55BBD0); } WRAPPER bool CProjectileInfo::IsProjectileInRange(float x1, float x2, float y1, float y2, float z1, float z2, bool remove) { EAXJMP(0x55BA50); } diff --git a/src/weapons/ProjectileInfo.h b/src/weapons/ProjectileInfo.h index 06ead482..e1faf028 100644 --- a/src/weapons/ProjectileInfo.h +++ b/src/weapons/ProjectileInfo.h @@ -6,5 +6,6 @@ class CProjectileInfo {
public:
static bool RemoveIfThisIsAProjectile(CObject *pObject);
+ static void RemoveAllProjectiles(void);
static bool IsProjectileInRange(float x1, float x2, float y1, float y2, float z1, float z2, bool remove);
};
\ No newline at end of file |