From 2c138b2b77cf661d9f119061963a726fdcde56d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?eray=20or=C3=A7unus?= Date: Mon, 15 Jul 2019 15:11:40 +0300 Subject: [PATCH] Phone, World, Ped --- src/control/Phones.cpp | 161 +++++++++++++++++++++-- src/control/Phones.h | 23 +++- src/core/EventList.h | 2 + src/core/General.h | 16 +++ src/core/Messages.cpp | 1 + src/core/Messages.h | 1 + src/core/Pad.cpp | 68 +++++----- src/core/Pad.h | 15 ++- src/core/World.cpp | 153 ++++++++++++++++++++-- src/core/World.h | 3 + src/peds/CivilianPed.cpp | 24 ++++ src/peds/CivilianPed.h | 1 + src/peds/Ped.cpp | 268 ++++++++++++++++++++++++++++++++++++--- src/peds/Ped.h | 17 ++- src/weapons/Weapon.cpp | 6 + src/weapons/Weapon.h | 1 + 16 files changed, 677 insertions(+), 83 deletions(-) diff --git a/src/control/Phones.cpp b/src/control/Phones.cpp index 028d80a9..376e2757 100644 --- a/src/control/Phones.cpp +++ b/src/control/Phones.cpp @@ -2,12 +2,18 @@ #include "patcher.h" #include "Phones.h" #include "Pools.h" +#include "ModelIndices.h" +#include "Ped.h" +#include "Pad.h" +#include "Messages.h" CPhoneInfo &gPhoneInfo = *(CPhoneInfo*)0x732A20; bool &CPhoneInfo::isPhonePickedUp = *(bool*)0x6283AC; -bool &CPhoneInfo::isPhoneBeingPickedUp = *(bool*)0x6283B4; +uint32 &CPhoneInfo::phoneMessagesTimer = *(uint32*)0x6283A8; CPhone *&CPhoneInfo::pickedUpPhone = *(CPhone**)0x6283B0; +bool &CPhoneInfo::isPhoneBeingPickedUp = *(bool*)0x6283B4; +CPed *&CPhoneInfo::pedWhoPickingUpPhone = *(CPed**)0x6283B8; int CPhoneInfo::FindNearestFreePhone(CVector *pos) @@ -69,21 +75,20 @@ CPhoneInfo::Load(CPhoneInfo *source, uint8 buffer) CPhone *phone = &source->m_aPhones[phoneId]; m_aPhones[phoneId].m_vecPos = phone->m_vecPos; - memcpy(m_aPhones[phoneId].m_apMessages, phone->m_apMessages, sizeof(uint16*) * 6); + memcpy(m_aPhones[phoneId].m_apMessages, phone->m_apMessages, sizeof(wchar*) * 6); m_aPhones[phoneId].m_pEntity = phone->m_pEntity; m_aPhones[phoneId].m_nState = phone->m_nState; m_aPhones[phoneId].field_30 = phone->field_30; + // It's saved as building pool index in save file, convert it to true entity if (phone->m_pEntity) { - // It's saved as building pool index in save file, convert it to true entity - CBuilding *actualEntity = CPools::GetBuildingPool()->GetSlot((int)phone->m_pEntity - 1); - m_aPhones[phoneId].m_pEntity = actualEntity; + m_aPhones[phoneId].m_pEntity = CPools::GetBuildingPool()->GetSlot((int)phone->m_pEntity - 1); } } } void -CPhoneInfo::SetPhoneMessage_JustOnce(int phoneId, uint16 *msg1, uint16 *msg2, uint16 *msg3, uint16 *msg4, uint16 *msg5, uint16 *msg6) +CPhoneInfo::SetPhoneMessage_JustOnce(int phoneId, wchar *msg1, wchar *msg2, wchar *msg3, wchar *msg4, wchar *msg5, wchar *msg6) { // If there is at least one message, it should be msg1. if (msg1) { @@ -100,7 +105,7 @@ CPhoneInfo::SetPhoneMessage_JustOnce(int phoneId, uint16 *msg1, uint16 *msg2, ui } void -CPhoneInfo::SetPhoneMessage_Repeatedly(int phoneId, uint16 *msg1, uint16 *msg2, uint16 *msg3, uint16 *msg4, uint16 *msg5, uint16 *msg6) +CPhoneInfo::SetPhoneMessage_Repeatedly(int phoneId, wchar *msg1, wchar *msg2, wchar *msg3, wchar *msg4, wchar *msg5, wchar *msg6) { // If there is at least one message, it should be msg1. if (msg1) { @@ -116,6 +121,137 @@ CPhoneInfo::SetPhoneMessage_Repeatedly(int phoneId, uint16 *msg1, uint16 *msg2, } } +int +CPhoneInfo::GrabPhone(float xPos, float yPos) +{ + // "Grab" doesn't mean picking up the phone, it means allocating some particular phone to + // whoever called the 024A opcode first with the position parameters closest to phone. + // Same phone won't be available on next run of this function. + + int nearestPhoneId = -1; + CVector pos(xPos, yPos, 0.0f); + float nearestPhoneDist = 100.0f; + + for (int phoneId = m_nNum; phoneId < m_nMax; phoneId++) { + float phoneDistance = (m_aPhones[phoneId].m_vecPos - pos).Magnitude2D(); + if (phoneDistance < nearestPhoneDist) { + nearestPhoneDist = phoneDistance; + nearestPhoneId = phoneId; + } + } + m_aPhones[nearestPhoneId].m_nState = PHONE_STATE_MESSAGE_REMOVED; + + CPhone oldFirstPhone = m_aPhones[m_nNum]; + m_aPhones[m_nNum] = m_aPhones[nearestPhoneId]; + m_aPhones[nearestPhoneId] = oldFirstPhone; + m_nNum++; + return m_nNum - 1; +} + +void +CPhoneInfo::Initialise(void) +{ + CBuildingPool *pool = CPools::GetBuildingPool(); + pedWhoPickingUpPhone = nil; + isPhonePickedUp = false; + isPhoneBeingPickedUp = false; + pickedUpPhone = nil; + m_nMax = 0; + m_nNum = 0; + for (int v5 = pool->GetSize() - 1; v5 >= 0; v5--) { + CBuilding *building = pool->GetSlot(v5); + if (building) { + if (building->m_modelIndex == MI_PHONEBOOTH1) { + CPhone *maxPhone = &m_aPhones[m_nMax]; + maxPhone->m_nState = PHONE_STATE_FREE; + maxPhone->m_vecPos = *(building->GetPosition()); + maxPhone->m_pEntity = building; + m_nMax++; + } + } + } +} + +void +CPhoneInfo::Save(CPhoneInfo *destination, uint32 *size) +{ + *size = sizeof(CPhoneInfo); + destination->m_nMax = this->m_nMax; + destination->m_nNum = m_nNum; + for(int phoneId = 0; phoneId < 50; phoneId++) { + CPhone* phone = &destination->m_aPhones[phoneId]; + + phone->m_vecPos = m_aPhones[phoneId].m_vecPos; + memcpy(phone->m_apMessages, m_aPhones[phoneId].m_apMessages, sizeof(wchar*) * 6); + phone->m_pEntity = m_aPhones[phoneId].m_pEntity; + phone->m_nState = m_aPhones[phoneId].m_nState; + phone->field_30 = m_aPhones[phoneId].field_30; + + // Convert entity pointer to building pool index while saving + if (phone->m_pEntity) { + phone->m_pEntity = (CEntity*) CPools::GetBuildingPool()->GetJustIndex((CBuilding*)phone->m_pEntity) + 1; + } + } +} + +void +CPhoneInfo::Shutdown(void) +{ + m_nMax = 0; + m_nNum = 0; +} + +void +PhonePutDownCB(CAnimBlendAssociation *assoc, void *arg) +{ + assoc->flags |= ASSOC_DELETEFADEDOUT; + assoc->blendDelta = -1000.0f; + CPad::GetPad(0)->DisablePlayerControls &= ~PLAYERCONTROL_DISABLED_40; + CPed *ped = (CPed*)arg; + + if (assoc->blendAmount > 0.5f) + ped->m_ped_flagC10 = true; + + if (ped->m_nPedState == PED_MAKE_CALL) + ped->m_nPedState = PED_IDLE; +} + +void +PhonePickUpCB(CAnimBlendAssociation *assoc, void *arg) +{ + CPhone *phone = (CPhone*)arg; + int messagesDisplayTime = 0; + + for(int i=0; i < 6; i++) { + wchar *msg = phone->m_apMessages[i]; + if (msg) { + CMessages::AddMessage(msg, 3000, 0); + messagesDisplayTime += 3000; + } + } + + CPhoneInfo::isPhoneBeingPickedUp = false; + CPhoneInfo::isPhonePickedUp = true; + CPhoneInfo::pickedUpPhone = phone; + CPhoneInfo::phoneMessagesTimer = CTimer::GetTimeInMilliseconds() + messagesDisplayTime; + + if (phone->m_nState == PHONE_STATE_ONETIME_MESSAGE_SET) { + phone->m_nState = PHONE_STATE_ONETIME_MESSAGE_SHOWN; + } else { + phone->m_nState = PHONE_STATE_REPEATED_MESSAGE_SHOWN; + phone->m_lastTimeRepeatedMsgShown = CTimer::GetTimeInMilliseconds(); + } + + CPed *ped = CPhoneInfo::pedWhoPickingUpPhone; + ped->m_nMoveState = PEDMOVE_STILL; + CAnimManager::BlendAnimation((RpClump*)ped->m_rwObject, ASSOCGRP_STD, ANIM_IDLE_STANCE, 8.0f); + + if (assoc->blendAmount > 0.5f && ped) + CAnimManager::BlendAnimation((RpClump*)ped->m_rwObject, ASSOCGRP_STD, ANIM_PHONE_TALK, 8.0f); + + CPhoneInfo::pedWhoPickingUpPhone = nil; +} + STARTPATCHES InjectHook(0x42F720, &CPhoneInfo::FindNearestFreePhone, PATCH_JUMP); InjectHook(0x42FD50, &CPhoneInfo::PhoneAtThisPosition, PATCH_JUMP); @@ -124,7 +260,10 @@ STARTPATCHES InjectHook(0x430120, &CPhoneInfo::Load, PATCH_JUMP); InjectHook(0x42FF90, &CPhoneInfo::SetPhoneMessage_JustOnce, PATCH_JUMP); InjectHook(0x42FF30, &CPhoneInfo::SetPhoneMessage_Repeatedly, PATCH_JUMP); -ENDPATCHES - -WRAPPER void PhonePutDownCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x42F570); } -WRAPPER void PhonePickUpCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x42F470); } + InjectHook(0x430060, &CPhoneInfo::Save, PATCH_JUMP); + InjectHook(0x42F710, &CPhoneInfo::Shutdown, PATCH_JUMP); + InjectHook(0x42F640, &CPhoneInfo::Initialise, PATCH_JUMP); + InjectHook(0x42FDB0, &CPhoneInfo::GrabPhone, PATCH_JUMP); + InjectHook(0x42F570, &PhonePutDownCB, PATCH_JUMP); + InjectHook(0x42F470, &PhonePickUpCB, PATCH_JUMP); +ENDPATCHES \ No newline at end of file diff --git a/src/control/Phones.h b/src/control/Phones.h index 74f24d25..35389f3f 100644 --- a/src/control/Phones.h +++ b/src/control/Phones.h @@ -1,7 +1,9 @@ #pragma once #include "Physical.h" -#include "AnimBlendAssociation.h" + +class CPed; +class CAnimBlendAssociation; enum { PHONE_STATE_FREE, @@ -19,7 +21,7 @@ enum { struct CPhone { CVector m_vecPos; - uint16 *m_apMessages[6]; + wchar *m_apMessages[6]; uint32 m_lastTimeRepeatedMsgShown; CEntity *m_pEntity; // it's building pool index in save files int32 m_nState; @@ -29,10 +31,13 @@ struct CPhone static_assert(sizeof(CPhone) == 0x34, "CPhone: error"); class CPhoneInfo { - static bool &isPhonePickedUp; - static bool &isPhoneBeingPickedUp; - static CPhone *&pickedUpPhone; public: + static bool &isPhonePickedUp; + static uint32 &phoneMessagesTimer; + static CPhone *&pickedUpPhone; + static bool &isPhoneBeingPickedUp; + static CPed *&pedWhoPickingUpPhone; + int32 m_nMax; int32 m_nNum; CPhone m_aPhones[50]; @@ -45,8 +50,12 @@ public: bool HasMessageBeenDisplayed(int); bool IsMessageBeingDisplayed(int); void Load(CPhoneInfo *source, uint8 buffer); - void SetPhoneMessage_JustOnce(int phoneId, uint16 *msg1, uint16 *msg2, uint16 *msg3, uint16 *msg4, uint16 *msg5, uint16 *msg6); - void SetPhoneMessage_Repeatedly(int phoneId, uint16 *msg1, uint16 *msg2, uint16 *msg3, uint16 *msg4, uint16 *msg5, uint16 *msg6); + void SetPhoneMessage_JustOnce(int phoneId, wchar *msg1, wchar *msg2, wchar *msg3, wchar *msg4, wchar *msg5, wchar *msg6); + void SetPhoneMessage_Repeatedly(int phoneId, wchar *msg1, wchar *msg2, wchar *msg3, wchar *msg4, wchar *msg5, wchar *msg6); + int GrabPhone(float, float); + void Initialise(void); + void Save(CPhoneInfo*, uint32*); + void Shutdown(void); }; extern CPhoneInfo &gPhoneInfo; diff --git a/src/core/EventList.h b/src/core/EventList.h index d0fc0847..9f5756be 100644 --- a/src/core/EventList.h +++ b/src/core/EventList.h @@ -63,3 +63,5 @@ public: static bool FindClosestEvent(eEventType type, CVector posn, int32 *event); static void ReportCrimeForEvent(eEventType type, int32, bool); }; + +extern CEvent *gaEvent; \ No newline at end of file diff --git a/src/core/General.h b/src/core/General.h index 64613478..7c0c9562 100644 --- a/src/core/General.h +++ b/src/core/General.h @@ -36,6 +36,22 @@ public: } } + static float LimitAngle(float angle) + { + float result = angle; + + while (result >= 180.0f) { + result -= 2 * 180.0f; + } + + while (result < -180.0f) { + result += 2 * 180.0f; + } + + return result; + } + + static float LimitRadianAngle(float angle) { float result; diff --git a/src/core/Messages.cpp b/src/core/Messages.cpp index 7fc23593..aedcb0b9 100644 --- a/src/core/Messages.cpp +++ b/src/core/Messages.cpp @@ -9,6 +9,7 @@ WRAPPER char CMessages::WideStringCompare(wchar* str1, wchar* str2, unsigned sho WRAPPER void CMessages::InsertNumberInString(wchar* src, int n1, int n2, int n3, int n4, int n5, int n6, wchar* dst) { EAXJMP(0x52A1A0); } WRAPPER void CMessages::InsertPlayerControlKeysInString(wchar* src) { EAXJMP(0x52A490); } WRAPPER int CMessages::GetWideStringLength(wchar* src) { EAXJMP(0x529490); } +WRAPPER void CMessages::AddMessage(wchar*, uint32, uint16) { EAXJMP(0x529900); } tPreviousBrief *CMessages::PreviousBriefs = (tPreviousBrief *)0x713C08; tMessage *CMessages::BriefMessages = (tMessage *)0x8786E0; diff --git a/src/core/Messages.h b/src/core/Messages.h index 69cf117c..e1f4ced1 100644 --- a/src/core/Messages.h +++ b/src/core/Messages.h @@ -41,4 +41,5 @@ public: static void InsertNumberInString(wchar* src, int n1, int n2, int n3, int n4, int n5, int n6, wchar* dst); static void InsertPlayerControlKeysInString(wchar* src); static int GetWideStringLength(wchar *src); + static void AddMessage(wchar*, uint32, uint16); }; diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp index 9c5e1c8a..1db50493 100644 --- a/src/core/Pad.cpp +++ b/src/core/Pad.cpp @@ -155,7 +155,7 @@ void CPad::Clear(bool bResetPlayerControls) ShakeDur = 0; if ( bResetPlayerControls ) - DisablePlayerControls = false; + DisablePlayerControls = PLAYERCONTROL_ENABLED; bApplyBrakes = false; @@ -659,7 +659,7 @@ CPad *CPad::GetPad(int32 pad) int16 CPad::GetSteeringLeftRight(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return 0; switch ( Mode ) @@ -692,7 +692,7 @@ int16 CPad::GetSteeringLeftRight(void) int16 CPad::GetSteeringUpDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return 0; switch ( Mode ) @@ -725,7 +725,7 @@ int16 CPad::GetSteeringUpDown(void) int16 CPad::GetCarGunUpDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return 0; switch ( Mode ) @@ -752,7 +752,7 @@ int16 CPad::GetCarGunUpDown(void) int16 CPad::GetCarGunLeftRight(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return 0; switch ( Mode ) @@ -779,7 +779,7 @@ int16 CPad::GetCarGunLeftRight(void) int16 CPad::GetPedWalkLeftRight(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return 0; switch ( Mode ) @@ -813,7 +813,7 @@ int16 CPad::GetPedWalkLeftRight(void) int16 CPad::GetPedWalkUpDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return 0; switch ( Mode ) @@ -876,7 +876,7 @@ int16 CPad::GetAnalogueUpDown(void) bool CPad::GetLookLeft(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; return !!(NewState.LeftShoulder2 && !NewState.RightShoulder2); @@ -884,7 +884,7 @@ bool CPad::GetLookLeft(void) bool CPad::GetLookRight(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; return !!(NewState.RightShoulder2 && !NewState.LeftShoulder2); @@ -893,7 +893,7 @@ bool CPad::GetLookRight(void) bool CPad::GetLookBehindForCar(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; return !!(NewState.RightShoulder2 && NewState.LeftShoulder2); @@ -901,7 +901,7 @@ bool CPad::GetLookBehindForCar(void) bool CPad::GetLookBehindForPed(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; return !!NewState.RightShock; @@ -909,7 +909,7 @@ bool CPad::GetLookBehindForPed(void) bool CPad::GetHorn(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -948,7 +948,7 @@ bool CPad::GetHorn(void) bool CPad::HornJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -988,7 +988,7 @@ bool CPad::HornJustDown(void) bool CPad::GetCarGunFired(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1015,7 +1015,7 @@ bool CPad::GetCarGunFired(void) bool CPad::CarGunJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1042,7 +1042,7 @@ bool CPad::CarGunJustDown(void) int16 CPad::GetHandBrake(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return 0; switch ( Mode ) @@ -1075,7 +1075,7 @@ int16 CPad::GetHandBrake(void) int16 CPad::GetBrake(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return 0; switch ( Mode ) @@ -1113,7 +1113,7 @@ int16 CPad::GetBrake(void) bool CPad::GetExitVehicle(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1140,7 +1140,7 @@ bool CPad::GetExitVehicle(void) bool CPad::ExitVehicleJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1167,7 +1167,7 @@ bool CPad::ExitVehicleJustDown(void) int32 CPad::GetWeapon(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1200,7 +1200,7 @@ int32 CPad::GetWeapon(void) bool CPad::WeaponJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1233,7 +1233,7 @@ bool CPad::WeaponJustDown(void) int16 CPad::GetAccelerate(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return 0; switch ( Mode ) @@ -1319,7 +1319,7 @@ bool CPad::CycleCameraModeDownJustDown(void) bool CPad::ChangeStationJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1359,7 +1359,7 @@ bool CPad::ChangeStationJustDown(void) bool CPad::CycleWeaponLeftJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; return !!(NewState.LeftShoulder2 && !OldState.LeftShoulder2); @@ -1367,7 +1367,7 @@ bool CPad::CycleWeaponLeftJustDown(void) bool CPad::CycleWeaponRightJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; return !!(NewState.RightShoulder2 && !OldState.RightShoulder2); @@ -1375,7 +1375,7 @@ bool CPad::CycleWeaponRightJustDown(void) bool CPad::GetTarget(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1402,7 +1402,7 @@ bool CPad::GetTarget(void) bool CPad::TargetJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1429,7 +1429,7 @@ bool CPad::TargetJustDown(void) bool CPad::JumpJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; return !!(NewState.Square && !OldState.Square); @@ -1437,7 +1437,7 @@ bool CPad::JumpJustDown(void) bool CPad::GetSprint(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1464,7 +1464,7 @@ bool CPad::GetSprint(void) bool CPad::ShiftTargetLeftJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; return !!(NewState.LeftShoulder2 && !OldState.LeftShoulder2); @@ -1472,7 +1472,7 @@ bool CPad::ShiftTargetLeftJustDown(void) bool CPad::ShiftTargetRightJustDown(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; return !!(NewState.RightShoulder2 && !OldState.RightShoulder2); @@ -1592,7 +1592,7 @@ bool CPad::GetAnaloguePadRightJustUp(void) bool CPad::ForceCameraBehindPlayer(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1625,7 +1625,7 @@ bool CPad::ForceCameraBehindPlayer(void) bool CPad::SniperZoomIn(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) @@ -1652,7 +1652,7 @@ bool CPad::SniperZoomIn(void) bool CPad::SniperZoomOut(void) { - if ( DisablePlayerControls ) + if ( ArePlayerControlsDisabled() ) return false; switch ( Mode ) diff --git a/src/core/Pad.h b/src/core/Pad.h index 30a9980b..f853a8cd 100644 --- a/src/core/Pad.h +++ b/src/core/Pad.h @@ -51,6 +51,17 @@ enum Key }; */ +enum { + PLAYERCONTROL_ENABLED = 0, + PLAYERCONTROL_DISABLED_1 = 1, + PLAYERCONTROL_DISABLED_2 = 2, + PLAYERCONTROL_DISABLED_4 = 4, + PLAYERCONTROL_DISABLED_8 = 8, + PLAYERCONTROL_DISABLED_10 = 16, + PLAYERCONTROL_DISABLED_20 = 32, + PLAYERCONTROL_DISABLED_40 = 64, // used on phone calls + PLAYERCONTROL_DISABLED_80 = 128, +}; class CControllerState { @@ -188,7 +199,7 @@ public: uint8 ShakeFreq; int8 bHornHistory[5]; uint8 iCurrHornHistory; - bool DisablePlayerControls; + uint8 DisablePlayerControls; int8 bApplyBrakes; char _unk[12]; //int32 unk[3]; char _pad0[3]; @@ -362,6 +373,8 @@ public: int32 GetLeftShoulder2(void) { return NewState.LeftShoulder2; } int32 GetRightShoulder1(void) { return NewState.RightShoulder1; } int32 GetRightShoulder2(void) { return NewState.RightShoulder2; } + + bool ArePlayerControlsDisabled(void) { return DisablePlayerControls != PLAYERCONTROL_ENABLED; } }; VALIDATE_SIZE(CPad, 0xFC); diff --git a/src/core/World.cpp b/src/core/World.cpp index a31f87a7..a9ec1f2a 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -11,11 +11,13 @@ #include "Garages.h" #include "TempColModels.h" #include "World.h" +#include "ModelIndices.h" CPtrList *CWorld::ms_bigBuildingsList = (CPtrList*)0x6FAB60; CPtrList &CWorld::ms_listMovingEntityPtrs = *(CPtrList*)0x8F433C; CSector (*CWorld::ms_aSectors)[NUMSECTORS_X] = (CSector (*)[NUMSECTORS_Y])0x665608; uint16 &CWorld::ms_nCurrentScanCode = *(uint16*)0x95CC64; +CColPoint &CWorld::ms_testSpherePoint = *(CColPoint*)0x6E64C0; uint8 &CWorld::PlayerInFocus = *(uint8 *)0x95CD61; CPlayerInfo *CWorld::Players = (CPlayerInfo *)0x9412F0; @@ -617,29 +619,158 @@ CWorld::FindObjectsInRange(CVector ¢re, float distance, bool ignoreZ, short for(int curX = minX; curX <= maxX; curX++) { CSector *sector = GetSector(curX, curY); if (checkBuildings) { - CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, distance, ignoreZ, nextObject, lastObject, objects); - CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, distance, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); } if (checkVehicles) { - CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, distance, ignoreZ, nextObject, lastObject, objects); - CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, distance, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); } if (checkPeds) { - CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, distance, ignoreZ, nextObject, lastObject, objects); - CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, distance, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); } if (checkObjects) { - CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, distance, ignoreZ, nextObject, lastObject, objects); - CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, distance, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); } if (checkDummies) { - CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, distance, ignoreZ, nextObject, lastObject, objects); - CWorld::FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, distance, ignoreZ, nextObject, lastObject, objects); + FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects); } } } } +CEntity* +CWorld::TestSphereAgainstWorld(CVector centre, float distance, CEntity* entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects) +{ + CEntity* foundE = nil; + + int minX = GetSectorIndexX(centre.x - distance); + if (minX <= 0) + minX = 0; + + int minY = GetSectorIndexY(centre.y - distance); + if (minY <= 0) + minY = 0; + + int maxX = GetSectorIndexX(centre.x + distance); + if (maxX >= 100) + maxX = 100; + + int maxY = GetSectorIndexY(centre.y + distance); + if (maxY >= 100) + maxY = 100; + + AdvanceCurrentScanCode(); + + for (int curY = minY; curY <= maxY; curY++) { + for (int curX = minX; curX <= maxX; curX++) { + CSector* sector = GetSector(curX, curY); + if (checkBuildings) { + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, distance, entityToIgnore, false); + if (foundE) + return foundE; + + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, distance, entityToIgnore, false); + if (foundE) + return foundE; + } + if (checkVehicles) { + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, distance, entityToIgnore, false); + if (foundE) + return foundE; + + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, distance, entityToIgnore, false); + if (foundE) + return foundE; + } + if (checkPeds) { + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, distance, entityToIgnore, false); + if (foundE) + return foundE; + + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, distance, entityToIgnore, false); + if (foundE) + return foundE; + } + if (checkObjects) { + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, distance, entityToIgnore, ignoreSomeObjects); + if (foundE) + return foundE; + + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, distance, entityToIgnore, ignoreSomeObjects); + if (foundE) + return foundE; + } + if (checkDummies) { + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, distance, entityToIgnore, false); + if (foundE) + return foundE; + + foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, distance, entityToIgnore, false); + if (foundE) + return foundE; + } + } + } + return foundE; +} + +CEntity* +CWorld::TestSphereAgainstSectorList(CPtrList &list, CVector spherePos, float radius, CEntity *entityToIgnore, bool ignoreSomeObjects) +{ + static CColModel sphereCol; + + sphereCol.boundingSphere.center.x = 0.0f; + sphereCol.boundingSphere.center.y = 0.0f; + sphereCol.boundingSphere.center.z = 0.0f; + sphereCol.boundingSphere.radius = radius; + sphereCol.boundingBox.min.x = -radius; + sphereCol.boundingBox.min.y = -radius; + sphereCol.boundingBox.min.z = -radius; + sphereCol.boundingBox.max.x = radius; + sphereCol.boundingBox.max.y = radius; + sphereCol.boundingBox.max.z = radius; + sphereCol.numSpheres = 1; + sphereCol.spheres = &sphereCol.boundingSphere; + sphereCol.numLines = 0; + sphereCol.numBoxes = 0; + sphereCol.numTriangles = 0; + sphereCol.ownsCollisionVolumes = false; + + CMatrix sphereMat; + sphereMat.SetTranslate(spherePos); + + for(CPtrNode *node=list.first; node; node = node->next) { + CEntity *e = (CEntity*)node->item; + + if (e->m_scanCode != GetCurrentScanCode()) { + e->m_scanCode = GetCurrentScanCode(); + + if (e != entityToIgnore && e->bUsesCollision && !(ignoreSomeObjects && CameraToIgnoreThisObject(e))) { + CVector diff = spherePos - e->GetPosition(); + float distance = diff.Magnitude(); + + if (e->GetBoundRadius() + radius > distance) { + CColModel *eCol = CModelInfo::GetModelInfo(e->m_modelIndex)->GetColModel(); + int collidedSpheres = CCollision::ProcessColModels(sphereMat, sphereCol, e->GetMatrix(), + *eCol, &ms_testSpherePoint, nil, nil); + + if (collidedSpheres != 0 || + (e->IsVehicle() && ((CVehicle*)e)->m_vehType == VEHICLE_TYPE_CAR && + e->m_modelIndex != MI_DODO && radius + eCol->boundingBox.max.x > distance)) { + return e; + } + } + } + } + } + + return nil; +} + float CWorld::FindGroundZForCoord(float x, float y) { @@ -790,6 +921,8 @@ STARTPATCHES InjectHook(0x4B2200, CWorld::FindObjectsInRange, PATCH_JUMP); InjectHook(0x4B2540, CWorld::FindObjectsInRangeSectorList, PATCH_JUMP); + InjectHook(0x4B4AC0, CWorld::TestSphereAgainstSectorList, PATCH_JUMP); + InjectHook(0x4B4710, CWorld::TestSphereAgainstWorld, PATCH_JUMP); InjectHook(0x4B3A80, CWorld::FindGroundZForCoord, PATCH_JUMP); InjectHook(0x4B3AE0, CWorld::FindGroundZFor3DCoord, PATCH_JUMP); InjectHook(0x4B3B50, CWorld::FindRoofZFor3DCoord, PATCH_JUMP); diff --git a/src/core/World.h b/src/core/World.h index d6063d70..a8650d93 100644 --- a/src/core/World.h +++ b/src/core/World.h @@ -56,6 +56,7 @@ class CWorld static CPtrList &ms_listMovingEntityPtrs; static CSector (*ms_aSectors)[NUMSECTORS_X]; // [NUMSECTORS_Y][NUMSECTORS_X]; static uint16 &ms_nCurrentScanCode; + static CColPoint &ms_testSpherePoint; public: static uint8 &PlayerInFocus; @@ -94,6 +95,8 @@ public: static bool GetIsLineOfSightSectorClear(CSector §or, const CColLine &line, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false); static bool GetIsLineOfSightSectorListClear(CPtrList &list, const CColLine &line, bool ignoreSeeThrough, bool ignoreSomeObjects = false); + static CEntity* TestSphereAgainstWorld(CVector, float, CEntity*, bool, bool, bool, bool, bool, bool); + static CEntity* TestSphereAgainstSectorList(CPtrList&, CVector, float, CEntity*, bool); static void FindObjectsInRangeSectorList(CPtrList&, CVector&, float, bool, short*, short, CEntity**); static void FindObjectsInRange(CVector&, float, bool, short*, short, CEntity**, bool, bool, bool, bool, bool); static float FindGroundZForCoord(float x, float y); diff --git a/src/peds/CivilianPed.cpp b/src/peds/CivilianPed.cpp index cf8a0580..383a3e56 100644 --- a/src/peds/CivilianPed.cpp +++ b/src/peds/CivilianPed.cpp @@ -1,6 +1,7 @@ #include "common.h" #include "patcher.h" #include "CivilianPed.h" +#include "Phones.h" WRAPPER void CCivilianPed::ProcessControl(void) { EAXJMP(0x4BFFE0); } @@ -13,6 +14,28 @@ CCivilianPed::CCivilianPed(int pedtype, int mi) : CPed(pedtype) } } +bool +CCivilianPed::ProcessNearestFreePhone(int unused) +{ + if (m_nPedState == PED_SEEK_POS) + return false; + + int phoneId = gPhoneInfo.FindNearestFreePhone(&GetPosition()); + + if (phoneId == -1) + return false; + + if (gPhoneInfo.m_aPhones[phoneId].m_nState != PHONE_STATE_FREE) + return false; + + field_31C = 1; + SetMoveState(PEDMOVE_RUN); + SetSeek(gPhoneInfo.m_aPhones[phoneId].m_vecPos, 0.3f); + m_phoneId = phoneId; + m_lookingForPhone = unused; + return true; +} + class CCivilianPed_ : public CCivilianPed { public: @@ -23,4 +46,5 @@ public: STARTPATCHES InjectHook(0x4BFF30, &CCivilianPed_::ctor, PATCH_JUMP); InjectHook(0x4BFFC0, &CCivilianPed_::dtor, PATCH_JUMP); + InjectHook(0x4C10C0, &CCivilianPed::ProcessNearestFreePhone, PATCH_JUMP); ENDPATCHES diff --git a/src/peds/CivilianPed.h b/src/peds/CivilianPed.h index 14859a5c..e5e63682 100644 --- a/src/peds/CivilianPed.h +++ b/src/peds/CivilianPed.h @@ -9,5 +9,6 @@ public: ~CCivilianPed(void) { } void ProcessControl(void); + bool ProcessNearestFreePhone(int); }; static_assert(sizeof(CCivilianPed) == 0x53C, "CCivilianPed: error"); diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index 4ad4ac1b..45074d2b 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -25,6 +25,7 @@ #include "PointLights.h" #include "Pad.h" #include "Phones.h" +#include "EventList.h" WRAPPER void CPed::KillPedWithCar(CVehicle *veh, float impulse) { EAXJMP(0x4EC430); } WRAPPER void CPed::Say(uint16 audio) { EAXJMP(0x4E5A10); } @@ -32,7 +33,7 @@ WRAPPER void CPed::SetDie(AnimationId anim, float arg1, float arg2) { EAXJMP(0x4 WRAPPER void CPed::SetDead(void) { EAXJMP(0x4D3970); } WRAPPER void CPed::SpawnFlyingComponent(int, int8) { EAXJMP(0x4EB060); } WRAPPER void CPed::RestorePreviousState(void) { EAXJMP(0x4C5E30); } -WRAPPER void CPed::ClearAttack(void) { EAXJMP(0x4E6790); } +WRAPPER void CPed::SetPointGunAt(CEntity*) { EAXJMP(0x4E5F70); } WRAPPER void CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *dragAssoc, void *arg) { EAXJMP(0x4E2480); } WRAPPER void CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation *dragAssoc, void *arg) { EAXJMP(0x4E2920); } WRAPPER void CPed::SetPedPositionInCar(void) { EAXJMP(0x4D4970); } @@ -45,7 +46,7 @@ WRAPPER void CPed::SetFollowRoute(int16, int16) { EAXJMP(0x4DD690); } WRAPPER void CPed::SetDuck(uint32) { EAXJMP(0x4E4920); } WRAPPER void CPed::RegisterThreatWithGangPeds(CEntity*) { EAXJMP(0x4E3870); } WRAPPER void CPed::MakeChangesForNewWeapon(int8) { EAXJMP(0x4F2560); } -WRAPPER bool CPed::Seek(void) { EAXJMP(0x4D1640); } +WRAPPER void CPed::SetSeek(CVector, float) { EAXJMP(0x4D14B0); } bool &CPed::bNastyLimbsCheat = *(bool*)0x95CD44; bool &CPed::bPedCheat2 = *(bool*)0x95CD5A; @@ -272,8 +273,8 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) bPedPhysics = true; bUseCollisionRecords = true; - m_vecAnimMoveDelta.x = 0.0; - m_vecAnimMoveDelta.y = 0.0; + m_vecAnimMoveDelta.x = 0.0f; + m_vecAnimMoveDelta.y = 0.0f; m_fHealth = 100.0f; m_fArmour = 0.0f; m_nPedType = pedType; @@ -290,9 +291,9 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) bInVehicle = 0; m_pMyVehicle = nil; m_pVehicleAnim = nil; - m_vecOffsetSeek.x = 0.0; - m_vecOffsetSeek.y = 0.0; - m_vecOffsetSeek.z = 0.0; + m_vecOffsetSeek.x = 0.0f; + m_vecOffsetSeek.y = 0.0f; + m_vecOffsetSeek.z = 0.0f; m_pedFormation = 0; m_lastThreatTimer = 0; m_nPedStateTimer = 0; @@ -907,8 +908,8 @@ CPed::ClearAimFlag(void) m_pedIK.m_flags &= ~CPedIK:: FLAG_4; } - if (CPed::IsPlayer()) - ((CPlayerPed*)this)->m_fFPSMoveHeading = 0.0; + if (IsPlayer()) + ((CPlayerPed*)this)->m_fFPSMoveHeading = 0.0f; } void @@ -919,14 +920,14 @@ CPed::ClearLookFlag(void) { m_ped_flagI1 = false; m_pedIK.m_flags &= ~CPedIK::FLAG_2; - if (CPed::IsPlayer()) + if (IsPlayer()) m_lookTimer = CTimer::GetTimeInMilliseconds() + 2000; else m_lookTimer = CTimer::GetTimeInMilliseconds() + 4000; if (m_nPedState == PED_LOOK_HEADING || m_nPedState == PED_LOOK_ENTITY) { - CPed::RestorePreviousState(); - CPed::ClearLookFlag(); + RestorePreviousState(); + ClearLookFlag(); } } } @@ -1739,10 +1740,10 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) float limitedAngle = CGeneral::LimitRadianAngle(m_fRotationDest); float timeUntilStateChange = (m_nPedStateTimer - CTimer::GetTimeInMilliseconds())/600.0f; - m_vecOffsetSeek.z = 0.0; + m_vecOffsetSeek.z = 0.0f; if (timeUntilStateChange <= 0.0f) { - m_vecOffsetSeek.x = 0.0; - m_vecOffsetSeek.y = 0.0; + m_vecOffsetSeek.x = 0.0f; + m_vecOffsetSeek.y = 0.0f; } else { neededPos -= timeUntilStateChange * m_vecOffsetSeek; } @@ -2509,7 +2510,7 @@ CPed::SetObjective(eObjective newObj, void *entity) if (newObj == OBJECTIVE_SOLICIT) { m_objectiveTimer = CTimer::GetTimeInMilliseconds() + 10000; } else if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == MISSION_CHAR && - (m_carInObjective->m_status == STATUS_PLAYER_DISABLED || CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls)) { + (m_carInObjective->m_status == STATUS_PLAYER_DISABLED || CPad::GetPad(CWorld::PlayerInFocus)->ArePlayerControlsDisabled())) { SetObjectiveTimer(14000); } else { m_objectiveTimer = 0; @@ -2906,6 +2907,232 @@ CPed::CheckAroundForPossibleCollisions(void) } } +bool +CPed::MakePhonecall(void) +{ + if (CTimer::GetTimeInMilliseconds() <= m_phoneTalkTimer) + return false; + + SetIdle(); + gPhoneInfo.m_aPhones[m_phoneId].m_nState = PHONE_STATE_FREE; + m_phoneId = -1; + return true; +} + +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; + 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, 0); + + phoneDir = CGeneral::LimitRadianAngle(phoneDir); + m_moved = CVector2D(0.0f, 0.0f); + + if (currentRot - PI > phoneDir) + phoneDir += 2 * PI; + else if (PI + currentRot < phoneDir) + phoneDir -= 2 * PI; + + float neededTurn = currentRot - phoneDir; + + if (Abs(neededTurn) <= 0.75f) { + SetIdle(); + ClearLookFlag(); + m_phoneTalkTimer = CTimer::GetTimeInMilliseconds() + 10000; + return true; + } else { + m_fRotationCur -= neededTurn * 0.2f; + return false; + } +} + +CPed * +CPed::CheckForDeadPeds(void) +{ + int event; + if (CEventList::FindClosestEvent(EVENT_DEAD_PED, GetPosition(), &event)) { + int pedHandle = gaEvent[event].entityRef; + if (pedHandle && gaEvent[event].entityType == EVENT_ENTITY_PED) { + m_ped_flagD2 = true; + return CPools::GetPed(pedHandle); + } + } + m_ped_flagD2 = false; + return nil; +} + +bool +CPed::CheckForExplosions(CVector2D &area) +{ + int event = 0; + if (CEventList::FindClosestEvent(EVENT_EXPLOSION, GetPosition(), &event)) { + area.x = gaEvent[event].posn.x; + area.y = gaEvent[event].posn.y; + CEntity *actualEntity = nil; + + switch (gaEvent[event].entityType) { + case EVENT_ENTITY_PED: + actualEntity = CPools::GetPed(gaEvent[event].entityRef); + break; + case EVENT_ENTITY_VEHICLE: + actualEntity = CPools::GetVehicle(gaEvent[event].entityRef); + break; + case EVENT_ENTITY_OBJECT: + actualEntity = CPools::GetObject(gaEvent[event].entityRef); + break; + default: + break; + } + + if (actualEntity) { + m_pEventEntity = actualEntity; + m_pEventEntity->RegisterReference((CEntity **) &m_pEventEntity); + m_ped_flagD2 = true; + } else + m_ped_flagD2 = false; + + CEventList::ClearEvent(event); + return true; + } else if (CEventList::FindClosestEvent(EVENT_FIRE, GetPosition(), &event)) { + area.x = gaEvent[event].posn.x; + area.y = gaEvent[event].posn.y; + CEventList::ClearEvent(event); + m_ped_flagD2 = false; + return true; + } + + m_ped_flagD2 = false; + return false; +} + +CPed * +CPed::CheckForGunShots(void) +{ + int event; + if (CEventList::FindClosestEvent(EVENT_GUNSHOT, GetPosition(), &event)) { + int pedHandle = gaEvent[event].entityRef; + if (pedHandle && gaEvent[event].entityType == EVENT_ENTITY_PED) { + // Is that a bug?!? + m_ped_flagD2 = false; + return CPools::GetPed(pedHandle); + } + } + m_ped_flagD2 = false; + return nil; +} + +uint8 +CPed::CheckForPointBlankPeds(CPed *pedToVerify) +{ + float pbDistance = 1.1f; + if (GetWeapon()->IsType2Handed()) + pbDistance = 1.6f; + + for(int i=0; iGetPosition() - GetPosition(); + if (diff.Magnitude() < pbDistance) { + + float neededAngle = CGeneral::GetRadianAngleBetweenPoints( + nearPed->GetPosition().x, nearPed->GetPosition().y, + GetPosition().x, GetPosition().y); + neededAngle = CGeneral::LimitRadianAngle(neededAngle); + m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); + + float neededTurn = Abs(neededTurn - m_fRotationCur); + + if (neededTurn > PI) + neededTurn = 2*PI - neededTurn; + + PedState nearPedState = nearPed->m_nPedState; + + if (nearPedState == PED_FALL || nearPedState == PED_GETUP || nearPedState == PED_DIE || nearPedState == PED_DEAD || nearPedState == PED_DIVE_AWAY) + return 0; + + if (neededTurn < DEGTORAD(60.0f)) { + if (pedToVerify == nearPed) + return 1; + else + return 2; + } + } + } + } + return 0; +} + +bool +CPed::CheckIfInTheAir(void) +{ + if (bInVehicle) + return false; + + CVector pos = GetPosition(); + CColPoint foundColPoint; + CEntity *foundEntity; + + float startZ = pos.z - 1.54f; + bool foundGround = CWorld::ProcessVerticalLine(pos, startZ, foundColPoint, foundEntity, true, true, false, true, false, false, false); + if (!foundGround && m_nPedState != PED_JUMP) + { + pos.z -= 1.04f; + if (CWorld::TestSphereAgainstWorld(pos, 0.15f, this, true, false, false, false, false, false)) + foundGround = true; + } + return !foundGround; +} + +void +CPed::ClearAll(void) +{ + if (!IsPedInControl() && m_nPedState != PED_DEAD) + return; + + m_nPedState = PED_NONE; + m_nMoveState = PEDMOVE_NONE; + m_pSeekTarget = nil; + m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f); + m_fleeFromPosX = 0.0f; + m_fleeFromPosY = 0.0f; + m_fleeFrom = nil; + m_fleeTimer = 0; + bUsesCollision = true; + ClearAimFlag(); + ClearLookFlag(); + bIsPointingGunAt = false; + m_ped_flagC4 = true; + m_ped_flagH1 = false; + m_pCollidingEntity = nil; +} + +void +CPed::ClearAttack(void) +{ + if (m_nPedState != PED_ATTACK || bIsDucking || m_nWaitState == WAITSTATE_PLAYANIM_DUCK) + return; + + if (bIsPointingGunAt) { + if (m_pLookTarget) + SetPointGunAt(m_pLookTarget); + else + ClearPointGunAt(); + } else if (m_objective != OBJECTIVE_NONE) { + SetIdle(); + } else { + RestorePreviousState(); + } +} + WRAPPER void CPed::PedGetupCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE810); } WRAPPER void CPed::PedStaggerCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8D0); } WRAPPER void CPed::PedEvadeCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D36E0); } @@ -2999,4 +3226,13 @@ STARTPATCHES InjectHook(0x4D1390, &CPed::TurnBody, PATCH_JUMP); InjectHook(0x4D3AC0, &CPed::Chat, PATCH_JUMP); InjectHook(0x4D0490, &CPed::CheckAroundForPossibleCollisions, PATCH_JUMP); + InjectHook(0x4D3E20, &CPed::MakePhonecall, PATCH_JUMP); + InjectHook(0x4D3CC0, &CPed::FacePhone, PATCH_JUMP); + InjectHook(0x4D4860, &CPed::CheckForDeadPeds, PATCH_JUMP); + InjectHook(0x4D4650, &CPed::CheckForExplosions, PATCH_JUMP); + InjectHook(0x4D47D0, &CPed::CheckForGunShots, PATCH_JUMP); + InjectHook(0x4E6990, &CPed::CheckForPointBlankPeds, PATCH_JUMP); + InjectHook(0x4D0BE0, &CPed::CheckIfInTheAir, PATCH_JUMP); + InjectHook(0x4C7F20, &CPed::ClearAll, PATCH_JUMP); + InjectHook(0x4E6790, &CPed::ClearAttack, PATCH_JUMP); ENDPATCHES diff --git a/src/peds/Ped.h b/src/peds/Ped.h index cd7d88af..8439e0f8 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -198,13 +198,13 @@ public: uint8 bRespondsToThreats : 1; uint8 m_ped_flagC4 : 1; // false when in bus, bRenderPedInCar? uint8 m_ped_flagC8 : 1; - uint8 m_ped_flagC10 : 1; + uint8 m_ped_flagC10 : 1; // related with phone uint8 m_ped_flagC20 : 1; // just left some body part? uint8 m_ped_flagC40 : 1; uint8 m_ped_flagC80 : 1; uint8 m_ped_flagD1 : 1; - uint8 m_ped_flagD2 : 1; + uint8 m_ped_flagD2 : 1; // seen an event uint8 m_ped_flagD4 : 1; uint8 m_ped_flagD8 : 1; uint8 m_ped_flagD10 : 1; @@ -328,7 +328,7 @@ public: uint8 field_31C; uint8 field_31D; int16 m_phoneId; - uint32 m_lookingForPhone; + uint32 m_lookingForPhone; // unused uint32 m_phoneTalkTimer; void *m_lastAccident; int32 m_nPedType; @@ -459,7 +459,16 @@ public: void Chat(void); void MakeChangesForNewWeapon(int8); void CheckAroundForPossibleCollisions(void); - bool Seek(void); + void SetSeek(CVector, float); + bool MakePhonecall(void); + bool FacePhone(void); + CPed *CheckForDeadPeds(void); + bool CheckForExplosions(CVector2D &area); + CPed *CheckForGunShots(void); + uint8 CheckForPointBlankPeds(CPed*); + bool CheckIfInTheAir(void); + void ClearAll(void); + void SetPointGunAt(CEntity*); // Static methods static void GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float offset); diff --git a/src/weapons/Weapon.cpp b/src/weapons/Weapon.cpp index 90a6408b..cd63544f 100644 --- a/src/weapons/Weapon.cpp +++ b/src/weapons/Weapon.cpp @@ -35,6 +35,12 @@ CWeapon::Reload(void) m_nAmmoInClip = m_nAmmoTotal; } +bool +CWeapon::IsType2Handed(void) +{ + return m_eWeaponType >= WEAPONTYPE_SHOTGUN && m_eWeaponType <= WEAPONTYPE_FLAMETHROWER && m_eWeaponType != WEAPONTYPE_ROCKETLAUNCHER; +} + bool CWeapon::IsTypeMelee(void) { diff --git a/src/weapons/Weapon.h b/src/weapons/Weapon.h index 81516c4e..fc1d9988 100644 --- a/src/weapons/Weapon.h +++ b/src/weapons/Weapon.h @@ -65,5 +65,6 @@ public: bool Fire(CEntity*, CVector*); void AddGunshell(CEntity*, CVector const&, CVector2D const&, float); bool IsTypeMelee(void); + bool IsType2Handed(void); }; static_assert(sizeof(CWeapon) == 0x18, "CWeapon: error");