summaryrefslogtreecommitdiffstats
path: root/src/peds
diff options
context:
space:
mode:
Diffstat (limited to 'src/peds')
-rw-r--r--src/peds/CivilianPed.cpp396
-rw-r--r--src/peds/CivilianPed.h1
-rw-r--r--src/peds/EmergencyPed.cpp435
-rw-r--r--src/peds/EmergencyPed.h34
-rw-r--r--src/peds/Ped.cpp1072
-rw-r--r--src/peds/Ped.h34
-rw-r--r--src/peds/PedStats.cpp3
-rw-r--r--src/peds/PlayerPed.cpp358
-rw-r--r--src/peds/PlayerPed.h4
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);