diff options
Diffstat (limited to 'src/control')
-rw-r--r-- | src/control/Phones.cpp | 161 | ||||
-rw-r--r-- | src/control/Phones.h | 21 |
2 files changed, 165 insertions, 17 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 { +public: static bool &isPhonePickedUp; - static bool &isPhoneBeingPickedUp; + static uint32 &phoneMessagesTimer; static CPhone *&pickedUpPhone; -public: + 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; |