summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md6
-rw-r--r--src/animation/AnimBlendAssocGroup.cpp15
-rw-r--r--src/animation/AnimBlendAssociation.h2
-rw-r--r--src/animation/AnimManager.cpp5
-rw-r--r--src/animation/RpAnimBlend.cpp3
-rw-r--r--src/audio/AudioManager.cpp162
-rw-r--r--src/audio/AudioManager.h12
-rw-r--r--src/audio/sampman.cpp14
-rw-r--r--src/control/AccidentManager.cpp16
-rw-r--r--src/control/AccidentManager.h1
-rw-r--r--src/control/PathFind.cpp2
-rw-r--r--src/control/PathFind.h2
-rw-r--r--src/control/Phones.cpp205
-rw-r--r--src/control/Phones.h45
-rw-r--r--src/control/Replay.cpp2
-rw-r--r--src/control/Script.cpp64
-rw-r--r--src/core/ControllerConfig.cpp105
-rw-r--r--src/core/CutsceneMgr.cpp15
-rw-r--r--src/core/Directory.cpp3
-rw-r--r--src/core/Explosion.cpp1
-rw-r--r--src/core/Explosion.h1
-rw-r--r--src/core/Fire.cpp21
-rw-r--r--src/core/Fire.h3
-rw-r--r--src/core/Frontend.cpp758
-rw-r--r--src/core/Frontend.h12
-rw-r--r--src/core/General.h23
-rw-r--r--src/core/Pad.cpp4
-rw-r--r--src/core/Pad.h4
-rw-r--r--src/core/PlayerInfo.cpp500
-rw-r--r--src/core/PlayerInfo.h26
-rw-r--r--src/core/PlayerSkin.cpp4
-rw-r--r--src/core/Radar.cpp4
-rw-r--r--src/core/Stats.cpp2
-rw-r--r--src/core/Stats.h2
-rw-r--r--src/core/Streaming.cpp27
-rw-r--r--src/core/TempColModels.cpp276
-rw-r--r--src/core/TxdStore.cpp3
-rw-r--r--src/core/User.cpp12
-rw-r--r--src/core/User.h4
-rw-r--r--src/core/World.cpp48
-rw-r--r--src/core/World.h2
-rw-r--r--src/core/common.h4
-rw-r--r--src/core/config.h2
-rw-r--r--src/core/re3.cpp13
-rw-r--r--src/entities/Entity.h2
-rw-r--r--src/modelinfo/ClumpModelInfo.cpp5
-rw-r--r--src/modelinfo/ModelIndices.cpp3
-rw-r--r--src/modelinfo/ModelInfo.cpp3
-rw-r--r--src/modelinfo/PedModelInfo.cpp3
-rw-r--r--src/modelinfo/SimpleModelInfo.cpp3
-rw-r--r--src/objects/CutsceneHead.cpp3
-rw-r--r--src/objects/ParticleObject.cpp2
-rw-r--r--src/peds/CivilianPed.cpp396
-rw-r--r--src/peds/CivilianPed.h1
-rw-r--r--src/peds/EmergencyPed.cpp435
-rw-r--r--src/peds/EmergencyPed.h34
-rw-r--r--src/peds/Ped.cpp1072
-rw-r--r--src/peds/Ped.h34
-rw-r--r--src/peds/PedStats.cpp3
-rw-r--r--src/peds/PlayerPed.cpp358
-rw-r--r--src/peds/PlayerPed.h4
-rw-r--r--src/render/Particle.cpp6
-rw-r--r--src/render/Renderer.cpp2
-rw-r--r--src/render/Renderer.h2
-rw-r--r--src/render/Shadows.cpp4
-rw-r--r--src/skel/win/win.cpp7
-rw-r--r--src/vehicles/Automobile.cpp4
-rw-r--r--src/vehicles/Vehicle.h4
-rw-r--r--src/weapons/ProjectileInfo.cpp2
-rw-r--r--src/weapons/ProjectileInfo.h1
70 files changed, 4005 insertions, 823 deletions
diff --git a/README.md b/README.md
index 6d4d6afd..0817340f 100644
--- a/README.md
+++ b/README.md
@@ -46,13 +46,11 @@ CBulletInfo
CBulletTraces
CCam
CCamera
-CCivilianPed
CCopPed
CCrane
CCranes
CCullZone
CCullZones
-CEmergencyPed
CExplosion
CFallingGlassPane
CFire
@@ -64,10 +62,8 @@ CGlass
CMenuManager
CMotionBlurStreaks
CPacManPickups
-CPed - being worked on
CPedIK
-CPhoneInfo - one function left
-CPlayerInfo
+CPedPath
CPlayerPed
CProjectile
CProjectileInfo
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