mirror of
https://github.com/halpz/re3.git
synced 2025-07-04 07:50:42 +00:00
merge with upstream
This commit is contained in:
@ -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
|
||||
|
@ -8,6 +8,7 @@ public:
|
||||
CCivilianPed(int, int);
|
||||
~CCivilianPed(void) { }
|
||||
|
||||
void CivilianAI(void);
|
||||
void ProcessControl(void);
|
||||
};
|
||||
static_assert(sizeof(CCivilianPed) == 0x53C, "CCivilianPed: error");
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
1072
src/peds/Ped.cpp
1072
src/peds/Ped.cpp
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user