From d031943f2ab25e36422285ec9d544beff03e1492 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Thu, 14 May 2020 13:46:11 +0300 Subject: [PATCH] more pedattractor --- src/peds/CivilianPed.cpp | 113 ++++++++++ src/peds/CivilianPed.h | 4 + src/peds/Ped.cpp | 441 +++++++++++++++++++++++++++++++++++++-- src/peds/Ped.h | 37 +++- src/peds/PedAttactor.cpp | 233 +++++++++++++++++++-- src/peds/PedAttractor.h | 285 +++++++++++++------------ 6 files changed, 934 insertions(+), 179 deletions(-) diff --git a/src/peds/CivilianPed.cpp b/src/peds/CivilianPed.cpp index 1d6782fc..7d4f4d12 100644 --- a/src/peds/CivilianPed.cpp +++ b/src/peds/CivilianPed.cpp @@ -9,6 +9,8 @@ #include "World.h" #include "Vehicle.h" #include "SurfaceTable.h" +#include "Weather.h" +#include "PedAttractor.h" CCivilianPed::CCivilianPed(ePedType pedtype, uint32 mi) : CPed(pedtype) { @@ -16,6 +18,8 @@ CCivilianPed::CCivilianPed(ePedType pedtype, uint32 mi) : CPed(pedtype) for (int i = 0; i < ARRAY_SIZE(m_nearPeds); i++) { m_nearPeds[i] = nil; } + m_nAttractorCycleState = 0; + m_bAttractorUnk = (CGeneral::GetRandomNumberInRange(0.0f, 1.0f) < 1.25f); } void @@ -365,6 +369,10 @@ CCivilianPed::ProcessControl(void) if (IsPedInControl()) CivilianAI(); + if (CharCreatedBy == RANDOM_CHAR) { + UseNearbyAttractors(); + } + if (CTimer::GetTimeInMilliseconds() > m_timerUnused) { m_stateUnused = 0; m_timerUnused = 0; @@ -373,3 +381,108 @@ CCivilianPed::ProcessControl(void) if (m_moved.Magnitude() > 0.0f) Avoid(); } + +const int32 gFrequencyOfAttractorAttempt = 11; +const float gDistanceToSeekAttractors = 50.0f; +const float gMaxDistanceToAttract = 10.0f; + +void CCivilianPed::UseNearbyAttractors() +{ + if (CWeather::Rain < 0.2f && !m_bAttractorUnk) + return; + if (HasAttractor()) + return; + if (m_nAttractorCycleState != gFrequencyOfAttractorAttempt) { + m_nAttractorCycleState++; + return; + } + m_nAttractorCycleState = 0; + if (!IsPedInControl()) + return; + if (m_nPedState == PED_FLEE_ENTITY) + return; + + float left = GetPosition().x - gDistanceToSeekAttractors; + float right = GetPosition().x + gDistanceToSeekAttractors; + float top = GetPosition().y - gDistanceToSeekAttractors; + float bottom = GetPosition().y + gDistanceToSeekAttractors; + int xstart = Max(0, CWorld::GetSectorIndexX(left)); + int xend = Min(NUMSECTORS_X - 1, CWorld::GetSectorIndexX(right)); + int ystart = Max(0, CWorld::GetSectorIndexY(top)); + int yend = Min(NUMSECTORS_Y - 1, CWorld::GetSectorIndexY(bottom)); + assert(xstart <= xend); + assert(ystart <= yend); + + float minDistance = SQR(gMaxDistanceToAttract); + C2dEffect* pClosestAttractor = nil; + CEntity* pAttractorEntity = nil; + + for (int y = ystart; y <= yend; y++) { + for (int x = xstart; x <= xend; x++) { + CSector* s = CWorld::GetSector(x, y); + for (CPtrNode* pNode = s->m_lists[ENTITYLIST_BUILDINGS].first; pNode != nil; pNode = pNode->next) { + CEntity* pEntity = (CEntity*)pNode->item; + if (!pEntity->IsObject()) + continue; + // TODO: some flag check + CBaseModelInfo* pModelInfo = CModelInfo::GetModelInfo(pEntity->GetModelIndex()); + for (int i = 0; i < pModelInfo->GetNum2dEffects(); i++) { + C2dEffect* pEffect = pModelInfo->Get2dEffect(i); + if (pEffect->type != EFFECT_PED_ATTRACTOR) + continue; + if (!IsAttractedTo(pEffect->pedattr.type)) + continue; + CVector pos; + CPedAttractorManager::ComputeEffectPos(pEffect, GetMatrix(), pos); + if ((pos - GetPosition()).MagnitudeSqr() < minDistance) { + CPedAttractorManager* pManager = GetPedAttractorManager(); + if (pManager->HasEmptySlot(pEffect) && pManager->IsApproachable(pEffect, pEntity->GetMatrix(), 0, this)) { + pClosestAttractor = pEffect; + pAttractorEntity = pEntity; + minDistance = (pos - GetPosition()).MagnitudeSqr(); + } + } + } + } + for (CPtrNode* pNode = s->m_lists[ENTITYLIST_OBJECTS].first; pNode != nil; pNode = pNode->next) { + CEntity* pEntity = (CEntity*)pNode->item; + if (!pEntity->IsObject()) + continue; + // TODO: some flag check + CBaseModelInfo* pModelInfo = CModelInfo::GetModelInfo(pEntity->GetModelIndex()); + for (int i = 0; i < pModelInfo->GetNum2dEffects(); i++) { + C2dEffect* pEffect = pModelInfo->Get2dEffect(i); + if (pEffect->type != EFFECT_PED_ATTRACTOR) + continue; + if (!IsAttractedTo(pEffect->pedattr.type)) + continue; + CVector pos; + CPedAttractorManager::ComputeEffectPos(pEffect, GetMatrix(), pos); + if ((pos - GetPosition()).MagnitudeSqr() < minDistance) { + CPedAttractorManager* pManager = GetPedAttractorManager(); + if (pManager->HasEmptySlot(pEffect) && pManager->IsApproachable(pEffect, pEntity->GetMatrix(), 0, this)) { + pClosestAttractor = pEffect; + pAttractorEntity = pEntity; + minDistance = (pos - GetPosition()).MagnitudeSqr(); + } + } + } + } + } + } + if (pClosestAttractor) + GetPedAttractorManager()->RegisterPedWithAttractor(this, pClosestAttractor, pAttractorEntity->GetMatrix()); +} + +bool CCivilianPed::IsAttractedTo(int8 type) +{ + switch (type) { + case ATTRACTOR_ATM: return true; + case ATTRACTOR_SEAT: return true; + case ATTRACTOR_STOP: return true; + case ATTRACTOR_PIZZA: return true; + case ATTRACTOR_SHELTER: return CWeather::Rain >= 0.2f; + case ATTRACTOR_ICECREAM: return true; + } + return false; +} diff --git a/src/peds/CivilianPed.h b/src/peds/CivilianPed.h index 8418a99f..558380b7 100644 --- a/src/peds/CivilianPed.h +++ b/src/peds/CivilianPed.h @@ -4,12 +4,16 @@ class CCivilianPed : public CPed { + bool m_bAttractorUnk; + int32 m_nAttractorCycleState; public: CCivilianPed(ePedType, uint32); ~CCivilianPed(void) { } void CivilianAI(void); void ProcessControl(void); + void UseNearbyAttractors(void); + bool IsAttractedTo(int8); }; #ifndef PED_SKIN VALIDATE_SIZE(CCivilianPed, 0x53C); diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index ec8a1bb9..4c3727cf 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -57,6 +57,7 @@ #include "Timecycle.h" #include "ParticleObject.h" #include "Floater.h" +#include "PedAttractor.h" #define CAN_SEE_ENTITY_ANGLE_THRESHOLD DEGTORAD(60.0f) @@ -384,6 +385,8 @@ CPed::DebugRenderOnePedText(void) CPed::~CPed(void) { CWorld::Remove(this); + if (m_attractor) + GetPedAttractorManager()->DeRegisterPed(this, m_attractor); CRadar::ClearBlipForEntity(BLIP_CHAR, CPools::GetPedPool()->GetIndex(this)); if (InVehicle()){ uint8 door_flag = GetCarDoorFlag(m_vehEnterType); @@ -452,7 +455,9 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) CharCreatedBy = RANDOM_CHAR; m_leader = nil; m_pedInObjective = nil; + m_attractorHeading = 0.0f; m_carInObjective = nil; + m_attractorHeading = 0.0f; bInVehicle = false; m_pMyVehicle = nil; m_pVehicleAnim = nil; @@ -489,6 +494,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) m_vecSeekPos = CVector(0.0f, 0.0f, 0.0f); m_wepSkills = 0; m_distanceToCountSeekDone = 1.0f; + m_acceptableHeadingOffset = 0.1f; bRunningToPhone = false; m_phoneId = -1; m_lastAccident = 0; @@ -611,6 +617,8 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) bSomeVCflag1 = false; #endif + bReachedAttractorHeadingTarget = false; + bTurnedAroundOnAttractor = false; bCarPassenger = false; bMiamiViceCop = false; bDeadPedInFrontOfCar = false; @@ -3666,6 +3674,8 @@ CPed::SetStoredState(void) void CPed::SetDie(AnimationId animId, float delta, float speed) { + if (m_attractor) + GetPedAttractorManager()->DeRegisterPed(this, m_attractor); CPlayerPed *player = FindPlayerPed(); if (player == this) { if (!player->m_bCanBeDamaged) @@ -5518,8 +5528,45 @@ CPed::SetWaitState(eWaitState state, void *time) m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2500; CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 4.0f); break; + case WAITSTATE_SIT_DOWN: + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f); // TODO(MIAMI): proper anim! + animAssoc->SetFinishCallback(FinishedWaitCB, this); + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 10000; + break; + case WAITSTATE_SIT_UP: + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f); // TODO(MIAMI): proper anim! + animAssoc->SetFinishCallback(FinishedWaitCB, this); + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 100000; + break; + case WAITSTATE_SIT_IDLE: + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 5000.0f); // TODO(MIAMI): proper anim! + animAssoc->SetFinishCallback(FinishedWaitCB, this); + if (time) + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + *(int*)time; + else + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(25000, 30000); + break; + case WAITSTATE_USE_ATM: + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 5000.0f); // TODO(MIAMI): proper anim! + animAssoc->SetFinishCallback(FinishedWaitCB, this); + if (time) + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + *(int*)time; + else + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 100000; + break; + case WAITSTATE_SUN_BATHE_PRE: + case WAITSTATE_SUN_BATHE_DOWN: + case WAITSTATE_SUN_BATHE_IDLE: + case WAITSTATE_RIOT: + case WAITSTATE_FAST_FALL: + case WAITSTATE_BOMBER: + case WAITSTATE_STRIPPER: + case WAITSTATE_GROUND_ATTACK: + case WAITSTATE_LANCESITTING: + case WAITSTATE_PLAYANIM_HANDSUP_SIMPLE: + assert(0); default: - m_nWaitState = WAITSTATE_FALSE; + ClearWaitState(); RestoreHeadingRate(); return; } @@ -7177,7 +7224,7 @@ CPed::Wait(void) CPed *pedWeLook; if (DyingOrDead()) { - m_nWaitState = WAITSTATE_FALSE; + ClearWaitState(); RestoreHeadingRate(); return; } @@ -7187,7 +7234,7 @@ CPed::Wait(void) case WAITSTATE_TRAFFIC_LIGHTS: if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { if (CTrafficLights::LightForPeds() == PED_LIGHTS_WALK) { - m_nWaitState = WAITSTATE_FALSE; + ClearWaitState(); SetMoveState(PEDMOVE_WALK); } } @@ -7196,7 +7243,7 @@ CPed::Wait(void) case WAITSTATE_CROSS_ROAD: if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { if (CGeneral::GetRandomNumber() & 1 || !m_nWaitTimer) - m_nWaitState = WAITSTATE_FALSE; + ClearWaitState(); else SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, nil); @@ -7210,7 +7257,7 @@ CPed::Wait(void) case WAITSTATE_CROSS_ROAD_LOOK: if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { - m_nWaitState = WAITSTATE_FALSE; + ClearWaitState(); animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS); if (animAssoc) { animAssoc->blendDelta = -8.0f; @@ -7227,7 +7274,7 @@ CPed::Wait(void) CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f); } } else { - m_nWaitState = WAITSTATE_FALSE; + ClearWaitState(); SetMoveState(PEDMOVE_WALK); } break; @@ -7238,13 +7285,13 @@ CPed::Wait(void) m_collidingThingTimer = CTimer::GetTimeInMilliseconds() + 2500; } } else { - m_nWaitState = WAITSTATE_FALSE; + ClearWaitState(); } break; case WAITSTATE_TURN180: if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { - m_nWaitState = WAITSTATE_FALSE; + ClearWaitState(); SetMoveState(PEDMOVE_WALK); m_fRotationCur = m_fRotationCur + PI; if (m_nPedState == PED_INVESTIGATE) @@ -7263,7 +7310,7 @@ CPed::Wait(void) animAssoc->SetFinishCallback(FinishedWaitCB, this); m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000; } else { - m_nWaitState = WAITSTATE_FALSE; + ClearWaitState(); } } break; @@ -7292,7 +7339,7 @@ CPed::Wait(void) if (animAssoc->animId == ANIM_TURN_180) { m_fRotationCur = CGeneral::LimitRadianAngle(PI + m_fRotationCur); - m_nWaitState = WAITSTATE_FALSE; + ClearWaitState(); SetMoveState(PEDMOVE_WALK); m_nStoredMoveState = PEDMOVE_NONE; m_panicCounter = 0; @@ -7329,7 +7376,7 @@ CPed::Wait(void) case WAITSTATE_LOOK_ABOUT: if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { - m_nWaitState = WAITSTATE_FALSE; + ClearWaitState(); animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_HBHB); if (animAssoc) { animAssoc->blendDelta = -8.0f; @@ -7356,7 +7403,7 @@ CPed::Wait(void) TurnBody(); } else { - m_nWaitState = WAITSTATE_FALSE; + ClearWaitState(); m_nWaitTimer = 0; if (m_pLookTarget && m_pLookTarget->IsPed()) { @@ -7431,7 +7478,7 @@ CPed::Wait(void) animAssoc->blendDelta = -4.0f; animAssoc->flags |= ASSOC_DELETEFADEDOUT; } - m_nWaitState = WAITSTATE_FALSE; + ClearWaitState(); } #ifdef VC_PED_PORTS else if (m_nWaitState == WAITSTATE_PLAYANIM_TAXI) { @@ -7455,13 +7502,59 @@ CPed::Wait(void) animAssoc->flags |= ASSOC_DELETEFADEDOUT; CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f); int timer = 2000; - m_nWaitState = WAITSTATE_FALSE; + ClearWaitState(); SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, &timer); } } else { - m_nWaitState = WAITSTATE_FALSE; + ClearWaitState(); } break; + case WAITSTATE_SIT_DOWN: + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + ClearWaitState(); + SetWaitState(WAITSTATE_SIT_IDLE, 0); + } + break; + //case WAITSTATE_SIT_DOWN_RVRS: + case WAITSTATE_SIT_UP: + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + if (m_attractor) + GetPedAttractorManager()->BroadcastDeparture(this, m_attractor); + ClearWaitState(); + //TODO(MIAMI): scan for threats! + } + break; + case WAITSTATE_SIT_IDLE: + if (bTurnedAroundOnAttractor) { + m_fRotationCur += PI; + m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); + m_fRotationDest = m_fRotationCur; + bTurnedAroundOnAttractor = false; + } + // TODO(MIAMI): scan for threats! + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + ClearWaitState(); + SetWaitState(WAITSTATE_SIT_UP, 0); + } + break; + case WAITSTATE_USE_ATM: + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + if (m_attractor) + GetPedAttractorManager()->BroadcastDeparture(this, m_attractor); + ClearWaitState(); + } + break; + case WAITSTATE_SUN_BATHE_PRE: + case WAITSTATE_SUN_BATHE_DOWN: + case WAITSTATE_SUN_BATHE_IDLE: + case WAITSTATE_RIOT: + case WAITSTATE_FAST_FALL: + case WAITSTATE_BOMBER: + case WAITSTATE_STRIPPER: + case WAITSTATE_GROUND_ATTACK: + case WAITSTATE_LANCESITTING: + case WAITSTATE_PLAYANIM_HANDSUP_SIMPLE: + assert(0); default: break; } @@ -9461,7 +9554,7 @@ CPed::ProcessControl(void) } else if (m_nPedStateTimer < 1001) { m_nPedStateTimer = 0; } - } else { + } else if (!GetPedAttractorManager()->IsInQueue(this, m_attractor)) { if (m_panicCounter == 50 && IsPedInControl()) { SetWaitState(WAITSTATE_STUCK, nil); // Leftover @@ -12668,9 +12761,21 @@ CPed::ProcessObjective(void) case OBJECTIVE_SET_LEADER: break; case OBJECTIVE_IDLE: - SetIdle(); - m_objective = OBJECTIVE_NONE; - SetMoveState(PEDMOVE_STILL); + if (GetPedState() == PED_DRIVING) + m_objective = OBJECTIVE_NONE; + else { + SetIdle(); + if (m_attractor) { + if (m_objectiveTimer && CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + GetPedAttractorManager()->BroadcastDeparture(this, m_attractor); + m_objectiveTimer = 0; + } + } + else { + m_objective = OBJECTIVE_NONE; + SetMoveState(PEDMOVE_STILL); + } + } break; case OBJECTIVE_FLEE_TILL_SAFE: if (InVehicle()) { @@ -13851,6 +13956,187 @@ CPed::ProcessObjective(void) } break; } + case OBJECTIVE_USE_SEAT_ATTRACTOR: + case OBJECTIVE_USE_ATM_ATTRACTOR: + case OBJECTIVE_USE_STOP_ATTRACTOR: + case OBJECTIVE_USE_PIZZA_ATTRACTOR: + case OBJECTIVE_USE_SHELTER_ATTRACTOR: + case OBJECTIVE_USE_ICECREAM_ATTRACTOR: + if (CTimer::GetTimeInMilliseconds() > m_objectiveTimer) { + m_objectiveTimer = 0; + if (m_attractor) + GetPedAttractorManager()->DeRegisterPed(this, m_attractor); + } + else { + CVector distance = m_nextRoutePointPos - GetPosition(); + distance.z = 0.0f; + if (m_objective == OBJECTIVE_USE_SHELTER_ATTRACTOR) { + if (m_nMoveState == PEDMOVE_SPRINT && distance.Magnitude() < SQR(2.0f)) { + SetMoveState(PEDMOVE_WALK); + bIsRunning = false; + } + else if (CWeather::Rain < 0.2f && m_attractor) { + GetPedAttractorManager()->DeRegisterPed(this, m_attractor); + return; + } + } + else if (m_objective == OBJECTIVE_USE_ICECREAM_ATTRACTOR) { + if (m_nMoveState == PEDMOVE_SPRINT && distance.Magnitude() < SQR(4.0f)) { + SetMoveState(PEDMOVE_WALK); + bIsRunning = false; + } + CVehicle* pIceCreamVan = GetPedAttractorManager()->GetIceCreamVanForEffect(m_attractor->GetEffect()); + if (0.01f * CTimer::GetTimeStep() * 5.0f < pIceCreamVan->m_fDistanceTravelled) { + GetPedAttractorManager()->DeRegisterPed(this, m_attractor); + return; + } + if (!pIceCreamVan->pDriver || + !pIceCreamVan->pDriver->IsPlayer() || + pIceCreamVan->pDriver->GetPedState() == PED_ARRESTED || + pIceCreamVan->pDriver->GetPedState() == PED_DEAD) { + GetPedAttractorManager()->DeRegisterPed(this, m_attractor); + return; + } + if (!pIceCreamVan->m_bSirenOrAlarm) { + GetPedAttractorManager()->DeRegisterPed(this, m_attractor); + return; + } + if (pIceCreamVan->GetStatus() == STATUS_WRECKED) { + GetPedAttractorManager()->DeRegisterPed(this, m_attractor); + return; + } + } + if (sq(m_distanceToCountSeekDone) < distance.MagnitudeSqr()) { + if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer || GetPedState() != PED_SEEK_POS) + SetSeek(m_vecSeekPos, m_distanceToCountSeekDone); + } + else { + if (!bReachedAttractorHeadingTarget) { + float fHeadingDistance = m_fRotationCur - m_attractorHeading; + float fSinHeading = Sin(fHeadingDistance); + float fCosHeading = Cos(fHeadingDistance); + if (fSinHeading > 0.0f) { + if (fCosHeading > 0.0f) + m_attractorHeading = m_fRotationCur - Asin(fSinHeading); + else + m_attractorHeading = m_fRotationCur - Acos(fCosHeading); + } + else { + if (fCosHeading > 0.0f) + m_attractorHeading = m_fRotationCur - Asin(fSinHeading); + else + m_attractorHeading = m_fRotationCur + Acos(fCosHeading); + } + m_fRotationDest = m_attractorHeading; + m_headingRate = 3.5f; + bReachedAttractorHeadingTarget = true; + bTurnedAroundOnAttractor = false; + } + if (Abs(m_fRotationCur - m_attractorHeading) >= m_acceptableHeadingOffset && + Abs(m_fRotationCur - m_attractorHeading + TWOPI) >= m_acceptableHeadingOffset && + Abs(m_fRotationCur - m_attractorHeading - TWOPI) >= m_acceptableHeadingOffset) + SetMoveState(PEDMOVE_STILL); + else { + m_fRotationDest = m_fRotationCur; + bReachedAttractorHeadingTarget = false; + bObjectiveCompleted = true; + bScriptObjectiveCompleted = true; + RestoreHeadingRate(); + GetPedAttractorManager()->BroadcastArrival(this, m_attractor); + if (GetPedAttractorManager()->IsAtHeadOfQueue(this, m_attractor)) { + switch (m_objective) { + case OBJECTIVE_USE_SEAT_ATTRACTOR: + if (bTurnedAroundOnAttractor) { + ClearObjective(); + SetWaitState(WAITSTATE_SIT_DOWN, 0); + } + else { + ClearObjective(); + SetWaitState(WAITSTATE_SIT_DOWN_RVRS, 0); + } + break; + case OBJECTIVE_USE_ATM_ATTRACTOR: + ClearObjective(); + SetWaitState(WAITSTATE_USE_ATM, 0); + break; + case OBJECTIVE_USE_STOP_ATTRACTOR: + ClearObjective(); + SetObjective(OBJECTIVE_WAIT_FOR_BUS); + break; + case OBJECTIVE_USE_PIZZA_ATTRACTOR: + ClearObjective(); + m_prevObjective = OBJECTIVE_NONE; + SetObjective(OBJECTIVE_IDLE); + m_objectiveTimer = CTimer::GetTimeInMilliseconds() + m_attractor->GetHeadOfQueueWaitTime(); + break; + case OBJECTIVE_USE_SHELTER_ATTRACTOR: + m_prevObjective = OBJECTIVE_NONE; + SetObjective(OBJECTIVE_WAIT_FOR_RAIN_TO_END); + break; + case OBJECTIVE_USE_ICECREAM_ATTRACTOR: + m_prevObjective = OBJECTIVE_NONE; + SetObjective(OBJECTIVE_PURCHASE_ICECREAM); + break; + } + } + } + } + } + return; + case OBJECTIVE_WAIT_FOR_RAIN_TO_END: + SetIdle(); + if (m_attractor && CWeather::Rain < 0.2f) + GetPedAttractorManager()->DeRegisterPed(this, m_attractor); + break; + case OBJECTIVE_WAIT_FOR_BUS: + SetIdle(); + if (m_attractor) { + float left = GetPosition().x - 10.0f; + float right = GetPosition().x + 10.0f; + float top = GetPosition().y - 10.0f; + float bottom = GetPosition().y + 10.0f; + int xstart = Max(0, CWorld::GetSectorIndexX(left)); + int xend = Min(NUMSECTORS_X - 1, CWorld::GetSectorIndexX(right)); + int ystart = Max(0, CWorld::GetSectorIndexY(top)); + int yend = Min(NUMSECTORS_Y - 1, CWorld::GetSectorIndexY(bottom)); + assert(xstart <= xend); + assert(ystart <= yend); + + float minDistance = SQR(10.0f); + CVehicle* pBus = nil; + + for (int y = ystart; y <= yend; y++) { + for (int x = xstart; x <= xend; x++) { + CSector* s = CWorld::GetSector(x, y); + for (CPtrNode* pNode = s->m_lists[ENTITYLIST_VEHICLES].first; pNode != nil; pNode = pNode->next) { + CEntity* pEntity = (CEntity*)pNode->item; + if (!pEntity->IsVehicle()) + continue; + CVehicle* pVehicle = (CVehicle*)pEntity; + if (!pVehicle->bIsBus) + continue; + if (pVehicle->GetMoveSpeed().MagnitudeSqr() >= SQR(0.005f)) + continue; + float distanceSq = (GetPosition() - pVehicle->GetPosition()).MagnitudeSqr(); + if (distanceSq < minDistance) { + minDistance = distanceSq; + pBus = pVehicle; + } + } + } + } + + if (pBus) { + if (pBus->m_nNumPassengers >= pBus->m_nNumMaxPassengers - 1) + SetObjective(OBJECTIVE_IDLE); + else { + GetPedAttractorManager()->DeRegisterPed(this, m_attractor); + SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, pBus); + bDontDragMeOutCar = true; // TODO(MIAMI): check, add more flags + } + } + } + break; #endif } if (bObjectiveCompleted @@ -16939,6 +17225,22 @@ CPed::WarpPedIntoCar(CVehicle *car) bChangedSeat = true; } +void +CPed::SetObjective(eObjective newObj, float heading, const CVector& pos) +{ + switch (newObj) { + case OBJECTIVE_USE_SEAT_ATTRACTOR: + case OBJECTIVE_USE_ATM_ATTRACTOR: + case OBJECTIVE_USE_STOP_ATTRACTOR: + case OBJECTIVE_USE_PIZZA_ATTRACTOR: + case OBJECTIVE_USE_SHELTER_ATTRACTOR: + case OBJECTIVE_USE_ICECREAM_ATTRACTOR: + ClearPointGunAt(); + SetObjective(newObj, pos); + m_attractorHeading = heading; + } +} + void CPed::SetObjective(eObjective newObj, CVector dest) { @@ -16988,14 +17290,50 @@ CPed::SetObjective(eObjective newObj, CVector dest) break; case OBJECTIVE_GOTO_AREA_ANY_MEANS: case OBJECTIVE_GOTO_AREA_ON_FOOT: + case OBJECTIVE_USE_SEAT_ATTRACTOR: + case OBJECTIVE_USE_ATM_ATTRACTOR: + case OBJECTIVE_USE_STOP_ATTRACTOR: + case OBJECTIVE_USE_PIZZA_ATTRACTOR: + case OBJECTIVE_USE_SHELTER_ATTRACTOR: + case OBJECTIVE_USE_ICECREAM_ATTRACTOR: bIsRunning = false; m_pNextPathNode = nil; m_nextRoutePointPos = dest; m_vecSeekPos = m_nextRoutePointPos; m_distanceToCountSeekDone = 0.5f; - bUsePedNodeSeek = true; - if (sq(m_distanceToCountSeekDone) > (m_nextRoutePointPos - GetPosition()).MagnitudeSqr2D()) - return; + if (m_objective == OBJECTIVE_USE_ATM_ATTRACTOR) { + m_distanceToCountSeekDone = m_attractor->GetDistanceToCountSeekDone(); + m_acceptableHeadingOffset = m_attractor->GetAcceptableHeading(); + } + if (m_objective == OBJECTIVE_USE_SEAT_ATTRACTOR) { + m_distanceToCountSeekDone = m_attractor->GetDistanceToCountSeekDone(); + m_acceptableHeadingOffset = m_attractor->GetAcceptableHeading(); + } + if (m_objective == OBJECTIVE_USE_STOP_ATTRACTOR) { + m_distanceToCountSeekDone = m_attractor->GetDistanceToCountSeekDone(); + m_acceptableHeadingOffset = m_attractor->GetAcceptableHeading(); + } + if (m_objective == OBJECTIVE_USE_PIZZA_ATTRACTOR) { + m_distanceToCountSeekDone = m_attractor->GetDistanceToCountSeekDone(); + m_acceptableHeadingOffset = m_attractor->GetAcceptableHeading(); + } + if (m_objective == OBJECTIVE_USE_SHELTER_ATTRACTOR) { + bIsRunning = true; + m_distanceToCountSeekDone = m_attractor->GetDistanceToCountSeekDone(); + m_acceptableHeadingOffset = m_attractor->GetAcceptableHeading(); + } + if (m_objective == OBJECTIVE_USE_ICECREAM_ATTRACTOR) { + bIsRunning = true; + m_distanceToCountSeekDone = m_attractor->GetDistanceToCountSeekDone(); + m_acceptableHeadingOffset = m_attractor->GetAcceptableHeading(); + } + bUsePedNodeSeek = false; + if (sq(m_distanceToCountSeekDone) > (m_nextRoutePointPos - GetPosition()).MagnitudeSqr2D()) { + if (!IsUseAttractorObjective(m_objective)) + return; + if (Abs(m_fRotationCur - m_attractorHeading) < m_acceptableHeadingOffset) + return; + } break; case OBJECTIVE_RUN_TO_AREA: bIsRunning = true; @@ -17622,6 +17960,65 @@ CPed::SetExitBoat(CVehicle *boat) CWaterLevel::FreeBoatWakeArray(); } +void +CPed::SetNewAttraction(CPedAttractor* pAttractor, const CVector& pos, float heading, float time, int32 qid) +{ + if (!m_attractor) + m_attractor = pAttractor; + if (m_attractor != pAttractor) + return; + switch (pAttractor->GetEffect()->pedattr.type) { + case ATTRACTOR_ATM: SetObjective(OBJECTIVE_USE_ATM_ATTRACTOR, heading, pos); break; + case ATTRACTOR_SEAT: SetObjective(OBJECTIVE_USE_SEAT_ATTRACTOR, heading, pos); break; + case ATTRACTOR_STOP: SetObjective(OBJECTIVE_USE_STOP_ATTRACTOR, heading, pos); break; + case ATTRACTOR_PIZZA: SetObjective(OBJECTIVE_USE_PIZZA_ATTRACTOR, heading, pos); break; + case ATTRACTOR_SHELTER: SetObjective(OBJECTIVE_USE_SHELTER_ATTRACTOR, heading, pos); break; + case ATTRACTOR_ICECREAM: SetObjective(OBJECTIVE_USE_ICECREAM_ATTRACTOR, heading, pos); break; + default: return; + } + SetObjectiveTimer(time); + m_positionInQueue = qid; +} + +void +CPed::ClearWaitState(void) +{ + switch (m_nWaitState) { + case WAITSTATE_PLAYANIM_CHAT: + case WAITSTATE_SIT_DOWN: + case WAITSTATE_SIT_DOWN_RVRS: + case WAITSTATE_SIT_UP: + case WAITSTATE_SIT_IDLE: + case WAITSTATE_USE_ATM: + if (CTimer::GetTimeInMilliseconds() <= m_nWaitTimer) { + AnimationId id; + switch (m_nWaitState) { // TODO(MIAMI): actual! + case WAITSTATE_PLAYANIM_CHAT: id = ANIM_IDLE_CHAT; break; + case WAITSTATE_SIT_DOWN: id = ANIM_XPRESS_SCRATCH; break; + case WAITSTATE_SIT_DOWN_RVRS: id = ANIM_XPRESS_SCRATCH; break; + case WAITSTATE_SIT_UP: id = ANIM_XPRESS_SCRATCH; break; + case WAITSTATE_SIT_IDLE: id = ANIM_XPRESS_SCRATCH; break; + case WAITSTATE_USE_ATM: id = ANIM_XPRESS_SCRATCH; break; + } + CAnimBlendAssociation* pAssoc = RpAnimBlendClumpGetAssociation(GetClump(), id); + if (pAssoc) + pAssoc->blendDelta = -8.0f; + if (m_attractor) + GetPedAttractorManager()->DeRegisterPed(this, m_attractor); + break; + } + case WAITSTATE_RIOT: + case WAITSTATE_FAST_FALL: + case WAITSTATE_BOMBER: + case WAITSTATE_STRIPPER: + case WAITSTATE_GROUND_ATTACK: + case WAITSTATE_LANCESITTING: + case WAITSTATE_PLAYANIM_HANDSUP_SIMPLE: + assert(0); + } + m_nWaitState = WAITSTATE_FALSE; +} + #ifdef COMPATIBLE_SAVES void CPed::Save(uint8*& buf) diff --git a/src/peds/Ped.h b/src/peds/Ped.h index d8df1f49..60325812 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -149,7 +149,22 @@ enum eWaitState { WAITSTATE_PLAYANIM_HANDSUP, WAITSTATE_PLAYANIM_HANDSCOWER, WAITSTATE_PLAYANIM_CHAT, - WAITSTATE_FINISH_FLEE + WAITSTATE_FINISH_FLEE, + WAITSTATE_SIT_DOWN, + WAITSTATE_SIT_DOWN_RVRS, + WAITSTATE_SIT_UP, + WAITSTATE_SIT_IDLE, + WAITSTATE_USE_ATM, + WAITSTATE_SUN_BATHE_PRE, + WAITSTATE_SUN_BATHE_DOWN, + WAITSTATE_SUN_BATHE_IDLE, + WAITSTATE_RIOT, + WAITSTATE_FAST_FALL, + WAITSTATE_BOMBER, + WAITSTATE_STRIPPER, + WAITSTATE_GROUND_ATTACK, + WAITSTATE_LANCESITTING, + WAITSTATE_PLAYANIM_HANDSUP_SIMPLE, }; enum eObjective : uint32 { @@ -201,14 +216,13 @@ enum eObjective : uint32 { OBJECTIVE_USE_SHELTER_ATTRACTOR, OBJ_46, OBJ_47, - OBJ_48, + OBJECTIVE_WAIT_FOR_RAIN_TO_END, OBJ_49, OBJ_50, OBJ_51, - OBJ_52, + OBJECTIVE_WAIT_FOR_BUS, OBJECTIVE_USE_ICECREAM_ATTRACTOR, - OBJ_53, - OBJ_54, + OBJECTIVE_PURCHASE_ICECREAM, OBJ_55, OBJ_56, OBJ_57, @@ -414,6 +428,8 @@ public: uint32 m_ped_flagI40 : 1; // bMakePedsRunToPhonesToReportCrimes makes use of this as runover by car indicator uint32 m_ped_flagI80 : 1; // KANGAROO_CHEAT define makes use of this as cheat toggle + uint32 bReachedAttractorHeadingTarget : 1; // 0x154 0x40 + uint32 bTurnedAroundOnAttractor : 1; // 0x154 0x80 uint32 bHasAlreadyUsedAttractor : 1; // 0x155 0x1 uint32 bCarPassenger : 1; // 0x155 0x4 uint32 bMiamiViceCop : 1; // 0x155 0x20 @@ -425,6 +441,7 @@ public: CPed *m_pedInObjective; CVehicle *m_carInObjective; CVector m_nextRoutePointPos; + float m_attractorHeading; CPed *m_leader; eFormation m_pedFormation; uint32 m_fearFlags; @@ -482,7 +499,7 @@ public: CVehicle *m_pMyVehicle; bool bInVehicle; float m_distanceToCountSeekDone; - + float m_acceptableHeadingOffset; CPedAttractor* m_attractor; int32 m_positionInQueue; CVehicle* m_vehicleInAccident; @@ -610,6 +627,7 @@ public: void SetObjective(eObjective, int16, int16); void SetObjective(eObjective, CVector); void SetObjective(eObjective, CVector, float); + void SetObjective(eObjective, float, const CVector&); void ClearChat(void); void InformMyGangOfAttack(CEntity*); void ReactToAttack(CEntity*); @@ -822,6 +840,7 @@ public: #endif void SetNewAttraction(CPedAttractor* pAttractor, const CVector& pos, float, float, int); + void ClearWaitState(void); bool HasWeapon(uint8 weaponType) { return m_weapons[weaponType].m_eWeaponType == weaponType; } CWeapon &GetWeapon(uint8 weaponType) { return m_weapons[weaponType]; } @@ -837,6 +856,12 @@ public: bool Driving(void) { return m_nPedState == PED_DRIVING; } bool InVehicle(void) { return bInVehicle && m_pMyVehicle; } // True when ped is sitting/standing in vehicle, not in enter/exit state. bool EnteringCar(void) { return m_nPedState == PED_ENTER_CAR || m_nPedState == PED_CARJACK; } + bool HasAttractor(void) { return m_attractor != nil; } + bool IsUseAttractorObjective(eObjective obj) { + return obj == OBJECTIVE_USE_ATM_ATTRACTOR || obj == OBJECTIVE_USE_ICECREAM_ATTRACTOR || + obj == OBJECTIVE_USE_PIZZA_ATTRACTOR || obj == OBJECTIVE_USE_SEAT_ATTRACTOR || + obj == OBJECTIVE_USE_SHELTER_ATTRACTOR || obj == OBJECTIVE_USE_STOP_ATTRACTOR; + } void ReplaceWeaponWhenExitingVehicle(void); void RemoveWeaponWhenEnteringVehicle(void); diff --git a/src/peds/PedAttactor.cpp b/src/peds/PedAttactor.cpp index 9e3e6ae4..bef14308 100644 --- a/src/peds/PedAttactor.cpp +++ b/src/peds/PedAttactor.cpp @@ -3,9 +3,16 @@ #include "General.h" #include "Vehicle.h" +#include "World.h" const int gcMaxSizeOfAtmQueue = 1; +const int gcMaxSizeOfSeatQueue = 1; +const int gcMaxSizeOfStopQueue = 5; +const int gcMaxSizeOfPizzaQueue = 5; const int gcMaxSizeOfShelterQueue = 5; +const int gcMaxSizeOfIceCreamQueue = 1; + +std::vector CPedShelterAttractor::ms_displacements; CPedAttractorManager* GetPedAttractorManager() { @@ -107,7 +114,7 @@ CVehicle* CPedAttractorManager::GetIceCreamVanForEffect(C2dEffect* pEffect) return nil; } -const CPedAttractor* CPedAttractorManager::FindAssociatedAttractor(const C2dEffect* pEffect, std::vector vecAttractors) +const CPedAttractor* CPedAttractorManager::FindAssociatedAttractor(const C2dEffect* pEffect, std::vector& vecAttractors) { if (vecAttractors.empty()) return nil; @@ -140,20 +147,21 @@ void CPedAttractorManager::RemoveIceCreamVanEffects(C2dEffect* pEffect) } } -CPedAttractor::CPedAttractor(C2dEffect* pEffect, CMatrix const& matrix, int32 maxpeds, float qdist, float waitTime, float approachTime, float unk8, float unk9, float posdisp, float headdisp) : - p2dEffect(p2dEffect), +CPedAttractor::CPedAttractor(C2dEffect* pEffect, const CMatrix& matrix, int32 maxpeds, float qdist, float waitTime, float approachTime, float distance, float headingdiff, float posdisp, float headdisp) : + p2dEffect(pEffect), m_nMaxPedsInAttractor(maxpeds), m_fQueueDistance(qdist), m_fTimeInWaitQueue(waitTime), m_fTimeInApproachingQueue(approachTime), - field_30(unk8), - field_34(unk9), + m_fDistanceToUseAttractor(distance), + m_fAcceptableHeading(headingdiff), m_fMaxPositionDisplacement(posdisp), - m_fMaxHeadingDisplacement(headdisp), - vecEffectPos(Multiply3x3(matrix, pEffect->pos)), - vecQueueDir(Multiply3x3(matrix, pEffect->pedattr.queueDir)), - vecUseDir(Multiply3x3(matrix, pEffect->pedattr.useDir)) -{} + m_fMaxHeadingDisplacement(headdisp) +{ + CPedAttractorManager::ComputeEffectPos(pEffect, matrix, vecEffectPos); + CPedAttractorManager::ComputeEffectQueueDir(pEffect, matrix, vecQueueDir); + CPedAttractorManager::ComputeEffectUseDir(pEffect, matrix, vecUseDir); +} float CPedAttractor::ComputeDeltaHeading() const { @@ -184,7 +192,7 @@ void CPedAttractor::ComputeAttractPos(int32 qid, CVector& pos) const } } -CVector CPedShelterAttractor::GetDisplacement(int32 qid) +CVector CPedShelterAttractor::GetDisplacement(int32 qid) const { if (ms_displacements.empty()) { int i = 0; @@ -208,6 +216,13 @@ CVector CPedShelterAttractor::GetDisplacement(int32 qid) return ms_displacements[qid]; } +void CPedShelterAttractor::ComputeAttractPos(int32 qid, CVector& pos) const +{ + if (!p2dEffect) + return; + pos = vecEffectPos + GetDisplacement(qid); +} + void CPedAttractor::ComputeAttractHeading(int32 qid, float& heading) const { heading = CGeneral::GetRadianAngleBetweenPoints(qid != 0 ? vecQueueDir.x : vecUseDir.x, qid != 0 ? vecQueueDir.y : vecUseDir.y, 0.0f, 0.0f); @@ -254,7 +269,7 @@ static bool IsPedUsingAttractorOfThisType(int8 type, CPed* pPed) return true; break; case ATTRACTOR_STOP: - if (pPed->m_objective == OBJECTIVE_USE_STOP_ATTRACTOR || pPed->m_objective == OBJ_52 || pPed->m_objective == OBJECTIVE_IDLE) + if (pPed->m_objective == OBJECTIVE_USE_STOP_ATTRACTOR || pPed->m_objective == OBJECTIVE_WAIT_FOR_BUS || pPed->m_objective == OBJECTIVE_IDLE) return true; break; case ATTRACTOR_PIZZA: @@ -262,11 +277,11 @@ static bool IsPedUsingAttractorOfThisType(int8 type, CPed* pPed) return true; break; case ATTRACTOR_SHELTER: - if (pPed->m_objective == OBJECTIVE_USE_SHELTER_ATTRACTOR || pPed->m_objective == OBJ_48) + if (pPed->m_objective == OBJECTIVE_USE_SHELTER_ATTRACTOR || pPed->m_objective == OBJECTIVE_WAIT_FOR_RAIN_TO_END) return true; break; case ATTRACTOR_ICECREAM: - if (pPed->m_objective == OBJECTIVE_USE_ICECREAM_ATTRACTOR || pPed->m_objective == OBJ_54) + if (pPed->m_objective == OBJECTIVE_USE_ICECREAM_ATTRACTOR || pPed->m_objective == OBJECTIVE_PURCHASE_ICECREAM) return true; break; } @@ -289,6 +304,7 @@ bool CPedAttractor::DeRegisterPed(CPed* pPed) return true; } pPed->SetWanderPath(CGeneral::GetNodeHeadingFromVector(-vecQueueDir.x, -vecQueueDir.y)); + vApproachingQueue.erase(pPedIt); return true; } return BroadcastDeparture(pPed); @@ -404,6 +420,29 @@ bool CPedShelterAttractor::BroadcastDeparture(CPed* pPed) return true; } +bool CPedAttractor::IsRegisteredWithPed(CPed* pPed) const +{ + for (std::vector::const_iterator pPedIt = vWaitingQueue.cbegin(); pPedIt != vWaitingQueue.cend(); ++pPedIt) { + if (*pPedIt == pPed) + return true; + } + for (std::vector::const_iterator pPedIt = vApproachingQueue.cbegin(); pPedIt != vApproachingQueue.cend(); ++pPedIt) { + if (*pPedIt == pPed) { + return true; + } + } + return false; +} + +bool CPedAttractor::IsInQueue(CPed* pPed) const +{ + for (std::vector::const_iterator pPedIt = vWaitingQueue.cbegin(); pPedIt != vWaitingQueue.cend(); ++pPedIt) { + if (*pPedIt == pPed) + return true; + } + return false; +} + CPedAttractor* CPedAttractorManager::RegisterPedWithAttractor(CPed* pPed, C2dEffect* pEffect, const CMatrix& matrix) { if (pEffect->type != EFFECT_PED_ATTRACTOR) @@ -427,7 +466,7 @@ bool CPedAttractorManager::DeRegisterPed(CPed* pPed, CPedAttractor* pAttractor) return false; if (pAttractor->GetEffect()->type != EFFECT_PED_ATTRACTOR) return nil; - if (IsPedRegisteredWithEffect(pPed)) + if (!IsPedRegisteredWithEffect(pPed)) return nil; switch (pAttractor->GetEffect()->pedattr.type) { case ATTRACTOR_ATM: return DeRegisterPed(pPed, pAttractor, vAtmAttractors); @@ -516,6 +555,27 @@ bool CPedAttractorManager::IsInQueue(CPed* pPed, CPedAttractor* pAttractor) return nil; } +bool CPedAttractorManager::HasEmptySlot(const C2dEffect* pEffect) +{ + if (!pEffect) + return false; + if (pEffect->type != EFFECT_PED_ATTRACTOR) + return nil; + const CPedAttractor* pAttractor; + switch (pEffect->pedattr.type) { + case ATTRACTOR_ATM: pAttractor = FindAssociatedAttractor(pEffect, vAtmAttractors); break; + case ATTRACTOR_SEAT: pAttractor = FindAssociatedAttractor(pEffect, vSeatAttractors); break; + case ATTRACTOR_STOP: pAttractor = FindAssociatedAttractor(pEffect, vStopAttractors); break; + case ATTRACTOR_PIZZA: pAttractor = FindAssociatedAttractor(pEffect, vPizzaAttractors); break; + case ATTRACTOR_SHELTER: pAttractor = FindAssociatedAttractor(pEffect, vShelterAttractors); break; + case ATTRACTOR_ICECREAM: pAttractor = FindAssociatedAttractor(pEffect, vIceCreamAttractors); break; + default: return true; + } + if (!pAttractor) + return true; + return pAttractor->GetNoOfRegisteredPeds() < pAttractor->GetMaxPedsInAttractor(); +} + bool CPedAttractorManager::IsPedRegisteredWithEffect(CPed* pPed) { return IsPedRegistered(pPed, vAtmAttractors) || @@ -526,11 +586,21 @@ bool CPedAttractorManager::IsPedRegisteredWithEffect(CPed* pPed) IsPedRegistered(pPed, vIceCreamAttractors); } -void ComputeEffectPos(const C2dEffect* pEffect, const CMatrix& matrix, CVector& pos) +void CPedAttractorManager::ComputeEffectPos(const C2dEffect* pEffect, const CMatrix& matrix, CVector& pos) { pos = matrix.GetPosition() + Multiply3x3(matrix, pEffect->pos); } +void CPedAttractorManager::ComputeEffectQueueDir(const C2dEffect* pEffect, const CMatrix& matrix, CVector& pos) +{ + pos = Multiply3x3(matrix, pEffect->pedattr.queueDir); +} + +void CPedAttractorManager::ComputeEffectUseDir(const C2dEffect* pEffect, const CMatrix& matrix, CVector& pos) +{ + pos = Multiply3x3(matrix, pEffect->pedattr.useDir); +} + CPedAttractor* CPedAttractorManager::RegisterPed(CPed* pPed, C2dEffect* pEffect, const CMatrix& matrix, std::vector& vecAttractors) { CPedAttractor* pRegisteredAttractor = nil; @@ -552,8 +622,139 @@ CPedAttractor* CPedAttractorManager::RegisterPed(CPed* pPed, C2dEffect* pEffect, } switch (pEffect->pedattr.type) { case ATTRACTOR_ATM: vecAttractors.push_back(new CPedAtmAttractor(pEffect, matrix, gcMaxSizeOfAtmQueue, 1.0f, 30000.0f, 3000.0f, 0.2f, 0.15f, 0.1f, 0.1f)); break; + case ATTRACTOR_SEAT: vecAttractors.push_back(new CPedSeatAttractor(pEffect, matrix, gcMaxSizeOfSeatQueue, 1.0f, 30000.0f, 3000.0f, 0.125f, 0.1f, 0.1f, 0.1f)); break; + case ATTRACTOR_STOP: vecAttractors.push_back(new CPedStopAttractor(pEffect, matrix, gcMaxSizeOfStopQueue, 1.0f, 30000.0f, 3000.0f, 0.2f, 0.1f, 0.1f, 0.1f)); break; + case ATTRACTOR_PIZZA: vecAttractors.push_back(new CPedPizzaAttractor(pEffect, matrix, gcMaxSizeOfPizzaQueue, 1.0f, 30000.0f, 3000.0f, 0.2f, 0.1f, 0.1f, 0.1f)); break; + case ATTRACTOR_SHELTER: vecAttractors.push_back(new CPedShelterAttractor(pEffect, matrix, gcMaxSizeOfShelterQueue, 1.0f, 30000.0f, 3000.0f, 0.5f, 6.28f, 0.1f, 0.1f)); break; + case ATTRACTOR_ICECREAM: vecAttractors.push_back(new CPedIceCreamAttractor(pEffect, matrix, gcMaxSizeOfIceCreamQueue, 1.0f, 30000.0f, 3000.0f, 0.2f, 0.3f, 0.1f, 0.1f)); break; } if (pRegisteredAttractor) pRegisteredAttractor->RegisterPed(pPed); return pRegisteredAttractor; } + +bool CPedAttractorManager::DeRegisterPed(CPed* pPed, CPedAttractor* pAttractor, std::vector& vecAttractors) +{ + if (!pAttractor) + return false; + CPedAttractor* pFound = nil; + for (std::vector::const_iterator pAttractorIt = vecAttractors.cbegin(); pAttractorIt != vecAttractors.cend(); ++pAttractorIt) { + if (*pAttractorIt == pAttractor) { + pFound = *pAttractorIt; + break; + } + } + if (!pFound) + return false; + pFound->DeRegisterPed(pPed); + if (pFound->GetNoOfRegisteredPeds() != 0) + return true; + for (std::vector::const_iterator pAttractorIt = vecAttractors.cbegin(); pAttractorIt != vecAttractors.cend(); ++pAttractorIt) { + if (*pAttractorIt == pAttractor) { + vecAttractors.erase(pAttractorIt); + break; + } + } + delete pAttractor; + return true; +} + +bool CPedAttractorManager::BroadcastArrival(CPed* pPed, CPedAttractor* pAttractor, std::vector& vecAttractors) +{ + if (!pAttractor) + return false; + CPedAttractor* pFound = nil; + for (std::vector::const_iterator pAttractorIt = vecAttractors.cbegin(); pAttractorIt != vecAttractors.cend(); ++pAttractorIt) { + if (*pAttractorIt == pAttractor) { + pFound = *pAttractorIt; + break; + } + } + if (!pFound) + return false; + pFound->BroadcastArrival(pPed); + return true; +} + +bool CPedAttractorManager::BroadcastDeparture(CPed* pPed, CPedAttractor* pAttractor, std::vector& vecAttractors) +{ + if (!pAttractor) + return false; + CPedAttractor* pFound = nil; + for (std::vector::const_iterator pAttractorIt = vecAttractors.cbegin(); pAttractorIt != vecAttractors.cend(); ++pAttractorIt) { + if (*pAttractorIt == pAttractor) { + pFound = *pAttractorIt; + break; + } + } + if (!pFound) + return false; + pFound->DeRegisterPed(pPed); + if (pFound->GetNoOfRegisteredPeds() != 0) + return true; + for (std::vector::const_iterator pAttractorIt = vecAttractors.cbegin(); pAttractorIt != vecAttractors.cend(); ++pAttractorIt) { + if (*pAttractorIt == pAttractor) { + vecAttractors.erase(pAttractorIt); + break; + } + } + delete pAttractor; + return true; +} + +bool CPedAttractorManager::IsInQueue(CPed* pPed, CPedAttractor* pAttractor, std::vector& vecAttractors) +{ + if (!pAttractor) + return false; + for (std::vector::const_iterator pAttractorIt = vecAttractors.cbegin(); pAttractorIt != vecAttractors.cend(); ++pAttractorIt) { + if (*pAttractorIt == pAttractor) { + return (*pAttractorIt)->IsInQueue(pPed); + } + } + return false; +} + +bool CPedAttractorManager::IsAtHeadOfQueue(CPed* pPed, CPedAttractor* pAttractor, std::vector& vecAttractors) +{ + if (!pAttractor) + return false; + for (std::vector::const_iterator pAttractorIt = vecAttractors.cbegin(); pAttractorIt != vecAttractors.cend(); ++pAttractorIt) { + if (*pAttractorIt == pAttractor) { + return (*pAttractorIt)->IsAtHeadOfQueue(pPed); + } + } + return false; +} + +bool CPedAttractorManager::IsPedRegistered(CPed* pPed, std::vector& vecAttractors) +{ + for (std::vector::const_iterator pAttractorIt = vecAttractors.cbegin(); pAttractorIt != vecAttractors.cend(); ++pAttractorIt) { + if ((*pAttractorIt)->IsRegisteredWithPed(pPed)) + return true; + } + return false; +} + +bool CPedAttractorManager::IsApproachable(C2dEffect* pEffect, const CMatrix& matrix, int32, CPed* pPed) +{ + if (pEffect->pedattr.type == ATTRACTOR_SHELTER) { + CVector pos; + ComputeEffectPos(pEffect, matrix, pos); + return CWorld::GetIsLineOfSightClear(pPed->GetPosition(), pos, true, false, false, false, false, false); + } + CVector vecUseDir, vecEffectPos; + ComputeEffectUseDir(pEffect, matrix, vecUseDir); + ComputeEffectPos(pEffect, matrix, vecEffectPos); + float dp = -DotProduct(vecUseDir, vecEffectPos); + if (pEffect->pedattr.type == ATTRACTOR_ATM || pEffect->pedattr.type == ATTRACTOR_PIZZA || pEffect->pedattr.type == ATTRACTOR_ICECREAM) { + vecUseDir = vecUseDir; + dp = -dp; + } + if (dp + DotProduct(vecEffectPos, pPed->GetPosition()) > 0.0f) { + CVector vecPedToAttractor = pPed->GetPosition() - vecEffectPos; + vecPedToAttractor.Normalise(); + if (DotProduct(vecPedToAttractor, vecUseDir) > 0.25f /* && CWorld::IsWanderPathClear(pPed, vecEffectPos, 2.0f, 0) */) + return true; + } + return false; +} diff --git a/src/peds/PedAttractor.h b/src/peds/PedAttractor.h index 3e7e53df..3171d228 100644 --- a/src/peds/PedAttractor.h +++ b/src/peds/PedAttractor.h @@ -7,131 +7,7 @@ #define NUM_ATTRACTORS_FOR_ICECREAM_VAN 4 -enum ePedAttractorType -{ - ATTRACTOR_ATM = 0, - ATTRACTOR_SEAT, - ATTRACTOR_STOP, - ATTRACTOR_PIZZA, - ATTRACTOR_SHELTER, - ATTRACTOR_ICECREAM -}; - -class CPedAttractor -{ -protected: - C2dEffect* p2dEffect; - std::vector vApproachingQueue; - std::vector vWaitingQueue; - int32 m_nMaxPedsInAttractor; - float m_fQueueDistance; - float m_fTimeInWaitQueue; - float m_fTimeInApproachingQueue; - float field_30; - float field_34; - float m_fMaxPositionDisplacement; - float m_fMaxHeadingDisplacement; - CVector vecEffectPos; - CVector vecQueueDir; - CVector vecUseDir; - -public: - virtual float GetHeadOfQueueWaitTime() { return 0.0f; } - virtual ~CPedAttractor() {}; - virtual ePedAttractorType GetType() const = 0; - virtual void UpdatePedStateOnDeparture() const = 0; - virtual bool IsAtHeadOfQueue(CPed* pPed) const { return vWaitingQueue.front() == pPed; } - virtual void ComputeAttractPos(int32 id, CVector& pos) const; - virtual void ComputeAttractHeading(int32 id, float& pHeading) const; - virtual bool BroadcastDeparture(CPed* pPed); - - bool IsRegisteredWithPed(CPed* pPed) const; - bool DeRegisterPed(CPed* pPed); - float ComputeDeltaHeading() const; - float ComputeDeltaPos() const; - void ComputeAttractTime(int32 id, bool, float& time) const; - int32 GetNoOfRegisteredPeds() const { return vWaitingQueue.size() + vApproachingQueue.size(); } - int32 ComputeFreeSlot() const { return vWaitingQueue.size(); } - bool IsInQueue(CPed*) const; - bool RegisterPed(CPed*); - bool BroadcastArrival(CPed*); - - CPedAttractor(C2dEffect* pEffect, const CMatrix& matrix, int32 maxpeds, float qdist, float waitTime, float approachTime, float unk8, float unk9, float posdisp, float headdisp); - - C2dEffect* GetEffect() const { return p2dEffect; } - const CVector& GetEffectPos() const { return vecEffectPos; } -}; - -class CPedAtmAttractor : public CPedAttractor -{ -public: - virtual ePedAttractorType GetType() const override { return ATTRACTOR_ATM; }; - virtual void UpdatePedStateOnDeparture() const override; - CPedAtmAttractor(C2dEffect* pEffect, const CMatrix& matrix, int32 maxpeds, float qdist, float waitTime, float approachTime, float unk8, float unk9, float posdisp, float headdisp) : - CPedAttractor(pEffect, matrix, maxpeds, qdist, waitTime, approachTime, unk8, unk9, posdisp, headdisp) - {}; -}; - -class CPedIceCreamAttractor : public CPedAttractor -{ -public: - virtual ePedAttractorType GetType() const override { return ATTRACTOR_ICECREAM; } - virtual void UpdatePedStateOnDeparture() const override; - CPedIceCreamAttractor(C2dEffect* pEffect, const CMatrix& matrix, int32 maxpeds, float qdist, float waitTime, float approachTime, float unk8, float unk9, float posdisp, float headdisp) : - CPedAttractor(pEffect, matrix, maxpeds, qdist, waitTime, approachTime, unk8, unk9, posdisp, headdisp) - {}; -}; - -class CPedPizzaAttractor : public CPedAttractor -{ -public: - virtual float GetHeadOfQueueWaitTime() override { return 2000.0f; } - virtual ePedAttractorType GetType() const override { return ATTRACTOR_PIZZA; } - virtual void UpdatePedStateOnDeparture() const override; - CPedPizzaAttractor(C2dEffect* pEffect, const CMatrix& matrix, int32 maxpeds, float qdist, float waitTime, float approachTime, float unk8, float unk9, float posdisp, float headdisp) : - CPedAttractor(pEffect, matrix, maxpeds, qdist, waitTime, approachTime, unk8, unk9, posdisp, headdisp) - {}; -}; - -class CPedSeatAttractor : public CPedAttractor -{ -public: - virtual ePedAttractorType GetType() const override { return ATTRACTOR_SEAT; } - virtual void UpdatePedStateOnDeparture() const override; - CPedSeatAttractor(C2dEffect* pEffect, const CMatrix& matrix, int32 maxpeds, float qdist, float waitTime, float approachTime, float unk8, float unk9, float posdisp, float headdisp) : - CPedAttractor(pEffect, matrix, maxpeds, qdist, waitTime, approachTime, unk8, unk9, posdisp, headdisp) - {}; -}; - -class CPedShelterAttractor : public CPedAttractor -{ - static std::vector ms_displacements; -public: - virtual ePedAttractorType GetType() const override { return ATTRACTOR_SHELTER; } - virtual bool BroadcastDeparture(CPed*) override; - virtual void UpdatePedStateOnDeparture() const override; - virtual bool IsAtHeadOfQueue(CPed* pPed) const override { return true; } - virtual void ComputeAttractPos(int qid, CVector& pos) const override; - virtual void ComputeAttractHeading(int qid, float& heading) const override; - - CPedShelterAttractor(C2dEffect* pEffect, const CMatrix& matrix, int32 maxpeds, float qdist, float waitTime, float approachTime, float unk8, float unk9, float posdisp, float headdisp) : - CPedAttractor(pEffect, matrix, maxpeds, qdist, waitTime, approachTime, unk8, unk9, posdisp, headdisp) - {}; - - - CVector GetDisplacement(int32 qid); -}; - -class CPedStopAttractor : public CPedAttractor -{ -public: - virtual ePedAttractorType GetType() const override { return ATTRACTOR_STOP; } - virtual void UpdatePedStateOnDeparture() const override; - - CPedStopAttractor(C2dEffect* pEffect, const CMatrix& matrix, int32 maxpeds, float qdist, float waitTime, float approachTime, float unk8, float unk9, float posdisp, float headdisp) : - CPedAttractor(pEffect, matrix, maxpeds, qdist, waitTime, approachTime, unk8, unk9, posdisp, headdisp) - {}; -}; +class CPedAttractor; class CVehicleToEffect { @@ -165,24 +41,163 @@ public: bool BroadcastArrival(CPed* pPed, CPedAttractor* pAttractor); bool BroadcastArrival(CPed* pPed, CPedAttractor* pAttractor, std::vector& vecAttractors); const C2dEffect* GetEffectForIceCreamVan(CVehicle* pVehicle, const CVector& pos); - void ComputeEffectQueueDir(const C2dEffect* pEffect, const CMatrix& matrix, CVector& dir); bool IsApproachable(C2dEffect* pEffect, const CMatrix& matrix, int32, CPed* pPed); - void ComputeEffectUseDir(const C2dEffect* pEffect, const CMatrix& matrix, CVector& dir); - void ComputeEffectPos(const C2dEffect* pEffect, const CMatrix& matrix, CVector& pos); void RemoveIceCreamVanEffects(C2dEffect* pEffect); bool HasEmptySlot(const C2dEffect* pEffect); - const CPedAttractor* FindAssociatedAttractor(const C2dEffect* pEffect, std::vector vecAttractors); + const CPedAttractor* FindAssociatedAttractor(const C2dEffect* pEffect, std::vector& vecAttractors); bool IsInQueue(CPed* pPed, CPedAttractor* pAttractor); - bool IsInQueue(CPed* pPed, CPedAttractor* pAttractor, std::vector vecAttractors); + bool IsInQueue(CPed* pPed, CPedAttractor* pAttractor, std::vector& vecAttractors); bool IsAtHeadOfQueue(CPed* pPed, CPedAttractor* pAttractor); - bool IsAtHeadOfQueue(CPed* pPed, CPedAttractor* pAttractor, std::vector vecAttractors); + bool IsAtHeadOfQueue(CPed* pPed, CPedAttractor* pAttractor, std::vector& vecAttractors); bool BroadcastDeparture(CPed* pPed, CPedAttractor* pAttractor); - bool BroadcastDeparture(CPed* pPed, CPedAttractor* pAttractor, std::vector vecAttractors); + bool BroadcastDeparture(CPed* pPed, CPedAttractor* pAttractor, std::vector& vecAttractors); bool DeRegisterPed(CPed* pPed, CPedAttractor* pAttractor); - bool DeRegisterPed(CPed* pPed, CPedAttractor* pAttractor, std::vector vecAttractors); + bool DeRegisterPed(CPed* pPed, CPedAttractor* pAttractor, std::vector& vecAttractors); bool IsPedRegisteredWithEffect(CPed* pPed); - bool IsPedRegistered(CPed* pPed, std::vector vecAttractors); + bool IsPedRegistered(CPed* pPed, std::vector& vecAttractors); CVehicle* GetIceCreamVanForEffect(C2dEffect* pEffect); + + static void ComputeEffectPos(const C2dEffect* pEffect, const CMatrix& matrix, CVector& pos); + static void ComputeEffectQueueDir(const C2dEffect* pEffect, const CMatrix& matrix, CVector& pos); + static void ComputeEffectUseDir(const C2dEffect* pEffect, const CMatrix& matrix, CVector& pos); + }; -CPedAttractorManager* GetPedAttractorManager(); \ No newline at end of file +CPedAttractorManager* GetPedAttractorManager(); + +enum ePedAttractorType +{ + ATTRACTOR_ATM = 0, + ATTRACTOR_SEAT, + ATTRACTOR_STOP, + ATTRACTOR_PIZZA, + ATTRACTOR_SHELTER, + ATTRACTOR_ICECREAM +}; + +class CPedAttractor +{ +protected: + C2dEffect* p2dEffect; + std::vector vApproachingQueue; + std::vector vWaitingQueue; + int32 m_nMaxPedsInAttractor; + float m_fQueueDistance; + float m_fTimeInWaitQueue; + float m_fTimeInApproachingQueue; + float m_fDistanceToUseAttractor; + float m_fAcceptableHeading; + float m_fMaxPositionDisplacement; + float m_fMaxHeadingDisplacement; + CVector vecEffectPos; + CVector vecQueueDir; + CVector vecUseDir; + +public: + virtual float GetHeadOfQueueWaitTime() { return 0.0f; } + virtual ~CPedAttractor() {}; + virtual ePedAttractorType GetType() const = 0; + virtual void UpdatePedStateOnDeparture(CPed* pPed) const = 0; + virtual bool IsAtHeadOfQueue(CPed* pPed) const { return vWaitingQueue.front() == pPed; } + virtual void ComputeAttractPos(int32 id, CVector& pos) const; + virtual void ComputeAttractHeading(int32 id, float& pHeading) const; + virtual bool BroadcastDeparture(CPed* pPed); + + bool IsRegisteredWithPed(CPed* pPed) const; + bool DeRegisterPed(CPed* pPed); + float ComputeDeltaHeading() const; + float ComputeDeltaPos() const; + void ComputeAttractTime(int32 id, bool, float& time) const; + int32 GetNoOfRegisteredPeds() const { return vWaitingQueue.size() + vApproachingQueue.size(); } + int32 ComputeFreeSlot() const { return vWaitingQueue.size(); } + bool IsInQueue(CPed*) const; + bool RegisterPed(CPed*); + bool BroadcastArrival(CPed*); + + CPedAttractor(C2dEffect* pEffect, const CMatrix& matrix, int32 maxpeds, float qdist, float waitTime, float approachTime, float unk8, float unk9, float posdisp, float headdisp); + + C2dEffect* GetEffect() const { return p2dEffect; } + const CVector& GetEffectPos() const { return vecEffectPos; } + int32 GetMaxPedsInAttractor() const { return m_nMaxPedsInAttractor; } + float GetDistanceToCountSeekDone() const { return m_fDistanceToUseAttractor; } + float GetAcceptableHeading() const { return m_fAcceptableHeading; } +}; + +class CPedAtmAttractor : public CPedAttractor +{ +public: + virtual ePedAttractorType GetType() const override { return ATTRACTOR_ATM; }; + virtual void UpdatePedStateOnDeparture(CPed* pPed) const override { /* pPed->m_money += 20 * CGeneral::GetRandomNumberInRange(1, 51); */ }; + CPedAtmAttractor(C2dEffect* pEffect, const CMatrix& matrix, int32 maxpeds, float qdist, float waitTime, float approachTime, float unk8, float unk9, float posdisp, float headdisp) : + CPedAttractor(pEffect, matrix, maxpeds, qdist, waitTime, approachTime, unk8, unk9, posdisp, headdisp) + {}; +}; + +class CPedIceCreamAttractor : public CPedAttractor +{ +public: + virtual ~CPedIceCreamAttractor() override { GetPedAttractorManager()->RemoveIceCreamVanEffects(p2dEffect); } + virtual ePedAttractorType GetType() const override { return ATTRACTOR_ICECREAM; } + virtual void UpdatePedStateOnDeparture(CPed* pPed) const override {}; + CPedIceCreamAttractor(C2dEffect* pEffect, const CMatrix& matrix, int32 maxpeds, float qdist, float waitTime, float approachTime, float unk8, float unk9, float posdisp, float headdisp) : + CPedAttractor(pEffect, matrix, maxpeds, qdist, waitTime, approachTime, unk8, unk9, posdisp, headdisp) + {}; +}; + +class CPedPizzaAttractor : public CPedAttractor +{ +public: + virtual float GetHeadOfQueueWaitTime() override { return 2000.0f; } + virtual ePedAttractorType GetType() const override { return ATTRACTOR_PIZZA; } + virtual void UpdatePedStateOnDeparture(CPed* pPed) const override + { /* + if (pPed->m_money > 10) + pPed->m_money = 0; + else + pPed->m_money -= 10; + */ + } + CPedPizzaAttractor(C2dEffect* pEffect, const CMatrix& matrix, int32 maxpeds, float qdist, float waitTime, float approachTime, float unk8, float unk9, float posdisp, float headdisp) : + CPedAttractor(pEffect, matrix, maxpeds, qdist, waitTime, approachTime, unk8, unk9, posdisp, headdisp) + {}; +}; + +class CPedSeatAttractor : public CPedAttractor +{ +public: + virtual ePedAttractorType GetType() const override { return ATTRACTOR_SEAT; } + virtual void UpdatePedStateOnDeparture(CPed* pPed) const override {}; + CPedSeatAttractor(C2dEffect* pEffect, const CMatrix& matrix, int32 maxpeds, float qdist, float waitTime, float approachTime, float unk8, float unk9, float posdisp, float headdisp) : + CPedAttractor(pEffect, matrix, maxpeds, qdist, waitTime, approachTime, unk8, unk9, posdisp, headdisp) + {}; +}; + +class CPedShelterAttractor : public CPedAttractor +{ + static std::vector ms_displacements; +public: + virtual ePedAttractorType GetType() const override { return ATTRACTOR_SHELTER; } + virtual bool BroadcastDeparture(CPed*) override; + virtual void UpdatePedStateOnDeparture(CPed* pPed) const override {}; + virtual bool IsAtHeadOfQueue(CPed* pPed) const override { return true; } + virtual void ComputeAttractPos(int qid, CVector& pos) const override; + virtual void ComputeAttractHeading(int qid, float& heading) const override; + + CPedShelterAttractor(C2dEffect* pEffect, const CMatrix& matrix, int32 maxpeds, float qdist, float waitTime, float approachTime, float unk8, float unk9, float posdisp, float headdisp) : + CPedAttractor(pEffect, matrix, maxpeds, qdist, waitTime, approachTime, unk8, unk9, posdisp, headdisp) + {}; + + + CVector GetDisplacement(int32 qid) const; +}; + +class CPedStopAttractor : public CPedAttractor +{ +public: + virtual ePedAttractorType GetType() const override { return ATTRACTOR_STOP; } + virtual void UpdatePedStateOnDeparture(CPed* pPed) const override {}; + + CPedStopAttractor(C2dEffect* pEffect, const CMatrix& matrix, int32 maxpeds, float qdist, float waitTime, float approachTime, float unk8, float unk9, float posdisp, float headdisp) : + CPedAttractor(pEffect, matrix, maxpeds, qdist, waitTime, approachTime, unk8, unk9, posdisp, headdisp) + {}; +}; \ No newline at end of file