merge with upstream

This commit is contained in:
Nikolay Korolev 2020-01-01 02:42:00 +03:00
commit 5b0cf80a76
70 changed files with 4022 additions and 840 deletions

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -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++;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -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++ )
{

View File

@ -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;
}

View File

@ -21,6 +21,7 @@ class CAccidentManager
};
public:
uint16 CountActiveAccidents();
bool UnattendedAccidents();
CAccident* FindNearestAccident(CVector, float*);
void Update(void);
};

View File

@ -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];
}

View File

@ -36,7 +36,7 @@ struct CPathNode
uint8 bDisabled : 1;
uint8 bBetweenLevels : 1;
uint8 group;
int8 group;
/* For reference VC:
int16 prevIndex;
int16 nextIndex;

View File

@ -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

View File

@ -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);
void PhonePickUpCB(CAnimBlendAssociation *assoc, void *arg);
#ifdef TOGGLEABLE_BETA_FEATURES
extern CPed *crimeReporters[NUMPHONES];
bool isPhoneAvailable(int);
#endif

View File

@ -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;

View File

@ -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:

View File

@ -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
ENDPATCHES

View File

@ -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()

View File

@ -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;

View File

@ -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)

View File

@ -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);
};

View File

@ -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

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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; }

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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");

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -18,8 +18,8 @@ public:
void Process();
bool ProcessForDisplay();
int ProcessForDisplayTimer();
int ProcessForDisplayCounter();
void ProcessForDisplayClock();
void ProcessForDisplayCounter();
};
static_assert(sizeof(COnscreenTimerEntry) == 0x74, "COnscreenTimerEntry: error");

View File

@ -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
@ -1011,6 +1011,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)
{
@ -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

View File

@ -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();

View File

@ -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; }

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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{

View File

@ -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; \
}

View File

@ -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;

View File

@ -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{

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -8,6 +8,7 @@ public:
CCivilianPed(int, int);
~CCivilianPed(void) { }
void CivilianAI(void);
void ProcessControl(void);
};
static_assert(sizeof(CCivilianPed) == 0x53C, "CCivilianPed: error");

View File

@ -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

View File

@ -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");

File diff suppressed because it is too large Load Diff

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -24,6 +24,8 @@ bool gbShowPedRoadGroups;
bool gbShowCarRoadGroups;
bool gbShowCollisionPolys;
bool gbShowCollisionLines;
bool gbShowCullZoneDebugStuff;
bool gbBigWhiteDebugLightSwitchedOn;
bool gbDontRenderBuildings;
bool gbDontRenderBigBuildings;

View File

@ -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;

View File

@ -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,

View File

@ -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);

View File

@ -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]));

View File

@ -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");

View File

@ -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); }

View File

@ -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);
};