From 680fe0f7e6d4a94d5ee7f95dd6a5926012196e19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?eray=20or=C3=A7unus?= Date: Mon, 25 Nov 2019 05:25:10 +0300 Subject: [PATCH] CCivilianPed done & restore peds running to phone --- src/control/Phones.cpp | 4 +- src/control/Phones.h | 12 +- src/core/PlayerInfo.h | 8 +- src/core/config.h | 2 + src/core/re3.cpp | 3 +- src/peds/CivilianPed.cpp | 401 +++++++++++++++++++++++++++++++++++- src/peds/CivilianPed.h | 1 + src/peds/Ped.cpp | 214 ++++++++++++++----- src/peds/Ped.h | 16 +- src/render/Particle.cpp | 6 +- src/vehicles/Automobile.cpp | 2 +- 11 files changed, 590 insertions(+), 79 deletions(-) diff --git a/src/control/Phones.cpp b/src/control/Phones.cpp index ef978868..a5c4f74d 100644 --- a/src/control/Phones.cpp +++ b/src/control/Phones.cpp @@ -72,7 +72,7 @@ CPhoneInfo::Load(uint8 *buf, uint32 size) INITSAVEBUF m_nMax = ReadSaveBuf(buf); m_nNum = ReadSaveBuf(buf); - for (int i = 0; i < 50; i++) { + for (int i = 0; i < NUMPHONES; i++) { m_aPhones[i] = ReadSaveBuf(buf); // It's saved as building pool index in save file, convert it to true entity if (m_aPhones[i].m_pEntity) { @@ -174,7 +174,7 @@ CPhoneInfo::Save(uint8 *buf, uint32 *size) INITSAVEBUF WriteSaveBuf(buf, m_nMax); WriteSaveBuf(buf, m_nNum); - for(int phoneId = 0; phoneId < 50; phoneId++) { + for(int phoneId = 0; phoneId < NUMPHONES; phoneId++) { CPhone* phone = WriteSaveBuf(buf, m_aPhones[phoneId]); // Convert entity pointer to building pool index while saving diff --git a/src/control/Phones.h b/src/control/Phones.h index 99ec520c..62ea6f50 100644 --- a/src/control/Phones.h +++ b/src/control/Phones.h @@ -7,7 +7,7 @@ class CAnimBlendAssociation; enum { PHONE_STATE_FREE, - PHONE_STATE_1, + PHONE_STATE_REPORTING_CRIME, // CCivilianPed::ProcessControl sets it but unused PHONE_STATE_2, PHONE_STATE_MESSAGE_REMOVED, PHONE_STATE_ONETIME_MESSAGE_SET, @@ -18,14 +18,18 @@ enum { PHONE_STATE_9 }; -struct CPhone +class CPhone { +public: CVector m_vecPos; wchar *m_apMessages[6]; uint32 m_lastTimeRepeatedMsgShown; - CEntity *m_pEntity; // it's building pool index in save files + CEntity *m_pEntity; // stored as building pool index in save files int32 m_nState; uint8 field_30; + + CPhone() { } + ~CPhone() { } }; static_assert(sizeof(CPhone) == 0x34, "CPhone: error"); @@ -40,7 +44,7 @@ public: int32 m_nMax; int32 m_nNum; - CPhone m_aPhones[50]; + CPhone m_aPhones[NUMPHONES]; CPhoneInfo() { } ~CPhoneInfo() { } diff --git a/src/core/PlayerInfo.h b/src/core/PlayerInfo.h index ef21fb52..12c71766 100644 --- a/src/core/PlayerInfo.h +++ b/src/core/PlayerInfo.h @@ -27,13 +27,13 @@ public: int32 m_nCollectedPackages; int32 m_nTotalPackages; uint32 m_nLastBumpPlayerCarTimer; - int32 m_nSwitchTaxiTime; + uint32 m_nSwitchTaxiTime; bool m_bSwitchTaxi; int8 field_197; int8 field_198; int8 field_199; - int32 m_nNextSexFrequencyUpdateTime; - int32 m_nNextSexMoneyUpdateTime; + uint32 m_nNextSexFrequencyUpdateTime; + uint32 m_nNextSexMoneyUpdateTime; int32 m_nSexFrequency; CCivilianPed *m_pHooker; int8 m_WBState; // eWastedBustedState @@ -55,7 +55,7 @@ public: int8 field_254; int8 field_255; float m_fRoadDensity; - int32 m_nPreviousTimeRewardedForExplosion; + uint32 m_nPreviousTimeRewardedForExplosion; int32 m_nExplosionsSinceLastReward; int32 field_268; int32 field_272; diff --git a/src/core/config.h b/src/core/config.h index 175a5f61..166c2a68 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -87,6 +87,7 @@ enum Config { NUM_FIRES = 40, NUMPEDROUTES = 200, + NUMPHONES = 50, NUMVISIBLEENTITIES = 2000, NUMINVISIBLEENTITIES = 150, @@ -145,6 +146,7 @@ enum Config { #endif #define FIX_BUGS // fixes bugs that we've came across during reversing, TODO: use this more +#define TOGGLEABLE_BETA_FEATURES // toggleable from debug menu. doesn't have too many things // Pad #define KANGAROO_CHEAT diff --git a/src/core/re3.cpp b/src/core/re3.cpp index ab099726..d3b8200d 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -349,10 +349,11 @@ DebugMenuPopulate(void) DebugMenuAddVarBool8("Debug", "Don't render Objects", (int8*)&gbDontRenderObjects, nil); DebugMenuAddCmd("Debug", "Make peds follow you in formation", LetThemFollowYou); -#ifndef MASTER +#ifdef TOGGLEABLE_BETA_FEATURES DebugMenuAddVarBool8("Debug", "Toggle unused fight feature", (int8*)&CPed::bUnusedFightThingOnPlayer, nil); DebugMenuAddVarBool8("Debug", "Toggle banned particles", (int8*)&CParticle::bEnableBannedParticles, nil); DebugMenuAddVarBool8("Debug", "Toggle popping heads on headshot", (int8*)&CPed::bPopHeadsOnHeadshot, nil); + DebugMenuAddVarBool8("Debug", "Toggle peds running to phones to report crimes", (int8*)&CPed::bMakePedsRunToPhonesToReportCrimes, nil); #endif DebugMenuAddCmd("Debug", "Start Credits", CCredits::Start); diff --git a/src/peds/CivilianPed.cpp b/src/peds/CivilianPed.cpp index 93cdcb3d..34a0a35f 100644 --- a/src/peds/CivilianPed.cpp +++ b/src/peds/CivilianPed.cpp @@ -2,25 +2,420 @@ #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) +{ +#ifdef TOGGLEABLE_BETA_FEATURES + if (bRunningToPhone && m_nPedState != PED_SEEK_POS && m_nPedState != PED_FALL && m_nPedState != PED_GETUP && + m_nPedState != PED_DIVE_AWAY && m_nPedState != PED_MAKE_CALL && m_nPedState != PED_FACE_PHONE) { + bRunningToPhone = false; + if (gPhoneInfo.m_aPhones[m_phoneId].m_nState == PHONE_STATE_REPORTING_CRIME) + gPhoneInfo.m_aPhones[m_phoneId].m_nState = PHONE_STATE_FREE; + } +#endif + + 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; + } else if (bRunningToPhone) { + if (gPhoneInfo.m_aPhones[m_phoneId].m_nState != PHONE_STATE_FREE) { + RestorePreviousState(); + m_phoneId = -1; +#ifdef FIX_BUGS + bRunningToPhone = false; +#endif + } else { + gPhoneInfo.m_aPhones[m_phoneId].m_nState = PHONE_STATE_REPORTING_CRIME; + m_nPedState = PED_FACE_PHONE; + } + } 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(); + } + } + } +#ifdef TOGGLEABLE_BETA_FEATURES + else if (bRunningToPhone) { + // Designed for running to phone, but never used + CheckAroundForPossibleCollisions(); + } +#endif + 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/Ped.cpp b/src/peds/Ped.cpp index e9653cb3..f18273e8 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -272,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) @@ -286,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(); @@ -300,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)); @@ -866,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) @@ -2998,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 @@ -3046,7 +3050,7 @@ bool CPed::TurnBody(void) { float lookDir; - bool doneSmoothly = true; + bool turnDone = true; if (m_pLookTarget) { CVector &lookPos = m_pLookTarget->GetPosition(); @@ -3071,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(); @@ -3157,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) @@ -3168,6 +3173,15 @@ 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; @@ -3180,8 +3194,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, @@ -3189,14 +3217,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; @@ -3206,9 +3233,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 * @@ -4292,7 +4320,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; } @@ -4581,7 +4609,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); } @@ -4796,7 +4824,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 @@ -5880,6 +5908,13 @@ CPed::SetDead(void) if (m_nPedState == PED_DRIVING) bIsVisible = false; +#ifdef TOGGLEABLE_BETA_FEATURES + if (bRunningToPhone) { + if (gPhoneInfo.m_aPhones[m_phoneId].m_nState == PHONE_STATE_REPORTING_CRIME) + gPhoneInfo.m_aPhones[m_phoneId].m_nState = PHONE_STATE_FREE; + } +#endif + m_nPedState = PED_DEAD; m_pVehicleAnim = nil; m_pCollidingEntity = nil; @@ -7426,7 +7461,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; } @@ -7946,7 +7981,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; } @@ -8324,7 +8359,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; } @@ -8531,6 +8566,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; @@ -8659,7 +8698,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; } @@ -8677,7 +8716,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; } @@ -8695,7 +8734,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; } @@ -8713,7 +8752,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; } @@ -10343,6 +10382,11 @@ CPed::ProcessControl(void) #ifdef CAR_AIRBREAK if (!pad->ArePlayerControlsDisabled()) { if (pad->GetHorn()) { + float c = Cos(m_fRotationCur); + float s = Sin(m_fRotationCur); + m_pMyVehicle->GetRight() = CVector(c, 0.0f, 0.0f); + m_pMyVehicle->GetForward() = CVector(0.0f, s, 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()) { @@ -10461,7 +10505,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( @@ -11617,12 +11661,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); @@ -11634,8 +11686,11 @@ CPed::RunToReportCrime(eCrimeType crimeToReport) return false; bRunningToPhone = true; + SetSeek(gPhoneInfo.m_aPhones[phoneId].m_vecPos, 0.7f); // original: 0.35f SetMoveState(PEDMOVE_RUN); - SetSeek(gPhoneInfo.m_aPhones[phoneId].m_vecPos, 0.3f); +#ifdef FIX_BUGS + bIsRunning = true; +#endif m_phoneId = phoneId; m_crimeToReportOnPhone = crimeToReport; return true; @@ -11688,7 +11743,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; @@ -12338,7 +12393,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; @@ -12468,16 +12523,16 @@ CPed::ProcessObjective(void) } if (bInVehicle && m_pMyVehicle) { 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; @@ -13221,7 +13276,7 @@ CPed::ProcessObjective(void) if (bInVehicle && m_pMyVehicle) { 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); SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); @@ -13460,8 +13515,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, @@ -13724,15 +13779,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); @@ -14427,7 +14486,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); @@ -15354,7 +15413,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 @@ -15520,7 +15579,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; @@ -15747,21 +15806,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)) @@ -17145,6 +17204,46 @@ CPed::SetCarJack(CVehicle* car) 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); + } +} + class CPed_ : public CPed { public: @@ -17377,4 +17476,5 @@ STARTPATCHES 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 eb8fb3d0..58b189ee 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -246,6 +246,8 @@ enum PedState PED_UNKNOWN, // 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, @@ -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,7 +411,7 @@ 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; @@ -691,6 +695,7 @@ public: void WarpPedIntoCar(CVehicle*); void SetCarJack(CVehicle*); bool WarpPedToNearLeaderOffScreen(void); + void Solicit(void); // Static methods static CVector GetLocalPositionToOpenCarDoor(CVehicle *veh, uint32 component, float offset); @@ -798,10 +803,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); diff --git a/src/render/Particle.cpp b/src/render/Particle.cpp index 56ac9512..6956a887 100644 --- a/src/render/Particle.cpp +++ b/src/render/Particle.cpp @@ -12,7 +12,7 @@ #include "ParticleObject.h" #include "Particle.h" -#ifndef MASTER +#ifdef TOGGLEABLE_BETA_FEATURES bool CParticle::bEnableBannedParticles = false; #endif @@ -772,7 +772,7 @@ CParticle *CParticle::AddParticle(tParticleType type, CVector const &vecPos, CVe { if ( CTimer::GetIsPaused() ) return NULL; -#ifndef MASTER +#ifdef TOGGLEABLE_BETA_FEATURES if(!bEnableBannedParticles) #endif if ( ( type == PARTICLE_ENGINE_SMOKE @@ -1462,7 +1462,7 @@ void CParticle::Render() tParticleType type = psystem->m_Type; -#ifndef MASTER +#ifdef TOGGLEABLE_BETA_FEATURES if (!bEnableBannedParticles) #endif if ( type == PARTICLE_ENGINE_SMOKE diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 8bd2037e..d528ecca 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -1918,7 +1918,7 @@ CAutomobile::Render(void) CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()); if(GetModelIndex() == MI_RHINO && m_aCarNodes[CAR_BONNET]){ - // Rhino has no bonnet...what are we doing here? + // Rotate Rhino turret CMatrix m; CVector p; m.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BONNET]));