diff options
Diffstat (limited to 'src/peds')
-rw-r--r-- | src/peds/CivilianPed.cpp | 396 | ||||
-rw-r--r-- | src/peds/CivilianPed.h | 1 | ||||
-rw-r--r-- | src/peds/EmergencyPed.cpp | 435 | ||||
-rw-r--r-- | src/peds/EmergencyPed.h | 34 | ||||
-rw-r--r-- | src/peds/Ped.cpp | 1072 | ||||
-rw-r--r-- | src/peds/Ped.h | 34 | ||||
-rw-r--r-- | src/peds/PedStats.cpp | 3 | ||||
-rw-r--r-- | src/peds/PlayerPed.cpp | 358 | ||||
-rw-r--r-- | src/peds/PlayerPed.h | 4 |
9 files changed, 2139 insertions, 198 deletions
diff --git a/src/peds/CivilianPed.cpp b/src/peds/CivilianPed.cpp index 93cdcb3d..6fce25e8 100644 --- a/src/peds/CivilianPed.cpp +++ b/src/peds/CivilianPed.cpp @@ -2,25 +2,415 @@ #include "patcher.h" #include "CivilianPed.h" #include "Phones.h" - -WRAPPER void CCivilianPed::ProcessControl(void) { EAXJMP(0x4BFFE0); } +#include "General.h" +#include "PlayerPed.h" +#include "World.h" +#include "Vehicle.h" +#include "SurfaceTable.h" CCivilianPed::CCivilianPed(int pedtype, int mi) : CPed(pedtype) { SetModelIndex(mi); - for (int i = 0; i < 10; i++) { + for (int i = 0; i < ARRAY_SIZE(m_nearPeds); i++) { m_nearPeds[i] = nil; } } +void +CCivilianPed::CivilianAI(void) +{ + if (CTimer::GetTimeInMilliseconds() <= m_fleeTimer || m_objective != OBJECTIVE_NONE && !bRespondsToThreats + || !IsPedInControl()) { + + if (m_objective == OBJECTIVE_GUARD_SPOT) + return; + + if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS) { + if (m_pedInObjective) { + if (m_pedInObjective->IsPlayer()) + return; + } + } + if (CTimer::GetTimeInMilliseconds() <= m_lookTimer) + return; + + uint32 closestThreatFlag = ScanForThreats(); + if (closestThreatFlag == PED_FLAG_EXPLOSION) { + float angleToFace = CGeneral::GetRadianAngleBetweenPoints( + m_eventOrThreat.x, m_eventOrThreat.y, + GetPosition().x, GetPosition().y); + SetLookFlag(angleToFace, true); + SetLookTimer(500); + + } else if (closestThreatFlag == PED_FLAG_GUN) { + SetLookFlag(m_threatEntity, true); + SetLookTimer(500); + } + return; + } + uint32 closestThreatFlag = ScanForThreats(); + if (closestThreatFlag == PED_FLAG_GUN) { + if (!m_threatEntity || !m_threatEntity->IsPed()) + return; + + CPed *threatPed = (CPed*)m_threatEntity; + float threatDistSqr = (m_threatEntity->GetPosition() - GetPosition()).MagnitudeSqr2D(); + if (m_pedStats->m_fear <= m_pedStats->m_lawfulness) { + if (m_pedStats->m_temper <= m_pedStats->m_fear) { + if (!threatPed->IsPlayer() || !RunToReportCrime(CRIME_POSSESSION_GUN)) { + if (threatDistSqr < sq(10.0f)) { + Say(SOUND_PED_FLEE_SPRINT); + SetFlee(m_threatEntity, 10000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + } else { + SetFlee(m_threatEntity->GetPosition(), 5000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + SetMoveState(PEDMOVE_WALK); + } + } + } else if (m_objective != OBJECTIVE_NONE || GetWeapon()->IsTypeMelee()) { + SetFlee(m_threatEntity, 5000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + if (threatDistSqr < sq(20.0f)) { + SetMoveState(PEDMOVE_RUN); + Say(SOUND_PED_FLEE_SPRINT); + } else { + SetMoveState(PEDMOVE_WALK); + } + } else if (threatPed->IsPlayer() && FindPlayerPed()->m_pWanted->m_CurrentCops) { + SetFlee(m_threatEntity, 5000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + if (threatDistSqr < sq(10.0f)) { + SetMoveState(PEDMOVE_RUN); + } else { + SetMoveState(PEDMOVE_WALK); + } + } else { + SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, m_threatEntity); + } + } else { + if (threatDistSqr < sq(10.0f)) { + Say(SOUND_PED_FLEE_SPRINT); + SetFlee(m_threatEntity, 10000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + SetMoveState(PEDMOVE_SPRINT); + } else { + Say(SOUND_PED_FLEE_SPRINT); + SetFlee(m_threatEntity, 5000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + SetMoveState(PEDMOVE_RUN); + } + } + SetLookFlag(m_threatEntity, false); + SetLookTimer(500); + } else if (closestThreatFlag == PED_FLAG_DEADPEDS) { + float eventDistSqr = (m_pEventEntity->GetPosition() - GetPosition()).MagnitudeSqr2D(); + if (IsGangMember() && m_nPedType == ((CPed*)m_pEventEntity)->m_nPedType) { + if (eventDistSqr < sq(5.0f)) { + SetFlee(m_pEventEntity, 2000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + SetMoveState(PEDMOVE_RUN); + } + } else if (IsGangMember() || eventDistSqr > sq(5.0f)) { + bool investigateDeadPed = true; + CEntity *killerOfDeadPed = ((CPed*)m_pEventEntity)->m_threatEntity; + if (killerOfDeadPed && killerOfDeadPed->IsPed()) { + CVector killerPos = killerOfDeadPed->GetPosition(); + CVector deadPedPos = m_pEventEntity->GetPosition(); + if (CVector2D(killerPos - deadPedPos).MagnitudeSqr() < sq(10.0f)) + investigateDeadPed = false; + } + +#ifdef TOGGLEABLE_BETA_FEATURES + eCrimeType crime = (((CPed*)m_pEventEntity)->m_ped_flagI40 ? + (((CPed*)m_pEventEntity)->m_nPedType == PEDTYPE_COP ? CRIME_RUNOVER_COP : CRIME_RUNOVER_PED) : + (((CPed*)m_pEventEntity)->m_nPedType == PEDTYPE_COP ? CRIME_SHOOT_COP : CRIME_SHOOT_PED)); + bool eligibleToReport = bMakePedsRunToPhonesToReportCrimes && killerOfDeadPed && killerOfDeadPed->IsPed() && ((CPed*)killerOfDeadPed)->IsPlayer() && + m_pedStats->m_fear <= m_pedStats->m_lawfulness && m_pedStats->m_temper <= m_pedStats->m_fear; + if (IsGangMember() || !eligibleToReport || !RunToReportCrime(crime)) +#endif + if (investigateDeadPed) + SetInvestigateEvent(EVENT_DEAD_PED, CVector2D(m_pEventEntity->GetPosition()), 1.0f, 20000, 0.0f); + + } else { +#ifdef TOGGLEABLE_BETA_FEATURES + CEntity* killerOfDeadPed = ((CPed*)m_pEventEntity)->m_threatEntity; + eCrimeType crime = (((CPed*)m_pEventEntity)->m_ped_flagI40 ? + (((CPed*)m_pEventEntity)->m_nPedType == PEDTYPE_COP ? CRIME_RUNOVER_COP : CRIME_RUNOVER_PED) : + (((CPed*)m_pEventEntity)->m_nPedType == PEDTYPE_COP ? CRIME_SHOOT_COP : CRIME_SHOOT_PED)); + bool eligibleToReport = bMakePedsRunToPhonesToReportCrimes && killerOfDeadPed && killerOfDeadPed->IsPed() && ((CPed*)killerOfDeadPed)->IsPlayer() && + m_pedStats->m_fear <= m_pedStats->m_lawfulness && m_pedStats->m_temper <= m_pedStats->m_fear; + if(!eligibleToReport || !RunToReportCrime(crime)) +#endif + { + SetFlee(m_pEventEntity, 5000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + SetMoveState(PEDMOVE_RUN); + } + } + } else if (closestThreatFlag == PED_FLAG_EXPLOSION) { + CVector2D eventDistVec = m_eventOrThreat - GetPosition(); + float eventDistSqr = eventDistVec.MagnitudeSqr(); + if (eventDistSqr < sq(20.0f)) { + Say(SOUND_PED_FLEE_SPRINT); + SetFlee(m_eventOrThreat, 2000); + float angleToFace = CGeneral::GetRadianAngleBetweenPoints( + m_eventOrThreat.x, m_eventOrThreat.y, + GetPosition().x, GetPosition().y); + SetLookFlag(angleToFace, true); + SetLookTimer(500); + } else if (eventDistSqr < sq(40.0f)) { + if (m_ped_flagD2) { + if (CharCreatedBy != MISSION_CHAR && !IsGangMember()) + SetInvestigateEvent(EVENT_EXPLOSION, m_eventOrThreat, 6.0f, 30000, 0.0f); + + } else { + float eventHeading = CGeneral::GetRadianAngleBetweenPoints(eventDistVec.x, eventDistVec.y, 0.0f, 0.0f); + eventHeading = CGeneral::LimitRadianAngle(eventHeading); + if (eventHeading < 0.0f) + eventHeading = eventHeading + TWOPI; + + SetWanderPath(eventHeading / 8.0f); + } + } + } else { + if (m_threatEntity && m_threatEntity->IsPed()) { + CPed *threatPed = (CPed*)m_threatEntity; + if (m_pedStats->m_fear <= 100 - threatPed->m_pedStats->m_temper && threatPed->m_nPedType != PEDTYPE_COP) { + if (threatPed->GetWeapon()->IsTypeMelee() || !GetWeapon()->IsTypeMelee()) { + if (threatPed->IsPlayer() && FindPlayerPed()->m_pWanted->m_CurrentCops) { + if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS) { + SetFlee(m_threatEntity, 10000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + } + } else { + SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, m_threatEntity); + } + } + } else { + SetFlee(m_threatEntity, 10000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + SetMoveState(PEDMOVE_WALK); + } + } + } +} + +void +CCivilianPed::ProcessControl(void) +{ + if (m_nZoneLevel > LEVEL_NONE && m_nZoneLevel != CCollision::ms_collisionInMemory) + return; + + CPed::ProcessControl(); + + if (bWasPostponed) + return; + + if (DyingOrDead()) + return; + + GetWeapon()->Update(m_audioEntityId); + switch (m_nPedState) { + case PED_WANDER_RANGE: + case PED_WANDER_PATH: + if (IsVisible()) + ScanForInterestingStuff(); + break; + case PED_SEEK_ENTITY: + if (!m_pSeekTarget) { + RestorePreviousState(); + break; + } + m_vecSeekPos = m_pSeekTarget->GetPosition(); + + // fall through + case PED_SEEK_POS: + if (Seek()) { + if ((m_objective == OBJECTIVE_GOTO_AREA_ON_FOOT || m_objective == OBJECTIVE_RUN_TO_AREA) && m_pNextPathNode) { + m_pNextPathNode = nil; +#ifdef TOGGLEABLE_BETA_FEATURES + } else if (bRunningToPhone && m_objective < OBJECTIVE_FLEE_TILL_SAFE) { + if (!isPhoneAvailable(m_phoneId)) { + RestorePreviousState(); + crimeReporters[m_phoneId] = nil; + m_phoneId = -1; + bRunningToPhone = false; + } else { + crimeReporters[m_phoneId] = this; + m_nPedState = PED_FACE_PHONE; + } +#else + } else if (bRunningToPhone) { + if (gPhoneInfo.m_aPhones[m_phoneId].m_nState != PHONE_STATE_FREE) { + RestorePreviousState(); + m_phoneId = -1; + } else { + gPhoneInfo.m_aPhones[m_phoneId].m_nState = PHONE_STATE_REPORTING_CRIME; + m_nPedState = PED_FACE_PHONE; + } +#endif + } else if (m_objective != OBJECTIVE_KILL_CHAR_ANY_MEANS && m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT) { + if (m_objective == OBJECTIVE_FOLLOW_PED_IN_FORMATION) { + if (m_moved.Magnitude() == 0.0f) { + if (m_pedInObjective->m_nMoveState == PEDMOVE_STILL) + m_fRotationDest = m_pedInObjective->m_fRotationCur; + } + } else if (m_objective == OBJECTIVE_GOTO_CHAR_ON_FOOT + && m_pedInObjective && m_pedInObjective->m_nMoveState != PEDMOVE_STILL) { + SetMoveState(m_pedInObjective->m_nMoveState); + } else if (m_objective == OBJECTIVE_GOTO_AREA_ON_FOOT || m_objective == OBJECTIVE_RUN_TO_AREA) { + SetIdle(); + } else { + RestorePreviousState(); + } + } + } + break; + case PED_FACE_PHONE: + if (FacePhone()) + m_nPedState = PED_MAKE_CALL; + break; + case PED_MAKE_CALL: + if (MakePhonecall()) + SetWanderPath(CGeneral::GetRandomNumber() & 7); + break; + case PED_MUG: + Mug(); + break; + case PED_SOLICIT: + Solicit(); + break; + case PED_UNKNOWN: + { + int pedsInSameState = 0; + Idle(); + for (int i = 0; i < m_numNearPeds; ++i) { + CPed *nearPed = m_nearPeds[i]; + if (nearPed->m_nPedType == m_nPedType && nearPed->m_nPedState == PED_UNKNOWN) { + ++pedsInSameState; + } + } + if (pedsInSameState < 5) { + for (int j = 0; j < m_numNearPeds; ++j) { + CPed *nearPed = m_nearPeds[j]; + if (nearPed->m_nPedType == m_nPedType && nearPed->m_nPedState == PED_WANDER_PATH) { + nearPed->m_nPedState = PED_UNKNOWN; + } + } + } + break; + } + case PED_DRIVING: + if (m_nPedType != PEDTYPE_PROSTITUTE) + break; + + if (CWorld::Players[CWorld::PlayerInFocus].m_pHooker != this) + break; + + if (CTimer::GetTimeInMilliseconds() > CWorld::Players[CWorld::PlayerInFocus].m_nNextSexFrequencyUpdateTime) { + if (m_nPedState == PED_DRIVING + && m_pMyVehicle->pDriver && m_pMyVehicle->pDriver->IsPlayer() && m_pMyVehicle->pDriver->m_nPedState == PED_DRIVING) { + CColPoint foundCol; + CEntity* foundEnt; + + CWorld::ProcessVerticalLine(m_pMyVehicle->GetPosition(), -100.0f, + foundCol, foundEnt, true, false, false, false, false, false, nil); + + if (m_pMyVehicle->m_vecMoveSpeed.MagnitudeSqr() < sq(0.01f) + && foundCol.surfaceB != SURFACE_DEFAULT && foundCol.surfaceB != SURFACE_TARMAC && foundCol.surfaceB != SURFACE_PAVEMENT) { + + if (m_pMyVehicle->CarHasRoof()) { + m_pMyVehicle->ApplyTurnForce(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(-0.8f, -1.2f) * m_fMass, + GetPosition().x - m_pMyVehicle->GetPosition().x, GetPosition().y - m_pMyVehicle->GetPosition().y, 0.0f); + + DMAudio.PlayOneShot(m_pMyVehicle->m_audioEntityId, SOUND_CAR_JERK, 0.0f); + + int playerSexFrequency = CWorld::Players[CWorld::PlayerInFocus].m_nSexFrequency; + if (CWorld::Players[CWorld::PlayerInFocus].m_nMoney >= 10 && playerSexFrequency > 250) { + CWorld::Players[CWorld::PlayerInFocus].m_nNextSexFrequencyUpdateTime = CTimer::GetTimeInMilliseconds() + playerSexFrequency; + if (playerSexFrequency >= 350) { + CWorld::Players[CWorld::PlayerInFocus].m_nSexFrequency = max(250, playerSexFrequency - 30); + } else { + CWorld::Players[CWorld::PlayerInFocus].m_nSexFrequency = max(250, playerSexFrequency - 10); + } + + m_pMyVehicle->pDriver->m_fHealth = min(125.0f, 1.0f + m_pMyVehicle->pDriver->m_fHealth); + if (CWorld::Players[CWorld::PlayerInFocus].m_nSexFrequency == 250) + CWorld::Players[CWorld::PlayerInFocus].m_nNextSexFrequencyUpdateTime = CTimer::GetTimeInMilliseconds() + 3000; + } else { + bWanderPathAfterExitingCar = true; + CWorld::Players[CWorld::PlayerInFocus].m_pHooker = nil; + SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); + } + } else { + bWanderPathAfterExitingCar = true; + CWorld::Players[CWorld::PlayerInFocus].m_pHooker = nil; + m_pMyVehicle->pDriver->m_fHealth = 125.0f; + SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); + } + } else { + CWorld::Players[CWorld::PlayerInFocus].m_nNextSexFrequencyUpdateTime = CTimer::GetTimeInMilliseconds() + 3000; + int playerSexFrequency = CWorld::Players[CWorld::PlayerInFocus].m_nSexFrequency; + if (playerSexFrequency >= 1000 || playerSexFrequency <= 250) + CWorld::Players[CWorld::PlayerInFocus].m_nSexFrequency = 1200; + else + CWorld::Players[CWorld::PlayerInFocus].m_nSexFrequency = 250; + } + } else { + bWanderPathAfterExitingCar = true; + CWorld::Players[CWorld::PlayerInFocus].m_pHooker = nil; + SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); + } + } + + if (CTimer::GetTimeInMilliseconds() > CWorld::Players[CWorld::PlayerInFocus].m_nNextSexMoneyUpdateTime) { + int playerMoney = CWorld::Players[CWorld::PlayerInFocus].m_nMoney; + if (playerMoney <= 1) { + CWorld::Players[CWorld::PlayerInFocus].m_nSexFrequency = 250; + } else { + CWorld::Players[CWorld::PlayerInFocus].m_nMoney = max(0, playerMoney - 1); + } + CWorld::Players[CWorld::PlayerInFocus].m_nNextSexMoneyUpdateTime = CTimer::GetTimeInMilliseconds() + 1000; + } + break; + default: + break; + } + if (IsPedInControl()) + CivilianAI(); + + if (CTimer::GetTimeInMilliseconds() > m_timerUnused) { + m_stateUnused = 0; + m_timerUnused = 0; + } + + if (m_moved.Magnitude() > 0.0f) + Avoid(); +} + class CCivilianPed_ : public CCivilianPed { public: CCivilianPed *ctor(int pedtype, int mi) { return ::new (this) CCivilianPed(pedtype, mi); }; void dtor(void) { CCivilianPed::~CCivilianPed(); } + void ProcessControl_(void) { CCivilianPed::ProcessControl(); } }; STARTPATCHES InjectHook(0x4BFF30, &CCivilianPed_::ctor, PATCH_JUMP); InjectHook(0x4BFFC0, &CCivilianPed_::dtor, PATCH_JUMP); + InjectHook(0x4BFFE0, &CCivilianPed_::ProcessControl_, PATCH_JUMP); + + InjectHook(0x4C07A0, &CCivilianPed::CivilianAI, PATCH_JUMP); ENDPATCHES diff --git a/src/peds/CivilianPed.h b/src/peds/CivilianPed.h index 14859a5c..80845e62 100644 --- a/src/peds/CivilianPed.h +++ b/src/peds/CivilianPed.h @@ -8,6 +8,7 @@ public: CCivilianPed(int, int); ~CCivilianPed(void) { } + void CivilianAI(void); void ProcessControl(void); }; static_assert(sizeof(CCivilianPed) == 0x53C, "CCivilianPed: error"); diff --git a/src/peds/EmergencyPed.cpp b/src/peds/EmergencyPed.cpp index cbcfb403..16468270 100644 --- a/src/peds/EmergencyPed.cpp +++ b/src/peds/EmergencyPed.cpp @@ -2,37 +2,428 @@ #include "patcher.h" #include "EmergencyPed.h" #include "ModelIndices.h" - -class CEmergencyPed_ : public CEmergencyPed -{ -public: - CEmergencyPed *ctor(int pedtype) { return ::new (this) CEmergencyPed(pedtype); }; - void dtor(void) { CEmergencyPed::~CEmergencyPed(); } -}; - -WRAPPER void CEmergencyPed::ProcessControl(void) { EAXJMP(0x4C2F10); } +#include "Vehicle.h" +#include "Fire.h" +#include "General.h" +#include "CarCtrl.h" +#include "AccidentManager.h" CEmergencyPed::CEmergencyPed(uint32 type) : CPed(type) { switch (type){ - case PEDTYPE_EMERGENCY: - SetModelIndex(MI_MEDIC); - m_pRevivedPed = nil; - field_1360 = 0; - break; - case PEDTYPE_FIREMAN: - SetModelIndex(MI_FIREMAN); - m_pRevivedPed = nil; - break; - default: - break; + case PEDTYPE_EMERGENCY: + SetModelIndex(MI_MEDIC); + m_pRevivedPed = nil; + field_1360 = 0; + break; + case PEDTYPE_FIREMAN: + SetModelIndex(MI_FIREMAN); + m_pRevivedPed = nil; + break; + default: + break; } - m_nEmergencyPedState = 0; + m_nEmergencyPedState = EMERGENCY_PED_READY; m_pAttendedAccident = nil; - field_1356 = 0; + m_bStartedToCPR = false; +} + +bool +CEmergencyPed::InRange(CPed *victim) +{ + if (!m_pMyVehicle) + return true; + + if ((m_pMyVehicle->GetPosition() - victim->GetPosition()).Magnitude() > 30.0f) + return false; + + return true; } +void +CEmergencyPed::ProcessControl(void) +{ + if (m_nZoneLevel > LEVEL_NONE && m_nZoneLevel != CCollision::ms_collisionInMemory) + return; + + CPed::ProcessControl(); + if (bWasPostponed) + return; + + if(!DyingOrDead()) { + GetWeapon()->Update(m_audioEntityId); + + if (IsPedInControl() && m_moved.Magnitude() > 0.0f) + Avoid(); + + switch (m_nPedState) { + case PED_SEEK_POS: + Seek(); + break; + case PED_SEEK_ENTITY: + if (m_pSeekTarget) { + m_vecSeekPos = m_pSeekTarget->GetPosition(); + Seek(); + } else { + ClearSeek(); + } + break; + default: + break; + } + + switch (m_nPedType) { + case PEDTYPE_EMERGENCY: + if (IsPedInControl() || m_nPedState == PED_DRIVING) + MedicAI(); + break; + case PEDTYPE_FIREMAN: + if (IsPedInControl()) + FiremanAI(); + break; + default: + return; + } + } +} + +// This function was buggy and incomplete in both III and VC, firemen had to be in 5.0m range of fire etc. etc. +// Copied some code from MedicAI to make it work. +void +CEmergencyPed::FiremanAI(void) +{ + float fireDist; + CFire *nearestFire; + + switch (m_nEmergencyPedState) { + case EMERGENCY_PED_READY: + nearestFire = gFireManager.FindNearestFire(GetPosition(), &fireDist); + if (nearestFire) { + m_nPedState = PED_NONE; + SetSeek(nearestFire->m_vecPos, 1.0f); + SetMoveState(PEDMOVE_RUN); + m_nEmergencyPedState = EMERGENCY_PED_DETERMINE_NEXT_STATE; + m_pAttendedFire = nearestFire; +#ifdef FIX_BUGS + bIsRunning = true; + ++nearestFire->m_nFiremenPuttingOut; +#endif + } + break; + case EMERGENCY_PED_DETERMINE_NEXT_STATE: + nearestFire = gFireManager.FindNearestFire(GetPosition(), &fireDist); + if (nearestFire && nearestFire != m_pAttendedFire) { + m_nPedState = PED_NONE; + SetSeek(nearestFire->m_vecPos, 1.0f); + SetMoveState(PEDMOVE_RUN); +#ifdef FIX_BUGS + bIsRunning = true; + if (m_pAttendedFire) { + --m_pAttendedFire->m_nFiremenPuttingOut; + } + ++nearestFire->m_nFiremenPuttingOut; + m_pAttendedFire = nearestFire; + } else if (!nearestFire) { +#else + m_pAttendedFire = nearestFire; + } else { +#endif + m_nEmergencyPedState = EMERGENCY_PED_STOP; + } + + // "Extinguish" the fire (Will overwrite the stop decision above if the attended and nearest fires are same) + if (fireDist < 5.0f) { + SetIdle(); + m_nEmergencyPedState = EMERGENCY_PED_STAND_STILL; + } + break; + case EMERGENCY_PED_STAND_STILL: + if (!m_pAttendedFire->m_bIsOngoing) + m_nEmergencyPedState = EMERGENCY_PED_STOP; + + // Leftover + // fireDist = 30.0f; + nearestFire = gFireManager.FindNearestFire(GetPosition(), &fireDist); + if (nearestFire) { +#ifdef FIX_BUGS + if(nearestFire != m_pAttendedFire && (nearestFire->m_vecPos - GetPosition()).Magnitude() < 30.0f) +#endif + m_nEmergencyPedState = EMERGENCY_PED_DETERMINE_NEXT_STATE; + } + Say(SOUND_PED_EXTINGUISHING_FIRE); + break; + case EMERGENCY_PED_STOP: +#ifdef FIX_BUGS + bIsRunning = false; + if (m_pAttendedFire) +#endif + --m_pAttendedFire->m_nFiremenPuttingOut; + + m_nPedState = PED_NONE; + SetWanderPath(CGeneral::GetRandomNumber() & 7); + m_pAttendedFire = nil; + m_nEmergencyPedState = EMERGENCY_PED_READY; + SetMoveState(PEDMOVE_WALK); + break; + } +} + +void +CEmergencyPed::MedicAI(void) +{ + float distToEmergency; + if (!bInVehicle && IsPedInControl()) { + ScanForThreats(); + if (m_threatEntity && m_threatEntity->IsPed() && ((CPed*)m_threatEntity)->IsPlayer()) { + if (((CPed*)m_threatEntity)->GetWeapon()->IsTypeMelee()) { + SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, m_threatEntity); + } else { + SetFlee(m_threatEntity, 6000); + Say(SOUND_PED_FLEE_SPRINT); + } + return; + } + } + + if (InVehicle()) { + if (m_pMyVehicle->IsCar() && m_objective != OBJECTIVE_LEAVE_VEHICLE) { + if (gAccidentManager.FindNearestAccident(m_pMyVehicle->GetPosition(), &distToEmergency) + && distToEmergency < 25.0f && m_pMyVehicle->m_vecMoveSpeed.Magnitude() < 0.01f) { + + m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_NONE; + SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); + Say(SOUND_PED_LEAVE_VEHICLE); + } else if (m_pMyVehicle->pDriver == this && m_nPedState == PED_DRIVING + && m_pMyVehicle->AutoPilot.m_nCarMission == MISSION_NONE && !(CGeneral::GetRandomNumber() & 31)) { + + bool waitUntilMedicEntersCar = false; + for (int i = 0; i < m_numNearPeds; ++i) { + CPed *nearPed = m_nearPeds[i]; + if (nearPed->m_nPedType == PEDTYPE_EMERGENCY) { + if ((nearPed->m_nPedState == PED_SEEK_CAR || nearPed->m_nPedState == PED_ENTER_CAR) + && nearPed->m_pMyVehicle == m_pMyVehicle) { + waitUntilMedicEntersCar = true; + break; + } + } + } + if (!waitUntilMedicEntersCar) { + CCarCtrl::JoinCarWithRoadSystem(m_pMyVehicle); + m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE; + m_pMyVehicle->m_bSirenOrAlarm = 0; + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 12; + m_pMyVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_SLOW_DOWN_FOR_CARS; + if (m_pMyVehicle->bIsAmbulanceOnDuty) { + m_pMyVehicle->bIsAmbulanceOnDuty = false; + --CCarCtrl::NumAmbulancesOnDuty; + } + } + } + } + } + + CVector headPos, midPos; + CAccident *nearestAccident; + if (IsPedInControl()) { + switch (m_nEmergencyPedState) { + case EMERGENCY_PED_READY: + nearestAccident = gAccidentManager.FindNearestAccident(GetPosition(), &distToEmergency); + field_1360 = 0; + if (nearestAccident) { + m_pRevivedPed = nearestAccident->m_pVictim; + m_pRevivedPed->RegisterReference((CEntity**)&m_pRevivedPed); + m_pRevivedPed->m_pedIK.GetComponentPosition((RwV3d*)&midPos, PED_MID); + m_pRevivedPed->m_pedIK.GetComponentPosition((RwV3d*)&headPos, PED_HEAD); + SetSeek((headPos + midPos) * 0.5f, 1.0f); + SetObjective(OBJECTIVE_NONE); + bIsRunning = true; + m_nEmergencyPedState = EMERGENCY_PED_DETERMINE_NEXT_STATE; + m_pAttendedAccident = nearestAccident; + ++m_pAttendedAccident->m_nMedicsAttending; + } else { + if (m_pMyVehicle) { + if (!bInVehicle) { + if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || m_pMyVehicle->pDriver || m_pMyVehicle->m_nGettingInFlags) { + + CPed* driver = m_pMyVehicle->pDriver; + if (driver && driver->m_nPedType != PEDTYPE_EMERGENCY && m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT) { + SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, driver); + } else if (m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER + && m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER + && m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT) { + SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_pMyVehicle); + } + } else { + SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle); + } + } + } else if (m_nPedState != PED_WANDER_PATH) { + SetWanderPath(CGeneral::GetRandomNumber() & 7); + } + } + break; + case EMERGENCY_PED_DETERMINE_NEXT_STATE: + nearestAccident = gAccidentManager.FindNearestAccident(GetPosition(), &distToEmergency); + if (nearestAccident) { + if (nearestAccident != m_pAttendedAccident || m_nPedState != PED_SEEK_POS) { + m_pRevivedPed = nearestAccident->m_pVictim; + m_pRevivedPed->RegisterReference((CEntity**)&m_pRevivedPed); + if (!InRange(m_pRevivedPed)) { + m_nEmergencyPedState = EMERGENCY_PED_STOP; + break; + } + m_pRevivedPed->m_pedIK.GetComponentPosition((RwV3d*)&midPos, PED_MID); + m_pRevivedPed->m_pedIK.GetComponentPosition((RwV3d*)&headPos, PED_HEAD); + SetSeek((headPos + midPos) * 0.5f, nearestAccident->m_nMedicsPerformingCPR * 0.5f + 1.0f); + SetObjective(OBJECTIVE_NONE); + bIsRunning = true; + --m_pAttendedAccident->m_nMedicsAttending; + ++nearestAccident->m_nMedicsAttending; + m_pAttendedAccident = nearestAccident; + } + } else { + m_nEmergencyPedState = EMERGENCY_PED_STOP; + bIsRunning = false; + } + if (distToEmergency < 5.0f) { + if (m_pRevivedPed->m_pFire) { + bIsRunning = false; + SetMoveState(PEDMOVE_STILL); + } else if (distToEmergency < 4.5f) { + bIsRunning = false; + SetMoveState(PEDMOVE_WALK); + if (distToEmergency < 1.0f + || distToEmergency < 4.5f && m_pAttendedAccident->m_nMedicsPerformingCPR) { + m_nEmergencyPedState = EMERGENCY_PED_START_CPR; + } + } + } + break; + case EMERGENCY_PED_START_CPR: + if (!m_pRevivedPed || m_pRevivedPed->m_fHealth > 0.0f || m_pRevivedPed->bFadeOut) { + m_nEmergencyPedState = EMERGENCY_PED_DETERMINE_NEXT_STATE; + } else { + m_pRevivedPed->m_bloodyFootprintCount = CTimer::GetTimeInMilliseconds(); + SetMoveState(PEDMOVE_STILL); + m_nPedState = PED_CPR; + m_nLastPedState = PED_CPR; + SetLookFlag(m_pRevivedPed, 0); + SetLookTimer(500); + Say(SOUND_PED_HEALING); + if (m_pAttendedAccident->m_nMedicsPerformingCPR) { + SetIdle(); + m_nEmergencyPedState = EMERGENCY_PED_STAND_STILL; + } else { + m_nEmergencyPedState = EMERGENCY_PED_FACE_TO_PATIENT; + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CPR, 4.0f); + bIsDucking = true; + } + SetLookTimer(2000); + ++m_pAttendedAccident->m_nMedicsPerformingCPR; + m_bStartedToCPR = true; + } + break; + case EMERGENCY_PED_FACE_TO_PATIENT: + if (!m_pRevivedPed || m_pRevivedPed->m_fHealth > 0.0f) + m_nEmergencyPedState = EMERGENCY_PED_DETERMINE_NEXT_STATE; + else { + m_pRevivedPed->m_pedIK.GetComponentPosition((RwV3d*)&midPos, PED_MID); + m_pRevivedPed->m_pedIK.GetComponentPosition((RwV3d*)&headPos, PED_HEAD); + midPos = (headPos + midPos) * 0.5f; + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( + midPos.x, midPos.y, + GetPosition().x, GetPosition().y); + m_fRotationDest = CGeneral::LimitAngle(m_fRotationDest); + m_pLookTarget = m_pRevivedPed; + m_pLookTarget->RegisterReference((CEntity**)&m_pLookTarget); + TurnBody(); + + if (Abs(m_fRotationCur - m_fRotationDest) < DEGTORAD(45.0f)) + m_nEmergencyPedState = EMERGENCY_PED_PERFORM_CPR; + else + m_fRotationCur = (m_fRotationCur + m_fRotationDest) * 0.5f; + } + break; + case EMERGENCY_PED_PERFORM_CPR: + if (!m_pRevivedPed || m_pRevivedPed->m_fHealth > 0.0f) { + m_nEmergencyPedState = EMERGENCY_PED_DETERMINE_NEXT_STATE; + break; + } + m_pRevivedPed->m_pedIK.GetComponentPosition((RwV3d*)&midPos, PED_MID); + m_pRevivedPed->m_pedIK.GetComponentPosition((RwV3d*)&headPos, PED_HEAD); + midPos = (headPos + midPos) * 0.5f; + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( + midPos.x, midPos.y, + GetPosition().x, GetPosition().y); + m_fRotationDest = CGeneral::LimitAngle(m_fRotationDest); + m_pLookTarget = m_pRevivedPed; + m_pLookTarget->RegisterReference((CEntity**)&m_pLookTarget); + TurnBody(); + if (CTimer::GetTimeInMilliseconds() <= m_lookTimer) { + SetMoveState(PEDMOVE_STILL); + break; + } + m_nEmergencyPedState = EMERGENCY_PED_STOP_CPR; + m_nPedState = PED_NONE; + SetMoveState(PEDMOVE_WALK); + m_pVehicleAnim = nil; + if (!m_pRevivedPed->bBodyPartJustCameOff) { + m_pRevivedPed->m_fHealth = 100.0f; + m_pRevivedPed->m_nPedState = PED_NONE; + m_pRevivedPed->m_nLastPedState = PED_WANDER_PATH; + m_pRevivedPed->SetGetUp(); + m_pRevivedPed->bUsesCollision = true; + m_pRevivedPed->SetMoveState(PEDMOVE_WALK); + m_pRevivedPed->RestartNonPartialAnims(); + m_pRevivedPed->bIsPedDieAnimPlaying = false; + m_pRevivedPed->m_ped_flagH1 = false; + m_pRevivedPed->m_pCollidingEntity = nil; + } + break; + case EMERGENCY_PED_STOP_CPR: + m_nEmergencyPedState = EMERGENCY_PED_STOP; + bIsDucking = true; + break; + case EMERGENCY_PED_STAND_STILL: + if (!m_pRevivedPed || m_pRevivedPed->m_fHealth > 0.0f) + m_nEmergencyPedState = EMERGENCY_PED_DETERMINE_NEXT_STATE; + else { + if (!m_pAttendedAccident->m_pVictim) + m_nEmergencyPedState = EMERGENCY_PED_DETERMINE_NEXT_STATE; + if (!m_pAttendedAccident->m_nMedicsPerformingCPR) + m_nEmergencyPedState = EMERGENCY_PED_DETERMINE_NEXT_STATE; + if (gAccidentManager.UnattendedAccidents()) + m_nEmergencyPedState = EMERGENCY_PED_DETERMINE_NEXT_STATE; + } + break; + case EMERGENCY_PED_STOP: + m_bStartedToCPR = false; + m_nPedState = PED_NONE; + if (m_pAttendedAccident) { + m_pAttendedAccident->m_pVictim = nil; + --m_pAttendedAccident->m_nMedicsAttending; + m_pAttendedAccident = nil; + } + SetWanderPath(CGeneral::GetRandomNumber() & 7); + m_pRevivedPed = nil; + m_nEmergencyPedState = EMERGENCY_PED_READY; + SetMoveState(PEDMOVE_WALK); + break; + } + } +} + +class CEmergencyPed_ : public CEmergencyPed +{ +public: + CEmergencyPed* ctor(int pedtype) { return ::new (this) CEmergencyPed(pedtype); }; + void dtor(void) { CEmergencyPed::~CEmergencyPed(); } + void ProcessControl_(void) { CEmergencyPed::ProcessControl(); } +}; + STARTPATCHES InjectHook(0x4C2E40, &CEmergencyPed_::ctor, PATCH_JUMP); InjectHook(0x4C2EF0, &CEmergencyPed_::dtor, PATCH_JUMP); + InjectHook(0x4C2F10, &CEmergencyPed_::ProcessControl_, PATCH_JUMP); + InjectHook(0x4C3EC0, &CEmergencyPed::InRange, PATCH_JUMP); ENDPATCHES diff --git a/src/peds/EmergencyPed.h b/src/peds/EmergencyPed.h index f55fa4e2..5693e908 100644 --- a/src/peds/EmergencyPed.h +++ b/src/peds/EmergencyPed.h @@ -1,20 +1,40 @@ #pragma once -#include "Fire.h" #include "Ped.h" +class CAccident; +class CFire; + +enum EmergencyPedState +{ + EMERGENCY_PED_READY = 0x0, + EMERGENCY_PED_DETERMINE_NEXT_STATE = 0x1, // you can set that anytime you want + EMERGENCY_PED_START_CPR = 0x2, + EMERGENCY_PED_FLAG_4 = 0x4, // unused + EMERGENCY_PED_FLAG_8 = 0x8, // unused + EMERGENCY_PED_FACE_TO_PATIENT = 0x10, // for CPR + EMERGENCY_PED_PERFORM_CPR = 0x20, + EMERGENCY_PED_STOP_CPR = 0x40, + EMERGENCY_PED_STAND_STILL = 0x80, // waiting colleagues for medics, "extinguishing" fire for firemen + EMERGENCY_PED_STOP = 0x100, +}; + class CEmergencyPed : public CPed { public: // 0x53C - CPed* m_pRevivedPed; - int32 m_nEmergencyPedState; // looks like flags - void* m_pAttendedAccident; //TODO: CAccident* - CFire* m_pAttendedFire; - int8 field_1356; - int32 field_1360; + CPed *m_pRevivedPed; + EmergencyPedState m_nEmergencyPedState; + CAccident *m_pAttendedAccident; + CFire *m_pAttendedFire; + bool m_bStartedToCPR; // set but unused(?) + int32 field_1360; // also something for medics, unused(?) CEmergencyPed(uint32); + ~CEmergencyPed() { } + bool InRange(CPed*); void ProcessControl(void); + void FiremanAI(void); + void MedicAI(void); }; static_assert(sizeof(CEmergencyPed) == 0x554, "CEmergencyPed: error"); diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index 11aa480b..5d235507 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -49,15 +49,6 @@ #include "ParticleObject.h" #include "Floater.h" -WRAPPER void CPed::SetMoveAnim(void) { EAXJMP(0x4C5A40); } -WRAPPER void CPed::WanderPath(void) { EAXJMP(0x4D28D0); } -WRAPPER void CPed::SetEnterCar_AllClear(CVehicle*, uint32, uint32) { EAXJMP(0x4E0A40); } -WRAPPER bool CPed::WarpPedToNearEntityOffScreen(CEntity*) { EAXJMP(0x4E5570); } -WRAPPER void CPed::SetObjective(eObjective, CVector) { EAXJMP(0x4D8A90); } -WRAPPER void CPed::SetObjective(eObjective, CVector, float) { EAXJMP(0x4D8770); } -WRAPPER void CPed::SetCarJack(CVehicle*) { EAXJMP(0x4E0220); } -WRAPPER void CPed::WarpPedToNearLeaderOffScreen(void) { EAXJMP(0x4E52A0); } - #define FEET_OFFSET 1.04f CPed *gapTempPedList[50]; @@ -281,10 +272,14 @@ static char WaitStateText[][16] = { "Finish Flee", }; -#ifndef MASTER -int nDisplayDebugInfo = 0; +#ifdef TOGGLEABLE_BETA_FEATURES bool CPed::bUnusedFightThingOnPlayer = false; bool CPed::bPopHeadsOnHeadshot = false; +bool CPed::bMakePedsRunToPhonesToReportCrimes = false; +#endif + +#ifndef MASTER +int nDisplayDebugInfo = 0; void CPed::SwitchDebugDisplay(void) @@ -295,7 +290,7 @@ CPed::SwitchDebugDisplay(void) void CPed::DebugRenderOnePedText(void) { - if ((GetPosition() - TheCamera.GetPosition()).MagnitudeSqr() < 900.0f) { + if ((GetPosition() - TheCamera.GetPosition()).MagnitudeSqr() < sq(30.0f)) { float width, height; RwV3d screenCoords; CVector bitAbove = GetPosition(); @@ -309,7 +304,7 @@ CPed::DebugRenderOnePedText(void) CFont::SetBackgroundOn(); // Originally both of them were being divided by 60.0f. - float xScale = min(width / 190.0f, 0.7f); + float xScale = min(width / 240.0f, 0.7f); float yScale = min(height / 80.0f, 0.7f); CFont::SetScale(SCREEN_SCALE_X(xScale), SCREEN_SCALE_Y(yScale)); @@ -342,7 +337,7 @@ CPed::~CPed(void) { CWorld::Remove(this); CRadar::ClearBlipForEntity(BLIP_CHAR, CPools::GetPedPool()->GetIndex(this)); - if (bInVehicle && m_pMyVehicle){ + if (InVehicle()){ uint8 door_flag = GetCarDoorFlag(m_vehEnterType); if (m_pMyVehicle->pDriver == this) m_pMyVehicle->pDriver = nil; @@ -367,7 +362,7 @@ void CPed::FlagToDestroyWhenNextProcessed(void) { bRemoveFromWorld = true; - if (!bInVehicle || !m_pMyVehicle) + if (!InVehicle()) return; if (m_pMyVehicle->pDriver == this){ m_pMyVehicle->pDriver = nil; @@ -464,7 +459,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) m_wanderRangeBounds = nil; m_nPathNodes = 0; m_nCurPathNode = 0; - m_nPathState = 0; + m_nPathDir = 0; m_pLastPathNode = nil; m_pNextPathNode = nil; m_routeLastPoint = -1; @@ -574,9 +569,9 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) m_fAngleToEvent = 0.0f; m_numNearPeds = 0; - for (int i = 0; i < 10; i++) { + for (int i = 0; i < ARRAY_SIZE(m_nearPeds); i++) { m_nearPeds[i] = nil; - if (i < 8) { + if (i < ARRAY_SIZE(m_pPathNodesStates)) { m_pPathNodesStates[i] = nil; } } @@ -790,9 +785,7 @@ CPed::AimGun(void) if (m_pSeekTarget) { if (m_pSeekTarget->IsPed()) { ((CPed*)m_pSeekTarget)->m_pedIK.GetComponentPosition(&pos, PED_MID); - vector.x = pos.x; - vector.y = pos.y; - vector.z = pos.z; + vector = pos; } else { vector = m_pSeekTarget->GetPosition(); } @@ -877,7 +870,7 @@ CPed::RemoveBodyPart(PedNode nodeId, int8 direction) frame = GetNodeFrame(nodeId); if (frame) { if (CGame::nastyGame) { -#ifndef MASTER +#ifdef TOGGLEABLE_BETA_FEATURES if (bPopHeadsOnHeadshot || nodeId != PED_HEAD) #else if (nodeId != PED_HEAD) @@ -1448,8 +1441,15 @@ CPed::ClearPointGunAt(void) ClearLookFlag(); ClearAimFlag(); bIsPointingGunAt = false; +#ifndef VC_PED_PORTS if (m_nPedState == PED_AIM_GUN) { RestorePreviousState(); +#else + if (m_nPedState == PED_AIM_GUN || m_nPedState == PED_ATTACK) { + m_nPedState = PED_IDLE; + RestorePreviousState(); + } +#endif weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weaponInfo->m_AnimToPlay); if (!animAssoc || animAssoc->blendDelta < 0.0f) { @@ -1459,7 +1459,9 @@ CPed::ClearPointGunAt(void) animAssoc->flags |= ASSOC_DELETEFADEDOUT; animAssoc->blendDelta = -4.0f; } +#ifndef VC_PED_PORTS } +#endif } void @@ -1924,7 +1926,7 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) if (!stillGettingInOut) { m_fRotationCur = m_fRotationDest; } else { - float limitedAngle = CGeneral::LimitRadianAngle(m_fRotationDest); + float limitedDest = CGeneral::LimitRadianAngle(m_fRotationDest); float timeUntilStateChange = (m_nPedStateTimer - CTimer::GetTimeInMilliseconds())/600.0f; m_vecOffsetSeek.z = 0.0f; @@ -1935,12 +1937,12 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) neededPos -= timeUntilStateChange * m_vecOffsetSeek; } - if (PI + m_fRotationCur < limitedAngle) { - limitedAngle -= 2 * PI; - } else if (m_fRotationCur - PI > limitedAngle) { - limitedAngle += 2 * PI; + if (PI + m_fRotationCur < limitedDest) { + limitedDest -= 2 * PI; + } else if (m_fRotationCur - PI > limitedDest) { + limitedDest += 2 * PI; } - m_fRotationCur -= (m_fRotationCur - limitedAngle) * (1.0f - timeUntilStateChange); + m_fRotationCur -= (m_fRotationCur - limitedDest) * (1.0f - timeUntilStateChange); } if (seatPosMult > 0.2f || vehIsUpsideDown) { @@ -2148,7 +2150,7 @@ CPed::BuildPedLists(void) { if ((CTimer::GetFrameCounter() + (m_randomSeed % 256)) % 16) { - for(int i = 0; i < 10; ) { + for(int i = 0; i < ARRAY_SIZE(m_nearPeds); ) { if (m_nearPeds[i]) { if (m_nearPeds[i]->IsPointerValid()) { float distSqr = (GetPosition() - m_nearPeds[i]->GetPosition()).MagnitudeSqr2D(); @@ -2159,7 +2161,7 @@ CPed::BuildPedLists(void) } // If we arrive here, the ped we're checking isn't "near", so we should remove it. - for (int j = i; j < 9; j++) { + for (int j = i; j < ARRAY_SIZE(m_nearPeds) - 1; j++) { m_nearPeds[j] = m_nearPeds[j + 1]; m_nearPeds[j + 1] = nil; } @@ -2194,14 +2196,14 @@ CPed::BuildPedLists(void) } gapTempPedList[gnNumTempPedList] = nil; SortPeds(gapTempPedList, 0, gnNumTempPedList - 1); - for (m_numNearPeds = 0; m_numNearPeds < 10; m_numNearPeds++) { + for (m_numNearPeds = 0; m_numNearPeds < ARRAY_SIZE(m_nearPeds); m_numNearPeds++) { CPed *ped = gapTempPedList[m_numNearPeds]; if (!ped) break; m_nearPeds[m_numNearPeds] = ped; } - for (int pedToClear = m_numNearPeds; pedToClear < 10; pedToClear++) + for (int pedToClear = m_numNearPeds; pedToClear < ARRAY_SIZE(m_nearPeds); pedToClear++) m_nearPeds[pedToClear] = nil; } } @@ -2395,7 +2397,7 @@ CPed::CalculateNewVelocity(void) bool CPed::CanBeDeleted(void) { - if (this->bInVehicle) + if (bInVehicle) return false; switch (CharCreatedBy) { @@ -2775,6 +2777,12 @@ void CPed::SetIdle(void) { if (m_nPedState != PED_IDLE && m_nPedState != PED_MUG && m_nPedState != PED_FLEE_ENTITY) { +#ifdef VC_PED_PORTS + if (m_nPedState == PED_AIM_GUN) + ClearPointGunAt(); + + m_nLastPedState = PED_NONE; +#endif m_nPedState = PED_IDLE; SetMoveState(PEDMOVE_STILL); } @@ -2985,7 +2993,7 @@ CPed::ReactToAttack(CEntity *attacker) } #ifdef VC_PED_PORTS - if (m_nPedState == PED_DRIVING && bInVehicle && m_pMyVehicle + if (m_nPedState == PED_DRIVING && InVehicle() && (m_pMyVehicle->pDriver == this || m_pMyVehicle->pDriver && m_pMyVehicle->pDriver->m_nPedState == PED_DRIVING)) { if (m_pMyVehicle->VehicleCreatedBy == RANDOM_VEHICLE @@ -2994,7 +3002,7 @@ CPed::ReactToAttack(CEntity *attacker) CCarCtrl::SwitchVehicleToRealPhysics(m_pMyVehicle); m_pMyVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 60.0f * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity; + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity; m_pMyVehicle->m_status = STATUS_PHYSICS; } } else @@ -3042,7 +3050,7 @@ bool CPed::TurnBody(void) { float lookDir; - bool doneSmoothly = true; + bool turnDone = true; if (m_pLookTarget) { CVector &lookPos = m_pLookTarget->GetPosition(); @@ -3067,18 +3075,19 @@ CPed::TurnBody(void) m_fRotationDest = limitedLookDir; if (Abs(neededTurn) > 0.05f) { - doneSmoothly = false; + turnDone = false; currentRot -= neededTurn * 0.2f; } m_fRotationCur = currentRot; m_fLookDirection = limitedLookDir; - return doneSmoothly; + return turnDone; } void CPed::Chat(void) { + // We're already looking to our partner if (bIsLooking && TurnBody()) ClearLookFlag(); @@ -3153,7 +3162,7 @@ CPed::CheckAroundForPossibleCollisions(void) if (radius > 4.5f || radius < 1.0f) radius = 1.0f; - // According to code, developers gave up calculating Z diff. later. + // Developers gave up calculating Z diff. later according to asm. float diff = CVector(ourCentre - objCentre).MagnitudeSqr2D(); if (sq(radius + 1.0f) > diff) @@ -3164,11 +3173,23 @@ CPed::CheckAroundForPossibleCollisions(void) bool CPed::MakePhonecall(void) { +#ifdef TOGGLEABLE_BETA_FEATURES + if (bMakePedsRunToPhonesToReportCrimes) + if (!IsPlayer() && CTimer::GetTimeInMilliseconds() > m_phoneTalkTimer - 7000 && bRunningToPhone) { + + FindPlayerPed()->m_pWanted->RegisterCrime_Immediately(m_crimeToReportOnPhone, GetPosition(), + (m_crimeToReportOnPhone == CRIME_POSSESSION_GUN ? (int)m_threatEntity : (int)((CPed*)m_pEventEntity)->m_threatEntity), false); + bRunningToPhone = false; + } +#endif if (CTimer::GetTimeInMilliseconds() <= m_phoneTalkTimer) return false; SetIdle(); gPhoneInfo.m_aPhones[m_phoneId].m_nState = PHONE_STATE_FREE; +#ifdef TOGGLEABLE_BETA_FEATURES + crimeReporters[m_phoneId] = nil; +#endif m_phoneId = -1; return true; } @@ -3176,8 +3197,22 @@ CPed::MakePhonecall(void) bool CPed::FacePhone(void) { - // FIX: I don't think this function was working correctly, they confused LimitAngle with LimitRadianAngle etc., so I fixed them - float currentRot = m_fRotationCur; + // FIX: This function was broken since it's left unused early in development. +#ifdef FIX_BUGS + float phoneDir = CGeneral::GetRadianAngleBetweenPoints( + gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.x, gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.y, + GetPosition().x, GetPosition().y); + + SetLookFlag(phoneDir, false); + bool turnDone = TurnBody(); + if (turnDone) { + SetIdle(); + ClearLookFlag(); + m_phoneTalkTimer = CTimer::GetTimeInMilliseconds() + 10000; + } + return turnDone; +#else + float currentRot = RADTODEG(m_fRotationCur); float phoneDir = CGeneral::GetRadianAngleBetweenPoints( gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.x, gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.y, @@ -3185,14 +3220,13 @@ CPed::FacePhone(void) GetPosition().y); SetLookFlag(phoneDir, false); - - phoneDir = CGeneral::LimitRadianAngle(phoneDir); + phoneDir = CGeneral::LimitAngle(phoneDir); m_moved = CVector2D(0.0f, 0.0f); - if (currentRot - PI > phoneDir) - phoneDir += 2 * PI; - else if (PI + currentRot < phoneDir) - phoneDir -= 2 * PI; + if (currentRot - 180.0f > phoneDir) + phoneDir += 2 * 180.0f; + else if (180.0f + currentRot < phoneDir) + phoneDir -= 2 * 180.0f; float neededTurn = currentRot - phoneDir; @@ -3202,9 +3236,10 @@ CPed::FacePhone(void) m_phoneTalkTimer = CTimer::GetTimeInMilliseconds() + 10000; return true; } else { - m_fRotationCur -= neededTurn * 0.2f; + m_fRotationCur = DEGTORAD(currentRot - neededTurn * 0.2f); return false; } +#endif } CPed * @@ -3946,7 +3981,7 @@ CPed::InflictDamage(CEntity *damagedBy, eWeaponType method, float damage, ePedPi } */ } - for (int i = 0; i < 8; i++) { + for (int i = 0; i < ARRAY_SIZE(m_pMyVehicle->pPassengers); i++) { CPed* passenger = m_pMyVehicle->pPassengers[i]; if (passenger && passenger != this && damagedBy) passenger->ReactToAttack(damagedBy); @@ -4174,39 +4209,36 @@ CPed::SetWanderPath(int8 pathStateDest) SetIdle(); return false; } else { - - // m_nPathState is pure direction for values 1,2,3 and 5,6,7 - - m_nPathState = pathStateDest; + m_nPathDir = pathStateDest; if (pathStateDest == 0) pathStateDest = CGeneral::GetRandomNumberInRange(1, 7); ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, - m_nPathState, &nextPathState); + m_nPathDir, &nextPathState); - // Circular loop until we find a node for current m_nPathState + // Circular loop until we find a node for current m_nPathDir while (!m_pNextPathNode) { - m_nPathState = (m_nPathState+1) % 8; + m_nPathDir = (m_nPathDir+1) % 8; // We're at where we started and couldn't find any node - if (m_nPathState == pathStateDest) { + if (m_nPathDir == pathStateDest) { ClearAll(); SetIdle(); return false; } ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, - m_nPathState, &nextPathState); + m_nPathDir, &nextPathState); } // We did it, save next path state and return true - m_nPathState = nextPathState; + m_nPathDir = nextPathState; m_nPedState = PED_WANDER_PATH; SetMoveState(PEDMOVE_WALK); bIsRunning = false; return true; } } else { - m_nPathState = pathStateDest; + m_nPathDir = pathStateDest; bStartWanderPathOnFoot = true; return false; } @@ -4268,7 +4300,7 @@ CPed::RestorePreviousState(void) if (m_nPedState == PED_GETUP && !bGetUpAnimStarted) return; - if (bInVehicle && m_pMyVehicle) { + if (InVehicle()) { m_nPedState = PED_DRIVING; m_nLastPedState = PED_NONE; } else { @@ -4291,7 +4323,7 @@ CPed::RestorePreviousState(void) if (!bFindNewNodeAfterStateRestore) { if (m_pNextPathNode) { CVector diff = m_pNextPathNode->pos - GetPosition(); - if (diff.MagnitudeSqr() < 49.0f) { + if (diff.MagnitudeSqr() < sq(7.0f)) { SetMoveState(PEDMOVE_WALK); break; } @@ -4341,6 +4373,9 @@ CPed::SetPointGunAt(CEntity *to) if (to) { SetLookFlag(to, true); SetAimFlag(to); +#ifdef VC_PED_PORTS + SetLookTimer(INT_MAX); +#endif } if (m_nPedState == PED_AIM_GUN || bIsDucking || m_nWaitState == WAITSTATE_PLAYANIM_DUCK) @@ -4577,7 +4612,7 @@ CPed::SetEvasiveDive(CPhysical *reason, uint8 onlyRandomJump) if (reason->IsVehicle() && m_nPedType == PEDTYPE_COP) { if (veh->pDriver && veh->pDriver->IsPlayer()) { - CWanted *wanted = CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted; + CWanted *wanted = FindPlayerPed()->m_pWanted; wanted->RegisterCrime_Immediately(CRIME_RECKLESS_DRIVING, GetPosition(), (int)this, false); wanted->RegisterCrime_Immediately(CRIME_SPEEDING, GetPosition(), (int)this, false); } @@ -4792,7 +4827,7 @@ CPed::StartFightAttack(uint8 buttonPressure) animAssoc->SetFinishCallback(FinishFightMoveCB, this); m_fightState = FIGHTSTATE_NO_MOVE; m_takeAStepAfterAttack = false; -#ifndef MASTER +#ifdef TOGGLEABLE_BETA_FEATURES m_takeAStepAfterAttack = IsPlayer() && bUnusedFightThingOnPlayer; #endif @@ -5499,7 +5534,7 @@ CPed::CollideWithPed(CPed *collideWith) int colliderIsAtPlayerSafePosID = -1; int weAreAtPlayerSafePosID = -1; - for (int i = 0; i < 6; i++) { + for (int i = 0; i < ARRAY_SIZE(((CPlayerPed*)m_pedInObjective)->m_pPedAtSafePos); i++) { CPed *pedAtSafePos = ((CPlayerPed*)m_pedInObjective)->m_pPedAtSafePos[i]; if (pedAtSafePos == this) { weAreAtPlayerSafePosID = i; @@ -7422,7 +7457,7 @@ CPed::Flee(void) if (CTimer::GetTimeInMilliseconds() > m_fleeTimer && m_fleeTimer) { bool mayFinishFleeing = true; if (m_nPedState == PED_FLEE_ENTITY) { - if ((CVector2D(GetPosition()) - ms_vec2DFleePosition).MagnitudeSqr() < 900.0f) + if ((CVector2D(GetPosition()) - ms_vec2DFleePosition).MagnitudeSqr() < sq(30.0f)) mayFinishFleeing = false; } @@ -7452,10 +7487,10 @@ CPed::Flee(void) if (m_pNextPathNode && CTimer::GetTimeInMilliseconds() > m_standardTimer) { curDirectionShouldBe = CGeneral::GetNodeHeadingFromVector(GetPosition().x - ms_vec2DFleePosition.x, GetPosition().y - ms_vec2DFleePosition.y); - if (m_nPathState < curDirectionShouldBe) - m_nPathState += 8; + if (m_nPathDir < curDirectionShouldBe) + m_nPathDir += 8; - int dirDiff = m_nPathState - curDirectionShouldBe; + int dirDiff = m_nPathDir - curDirectionShouldBe; if (dirDiff > 2 && dirDiff < 6) { realLastNode = nil; m_pLastPathNode = m_pNextPathNode; @@ -7491,7 +7526,7 @@ CPed::Flee(void) curDirectionShouldBe += 8; if (m_pNextPathNode && m_pNextPathNode != realLastNode && m_pNextPathNode != m_pLastPathNode && curDirectionShouldBe - nextDirection != 4) { - m_nPathState = nextDirection; + m_nPathDir = nextDirection; m_standardTimer = CTimer::GetTimeInMilliseconds() + 2000; } else { bUsePedNodeSeek = false; @@ -7942,7 +7977,7 @@ CPed::Idle(void) CVector doorPos = GetPositionToOpenCarDoor(veh, m_vehEnterType); CVector doorDist = GetPosition() - doorPos; - if (doorDist.MagnitudeSqr() < 0.25f) { + if (doorDist.MagnitudeSqr() < sq(0.5f)) { SetMoveState(PEDMOVE_WALK); return; } @@ -8320,7 +8355,7 @@ CPed::InvestigateEvent(void) } for (int i = 0; i < m_numNearPeds; i++) { - if ((m_eventOrThreat - m_nearPeds[i]->GetPosition()).MagnitudeSqr() < 0.16f) { + if ((m_eventOrThreat - m_nearPeds[i]->GetPosition()).MagnitudeSqr() < sq(0.4f)) { SetMoveState(PEDMOVE_STILL); return; } @@ -8527,6 +8562,10 @@ CPed::KillPedWithCar(CVehicle *car, float impulse) if (car->pDriver) { CEventList::RegisterEvent((m_nPedType == PEDTYPE_COP ? EVENT_HIT_AND_RUN_COP : EVENT_HIT_AND_RUN), EVENT_ENTITY_PED, this, car->pDriver, 1000); +#ifdef TOGGLEABLE_BETA_FEATURES + if (bMakePedsRunToPhonesToReportCrimes) + m_ped_flagI40 = true; +#endif } ePedPieceTypes pieceToDamage; @@ -8655,7 +8694,7 @@ CPed::LookForInterestingNodes(void) objMat = &veh->GetMatrix(); effectPos = veh->GetMatrix() * effect->pos; effectDist = effectPos - GetPosition(); - if (effectDist.MagnitudeSqr() < 64.0f) { + if (effectDist.MagnitudeSqr() < sq(8.0f)) { found = true; break; } @@ -8673,7 +8712,7 @@ CPed::LookForInterestingNodes(void) objMat = &obj->GetMatrix(); effectPos = obj->GetMatrix() * effect->pos; effectDist = effectPos - GetPosition(); - if (effectDist.MagnitudeSqr() < 64.0f) { + if (effectDist.MagnitudeSqr() < sq(8.0f)) { found = true; break; } @@ -8691,7 +8730,7 @@ CPed::LookForInterestingNodes(void) objMat = &building->GetMatrix(); effectPos = building->GetMatrix() * effect->pos; effectDist = effectPos - GetPosition(); - if (effectDist.MagnitudeSqr() < 64.0f) { + if (effectDist.MagnitudeSqr() < sq(8.0f)) { found = true; break; } @@ -8709,7 +8748,7 @@ CPed::LookForInterestingNodes(void) objMat = &building->GetMatrix(); effectPos = building->GetMatrix() * effect->pos; effectDist = effectPos - GetPosition(); - if (effectDist.MagnitudeSqr() < 64.0f) { + if (effectDist.MagnitudeSqr() < sq(8.0f)) { found = true; break; } @@ -9201,7 +9240,7 @@ CPed::ProcessControl(void) float timeDependentDist; if (remainingBloodyFpTime >= 2000) { if (remainingBloodyFpTime <= 7000) - timeDependentDist = (remainingBloodyFpTime - 2000) / 5000 * 0.75f; + timeDependentDist = (remainingBloodyFpTime - 2000) / 5000.0f * 0.75f; else timeDependentDist = 0.75f; } else { @@ -9245,8 +9284,8 @@ CPed::ProcessControl(void) } else { CShadows::StoreStaticShadow( (uintptr)this + 17, SHADOWTYPE_DARK, gpBloodPoolTex, &bloodPos, - (remainingBloodyFpTime - 2000) / 5000 * 0.75f, 0.0f, - 0.0f, (remainingBloodyFpTime - 2000) / 5000 * -0.75f, + (remainingBloodyFpTime - 2000) / 5000.0f * 0.75f, 0.0f, + 0.0f, (remainingBloodyFpTime - 2000) / 5000.0f * -0.75f, 255, 255, 0, 0, 4.0f, 1.0f, 40.0f, false, 0.0f); } } @@ -10070,7 +10109,7 @@ CPed::ProcessControl(void) if (bStartWanderPathOnFoot) { if (IsPedInControl()) { ClearAll(); - SetWanderPath(m_nPathState); + SetWanderPath(m_nPathDir); bStartWanderPathOnFoot = false; } else if (m_nPedState == PED_DRIVING) { bWanderPathAfterExitingCar = true; @@ -10334,6 +10373,34 @@ CPed::ProcessControl(void) break; } + CPad* pad = CPad::GetPad(0); + +#ifdef CAR_AIRBREAK + if (!pad->ArePlayerControlsDisabled()) { + if (pad->GetHorn()) { + float c = Cos(m_fRotationCur); + float s = Sin(m_fRotationCur); + m_pMyVehicle->GetRight() = CVector(1.0f, 0.0f, 0.0f); + m_pMyVehicle->GetForward() = CVector(0.0f, 1.0f, 0.0f); + m_pMyVehicle->GetUp() = CVector(0.0f, 0.0f, 1.0f); + if (pad->GetAccelerate()) { + m_pMyVehicle->ApplyMoveForce(GetForward() * 30.0f); + } else if (pad->GetBrake()) { + m_pMyVehicle->ApplyMoveForce(-GetForward() * 30.0f); + } else { + int16 lr = pad->GetSteeringLeftRight(); + if (lr < 0) { + //m_pMyVehicle->ApplyTurnForce(20.0f * -GetRight(), GetForward()); + m_pMyVehicle->ApplyMoveForce(-GetRight() * 30.0f); + } else if (lr > 0) { + m_pMyVehicle->ApplyMoveForce(GetRight() * 30.0f); + } else { + m_pMyVehicle->ApplyMoveForce(0.0f, 0.0f, 50.0f); + } + } + } + } +#endif float steerAngle = m_pMyVehicle->m_fSteerAngle; CAnimBlendAssociation *lDriveAssoc; CAnimBlendAssociation *rDriveAssoc; @@ -10434,7 +10501,7 @@ CPed::ProcessControl(void) if (CGame::nastyGame) { if (!(CTimer::GetFrameCounter() & 3)) { CVector cameraDist = GetPosition() - TheCamera.GetPosition(); - if (cameraDist.MagnitudeSqr() < 2500.0f) { + if (cameraDist.MagnitudeSqr() < sq(50.0f)) { float length = (CGeneral::GetRandomNumber() & 127) * 0.0015f + 0.15f; CVector bloodPos( @@ -10835,6 +10902,12 @@ CPed::RemoveInCarAnims(void) animAssoc->blendDelta = -1000.0f; } +#ifdef VC_PED_PORTS + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_BOAT); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; +#endif + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LB); if (animAssoc) animAssoc->blendDelta = -1000.0f; @@ -11369,7 +11442,11 @@ CPed::PedSetInCarCB(CAnimBlendAssociation *animAssoc, void *arg) } } } - if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER +#ifdef VC_PED_PORTS + || ped->m_nPedState == PED_CARJACK +#endif + ) veh->bIsBeingCarJacked = false; if (veh->m_nNumGettingIn) @@ -11380,6 +11457,9 @@ CPed::PedSetInCarCB(CAnimBlendAssociation *animAssoc, void *arg) if (veh->IsBoat()) { if (ped->IsPlayer()) { +#ifdef VC_PED_PORTS + CCarCtrl::RegisterVehicleOfInterest(veh); +#endif if (veh->m_status == STATUS_SIMPLE) { veh->m_vecMoveSpeed = CVector(0.0f, 0.0f, -0.00001f); veh->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); @@ -11423,8 +11503,12 @@ CPed::PedSetInCarCB(CAnimBlendAssociation *animAssoc, void *arg) if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { for (int i = 0; i < veh->m_nNumMaxPassengers; ++i) { CPed *passenger = veh->pPassengers[i]; - if (passenger && passenger->CharCreatedBy == RANDOM_CHAR) + if (passenger && passenger->CharCreatedBy == RANDOM_CHAR) { passenger->SetObjective(OBJECTIVE_LEAVE_VEHICLE, veh); +#ifdef VC_PED_PORTS + passenger->m_leaveCarTimer = CTimer::GetTimeInMilliseconds(); +#endif + } } } else if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) { if (ped->m_nPedState == PED_CARJACK) { @@ -11579,12 +11663,20 @@ CPed::PedStaggerCB(CAnimBlendAssociation* animAssoc, void* arg) } // It's "CPhoneInfo::ProcessNearestFreePhone" in PC IDB, but it's not true, someone made it up. -// TO-DO: No peds run to phones to report crimes. Make this work. bool CPed::RunToReportCrime(eCrimeType crimeToReport) { +#ifdef TOGGLEABLE_BETA_FEATURES + if (!bMakePedsRunToPhonesToReportCrimes) + return false; + + if (bRunningToPhone) + return true; +#else + // They changed true into false to make this function unusable. So running to phone actually starts but first frame after that cancels it. if (m_nPedState == PED_SEEK_POS) return false; +#endif CVector pos = GetPosition(); int phoneId = gPhoneInfo.FindNearestFreePhone(&pos); @@ -11592,12 +11684,14 @@ CPed::RunToReportCrime(eCrimeType crimeToReport) if (phoneId == -1) return false; - if (gPhoneInfo.m_aPhones[phoneId].m_nState != PHONE_STATE_FREE) + CPhone *phone = &gPhoneInfo.m_aPhones[phoneId]; + if (phone->m_nState != PHONE_STATE_FREE) return false; bRunningToPhone = true; + SetSeek(phone->m_pEntity->GetPosition() - phone->m_pEntity->GetForward(), 1.3f); // original: phone.m_vecPos, 0.3f SetMoveState(PEDMOVE_RUN); - SetSeek(gPhoneInfo.m_aPhones[phoneId].m_vecPos, 0.3f); + bIsRunning = true; // not there in original m_phoneId = phoneId; m_crimeToReportOnPhone = crimeToReport; return true; @@ -11650,7 +11744,7 @@ CPed::RegisterThreatWithGangPeds(CEntity *attacker) if (nearVehDriver && nearVehDriver != this && nearVehDriver->m_nPedType == m_nPedType) { if (nearVeh->IsVehicleNormal() && nearVeh->IsCar()) { - nearVeh->AutoPilot.m_nCruiseSpeed = 60.0f * nearVeh->pHandling->Transmission.fUnkMaxVelocity * 0.8f; + nearVeh->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * nearVeh->pHandling->Transmission.fUnkMaxVelocity * 0.8f; nearVeh->AutoPilot.m_nCarMission = MISSION_RAMPLAYER_FARAWAY; nearVeh->m_status = STATUS_PHYSICS; nearVeh->AutoPilot.m_nTempAction = TEMPACT_NONE; @@ -11926,6 +12020,20 @@ CPed::ReplaceWeaponWhenExitingVehicle(void) } } +// Same, it's inlined in III. +inline void +CPed::RemoveWeaponWhenEnteringVehicle(void) +{ + if (IsPlayer() && HasWeapon(WEAPONTYPE_UZI) && GetWeapon(WEAPONTYPE_UZI).m_nAmmoTotal > 0) { + if (m_storedWeapon == WEAPONTYPE_UNIDENTIFIED) + m_storedWeapon = GetWeapon()->m_eWeaponType; + SetCurrentWeapon(WEAPONTYPE_UZI); + } else { + CWeaponInfo *ourWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + RemoveWeaponModel(ourWeapon->m_nModelId); + } +} + void CPed::PedSetOutTrainCB(CAnimBlendAssociation *animAssoc, void *arg) { @@ -12286,7 +12394,7 @@ CPed::PossiblyFindBetterPosToSeekCar(CVector *pos, CVehicle *veh) helperPos = GetPosition() - foundPos; helperPos.z = 0.0f; - if (helperPos.MagnitudeSqr() <= 0.25f) + if (helperPos.MagnitudeSqr() <= sq(0.5f)) return false; pos->x = foundPos.x; @@ -12297,11 +12405,8 @@ CPed::PossiblyFindBetterPosToSeekCar(CVector *pos, CVehicle *veh) void CPed::Render(void) { - if (!bInVehicle - || m_nPedState == PED_EXIT_CAR - || m_nPedState == PED_DRAG_FROM_CAR - || bRenderPedInCar && - sq(25.0f * TheCamera.LODDistMultiplier) >= (TheCamera.GetPosition() - GetPosition()).MagnitudeSqr()) { + if (!bInVehicle || m_nPedState == PED_EXIT_CAR || m_nPedState == PED_DRAG_FROM_CAR || + bRenderPedInCar && sq(25.0f * TheCamera.LODDistMultiplier) >= (TheCamera.GetPosition() - GetPosition()).MagnitudeSqr()) { CEntity::Render(); } } @@ -12331,7 +12436,7 @@ CPed::ProcessObjective(void) } if (m_pedInObjective) { - if (m_pedInObjective->bInVehicle && m_pedInObjective->m_nPedState != PED_DRAG_FROM_CAR && m_pedInObjective->m_pMyVehicle) { + if (m_pedInObjective->InVehicle() && m_pedInObjective->m_nPedState != PED_DRAG_FROM_CAR) { targetCarOrHisPos = m_pedInObjective->m_pMyVehicle->GetPosition(); } else { targetCarOrHisPos = m_pedInObjective->GetPosition(); @@ -12358,7 +12463,7 @@ CPed::ProcessObjective(void) SetMoveState(PEDMOVE_STILL); break; case OBJECTIVE_FLEE_TILL_SAFE: - if (bInVehicle && m_pMyVehicle) { + if (InVehicle()) { SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); bFleeAfterExitingCar = true; } else if (m_nPedState != PED_FLEE_POS) { @@ -12414,18 +12519,18 @@ CPed::ProcessObjective(void) SetObjective(OBJECTIVE_FLEE_TILL_SAFE); break; } - if (bInVehicle && m_pMyVehicle) { + if (InVehicle()) { if (distWithTarget.Magnitude() >= 20.0f - || m_pMyVehicle->m_vecMoveSpeed.MagnitudeSqr() >= 0.0004f) { + || m_pMyVehicle->m_vecMoveSpeed.MagnitudeSqr() >= sq(0.02f)) { if (m_pMyVehicle->pDriver == this && !m_pMyVehicle->m_nGettingInFlags) { m_pMyVehicle->m_status = STATUS_PHYSICS; m_pMyVehicle->AutoPilot.m_nPrevRouteNode = 0; if (m_nPedType == PEDTYPE_COP) { - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->m_nWantedLevel * 0.1f + 0.6f) * (60.0f * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity); + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = (FindPlayerPed()->m_pWanted->m_nWantedLevel * 0.1f + 0.6f) * (GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity); m_pMyVehicle->AutoPilot.m_nCarMission = CCarAI::FindPoliceCarMissionForWantedLevel(); } else { - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 60.0f * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity * 0.8f; + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity * 0.8f; m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_RAMPLAYER_FARAWAY; } m_pMyVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; @@ -12512,7 +12617,7 @@ CPed::ProcessObjective(void) case OBJECTIVE_KILL_CHAR_ON_FOOT: { bool killPlayerInNoPoliceZone = false; - if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT && bInVehicle && m_pMyVehicle) { + if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT && InVehicle()) { SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); break; } @@ -12867,7 +12972,7 @@ CPed::ProcessObjective(void) case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: { - if (bInVehicle && m_pMyVehicle) { + if (InVehicle()) { if (m_nPedState == PED_DRIVING) SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); } else if (m_nPedState != PED_FLEE_ENTITY) { @@ -13166,12 +13271,12 @@ CPed::ProcessObjective(void) { distWithTarget = m_nextRoutePointPos - GetPosition(); distWithTarget.z = 0.0f; - if (bInVehicle && m_pMyVehicle) { + if (InVehicle()) { CCarAI::GetCarToGoToCoors(m_pMyVehicle, &m_nextRoutePointPos); CCarCtrl::RegisterVehicleOfInterest(m_pMyVehicle); - if (distWithTarget.MagnitudeSqr() < 400.0f) { + if (distWithTarget.MagnitudeSqr() < sq(20.0f)) { m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; - CPed::ForceStoredObjective(OBJECTIVE_GOTO_AREA_ANY_MEANS); + ForceStoredObjective(OBJECTIVE_GOTO_AREA_ANY_MEANS); SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); } break; @@ -13215,7 +13320,7 @@ CPed::ProcessObjective(void) case OBJECTIVE_RUN_TO_AREA: { if ((m_objective == OBJECTIVE_GOTO_AREA_ON_FOOT || m_objective == OBJECTIVE_RUN_TO_AREA) - && bInVehicle && m_pMyVehicle) { + && InVehicle()) { SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); } else { distWithTarget = m_nextRoutePointPos - GetPosition(); @@ -13408,8 +13513,8 @@ CPed::ProcessObjective(void) return; } float distWithTargetScSqr = distWithTarget.MagnitudeSqr(); - if (distWithTargetScSqr <= 100.0f) { - if (distWithTargetScSqr <= 1.96f) { + if (distWithTargetScSqr <= sq(10.0f)) { + if (distWithTargetScSqr <= sq(1.4f)) { CAnimBlendAssociation *reloadAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_AK_RELOAD); m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( m_pedInObjective->GetPosition().x, m_pedInObjective->GetPosition().y, @@ -13476,12 +13581,16 @@ CPed::ProcessObjective(void) // fall through case OBJECTIVE_LEAVE_VEHICLE: if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) { - if (bInVehicle && m_pMyVehicle) { + if (InVehicle()) { if (m_nPedState != PED_EXIT_CAR && m_nPedState != PED_DRAG_FROM_CAR && m_nPedState != PED_EXIT_TRAIN && (m_nPedType != PEDTYPE_COP || m_pMyVehicle->m_vecMoveSpeed.MagnitudeSqr2D() < 0.000025f)) { if (m_pMyVehicle->IsTrain()) SetExitTrain(m_pMyVehicle); +#ifdef VC_PED_PORTS + else if (m_pMyVehicle->IsBoat()) + SetExitBoat(m_pMyVehicle); +#endif else SetExitCar(m_pMyVehicle, 0); } @@ -13494,14 +13603,11 @@ CPed::ProcessObjective(void) case OBJECTIVE_LEAVE_CAR_AND_DIE: { if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) { - if (bInVehicle && m_pMyVehicle) { - if (m_nPedState != PED_EXIT_CAR && m_nPedState != PED_DRAG_FROM_CAR - && m_nPedState != PED_EXIT_TRAIN) { - // VC calls SetExitBoat for boats, which is not seperate func. in III but housed in CPlayerInfo::Process. - // This obj. will probably break/crash game if ped was in boat. - if (m_pMyVehicle->IsTrain()) - SetExitTrain(m_pMyVehicle); - else if (m_pMyVehicle->bIsBus || m_pMyVehicle->IsBoat()) + if (InVehicle()) { + if (m_nPedState != PED_EXIT_CAR && m_nPedState != PED_DRAG_FROM_CAR && m_nPedState != PED_EXIT_TRAIN) { + if (m_pMyVehicle->IsBoat()) + SetExitBoat(m_pMyVehicle); + else if (m_pMyVehicle->bIsBus) SetExitCar(m_pMyVehicle, 0); else { eCarNodes doorNode = CAR_DOOR_LF; @@ -13672,15 +13778,19 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) if (m_nMoveState == PEDMOVE_NONE || m_nMoveState == PEDMOVE_STILL) return; - if (CharCreatedBy != MISSION_CHAR && obj->m_modelIndex == MI_PHONEBOOTH1) { - bool isRunning = m_nMoveState == PEDMOVE_RUN || m_nMoveState == PEDMOVE_SPRINT; - SetFlee(obj, 5000); - bUsePedNodeSeek = true; - m_pNextPathNode = nil; - if (!isRunning) - SetMoveState(PEDMOVE_WALK); - return; - } +#ifdef TOGGLEABLE_BETA_FEATURES + if (!bMakePedsRunToPhonesToReportCrimes) +#endif + if (CharCreatedBy != MISSION_CHAR && obj->m_modelIndex == MI_PHONEBOOTH1) { + bool isRunning = m_nMoveState == PEDMOVE_RUN || m_nMoveState == PEDMOVE_SPRINT; + SetFlee(obj, 5000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + if (!isRunning) + SetMoveState(PEDMOVE_WALK); + return; + } + CVector2D adjustedColMin(objColMin.x - 0.35f, objColMin.y - 0.35f); CVector2D adjustedColMax(objColMax.x + 0.35f, objColMax.y + 0.35f); @@ -14375,7 +14485,7 @@ CPed::ProcessEntityCollision(CEntity *collidingEnt, CColPoint *collidingPoints) #else float speedSqr = 0.0f; if (!m_ped_flagA2) { - if (m_vecMoveSpeed.z >= -0.25f && (speedSqr = m_vecMoveSpeed.MagnitudeSqr()) <= 0.25f) { + if (m_vecMoveSpeed.z >= -0.25f && (speedSqr = m_vecMoveSpeed.MagnitudeSqr()) <= sq(0.5f)) { if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL) && -0.016f * CTimer::GetTimeStep() > m_vecMoveSpeed.z) { InflictDamage(collidingEnt, WEAPONTYPE_FALL_DAMAGE, 15.0f, PEDPIECE_TORSO, 2); @@ -14691,7 +14801,7 @@ CPed::SetRadioStation(void) } } -bool +inline bool CPed::IsNotInWreckedVehicle() { return m_pMyVehicle != nil && m_pMyVehicle->m_status != STATUS_WRECKED; @@ -15302,7 +15412,7 @@ CPed::ScanForInterestingStuff(void) for (int i = 0; i < m_numNearPeds; ++i) { CPed *nearPed = m_nearPeds[i]; - if ((nearPed->GetPosition() - GetPosition()).MagnitudeSqr() > 49.0f) + if ((nearPed->GetPosition() - GetPosition()).MagnitudeSqr() > sq(7.0f)) break; if ((nearPed->m_nPedType == PEDTYPE_CIVFEMALE || nearPed->m_nPedType == PEDTYPE_CIVMALE @@ -15468,7 +15578,7 @@ CPed::ScanForThreats(void) CPed *deadPed = nil; if (fearFlags & PED_FLAG_DEADPEDS && CharCreatedBy != MISSION_CHAR - && (deadPed = CheckForDeadPeds()) != nil && (deadPed->GetPosition() - ourPos).MagnitudeSqr() < 400.0f) { + && (deadPed = CheckForDeadPeds()) != nil && (deadPed->GetPosition() - ourPos).MagnitudeSqr() < sq(20.0f)) { m_pEventEntity = deadPed; m_pEventEntity->RegisterReference((CEntity **) &m_pEventEntity); return PED_FLAG_DEADPEDS; @@ -15695,21 +15805,21 @@ CPed::SeekCar(void) } bool foundBetterPosToSeek = PossiblyFindBetterPosToSeekCar(&dest, vehToSeek); m_vecSeekPos = dest; - float distToDest = (m_vecSeekPos - GetPosition()).MagnitudeSqr(); + float distToDestSqr = (m_vecSeekPos - GetPosition()).MagnitudeSqr(); #ifndef VC_PED_PORTS if (bIsRunning) SetMoveState(PEDMOVE_RUN); #else if (bIsRunning || - vehToSeek->pDriver && distToDest > 4.0f && (Abs(vehToSeek->m_vecMoveSpeed.x) > 0.01f || Abs(vehToSeek->m_vecMoveSpeed.y) > 0.01f)) + vehToSeek->pDriver && distToDestSqr > sq(2.0f) && (Abs(vehToSeek->m_vecMoveSpeed.x) > 0.01f || Abs(vehToSeek->m_vecMoveSpeed.y) > 0.01f)) SetMoveState(PEDMOVE_RUN); #endif - else if (distToDest < 4.0f) + else if (distToDestSqr < sq(2.0f)) SetMoveState(PEDMOVE_WALK); - if (distToDest >= 1.0f) + if (distToDestSqr >= 1.0f) bCanPedEnterSeekedCar = false; - else if (2.0f * vehToSeek->GetColModel()->boundingBox.max.x > distToDest) + else if (2.0f * vehToSeek->GetColModel()->boundingBox.max.x > distToDestSqr) bCanPedEnterSeekedCar = true; if (vehToSeek->m_nGettingInFlags & GetCarDoorFlag(m_vehEnterType)) @@ -15717,6 +15827,7 @@ CPed::SeekCar(void) else bVehEnterDoorIsBlocked = false; + // Arrived to the car if (Seek()) { if (!foundBetterPosToSeek) { if (1.5f + GetPosition().z > dest.z && GetPosition().z - 0.5f < dest.z) { @@ -16066,7 +16177,7 @@ CPed::UpdateFromLeader(void) return; CVector leaderDist; - if (m_leader->bInVehicle && m_leader->m_pMyVehicle) + if (m_leader->InVehicle()) leaderDist = m_leader->m_pMyVehicle->GetPosition() - GetPosition(); else leaderDist = m_leader->GetPosition() - GetPosition(); @@ -16530,17 +16641,8 @@ CPed::WarpPedIntoCar(CVehicle *car) CWeaponInfo *ourWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); RemoveWeaponModel(ourWeapon->m_nModelId); } else { - // Because we can use Uzi for drive by - // RemoveWeaponWhenEnteringVehicle in VC - if (IsPlayer() && HasWeapon(WEAPONTYPE_UZI) && GetWeapon(WEAPONTYPE_UZI).m_nAmmoTotal > 0) { - if (m_storedWeapon == WEAPONTYPE_UNIDENTIFIED) - m_storedWeapon = GetWeapon()->m_eWeaponType; - SetCurrentWeapon(WEAPONTYPE_UZI); - } else { - CWeaponInfo *ourWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - RemoveWeaponModel(ourWeapon->m_nModelId); - } + RemoveWeaponWhenEnteringVehicle(); if (car->bLowVehicle) m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_LSIT, 100.0f); @@ -16554,6 +16656,676 @@ CPed::WarpPedIntoCar(CVehicle *car) bChangedSeat = true; } +void +CPed::SetObjective(eObjective newObj, CVector dest) +{ + if (DyingOrDead()) + return; + + if (m_prevObjective != OBJECTIVE_NONE && m_prevObjective == newObj) + return; + + SetObjectiveTimer(0); + if (m_objective == newObj) { + if (newObj == OBJECTIVE_GOTO_AREA_ANY_MEANS || newObj == OBJECTIVE_GOTO_AREA_ON_FOOT || newObj == OBJECTIVE_RUN_TO_AREA) { + if (m_nextRoutePointPos == dest) + return; + } else if (newObj == OBJECTIVE_GUARD_SPOT) { + if (m_vecSeekPosEx == dest) + return; + } + } + +#ifdef VC_PED_PORTS + ClearPointGunAt(); +#endif + bObjectiveCompleted = false; + switch (newObj) { + case OBJECTIVE_GUARD_SPOT: + m_vecSeekPosEx = dest; + m_distanceToCountSeekDoneEx = 5.0f; + SetMoveState(PEDMOVE_STILL); + break; + case OBJECTIVE_GUARD_AREA: + case OBJECTIVE_WAIT_IN_CAR: + case OBJECTIVE_WAIT_IN_CAR_THEN_GETOUT: + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + case OBJECTIVE_FOLLOW_PED_IN_FORMATION: + case OBJECTIVE_LEAVE_VEHICLE: + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + case OBJECTIVE_FOLLOW_CAR_IN_CAR: + case OBJECTIVE_FIRE_AT_OBJ_FROM_VEHICLE: + case OBJECTIVE_DESTROY_OBJ: + case OBJECTIVE_DESTROY_CAR: + break; + case OBJECTIVE_GOTO_AREA_ANY_MEANS: + case OBJECTIVE_GOTO_AREA_ON_FOOT: + bIsRunning = false; + m_pNextPathNode = nil; + m_nextRoutePointPos = dest; + m_vecSeekPos = m_nextRoutePointPos; + m_distanceToCountSeekDone = 0.5f; + bUsePedNodeSeek = true; + if (sq(m_distanceToCountSeekDone) > (m_nextRoutePointPos - GetPosition()).MagnitudeSqr2D()) + return; + break; + case OBJECTIVE_RUN_TO_AREA: + bIsRunning = true; + m_pNextPathNode = nil; + m_nextRoutePointPos = dest; + m_vecSeekPos = m_nextRoutePointPos; + m_distanceToCountSeekDone = 0.5f; + bUsePedNodeSeek = true; + if (sq(m_distanceToCountSeekDone) > (m_nextRoutePointPos - GetPosition()).MagnitudeSqr2D()) + return; + break; + } + + if (IsTemporaryObjective(m_objective)) { + m_prevObjective = newObj; + } else { + if (m_objective != newObj) + SetStoredObjective(); + + m_objective = newObj; + } +} + +void +CPed::SetMoveAnim(void) +{ + if (m_nStoredMoveState == m_nMoveState || !IsPedInControl()) + return; + + if (m_nMoveState == PEDMOVE_NONE) { + m_nStoredMoveState = PEDMOVE_NONE; + return; + } + + AssocGroupId animGroupToUse; + if (m_leader && m_leader->IsPlayer()) + animGroupToUse = ASSOCGRP_PLAYER; + else + animGroupToUse = m_animGroup; + + CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FLAG400); + if (!animAssoc) { + CAnimBlendAssociation *fightIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE); + animAssoc = fightIdleAssoc; + if (fightIdleAssoc && m_nPedState == PED_FIGHT) + return; + + if (fightIdleAssoc) { + CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); + if (!idleAssoc || idleAssoc->blendDelta <= 0.0f) { + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_IDLE_STANCE, 8.0f); + } + } + } + if (!animAssoc) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED); + if (animAssoc) + if (m_nWaitState == WAITSTATE_STUCK || m_nWaitState == WAITSTATE_FINISH_FLEE) + return; + + if (animAssoc) { + CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); + if (!idleAssoc || idleAssoc->blendDelta <= 0.0f) { + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_IDLE_STANCE, 4.0f); + } + } + } + if (!animAssoc) { + m_nStoredMoveState = m_nMoveState; + if (m_nMoveState == PEDMOVE_WALK || m_nMoveState == PEDMOVE_RUN || m_nMoveState == PEDMOVE_SPRINT) { + for (CAnimBlendAssociation *assoc = RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_PARTIAL); + assoc; assoc = RpAnimBlendGetNextAssociation(assoc, ASSOC_PARTIAL)) { + + if (!(assoc->flags & ASSOC_FADEOUTWHENDONE)) { + assoc->blendDelta = -2.0f; + assoc->flags |= ASSOC_DELETEFADEDOUT; + } + } + + ClearAimFlag(); + ClearLookFlag(); + } + + switch (m_nMoveState) { + case PEDMOVE_STILL: + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_IDLE_STANCE, 4.0f); + break; + case PEDMOVE_WALK: + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_WALK, 1.0f); + break; + case PEDMOVE_RUN: + if (m_nPedState == PED_FLEE_ENTITY) { + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_RUN, 3.0f); + } else { + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_RUN, 1.0f); + } + break; + case PEDMOVE_SPRINT: + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_SPRINT, 1.0f); + break; + default: + break; + } + + if (animAssoc) { + if (m_leader) { + CAnimBlendAssociation *walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_WALK); + if (!walkAssoc) + walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_RUN); + + if (!walkAssoc) + walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_SPRINT); + + if (walkAssoc) { + animAssoc->speed = walkAssoc->speed; + } else { + if (CharCreatedBy == MISSION_CHAR) + animAssoc->speed = 1.0f; + else + animAssoc->speed = 1.2f - m_randomSeed * 0.4f / MYRAND_MAX; + + } + } else { + if (CharCreatedBy == MISSION_CHAR) + animAssoc->speed = 1.0f; + else + animAssoc->speed = 1.2f - m_randomSeed * 0.4f / MYRAND_MAX; + } + } + } +} + +void +CPed::SetEnterCar_AllClear(CVehicle *car, uint32 doorNode, uint32 doorFlag) +{ + float zDiff = 0.0f; + RemoveWeaponWhenEnteringVehicle(); + car->m_nGettingInFlags |= doorFlag; + bVehEnterDoorIsBlocked = false; + if (m_nPedState != PED_SEEK_CAR && m_nPedState != PED_SEEK_IN_BOAT) + SetStoredState(); + + m_pSeekTarget = car; + m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); + m_vehEnterType = doorNode; + m_nPedState = PED_ENTER_CAR; + if (m_vehEnterType == CAR_DOOR_RF && m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && car->m_vehType != VEHICLE_TYPE_BIKE) { + car->bIsBeingCarJacked = true; + } + + m_pMyVehicle = (CVehicle*)m_pSeekTarget; + m_pMyVehicle->RegisterReference((CEntity**) &m_pMyVehicle); + ((CVehicle*)m_pSeekTarget)->m_nNumGettingIn++; + bUsesCollision = false; + CVector doorOpenPos = GetPositionToOpenCarDoor(car, m_vehEnterType); + + // Because buses have stairs + if (!m_pMyVehicle->bIsBus) + zDiff = max(0.0f, doorOpenPos.z - GetPosition().z); + + m_vecOffsetSeek = doorOpenPos - GetPosition(); + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 600; + if (car->IsBoat()) { + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DRIVE_BOAT, 100.0f); +#ifdef VC_PED_PORTS + PedSetInCarCB(nil, this); + m_ped_flagI4 = true; +#else + m_pVehicleAnim->SetFinishCallback(PedSetInCarCB, this); +#endif + if (IsPlayer()) + CWaterLevel::AllocateBoatWakeArray(); + } else { + if (zDiff > 4.4f) { + if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGNHI_RHS, 4.0f); + else + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGNHI_LHS, 4.0f); + + } else { + if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGN_RHS, 4.0f); + else + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGN_LHS, 4.0f); + } + m_pVehicleAnim->SetFinishCallback(PedAnimAlignCB, this); + car->AutoPilot.m_nCruiseSpeed = 0; + } +} + +void +CPed::WanderPath(void) +{ + if (!m_pNextPathNode) { + printf("THIS SHOULDN@T HAPPEN TOO OFTEN\n"); + SetIdle(); + return; + } + if (m_nWaitState == WAITSTATE_FALSE) { + if (m_nMoveState == PEDMOVE_STILL || m_nMoveState == PEDMOVE_NONE) + SetMoveState(PEDMOVE_WALK); + } + m_vecSeekPos = m_pNextPathNode->pos; + m_vecSeekPos.z += 1.0f; + + // Only returns true when ped is stuck(not stopped) I think, then we should assign new direction or wait state to him. + if (!Seek()) + return; + + CPathNode *previousLastNode = m_pLastPathNode; + uint8 randVal = (m_randomSeed + 3 * CTimer::GetFrameCounter()) % 100; + + // We don't prefer 180-degree turns in normal situations + uint8 dirWeWouldntPrefer = m_nPathDir; + if (dirWeWouldntPrefer <= 3) + dirWeWouldntPrefer += 4; + else + dirWeWouldntPrefer -= 4; + + CPathNode *nodeWeWouldntPrefer = nil; + uint8 dirToSet = 9; // means undefined + uint8 dirWeWouldntPrefer2 = 9; // means undefined + if (randVal <= 90) { + if (randVal > 80) { + m_nPathDir += 2; + m_nPathDir %= 8; + } + } else { + m_nPathDir -= 2; + if (m_nPathDir < 0) + m_nPathDir += 8; + } + + m_pLastPathNode = m_pNextPathNode; + ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, + m_nPathDir, &dirToSet); + + uint8 tryCount = 0; + + // NB: SetWanderPath checks for m_nPathDir == dirToStartWith, this one checks for tryCount > 7 + while (!m_pNextPathNode) { + tryCount++; + m_nPathDir = (m_nPathDir + 1) % 8; + + // We're at where we started and couldn't find any node + if (tryCount > 7) { + if (!nodeWeWouldntPrefer) { + ClearAll(); + SetIdle(); + // Probably this text carried over here after copy-pasting this loop from early version of SetWanderPath. + Error("Can't find valid path node, SetWanderPath, Ped.cpp"); + return; + } + m_pNextPathNode = nodeWeWouldntPrefer; + dirToSet = dirWeWouldntPrefer2; + } else { + ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, + m_nPathDir, &dirToSet); + if (m_pNextPathNode) { + if (dirToSet == dirWeWouldntPrefer) { + nodeWeWouldntPrefer = m_pNextPathNode; + dirWeWouldntPrefer2 = dirToSet; + m_pNextPathNode = nil; + } + } + } + } + + m_nPathDir = dirToSet; + if (m_pLastPathNode == m_pNextPathNode) { + m_pNextPathNode = previousLastNode; + SetWaitState(WAITSTATE_DOUBLEBACK, nil); + Say(SOUND_PED_WAIT_DOUBLEBACK); + } else if (ThePaths.TestForPedTrafficLight(m_pLastPathNode, m_pNextPathNode)) { + SetWaitState(WAITSTATE_TRAFFIC_LIGHTS, nil); + } else if (ThePaths.TestCrossesRoad(m_pLastPathNode, m_pNextPathNode)) { + SetWaitState(WAITSTATE_CROSS_ROAD, nil); + } else if (m_pNextPathNode == previousLastNode) { + SetWaitState(WAITSTATE_DOUBLEBACK, nil); + Say(SOUND_PED_WAIT_DOUBLEBACK); + } +} + +bool +CPed::WarpPedToNearEntityOffScreen(CEntity *warpTo) +{ + bool teleported = false; + if (GetIsOnScreen() || m_leaveCarTimer > CTimer::GetTimeInMilliseconds()) + return false; + + CVector warpToPos = warpTo->GetPosition(); + CVector distVec = warpToPos - GetPosition(); + float halfOfDist = distVec.Magnitude() * 0.5f; + CVector halfNormalizedDist = distVec / halfOfDist; + + CVector appropriatePos = GetPosition(); + CVector zCorrectedPos = appropriatePos; + int tryCount = min(10, halfOfDist); + for (int i = 0; i < tryCount; ++i) { + appropriatePos += halfNormalizedDist; + CPedPlacement::FindZCoorForPed(&zCorrectedPos); + + if (Abs(zCorrectedPos.z - warpToPos.z) >= 3.0f && Abs(zCorrectedPos.z - appropriatePos.z) >= 3.0f) + continue; + + appropriatePos.z = zCorrectedPos.z; + if (!TheCamera.IsSphereVisible(appropriatePos, 0.6f, &TheCamera.GetCameraMatrix()) + && CWorld::GetIsLineOfSightClear(appropriatePos, warpToPos, true, true, false, true, false, false, false) + && !CWorld::TestSphereAgainstWorld(appropriatePos, 0.6f, this, true, true, false, true, false, false)) { + teleported = true; + Teleport(appropriatePos); + } + } + m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 3000; + return teleported; +} + +bool +CPed::WarpPedToNearLeaderOffScreen(void) +{ + bool teleported = false; + if (GetIsOnScreen() || m_leaveCarTimer > CTimer::GetTimeInMilliseconds()) + return false; + + CVector warpToPos = m_leader->GetPosition(); + CVector distVec = warpToPos - GetPosition(); + float halfOfDist = distVec.Magnitude() * 0.5f; + CVector halfNormalizedDist = distVec / halfOfDist; + + CVector appropriatePos = GetPosition(); + CVector zCorrectedPos = appropriatePos; + int tryCount = min(10, halfOfDist); + for (int i = 0; i < tryCount; ++i) { + appropriatePos += halfNormalizedDist; + CPedPlacement::FindZCoorForPed(&zCorrectedPos); + + if (Abs(zCorrectedPos.z - warpToPos.z) >= 3.0f && Abs(zCorrectedPos.z - appropriatePos.z) >= 3.0f) + continue; + + appropriatePos.z = zCorrectedPos.z; + if (!TheCamera.IsSphereVisible(appropriatePos, 0.6f, &TheCamera.GetCameraMatrix()) + && CWorld::GetIsLineOfSightClear(appropriatePos, warpToPos, true, true, false, true, false, false, false) + && !CWorld::TestSphereAgainstWorld(appropriatePos, 0.6f, this, true, true, false, true, false, false)) { + teleported = true; + Teleport(appropriatePos); + } + } + m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 3000; + return teleported; +} + +void +CPed::SetCarJack_AllClear(CVehicle *car, uint32 doorNode, uint32 doorFlag) +{ + RemoveWeaponWhenEnteringVehicle(); + if (m_nPedState != PED_SEEK_CAR) + SetStoredState(); + + m_pSeekTarget = car; + m_pSeekTarget->RegisterReference((CEntity**)&m_pSeekTarget); + m_nPedState = PED_CARJACK; + car->bIsBeingCarJacked = true; + m_pMyVehicle = (CVehicle*)m_pSeekTarget; + m_pMyVehicle->RegisterReference((CEntity**)&m_pMyVehicle); + ((CVehicle*)m_pSeekTarget)->m_nNumGettingIn++; + + Say(m_nPedType == PEDTYPE_COP ? SOUND_PED_ARREST_COP : SOUND_PED_CAR_JACKING); + CVector carEnterPos; + carEnterPos = GetPositionToOpenCarDoor(car, m_vehEnterType); + + car->m_nGettingInFlags |= doorFlag; + m_vecOffsetSeek = carEnterPos - GetPosition(); + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 600; + float zDiff = max(0.0f, carEnterPos.z - GetPosition().z); + bUsesCollision = false; + + if (zDiff > 4.4f) { + if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGNHI_RHS, 4.0f); + else + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGNHI_LHS, 4.0f); + + } else { + if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGN_RHS, 4.0f); + else + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGN_LHS, 4.0f); + } + + m_pVehicleAnim->SetFinishCallback(PedAnimAlignCB, this); +} + +void +CPed::SetObjective(eObjective newObj, CVector dest, float safeDist) +{ + if (DyingOrDead()) + return; + + if (m_prevObjective != OBJECTIVE_NONE && m_prevObjective == newObj) + return; + + SetObjectiveTimer(0); + if (m_objective == newObj) { + if (newObj == OBJECTIVE_GOTO_AREA_ANY_MEANS || newObj == OBJECTIVE_GOTO_AREA_ON_FOOT || newObj == OBJECTIVE_RUN_TO_AREA) { + if (m_nextRoutePointPos == dest && m_distanceToCountSeekDone == safeDist) + return; + } else if (newObj == OBJECTIVE_GUARD_SPOT) { + if (m_vecSeekPosEx == dest && m_distanceToCountSeekDoneEx == safeDist) + return; + } + } + +#ifdef VC_PED_PORTS + ClearPointGunAt(); +#endif + bObjectiveCompleted = false; + if (IsTemporaryObjective(m_objective)) { + m_prevObjective = newObj; + } else { + if (m_objective != newObj) + SetStoredObjective(); + + m_objective = newObj; + } + + if (newObj == OBJECTIVE_GUARD_SPOT) { + m_vecSeekPosEx = dest; + m_distanceToCountSeekDoneEx = safeDist; + } else if (newObj == OBJECTIVE_GOTO_AREA_ANY_MEANS || newObj == OBJECTIVE_GOTO_AREA_ON_FOOT || newObj == OBJECTIVE_RUN_TO_AREA) { + m_pNextPathNode = nil; + m_nextRoutePointPos = dest; + m_vecSeekPos = m_nextRoutePointPos; + bUsePedNodeSeek = true; + } +} + +void +CPed::SetCarJack(CVehicle* car) +{ + uint8 doorFlag; + eDoors door; + CPed *pedInSeat = nil; + + if (car->IsBoat()) + return; + + switch (m_vehEnterType) { + case CAR_DOOR_RF: + doorFlag = CAR_DOOR_FLAG_RF; + door = DOOR_FRONT_RIGHT; + if (car->pPassengers[0]) { + pedInSeat = car->pPassengers[0]; + } else if (m_nPedType == PEDTYPE_COP) { + pedInSeat = car->pDriver; + } + break; + case CAR_DOOR_RR: + doorFlag = CAR_DOOR_FLAG_RR; + door = DOOR_REAR_RIGHT; + pedInSeat = car->pPassengers[2]; + break; + case CAR_DOOR_LF: + doorFlag = CAR_DOOR_FLAG_LF; + door = DOOR_FRONT_LEFT; + pedInSeat = car->pDriver; + break; + case CAR_DOOR_LR: + doorFlag = CAR_DOOR_FLAG_LR; + door = DOOR_REAR_LEFT; + pedInSeat = car->pPassengers[1]; + break; + default: + doorFlag = CAR_DOOR_FLAG_UNKNOWN; + break; + } + + if(car->bIsBus) + pedInSeat = car->pDriver; + + if (m_fHealth > 0.0f && (IsPlayer() || m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS || + (car->VehicleCreatedBy != MISSION_VEHICLE && car->m_modelIndex != MI_DODO))) + if (pedInSeat && !pedInSeat->IsPedDoingDriveByShooting() && pedInSeat->m_nPedState == PED_DRIVING) + if (m_nPedState != PED_CARJACK && !m_pVehicleAnim) + if ((car->IsDoorReady(door) || car->IsDoorFullyOpen(door))) + if (!car->bIsBeingCarJacked && !(doorFlag & car->m_nGettingInFlags) && !(doorFlag & car->m_nGettingOutFlags)) + SetCarJack_AllClear(car, m_vehEnterType, doorFlag); +} + +void +CPed::Solicit(void) +{ + if (m_standardTimer >= CTimer::GetTimeInMilliseconds() && m_carInObjective) { + CVector doorPos = GetPositionToOpenCarDoor(m_carInObjective, m_vehEnterType, 0.0f); + SetMoveState(PEDMOVE_STILL); + + // Game uses GetAngleBetweenPoints and converts it to radian + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( + doorPos.x, doorPos.y, + GetPosition().x, GetPosition().y); + + if (m_fRotationDest < 0.0f) { + m_fRotationDest = m_fRotationDest + TWOPI; + } else if (m_fRotationDest > TWOPI) { + m_fRotationDest = m_fRotationDest - TWOPI; + } + + if ((GetPosition() - doorPos).MagnitudeSqr() <= 1.0f) + return; + CAnimBlendAssociation *talkAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_HOOKERTALK); + if (talkAssoc) { + talkAssoc->blendDelta = -1000.0f; + talkAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + RestorePreviousState(); + RestorePreviousObjective(); + SetObjectiveTimer(10000); + } else if (!m_carInObjective) { + RestorePreviousState(); + RestorePreviousObjective(); + SetObjectiveTimer(10000); + } else if (CWorld::Players[CWorld::PlayerInFocus].m_nMoney <= 100) { + m_carInObjective = nil; + } else { + m_pVehicleAnim = nil; + SetLeader(m_carInObjective->pDriver); + } +} + +// Seperate function in VC, more logical. Not sure is it inlined in III. +void +CPed::SetExitBoat(CVehicle *boat) +{ +#ifndef VC_PED_PORTS + m_nPedState = PED_IDLE; + CVector firstPos = GetPosition(); + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 100.0f); + if (boat->m_modelIndex == MI_SPEEDER && boat->IsUpsideDown()) { + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_CRAWLOUT_RHS, 8.0f); + m_pVehicleAnim->SetFinishCallback(CPed::PedSetOutCarCB, this); + m_vehEnterType = CAR_DOOR_RF; + m_nPedState = PED_EXIT_CAR; + } else { + m_vehEnterType = CAR_DOOR_RF; + CPed::PedSetOutCarCB(nil, this); + bIsStanding = true; + m_pCurSurface = boat; + m_pCurSurface->RegisterReference((CEntity**)&m_pCurSurface); + } + GetPosition() = firstPos; + SetMoveState(PEDMOVE_STILL); + m_vecMoveSpeed = boat->m_vecMoveSpeed; + bTryingToReachDryLand = true; +#else + m_nPedState = PED_IDLE; + CVector newPos = GetPosition(); + RemoveInCarAnims(); + CColModel* boatCol = boat->GetColModel(); + if (boat->IsUpsideDown()) { + newPos = { 0.0f, 0.0f, boatCol->boundingBox.min.z }; + newPos = boat->GetMatrix() * newPos; + newPos.z += 1.0f; + m_vehEnterType = CAR_DOOR_RF; + PedSetOutCarCB(nil, this); + bIsStanding = true; + m_pCurSurface = boat; + m_pCurSurface->RegisterReference((CEntity**)&m_pCurSurface); + m_pCurrentPhysSurface = boat; + } else { +/* if (boat->m_modelIndex != MI_SKIMMER || boat->bIsInWater) { + if (boat->m_modelIndex == MI_SKIMMER) + newPos.z += 2.0f +*/ + m_vehEnterType = CAR_DOOR_RF; + PedSetOutCarCB(nil, this); + bIsStanding = true; + m_pCurSurface = boat; + m_pCurSurface->RegisterReference((CEntity**)&m_pCurSurface); + m_pCurrentPhysSurface = boat; + CColPoint foundCol; + CEntity *foundEnt = nil; + if (CWorld::ProcessVerticalLine(newPos, newPos.z - 1.4f, foundCol, foundEnt, false, true, false, false, false, false, nil)) + newPos.z = FEET_OFFSET + foundCol.point.z; +/* // VC specific + } else { + m_vehEnterType = CAR_DOOR_RF; + PedSetOutCarCB(nil, this); + bIsStanding = true; + SetMoveState(PEDMOVE_STILL); + bTryingToReachDryLand = true; + float upMult = 1.04f + boatCol->boundingBox.min.z; + float rightMult = 0.6f * boatCol->boundingBox.max.x; + newPos = upMult * boat->GetUp() + rightMult * boat->GetRight() + boat->GetPosition(); + GetPosition() = newPos; + if (m_pMyVehicle) { + PositionPedOutOfCollision(); + } else { + m_pMyVehicle = boat; + PositionPedOutOfCollision(); + m_pMyVehicle = nil; + } + return; + } +*/ } + GetPosition() = newPos; + SetMoveState(PEDMOVE_STILL); + m_vecMoveSpeed = boat->m_vecMoveSpeed; +#endif + // Not there in VC. + CWaterLevel::FreeBoatWakeArray(); +} + class CPed_ : public CPed { public: @@ -16569,6 +17341,7 @@ public: void Render_(void) { CPed::Render(); } void PreRender_(void) { CPed::PreRender(); } int32 ProcessEntityCollision_(CEntity *collidingEnt, CColPoint *collidingPoints) { return CPed::ProcessEntityCollision(collidingEnt, collidingPoints); } + void SetMoveAnim_(void) { CPed::SetMoveAnim(); } }; STARTPATCHES @@ -16583,6 +17356,7 @@ STARTPATCHES InjectHook(0x4D03F0, &CPed_::Render_, PATCH_JUMP); InjectHook(0x4CBB30, &CPed_::ProcessEntityCollision_, PATCH_JUMP); InjectHook(0x4CFDD0, &CPed_::PreRender_, PATCH_JUMP); + InjectHook(0x4C5A40, &CPed_::SetMoveAnim_, PATCH_JUMP); InjectHook(0x4CF8F0, &CPed::AddWeaponModel, PATCH_JUMP); InjectHook(0x4C6AA0, &CPed::AimGun, PATCH_JUMP); @@ -16622,6 +17396,8 @@ STARTPATCHES InjectHook(0x4D82C0, (void (CPed::*)(eObjective)) &CPed::SetObjective, PATCH_JUMP); InjectHook(0x4D83E0, (void (CPed::*)(eObjective, void*)) &CPed::SetObjective, PATCH_JUMP); InjectHook(0x4D89A0, (void (CPed::*)(eObjective, int16, int16)) &CPed::SetObjective, PATCH_JUMP); + InjectHook(0x4D8A90, (void (CPed::*)(eObjective, CVector)) &CPed::SetObjective, PATCH_JUMP); + InjectHook(0x4D8770, (void (CPed::*)(eObjective, CVector, float)) &CPed::SetObjective, PATCH_JUMP); InjectHook(0x4DDEC0, &CPed::ReactToAttack, PATCH_JUMP); InjectHook(0x4D0600, &CPed::SetIdle, PATCH_JUMP); InjectHook(0x4E0E00, &CPed::QuitEnteringCar, PATCH_JUMP); @@ -16777,4 +17553,10 @@ STARTPATCHES InjectHook(0x4D8F30, &CPed::UpdateFromLeader, PATCH_JUMP); InjectHook(0x4D4970, &CPed::SetPedPositionInCar, PATCH_JUMP); InjectHook(0x4D7D20, &CPed::WarpPedIntoCar, PATCH_JUMP); + InjectHook(0x4E0A40, &CPed::SetEnterCar_AllClear, PATCH_JUMP); + InjectHook(0x4D28D0, &CPed::WanderPath, PATCH_JUMP); + InjectHook(0x4E5570, &CPed::WarpPedToNearEntityOffScreen, PATCH_JUMP); + InjectHook(0x4E52A0, &CPed::WarpPedToNearLeaderOffScreen, PATCH_JUMP); + InjectHook(0x4E0220, &CPed::SetCarJack, PATCH_JUMP); + InjectHook(0x4D6780, &CPed::Solicit, PATCH_JUMP); ENDPATCHES
\ No newline at end of file diff --git a/src/peds/Ped.h b/src/peds/Ped.h index 446aab4b..49803418 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -243,9 +243,11 @@ enum PedState PED_STEP_AWAY, PED_ON_FIRE, - PED_UNKNOWN, // HANG_OUT in Fire_Head's idb + PED_UNKNOWN, // Same with IDLE, but also infects up to 5 peds with same pedType and WANDER_PATH, so they become stone too. HANG_OUT in Fire_Head's idb PED_STATES_NO_AI, + + // One of these states isn't on PS2 - start PED_JUMP, PED_FALL, PED_GETUP, @@ -256,6 +258,8 @@ enum PedState PED_ENTER_TRAIN, PED_EXIT_TRAIN, PED_ARREST_PLAYER, + // One of these states isn't on PS2 - end + PED_DRIVING, PED_PASSENGER, PED_TAXI_PASSENGER, @@ -363,7 +367,7 @@ public: uint8 bShakeFist : 1; // test shake hand at look entity uint8 bNoCriticalHits : 1; // if set, limbs won't came off - uint8 m_ped_flagI4 : 1; // we've been put to car by script? - related with cars + uint8 m_ped_flagI4 : 1; // we've been put to car by script or without align phase? - related with cars uint8 bHasAlreadyBeenRecorded : 1; uint8 bFallenDown : 1; #ifdef VC_PED_PORTS @@ -371,8 +375,8 @@ public: #else uint8 m_ped_flagI20 : 1; #endif - uint8 m_ped_flagI40 : 1; - uint8 m_ped_flagI80 : 1; + uint8 m_ped_flagI40 : 1; // bMakePedsRunToPhonesToReportCrimes makes use of this as runover by car indicator + uint8 m_ped_flagI80 : 1; // KANGAROO_CHEAT define makes use of this as cheat toggle uint8 stuff10[3]; uint8 CharCreatedBy; @@ -407,11 +411,11 @@ public: int32 m_nPrevMoveState; eWaitState m_nWaitState; uint32 m_nWaitTimer; - void *m_pPathNodesStates[8]; // seems unused, probably leftover from VC + void *m_pPathNodesStates[8]; // unused, probably leftover from VC CVector2D m_stPathNodeStates[10]; uint16 m_nPathNodes; int16 m_nCurPathNode; - int8 m_nPathState; + int8 m_nPathDir; private: int8 _pad2B5[3]; public: @@ -499,8 +503,8 @@ public: uint32 m_soundStart; uint16 m_lastQueuedSound; uint16 m_queuedSound; - CVector m_vecSeekPosEx; // used in objectives - float m_distanceToCountSeekDoneEx; // used in objectives + CVector m_vecSeekPosEx; // used for OBJECTIVE_GUARD_SPOT + float m_distanceToCountSeekDoneEx; // used for OBJECTIVE_GUARD_SPOT static void *operator new(size_t); static void *operator new(size_t, int); @@ -690,7 +694,9 @@ public: void ScanForInterestingStuff(void); void WarpPedIntoCar(CVehicle*); void SetCarJack(CVehicle*); - void WarpPedToNearLeaderOffScreen(void); + bool WarpPedToNearLeaderOffScreen(void); + void Solicit(void); + void SetExitBoat(CVehicle*); // Static methods static CVector GetLocalPositionToOpenCarDoor(CVehicle *veh, uint32 component, float offset); @@ -768,6 +774,7 @@ public: void SeekBoatPosition(void); void UpdatePosition(void); CObject *SpawnFlyingComponent(int, int8); + void SetCarJack_AllClear(CVehicle*, uint32, uint32); #ifdef VC_PED_PORTS bool CanPedJumpThis(CEntity*, CVector*); #else @@ -781,7 +788,9 @@ public: PedState GetPedState(void) { return m_nPedState; } void SetPedState(PedState state) { m_nPedState = state; } bool DyingOrDead(void) { return m_nPedState == PED_DIE || m_nPedState == PED_DEAD; } + bool InVehicle(void) { return bInVehicle && m_pMyVehicle; } // True when ped is sitting/standing in vehicle, not in enter/exit state. void ReplaceWeaponWhenExitingVehicle(void); + void RemoveWeaponWhenEnteringVehicle(void); bool IsNotInWreckedVehicle(); // set by 0482:set_threat_reaction_range_multiplier opcode @@ -796,10 +805,13 @@ public: static CVector2D ms_vec2DFleePosition; static CPedAudioData (&CommentWaitTime)[38]; -#ifndef MASTER +#ifdef TOGGLEABLE_BETA_FEATURES static bool bUnusedFightThingOnPlayer; static bool bPopHeadsOnHeadshot; + static bool bMakePedsRunToPhonesToReportCrimes; +#endif +#ifndef MASTER // Mobile things static void SwitchDebugDisplay(void); void DebugRenderOnePedText(void); @@ -809,7 +821,7 @@ public: class cPedParams { public: - char m_bDistanceCalculated; + bool m_bDistanceCalculated; char gap_1[3]; float m_fDistance; CPed *m_pPed; diff --git a/src/peds/PedStats.cpp b/src/peds/PedStats.cpp index f6508580..c393fddc 100644 --- a/src/peds/PedStats.cpp +++ b/src/peds/PedStats.cpp @@ -1,5 +1,6 @@ #include "common.h" #include "patcher.h" +#include "General.h" #include "FileMgr.h" #include "PedStats.h" @@ -112,7 +113,7 @@ CPedStats::GetPedStatType(char *name) int type; for(type = 0; type < NUM_PEDSTATS; type++) - if(strcmp(ms_apPedStats[type]->m_name, name) == 0) + if(!CGeneral::faststrcmp(ms_apPedStats[type]->m_name, name)) return type; return NUM_PEDSTATS; } diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp index 69cc316a..7c946dda 100644 --- a/src/peds/PlayerPed.cpp +++ b/src/peds/PlayerPed.cpp @@ -5,20 +5,15 @@ #include "WeaponEffects.h" #include "ModelIndices.h" #include "World.h" +#include "RpAnimBlend.h" +#include "General.h" CPlayerPed::~CPlayerPed() { delete m_pWanted; } -WRAPPER void CPlayerPed::ReApplyMoveAnims(void) { EAXJMP(0x4F07C0); } -WRAPPER void CPlayerPed::SetupPlayerPed(int32) { EAXJMP(0x4EFB60); } -WRAPPER void CPlayerPed::DeactivatePlayerPed(int32) { EAXJMP(0x4EFC00); } -WRAPPER void CPlayerPed::ReactivatePlayerPed(int32) { EAXJMP(0x4EFC20); } WRAPPER void CPlayerPed::KeepAreaAroundPlayerClear(void) { EAXJMP(0x4F3460); } -WRAPPER void CPlayerPed::MakeChangesForNewWeapon(int8) { EAXJMP(0x4F2560); } -WRAPPER void CPlayerPed::SetInitialState(void) { EAXJMP(0x4EFC40); } -WRAPPER void CPlayerPed::SetMoveAnim(void) { EAXJMP(0x4F3760); } WRAPPER void CPlayerPed::ProcessControl(void) { EAXJMP(0x4EFD90); } CPlayerPed::CPlayerPed(void) : CPed(PEDTYPE_PLAYER1) @@ -31,7 +26,7 @@ CPlayerPed::CPlayerPed(void) : CPed(PEDTYPE_PLAYER1) m_pWanted->Initialise(); m_pArrestingCop = nil; m_currentWeapon = WEAPONTYPE_UNARMED; - m_nSelectedWepSlot = 0; + m_nSelectedWepSlot = WEAPONTYPE_UNARMED; m_nSpeedTimer = 0; m_bSpeedTimerFlag = 0; m_pPointGunAt = nil; @@ -113,17 +108,364 @@ CPlayerPed::GetPlayerInfoForThisPlayerPed() return nil;
} +void
+CPlayerPed::SetupPlayerPed(int32 index)
+{
+ CPlayerPed *player = new CPlayerPed();
+ CWorld::Players[index].m_pPed = player;
+
+ player->SetOrientation(0.0f, 0.0f, 0.0f);
+
+ CWorld::Add(player);
+ player->m_wepAccuracy = 100; +} + +void
+CPlayerPed::DeactivatePlayerPed(int32 index)
+{
+ CWorld::Remove(CWorld::Players[index].m_pPed); +} + +void
+CPlayerPed::ReactivatePlayerPed(int32 index)
+{
+ CWorld::Add(CWorld::Players[index].m_pPed); +} + +void
+CPlayerPed::UseSprintEnergy(void)
+{
+ if (m_fCurrentStamina > -150.0f && !CWorld::Players[CWorld::PlayerInFocus].m_bInfiniteSprint
+ && !m_bAdrenalineActive) {
+ m_fCurrentStamina = m_fCurrentStamina - CTimer::GetTimeStep();
+ m_fStaminaProgress = m_fStaminaProgress + CTimer::GetTimeStep();
+ }
+
+ if (m_fStaminaProgress >= 500.0f) {
+ m_fStaminaProgress = 0;
+ if (m_fMaxStamina < 1000.0f)
+ m_fMaxStamina += 10.0f;
+ }
+} + +void
+CPlayerPed::MakeChangesForNewWeapon(int8 weapon)
+{
+ if (m_nPedState == PED_SNIPER_MODE) {
+ RestorePreviousState();
+ TheCamera.ClearPlayerWeaponMode();
+ }
+ SetCurrentWeapon(weapon);
+
+ GetWeapon()->m_nAmmoInClip = min(GetWeapon()->m_nAmmoTotal, CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_nAmountofAmmunition);
+
+ if (!(CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bCanAim))
+ ClearWeaponTarget();
+
+ CAnimBlendAssociation *weaponAnim = RpAnimBlendClumpGetAssociation(GetClump(), CWeaponInfo::GetWeaponInfo(WEAPONTYPE_SNIPERRIFLE)->m_AnimToPlay);
+ if (weaponAnim) {
+ weaponAnim->SetRun();
+ weaponAnim->flags |= ASSOC_FADEOUTWHENDONE;
+ }
+ TheCamera.ClearPlayerWeaponMode(); +} + +void
+CPlayerPed::ReApplyMoveAnims(void)
+{
+ static AnimationId moveAnims[] = { ANIM_WALK, ANIM_RUN, ANIM_SPRINT, ANIM_IDLE_STANCE, ANIM_WALK_START };
+
+ for(int i = 0; i < ARRAY_SIZE(moveAnims); i++) {
+ CAnimBlendAssociation *curMoveAssoc = RpAnimBlendClumpGetAssociation(GetClump(), moveAnims[i]);
+ if (curMoveAssoc) {
+ if (strcmp(CAnimManager::GetAnimAssociation(m_animGroup, moveAnims[i])->hierarchy->name, curMoveAssoc->hierarchy->name) != 0) {
+ CAnimBlendAssociation *newMoveAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, moveAnims[i]);
+ newMoveAssoc->blendDelta = curMoveAssoc->blendDelta;
+ newMoveAssoc->blendAmount = curMoveAssoc->blendAmount;
+ curMoveAssoc->blendDelta = -1000.0f;
+ curMoveAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ }
+ }
+ }
+} + +void
+CPlayerPed::SetInitialState(void)
+{
+ m_bAdrenalineActive = false;
+ m_nAdrenalineTime = 0;
+ CTimer::SetTimeStep(1.0f);
+ m_pSeekTarget = nil;
+ m_vecSeekPos = { 0.0f, 0.0f, 0.0f };
+ m_fleeFromPosX = 0.0f;
+ m_fleeFromPosY = 0.0f;
+ m_fleeFrom = nil;
+ m_fleeTimer = 0;
+ m_objective = OBJECTIVE_NONE;
+ m_prevObjective = OBJECTIVE_NONE;
+ bUsesCollision = true;
+ ClearAimFlag();
+ ClearLookFlag();
+ bIsPointingGunAt = false;
+ bRenderPedInCar = true;
+ if (m_pFire)
+ m_pFire->Extinguish();
+ RpAnimBlendClumpRemoveAllAssociations(GetClump());
+ m_nPedState = PED_IDLE;
+ SetMoveState(PEDMOVE_STILL);
+ m_nLastPedState = PED_NONE;
+ m_animGroup = ASSOCGRP_PLAYER;
+ m_fMoveSpeed = 0.0f;
+ m_nSelectedWepSlot = WEAPONTYPE_UNARMED;
+ m_bShouldEvade = false;
+ m_pEvadingFrom = nil;
+ bIsPedDieAnimPlaying = false;
+ SetRealMoveAnim();
+ m_bCanBeDamaged = true;
+ m_pedStats->m_temper = 50;
+ m_fWalkAngle = 0.0f;
+} + +void
+CPlayerPed::SetRealMoveAnim(void)
+{
+ CAnimBlendAssociation *curWalkAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK);
+ CAnimBlendAssociation *curRunAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN);
+ CAnimBlendAssociation *curSprintAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_SPRINT);
+ CAnimBlendAssociation *curWalkStartAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK_START);
+ CAnimBlendAssociation *curIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE);
+ CAnimBlendAssociation *curRunStopAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP);
+ CAnimBlendAssociation *curRunStopRAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP_R);
+ if (bResetWalkAnims) {
+ if (curWalkAssoc)
+ curWalkAssoc->SetCurrentTime(0.0f);
+ if (curRunAssoc)
+ curRunAssoc->SetCurrentTime(0.0f);
+ if (curSprintAssoc)
+ curSprintAssoc->SetCurrentTime(0.0f);
+ bResetWalkAnims = false;
+ }
+
+ if (!curIdleAssoc)
+ curIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED);
+ if (!curIdleAssoc)
+ curIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE);
+
+ if ((!curRunStopAssoc || !(curRunStopAssoc->IsRunning())) && (!curRunStopRAssoc || !(curRunStopRAssoc->IsRunning()))) {
+
+ if (curRunStopAssoc && curRunStopAssoc->blendDelta >= 0.0f || curRunStopRAssoc && curRunStopRAssoc->blendDelta >= 0.0f) {
+ if (curRunStopAssoc) {
+ curRunStopAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ curRunStopAssoc->blendAmount = 1.0f;
+ curRunStopAssoc->blendDelta = -8.0f;
+ } else if (curRunStopRAssoc) {
+ curRunStopRAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ curRunStopRAssoc->blendAmount = 1.0f;
+ curRunStopRAssoc->blendDelta = -8.0f;
+ }
+
+ RestoreHeadingRate();
+ if (!curIdleAssoc) {
+ if (m_fCurrentStamina < 0.0f && !CWorld::TestSphereAgainstWorld(GetPosition(), 0.0f,
+ nil, true, false, false, false, false, false)) {
+ curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 8.0f);
+
+ } else {
+ curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 8.0f);
+ }
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2500, 4000);
+ }
+ curIdleAssoc->blendAmount = 0.0f;
+ curIdleAssoc->blendDelta = 8.0f;
+
+ } else if (m_fMoveSpeed == 0.0f && !curSprintAssoc) {
+ if (!curIdleAssoc) {
+ if (m_fCurrentStamina < 0.0f && !CWorld::TestSphereAgainstWorld(GetPosition(), 0.0f,
+ nil, true, false, false, false, false, false)) {
+ curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 4.0f);
+
+ } else {
+ curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f);
+ }
+
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2500, 4000);
+ }
+
+ if (m_fCurrentStamina > 0.0f && curIdleAssoc->animId == ANIM_IDLE_TIRED) {
+ CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f);
+
+ } else if (m_nPedState != PED_FIGHT) {
+ if (m_fCurrentStamina < 0.0f && curIdleAssoc->animId != ANIM_IDLE_TIRED
+ && !CWorld::TestSphereAgainstWorld(GetPosition(), 0.0f, nil, true, false, false, false, false, false)) {
+ CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 4.0f);
+
+ } else if (curIdleAssoc->animId != ANIM_IDLE_STANCE) {
+ CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f);
+ }
+ }
+
+ m_nMoveState = PEDMOVE_STILL;
+ } else {
+ if (curIdleAssoc) {
+ if (curWalkStartAssoc) {
+ curWalkStartAssoc->blendAmount = 1.0f;
+ curWalkStartAssoc->blendDelta = 0.0f;
+ } else {
+ curWalkStartAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_WALK_START);
+ }
+ if (curWalkAssoc)
+ curWalkAssoc->SetCurrentTime(0.0f);
+ if (curRunAssoc)
+ curRunAssoc->SetCurrentTime(0.0f);
+
+ delete curIdleAssoc;
+ delete RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED);
+ delete RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE);
+ delete curSprintAssoc;
+
+ curSprintAssoc = nil;
+ m_nMoveState = PEDMOVE_WALK;
+ }
+ if (curRunStopAssoc) {
+ delete curRunStopAssoc;
+ RestoreHeadingRate();
+ }
+ if (curRunStopRAssoc) {
+ delete curRunStopRAssoc;
+ RestoreHeadingRate();
+ }
+ if (!curWalkAssoc) {
+ curWalkAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_WALK);
+ curWalkAssoc->blendAmount = 0.0f;
+ }
+ if (!curRunAssoc) {
+ curRunAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_RUN);
+ curRunAssoc->blendAmount = 0.0f;
+ }
+ if (curWalkStartAssoc && !(curWalkStartAssoc->IsRunning())) {
+ delete curWalkStartAssoc;
+ curWalkStartAssoc = nil;
+ curWalkAssoc->SetRun();
+ curRunAssoc->SetRun();
+ }
+ if (m_nMoveState == PEDMOVE_SPRINT) {
+ if (m_fCurrentStamina < 0.0f && (m_fCurrentStamina <= -150.0f || !curSprintAssoc || curSprintAssoc->blendDelta < 0.0f))
+ m_nMoveState = PEDMOVE_STILL;
+
+ if (curWalkStartAssoc)
+ m_nMoveState = PEDMOVE_STILL;
+ }
+
+ if (curSprintAssoc && (m_nMoveState != PEDMOVE_SPRINT || m_fMoveSpeed < 0.4f)) {
+ if (curSprintAssoc->blendAmount == 0.0f) {
+ curSprintAssoc->blendDelta = -1000.0f;
+ curSprintAssoc->flags |= ASSOC_DELETEFADEDOUT;
+
+ } else if (curSprintAssoc->blendDelta >= 0.0f || curSprintAssoc->blendAmount >= 0.8f) {
+ if (m_fMoveSpeed < 0.4f) {
+ AnimationId runStopAnim;
+ if (curSprintAssoc->currentTime / curSprintAssoc->hierarchy->totalLength < 0.5) // double
+ runStopAnim = ANIM_RUN_STOP;
+ else
+ runStopAnim = ANIM_RUN_STOP_R;
+ CAnimBlendAssociation* newRunStopAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, runStopAnim);
+ newRunStopAssoc->blendAmount = 1.0f;
+ newRunStopAssoc->SetDeleteCallback(RestoreHeadingRateCB, this);
+ m_headingRate = 0.0f;
+ curSprintAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ curSprintAssoc->blendDelta = -1000.0f;
+ curWalkAssoc->flags &= ~ASSOC_RUNNING;
+ curWalkAssoc->blendAmount = 0.0f;
+ curWalkAssoc->blendDelta = 0.0f;
+ curRunAssoc->flags &= ~ASSOC_RUNNING;
+ curRunAssoc->blendAmount = 0.0f;
+ curRunAssoc->blendDelta = 0.0f;
+ } else if (curSprintAssoc->blendDelta < 0.0f) {
+ curSprintAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ curSprintAssoc->blendDelta = -1.0f;
+ curRunAssoc->blendDelta = 1.0f;
+ }
+ } else if (m_fMoveSpeed < 1.0f) {
+ curSprintAssoc->blendDelta = -8.0f;
+ curRunAssoc->blendDelta = 8.0f;
+ }
+ } else if (curWalkStartAssoc) {
+ curWalkAssoc->flags &= ~ASSOC_RUNNING;
+ curRunAssoc->flags &= ~ASSOC_RUNNING;
+ curWalkAssoc->blendAmount = 0.0f;
+ curRunAssoc->blendAmount = 0.0f;
+
+ } else if (m_nMoveState == PEDMOVE_SPRINT) {
+ if (curSprintAssoc) {
+ if (curSprintAssoc->blendDelta < 0.0f) {
+ curSprintAssoc->blendDelta = 2.0f;
+ curRunAssoc->blendDelta = -2.0f;
+ }
+ } else {
+ curWalkAssoc->blendAmount = 0.0f;
+ curRunAssoc->blendAmount = 1.0f;
+ curSprintAssoc = CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_SPRINT, 2.0f);
+ }
+ UseSprintEnergy();
+ } else {
+ if (m_fMoveSpeed < 1.0f) {
+ curWalkAssoc->blendAmount = 1.0f;
+ curRunAssoc->blendAmount = 0.0f;
+ m_nMoveState = PEDMOVE_WALK;
+ } else if (m_fMoveSpeed < 2.0f) {
+ curWalkAssoc->blendAmount = 2.0f - m_fMoveSpeed;
+ curRunAssoc->blendAmount = m_fMoveSpeed - 1.0f;
+ m_nMoveState = PEDMOVE_RUN;
+ } else {
+ curWalkAssoc->blendAmount = 0.0f;
+ curRunAssoc->blendAmount = 1.0f;
+ m_nMoveState = PEDMOVE_RUN;
+ }
+ }
+ }
+ }
+ if (m_bAdrenalineActive) {
+ if (CTimer::GetTimeInMilliseconds() > m_nAdrenalineTime) {
+ m_bAdrenalineActive = false;
+ CTimer::SetTimeScale(1.0f);
+ if (curWalkStartAssoc)
+ curWalkStartAssoc->speed = 1.0f;
+ if (curWalkAssoc)
+ curWalkAssoc->speed = 1.0f;
+ if (curRunAssoc)
+ curRunAssoc->speed = 1.0f;
+ if (curSprintAssoc)
+ curSprintAssoc->speed = 1.0f;
+ } else {
+ CTimer::SetTimeScale(1.0f / 3);
+ if (curWalkStartAssoc)
+ curWalkStartAssoc->speed = 2.0f;
+ if (curWalkAssoc)
+ curWalkAssoc->speed = 2.0f;
+ if (curRunAssoc)
+ curRunAssoc->speed = 2.0f;
+ if (curSprintAssoc)
+ curSprintAssoc->speed = 2.0f;
+ }
+ }
+} + class CPlayerPed_ : public CPlayerPed { public: CPlayerPed* ctor(void) { return ::new (this) CPlayerPed(); } void dtor(void) { CPlayerPed::~CPlayerPed(); } + void SetMoveAnim_(void) { CPlayerPed::SetMoveAnim(); } }; STARTPATCHES InjectHook(0x4EF7E0, &CPlayerPed_::ctor, PATCH_JUMP); InjectHook(0x4EFB30, &CPlayerPed_::dtor, PATCH_JUMP); + InjectHook(0x4F3760, &CPlayerPed_::SetMoveAnim_, PATCH_JUMP); InjectHook(0x4F28A0, &CPlayerPed::ClearWeaponTarget, PATCH_JUMP); InjectHook(0x4F3700, &CPlayerPed::AnnoyPlayerPed, PATCH_JUMP); InjectHook(0x4F36C0, &CPlayerPed::GetPlayerInfoForThisPlayerPed, PATCH_JUMP); + InjectHook(0x4F2560, &CPlayerPed::MakeChangesForNewWeapon, PATCH_JUMP); + InjectHook(0x4F07C0, &CPlayerPed::ReApplyMoveAnims, PATCH_JUMP); + InjectHook(0x4F0880, &CPlayerPed::SetRealMoveAnim, PATCH_JUMP); ENDPATCHES diff --git a/src/peds/PlayerPed.h b/src/peds/PlayerPed.h index bd24ecd0..1de1b442 100644 --- a/src/peds/PlayerPed.h +++ b/src/peds/PlayerPed.h @@ -41,6 +41,7 @@ public: CPlayerPed(); ~CPlayerPed(); + void SetMoveAnim() { }; void ReApplyMoveAnims(void); void ClearWeaponTarget(void); @@ -50,10 +51,11 @@ public: void AnnoyPlayerPed(bool); void MakeChangesForNewWeapon(int8); void SetInitialState(void); - void SetMoveAnim(void); void ProcessControl(void); void ClearAdrenaline(void); + void UseSprintEnergy(void); class CPlayerInfo *GetPlayerInfoForThisPlayerPed(); + void SetRealMoveAnim(void); static void SetupPlayerPed(int32); static void DeactivatePlayerPed(int32); |