diff options
author | aap <aap@papnet.eu> | 2020-06-01 10:44:33 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-01 10:44:33 +0200 |
commit | 6d3e54369ce9ac826ab7c74da4be1c15d3ff3df0 (patch) | |
tree | 5f09d5f4358b1518262068d65ac713993b2cf437 | |
parent | Merge branch 'miami' of https://github.com/GTAmodding/re3 into miami (diff) | |
parent | fix (diff) | |
download | re3-6d3e54369ce9ac826ab7c74da4be1c15d3ff3df0.tar re3-6d3e54369ce9ac826ab7c74da4be1c15d3ff3df0.tar.gz re3-6d3e54369ce9ac826ab7c74da4be1c15d3ff3df0.tar.bz2 re3-6d3e54369ce9ac826ab7c74da4be1c15d3ff3df0.tar.lz re3-6d3e54369ce9ac826ab7c74da4be1c15d3ff3df0.tar.xz re3-6d3e54369ce9ac826ab7c74da4be1c15d3ff3df0.tar.zst re3-6d3e54369ce9ac826ab7c74da4be1c15d3ff3df0.zip |
Diffstat (limited to '')
-rw-r--r-- | src/audio/sampman.h | 4 | ||||
-rw-r--r-- | src/audio/sampman_miles.cpp | 11 | ||||
-rw-r--r-- | src/audio/sampman_null.cpp | 4 | ||||
-rw-r--r-- | src/audio/sampman_oal.cpp | 12 | ||||
-rw-r--r-- | src/control/CarCtrl.h | 2 | ||||
-rw-r--r-- | src/control/Darkel.cpp | 3 | ||||
-rw-r--r-- | src/control/GameLogic.cpp | 324 | ||||
-rw-r--r-- | src/control/GameLogic.h | 38 | ||||
-rw-r--r-- | src/control/PathFind.h | 6 | ||||
-rw-r--r-- | src/control/RoadBlocks.cpp | 242 | ||||
-rw-r--r-- | src/control/RoadBlocks.h | 18 | ||||
-rw-r--r-- | src/control/Script.cpp | 48 | ||||
-rw-r--r-- | src/core/Camera.cpp | 2 | ||||
-rw-r--r-- | src/core/Fire.cpp | 13 | ||||
-rw-r--r-- | src/core/Game.cpp | 1 | ||||
-rw-r--r-- | src/core/Pad.h | 9 | ||||
-rw-r--r-- | src/core/PlayerInfo.cpp | 2 | ||||
-rw-r--r-- | src/core/PlayerInfo.h | 9 | ||||
-rw-r--r-- | src/core/User.cpp | 4 | ||||
-rw-r--r-- | src/core/config.h | 5 | ||||
-rw-r--r-- | src/math/Matrix.h | 8 | ||||
-rw-r--r-- | src/peds/Ped.cpp | 36 | ||||
-rw-r--r-- | src/peds/Ped.h | 2 | ||||
-rw-r--r-- | src/render/Particle.h | 2 | ||||
-rw-r--r-- | src/save/GenericGameStorage.cpp | 4 |
25 files changed, 662 insertions, 147 deletions
diff --git a/src/audio/sampman.h b/src/audio/sampman.h index 655efb5c..b539854c 100644 --- a/src/audio/sampman.h +++ b/src/audio/sampman.h @@ -126,10 +126,10 @@ public: void StartChannel (uint32 nChannel); void StopChannel (uint32 nChannel); - void PreloadStreamedFile (uint8 nFile, uint8 nStream); + void PreloadStreamedFile (uint32 nFile, uint8 nStream); void PauseStream (uint8 nPauseFlag, uint8 nStream); void StartPreloadedStreamedFile (uint8 nStream); - bool StartStreamedFile (uint8 nFile, uint32 nPos, uint8 nStream); + bool StartStreamedFile (uint32 nFile, uint32 nPos, uint8 nStream); void StopStreamedFile (uint8 nStream); int32 GetStreamedFilePosition (uint8 nStream); void SetStreamedVolumeAndPan(uint8 nVolume, uint8 nPan, uint8 nEffectFlag, uint8 nStream); diff --git a/src/audio/sampman_miles.cpp b/src/audio/sampman_miles.cpp index 63e89cac..5893ea64 100644 --- a/src/audio/sampman_miles.cpp +++ b/src/audio/sampman_miles.cpp @@ -2030,7 +2030,7 @@ cSampleManager::StopChannel(uint32 nChannel) } void -cSampleManager::PreloadStreamedFile(uint8 nFile, uint8 nStream) +cSampleManager::PreloadStreamedFile(uint32 nFile, uint8 nStream) { if ( m_bInitialised ) { @@ -2081,7 +2081,7 @@ cSampleManager::StartPreloadedStreamedFile(uint8 nStream) } bool -cSampleManager::StartStreamedFile(uint8 nFile, uint32 nPos, uint8 nStream) +cSampleManager::StartStreamedFile(uint32 nFile, uint32 nPos, uint8 nStream) { uint32 position = nPos; char filename[MAX_PATH]; @@ -2287,7 +2287,12 @@ cSampleManager::SetStreamedVolumeAndPan(uint8 nVolume, uint8 nPan, uint8 nEffect if ( mp3Stream[nStream] ) { if ( nEffectFlag ) - AIL_set_stream_volume(mp3Stream[nStream], m_nEffectsFadeVolume*vol*m_nEffectsVolume >> 14); + { + if ( nStream == 1 ) // TODO(MIAMI): || nStream == 2 when we have second mission channel? + AIL_set_stream_volume(mp3Stream[nStream], 128*vol*m_nEffectsVolume >> 14); + else + AIL_set_stream_volume(mp3Stream[nStream], m_nEffectsFadeVolume*vol*m_nEffectsVolume >> 14); + } else AIL_set_stream_volume(mp3Stream[nStream], m_nMusicFadeVolume*vol*m_nMusicVolume >> 14); diff --git a/src/audio/sampman_null.cpp b/src/audio/sampman_null.cpp index 6ec8a521..3638e6fb 100644 --- a/src/audio/sampman_null.cpp +++ b/src/audio/sampman_null.cpp @@ -297,7 +297,7 @@ cSampleManager::StopChannel(uint32 nChannel) } void -cSampleManager::PreloadStreamedFile(uint8 nFile, uint8 nStream) +cSampleManager::PreloadStreamedFile(uint32 nFile, uint8 nStream) { ASSERT( nStream < MAX_STREAMS ); } @@ -315,7 +315,7 @@ cSampleManager::StartPreloadedStreamedFile(uint8 nStream) } bool -cSampleManager::StartStreamedFile(uint8 nFile, uint32 nPos, uint8 nStream) +cSampleManager::StartStreamedFile(uint32 nFile, uint32 nPos, uint8 nStream) { ASSERT( nStream < MAX_STREAMS ); diff --git a/src/audio/sampman_oal.cpp b/src/audio/sampman_oal.cpp index 5092a4b1..de55c2ed 100644 --- a/src/audio/sampman_oal.cpp +++ b/src/audio/sampman_oal.cpp @@ -1168,7 +1168,7 @@ cSampleManager::StopChannel(uint32 nChannel) } void -cSampleManager::PreloadStreamedFile(uint8 nFile, uint8 nStream) +cSampleManager::PreloadStreamedFile(uint32 nFile, uint8 nStream) { char filename[256]; @@ -1226,7 +1226,7 @@ cSampleManager::StartPreloadedStreamedFile(uint8 nStream) } bool -cSampleManager::StartStreamedFile(uint8 nFile, uint32 nPos, uint8 nStream) +cSampleManager::StartStreamedFile(uint32 nFile, uint32 nPos, uint8 nStream) { char filename[256]; @@ -1317,8 +1317,12 @@ cSampleManager::SetStreamedVolumeAndPan(uint8 nVolume, uint8 nPan, uint8 nEffect if ( stream ) { - if ( nEffectFlag ) - stream->SetVolume(m_nEffectsFadeVolume*nVolume*m_nEffectsVolume >> 14); + if ( nEffectFlag ) { + if ( nStream == 1 ) // TODO(MIAMI): || nStream == 2 when we have second mission channel? + stream->SetVolume(128*nVolume*m_nEffectsVolume >> 14); + else + stream->SetVolume(m_nEffectsFadeVolume*nVolume*m_nEffectsVolume >> 14); + } else stream->SetVolume(m_nMusicFadeVolume*nVolume*m_nMusicVolume >> 14); diff --git a/src/control/CarCtrl.h b/src/control/CarCtrl.h index ed63a0e2..6b4e94ee 100644 --- a/src/control/CarCtrl.h +++ b/src/control/CarCtrl.h @@ -16,8 +16,6 @@ enum{ MAX_CAR_MODELS_IN_ARRAY = 25, }; -#define LANE_WIDTH 5.0f - #ifdef FIX_BUGS #define FIX_PATHFIND_BUG #endif diff --git a/src/control/Darkel.cpp b/src/control/Darkel.cpp index cfd58340..b6489ef2 100644 --- a/src/control/Darkel.cpp +++ b/src/control/Darkel.cpp @@ -13,6 +13,7 @@ #include "Font.h" #include "Text.h" #include "Vehicle.h" +#include "GameLogic.h" #define FRENZY_ANY_PED -1 #define FRENZY_ANY_CAR -2 @@ -246,6 +247,8 @@ CDarkel::ResetOnPlayerDeath() void CDarkel::StartFrenzy(eWeaponType weaponType, int32 time, uint16 kill, int32 modelId0, wchar *text, int32 modelId2, int32 modelId3, int32 modelId4, bool standardSound, bool needHeadShot) { + CGameLogic::ClearShortCut(); + CGameLogic::RemoveShortCutDropOffPointForMission(); eWeaponType fixedWeapon; if (weaponType == WEAPONTYPE_UZI_DRIVEBY) fixedWeapon = WEAPONTYPE_UZI; diff --git a/src/control/GameLogic.cpp b/src/control/GameLogic.cpp index abb5c5f3..6cfaa042 100644 --- a/src/control/GameLogic.cpp +++ b/src/control/GameLogic.cpp @@ -19,13 +19,42 @@ #include "Fire.h" #include "Script.h" #include "Garages.h" +#include "Population.h" +#include "General.h" +#include "DMAudio.h" +#include "Radar.h" +#include "Pools.h" +#include "Hud.h" +#include "Particle.h" +#include "ColStore.h" +#include "Automobile.h" uint8 CGameLogic::ActivePlayers; +uint8 CGameLogic::ShortCutState; +CAutomobile* CGameLogic::pShortCutTaxi; +uint32 CGameLogic::NumAfterDeathStartPoints; +CVector CGameLogic::ShortCutStart; +float CGameLogic::ShortCutStartOrientation; +CVector CGameLogic::ShortCutDestination; +float CGameLogic::ShortCutDestinationOrientation; +uint32 CGameLogic::ShortCutTimer; +CVector CGameLogic::AfterDeathStartPoints[NUM_SHORTCUT_START_POINTS]; +float CGameLogic::AfterDeathStartPointOrientation[NUM_SHORTCUT_START_POINTS]; +CVector CGameLogic::ShortCutDropOffForMission; +float CGameLogic::ShortCutDropOffOrientationForMission; +bool CGameLogic::MissionDropOffReadyToBeUsed; + +//--MIAMI: file done except TODO + +#define SHORTCUT_TAXI_COST (9) void CGameLogic::InitAtStartOfGame() { ActivePlayers = 1; + ShortCutState = SHORTCUT_NONE; + pShortCutTaxi = nil; + NumAfterDeathStartPoints = 0; } void @@ -58,7 +87,10 @@ CGameLogic::SortOutStreamingAndMemory(const CVector &pos) CStreaming::DeleteRwObjectsAfterDeath(pos); CStreaming::RemoveUnusedModelsInLoadedList(); CGame::DrasticTidyUpMemory(true); + CWorld::Players[CWorld::PlayerInFocus].m_pPed->Undress("player"); + CStreaming::LoadSceneCollision(pos); CStreaming::LoadScene(pos); + CWorld::Players[CWorld::PlayerInFocus].m_pPed->Dress(); CTimer::Update(); } @@ -70,7 +102,9 @@ CGameLogic::Update() if (CCutsceneMgr::IsCutsceneProcessing()) return; + UpdateShortCut(); CPlayerInfo &pPlayerInfo = CWorld::Players[CWorld::PlayerInFocus]; + switch (pPlayerInfo.m_WBState) { case WBSTATE_PLAYING: if (pPlayerInfo.m_pPed->m_nPedState == PED_DEAD) { @@ -93,7 +127,7 @@ CGameLogic::Update() if (pPlayerInfo.m_bGetOutOfHospitalFree) { pPlayerInfo.m_bGetOutOfHospitalFree = false; } else { - pPlayerInfo.m_nMoney = Max(0, pPlayerInfo.m_nMoney - 1000); + pPlayerInfo.m_nMoney = Max(0, pPlayerInfo.m_nMoney - 100); pPlayerInfo.m_pPed->ClearWeapons(); } @@ -117,17 +151,20 @@ CGameLogic::Update() CRestart::OverridePoliceStationLevel = LEVEL_NONE; PassTime(720); RestorePlayerStuffDuringResurrection(pPlayerInfo.m_pPed, vecRestartPos, fRestartFloat); + AfterDeathArrestSetUpShortCutTaxi(); SortOutStreamingAndMemory(pPlayerInfo.GetPos()); TheCamera.m_fCamShakeForce = 0.0f; TheCamera.SetMotionBlur(0, 0, 0, 0, MBLUR_NONE); CPad::GetPad(0)->StopShaking(0); CReferences::RemoveReferencesToPlayer(); - CCarCtrl::CountDownToCarsAtStart = 2; + CPopulation::m_CountDownToPedsAtStart = 10; + CCarCtrl::CountDownToCarsAtStart = 10; CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls = PLAYERCONTROL_ENABLED; if (CRestart::bFadeInAfterNextDeath) { TheCamera.SetFadeColour(200, 200, 200); TheCamera.Fade(4.0f, FADE_IN); - } else CRestart::bFadeInAfterNextDeath = true; + } else + CRestart::bFadeInAfterNextDeath = true; } break; case WBSTATE_BUSTED: @@ -135,7 +172,30 @@ CGameLogic::Update() TheCamera.SetFadeColour(0, 0, 0); TheCamera.Fade(2.0f, FADE_OUT); } + + if (!CTheScripts::IsPlayerOnAMission() && pPlayerInfo.m_nBustedAudioStatus == 0) { + if (CGeneral::GetRandomNumberInRange(0, 4) == 0) + pPlayerInfo.m_nBustedAudioStatus = BUSTEDAUDIO_DONE; + else { + pPlayerInfo.m_nBustedAudioStatus = BUSTEDAUDIO_LOADING; + char name[12]; + sprintf(name, pPlayerInfo.m_nCurrentBustedAudio >= 10 ? "bust_%d" : "bust_0%d", pPlayerInfo.m_nCurrentBustedAudio); + DMAudio.ClearMissionAudio(); // TODO(MIAMI): argument is 0 + DMAudio.PreloadMissionAudio(name); // TODO(MIAMI): argument is 0 + pPlayerInfo.m_nCurrentBustedAudio = pPlayerInfo.m_nCurrentBustedAudio % 28 + 1; // enum? const? TODO + } + } + if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > 4000 && + pPlayerInfo.m_nBustedAudioStatus == BUSTEDAUDIO_LOADING && + DMAudio.GetMissionAudioLoadingStatus() == 1) { // TODO: argument is 0 + DMAudio.PlayLoadedMissionAudio(); // TODO: argument is 0 + pPlayerInfo.m_nBustedAudioStatus = BUSTEDAUDIO_DONE; + } + if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= 0x1000) { +#ifdef FIX_BUGS + pPlayerInfo.m_nBustedAudioStatus = BUSTEDAUDIO_NONE; +#endif pPlayerInfo.m_WBState = WBSTATE_PLAYING; int takeMoney; @@ -188,18 +248,21 @@ CGameLogic::Update() CRestart::OverridePoliceStationLevel = LEVEL_NONE; PassTime(720); RestorePlayerStuffDuringResurrection(pPlayerInfo.m_pPed, vecRestartPos, fRestartFloat); + AfterDeathArrestSetUpShortCutTaxi(); pPlayerInfo.m_pPed->ClearWeapons(); SortOutStreamingAndMemory(pPlayerInfo.GetPos()); TheCamera.m_fCamShakeForce = 0.0f; TheCamera.SetMotionBlur(0, 0, 0, 0, MBLUR_NONE); CPad::GetPad(0)->StopShaking(0); CReferences::RemoveReferencesToPlayer(); - CCarCtrl::CountDownToCarsAtStart = 2; + CPopulation::m_CountDownToPedsAtStart = 10; + CCarCtrl::CountDownToCarsAtStart = 10; CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls = PLAYERCONTROL_ENABLED; if (CRestart::bFadeInAfterNextArrest) { TheCamera.SetFadeColour(0, 0, 0); TheCamera.Fade(4.0f, FADE_IN); - } else CRestart::bFadeInAfterNextArrest = true; + } else + CRestart::bFadeInAfterNextArrest = true; } break; case WBSTATE_FAILED_CRITICAL_MISSION: @@ -233,7 +296,8 @@ CGameLogic::Update() TheCamera.SetMotionBlur(0, 0, 0, 0, MBLUR_NONE); CPad::GetPad(0)->StopShaking(0); CReferences::RemoveReferencesToPlayer(); - CCarCtrl::CountDownToCarsAtStart = 2; + CPopulation::m_CountDownToPedsAtStart = 10; + CCarCtrl::CountDownToCarsAtStart = 10; CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls = PLAYERCONTROL_ENABLED; TheCamera.SetFadeColour(0, 0, 0); TheCamera.Fade(4.0f, FADE_IN); @@ -247,11 +311,14 @@ CGameLogic::Update() void CGameLogic::RestorePlayerStuffDuringResurrection(CPlayerPed *pPlayerPed, CVector pos, float angle) { - pPlayerPed->m_fHealth = 100.0f; + ClearShortCut(); + CPlayerInfo* pPlayerInfo = pPlayerPed->GetPlayerInfoForThisPlayerPed(); + pPlayerPed->m_fHealth = pPlayerInfo->m_nMaxHealth; pPlayerPed->m_fArmour = 0.0f; pPlayerPed->bIsVisible = true; pPlayerPed->m_bloodyFootprintCountOrDeathTime = 0; pPlayerPed->bDoBloodyFootprints = false; + //TODO(MIAMI): clear drunk stuff pPlayerPed->ClearAdrenaline(); pPlayerPed->m_fCurrentStamina = pPlayerPed->m_fMaxStamina; if (pPlayerPed->m_pFire) @@ -260,27 +327,258 @@ CGameLogic::RestorePlayerStuffDuringResurrection(CPlayerPed *pPlayerPed, CVector pPlayerPed->m_pMyVehicle = nil; pPlayerPed->m_pVehicleAnim = nil; pPlayerPed->m_pWanted->Reset(); + pPlayerPed->bCancelEnteringCar = false; pPlayerPed->RestartNonPartialAnims(); - pPlayerPed->GetPlayerInfoForThisPlayerPed()->MakePlayerSafe(false); + pPlayerInfo->MakePlayerSafe(false); pPlayerPed->bRemoveFromWorld = false; pPlayerPed->ClearWeaponTarget(); pPlayerPed->SetInitialState(); CCarCtrl::ClearInterestingVehicleList(); - - pos.z += 1.0f; - pPlayerPed->Teleport(pos); - pPlayerPed->SetMoveSpeed(CVector(0.0f, 0.0f, 0.0f)); - + pPlayerPed->Teleport(pos + CVector(0.0f, 0.0f, 1.0f)); + pPlayerPed->SetMoveSpeed(0.0f, 0.0f, 0.0f); pPlayerPed->m_fRotationCur = DEGTORAD(angle); pPlayerPed->m_fRotationDest = pPlayerPed->m_fRotationCur; pPlayerPed->SetHeading(pPlayerPed->m_fRotationCur); CTheScripts::ClearSpaceForMissionEntity(pos, pPlayerPed); CWorld::ClearExcitingStuffFromArea(pos, 4000.0, 1); pPlayerPed->RestoreHeadingRate(); + CGame::currArea = AREA_MAIN_MAP; + //CStreaming::RemoveBuildingsNotInArea(0); // TODO(MIAMI) TheCamera.SetCameraDirectlyInFrontForFollowPed_CamOnAString(); + TheCamera.Restore(); CReferences::RemoveReferencesToPlayer(); CGarages::PlayerArrestedOrDied(); CStats::CheckPointReachedUnsuccessfully(); CWorld::Remove(pPlayerPed); CWorld::Add(pPlayerPed); + //CHud::ResetWastedText() // TODO(MIAMI) + CStreaming::StreamZoneModels(pos); + clearWaterDrop = true; +} + +void +CGameLogic::ClearShortCut() +{ + if (pShortCutTaxi) { + if (pShortCutTaxi->VehicleCreatedBy == MISSION_VEHICLE) { + pShortCutTaxi->VehicleCreatedBy = RANDOM_VEHICLE; + --CCarCtrl::NumMissionCars; + ++CCarCtrl::NumRandomCars; + } + CRadar::ClearBlipForEntity(BLIP_CAR, CPools::GetVehiclePool()->GetIndex(pShortCutTaxi)); + pShortCutTaxi = nil; + } + CPad::GetPad(0)->SetEnablePlayerControls(PLAYERCONTROL_SHORTCUT_TAXI); +} + +void +CGameLogic::SetUpShortCut(CVector vStartPos, float fStartAngle, CVector vEndPos, float fEndAngle) +{ + ClearShortCut(); + ShortCutState = SHORTCUT_INIT; + ShortCutStart = vStartPos; + ShortCutStartOrientation = fStartAngle; + ShortCutDestination = vEndPos; + ShortCutDestinationOrientation = fEndAngle; + CStreaming::RequestModel(MI_KAUFMAN, 0); +} + +void +CGameLogic::AbandonShortCutIfTaxiHasBeenMessedWith() +{ + if (!pShortCutTaxi) + return; + if (pShortCutTaxi->pDriver == nil || + pShortCutTaxi->pDriver->DyingOrDead() || + pShortCutTaxi->pDriver->GetPedState() == PED_DRAG_FROM_CAR || + pShortCutTaxi->pDriver->GetPedState() == PED_ON_FIRE || + pShortCutTaxi->pDriver->m_objective == OBJECTIVE_LEAVE_CAR_AND_DIE || + pShortCutTaxi->m_fHealth < 250.0f || + pShortCutTaxi->bRenderScorched) + ClearShortCut(); +} + +void +CGameLogic::AbandonShortCutIfPlayerMilesAway() +{ + if (!pShortCutTaxi) + return; + if ((FindPlayerCoors() - pShortCutTaxi->GetPosition()).Magnitude() > 120.0f) + ClearShortCut(); +} + +void +CGameLogic::UpdateShortCut() +{ + switch (ShortCutState) { + case SHORTCUT_INIT: + if (!CStreaming::HasModelLoaded(MI_KAUFMAN)) { + CStreaming::RequestModel(MI_KAUFMAN, 0); + return; + } + pShortCutTaxi = new CAutomobile(MI_KAUFMAN, RANDOM_VEHICLE); + if (!pShortCutTaxi) + return; + pShortCutTaxi->SetPosition(ShortCutStart); + pShortCutTaxi->SetHeading(DEGTORAD(ShortCutStartOrientation)); + pShortCutTaxi->PlaceOnRoadProperly(); + pShortCutTaxi->SetStatus(STATUS_PHYSICS); + pShortCutTaxi->AutoPilot.m_nCarMission = MISSION_STOP_FOREVER; + pShortCutTaxi->AutoPilot.m_nCruiseSpeed = 0; + pShortCutTaxi->SetUpDriver(); + pShortCutTaxi->VehicleCreatedBy = MISSION_VEHICLE; + ++CCarCtrl::NumMissionCars; + --CCarCtrl::NumRandomCars; + CTheScripts::ClearSpaceForMissionEntity(ShortCutStart, pShortCutTaxi); + CWorld::Add(pShortCutTaxi); + CRadar::SetEntityBlip(BLIP_CAR, CPools::GetVehiclePool()->GetIndex(pShortCutTaxi), 0, BLIP_DISPLAY_MARKER_ONLY); + ShortCutState = SHORTCUT_IDLE; + break; + case SHORTCUT_IDLE: + if (FindPlayerPed()->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && FindPlayerPed()->m_carInObjective == pShortCutTaxi) { + CPad::GetPad(0)->SetDisablePlayerControls(PLAYERCONTROL_SHORTCUT_TAXI); + FindPlayerPed()->SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, pShortCutTaxi); + ShortCutState = SHORTCUT_GETTING_IN; + } + AbandonShortCutIfTaxiHasBeenMessedWith(); + AbandonShortCutIfPlayerMilesAway(); + break; + case SHORTCUT_GETTING_IN: + if (pShortCutTaxi->pPassengers[0] == FindPlayerPed() || + pShortCutTaxi->pPassengers[1] == FindPlayerPed() || + pShortCutTaxi->pPassengers[2] == FindPlayerPed()) { + pShortCutTaxi->AutoPilot.m_nTempAction = TEMPACT_GOFORWARD; + pShortCutTaxi->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 2500; + TheCamera.SetFadeColour(0, 0, 0); + TheCamera.Fade(2.5f, 0); + ShortCutState = SHORTCUT_TRANSITION; + ShortCutTimer = CTimer::GetTimeInMilliseconds() + 3000; + CMessages::AddBigMessage(TheText.Get("TAXI"), 4500, 1); + } + AbandonShortCutIfTaxiHasBeenMessedWith(); + break; + case SHORTCUT_TRANSITION: + if (CTimer::GetTimeInMilliseconds() > ShortCutTimer) { + CTimer::Suspend(); + CColStore::RequestCollision(ShortCutDestination); + CStreaming::LoadSceneCollision(ShortCutDestination); + CStreaming::LoadScene(ShortCutDestination); + CTheScripts::ClearSpaceForMissionEntity(ShortCutDestination, pShortCutTaxi); + pShortCutTaxi->Teleport(ShortCutDestination); + pShortCutTaxi->SetHeading(DEGTORAD(ShortCutDestinationOrientation)); + pShortCutTaxi->PlaceOnRoadProperly(); + pShortCutTaxi->SetMoveSpeed(pShortCutTaxi->GetForward() * 0.4f); + ShortCutTimer = CTimer::GetTimeInMilliseconds() + 1500; + TheCamera.SetFadeColour(0, 0, 0); + TheCamera.Fade(1.0f, 1); + ShortCutState = SHORTCUT_ARRIVING; + CTimer::Resume(); + } + break; + case SHORTCUT_ARRIVING: + if (CTimer::GetTimeInMilliseconds() > ShortCutTimer) { + CWorld::Players[CWorld::PlayerInFocus].m_nMoney = Max(0, CWorld::Players[CWorld::PlayerInFocus].m_nMoney - SHORTCUT_TAXI_COST); + FindPlayerPed()->SetObjective(OBJECTIVE_LEAVE_VEHICLE, pShortCutTaxi); + FindPlayerPed()->m_carInObjective = pShortCutTaxi; + ShortCutState = SHORTCUT_GETTING_OUT; + } + AbandonShortCutIfTaxiHasBeenMessedWith(); + break; + case SHORTCUT_GETTING_OUT: + if (pShortCutTaxi->pPassengers[0] != FindPlayerPed() && + pShortCutTaxi->pPassengers[1] != FindPlayerPed() && + pShortCutTaxi->pPassengers[2] != FindPlayerPed()) { + CPad::GetPad(0)->SetEnablePlayerControls(PLAYERCONTROL_SHORTCUT_TAXI); + pShortCutTaxi->AutoPilot.m_nCarMission = MISSION_CRUISE; + pShortCutTaxi->AutoPilot.m_nCruiseSpeed = 18; + CCarCtrl::JoinCarWithRoadSystem(pShortCutTaxi); + pShortCutTaxi->VehicleCreatedBy = RANDOM_VEHICLE; + ++CCarCtrl::NumRandomCars; + --CCarCtrl::NumMissionCars; + CRadar::ClearBlipForEntity(BLIP_CAR, CPools::GetVehiclePool()->GetIndex(pShortCutTaxi)); + ShortCutState = SHORTCUT_NONE; + pShortCutTaxi = nil; + } + AbandonShortCutIfTaxiHasBeenMessedWith(); + break; + } +} + +void +CGameLogic::AddShortCutPointAfterDeath(CVector point, float angle) +{ + if (NumAfterDeathStartPoints >= NUM_SHORTCUT_START_POINTS) + return; + AfterDeathStartPoints[NumAfterDeathStartPoints] = point; + AfterDeathStartPointOrientation[NumAfterDeathStartPoints] = angle; + NumAfterDeathStartPoints++; +} + +void +CGameLogic::AddShortCutDropOffPointForMission(CVector point, float angle) +{ + ShortCutDropOffForMission = point; + ShortCutDropOffOrientationForMission = angle; + MissionDropOffReadyToBeUsed = true; +} + +void +CGameLogic::RemoveShortCutDropOffPointForMission() +{ + MissionDropOffReadyToBeUsed = false; +} + +void +CGameLogic::AfterDeathArrestSetUpShortCutTaxi() +{ + if (!MissionDropOffReadyToBeUsed) + return; + int nClosestPoint = -1; + float fDistanceToPoint = 999999.9f; + for (int i = 0; i < NUM_SHORTCUT_START_POINTS; i++) { + float dist = (AfterDeathStartPoints[i] - FindPlayerCoors()).Magnitude(); + if (dist < fDistanceToPoint) { + fDistanceToPoint = dist; + nClosestPoint = i; + } + } + if (fDistanceToPoint < 100.0f) + SetUpShortCut(AfterDeathStartPoints[nClosestPoint], + AfterDeathStartPointOrientation[nClosestPoint], + ShortCutDropOffForMission, + ShortCutDropOffOrientationForMission); + MissionDropOffReadyToBeUsed = false; +} + +void +CGameLogic::Save(uint8* buf, uint32* size) +{ +INITSAVEBUF + WriteSaveBuf(buf, NumAfterDeathStartPoints); + *size += sizeof(NumAfterDeathStartPoints); + for (int i = 0; i < NUM_SHORTCUT_START_POINTS; i++) { + WriteSaveBuf(buf, AfterDeathStartPoints[i].x); + *size += sizeof(AfterDeathStartPoints[i].x); + WriteSaveBuf(buf, AfterDeathStartPoints[i].y); + *size += sizeof(AfterDeathStartPoints[i].y); + WriteSaveBuf(buf, AfterDeathStartPoints[i].z); + *size += sizeof(AfterDeathStartPoints[i].z); + WriteSaveBuf(buf, AfterDeathStartPointOrientation[i]); + *size += sizeof(AfterDeathStartPointOrientation[i]); + } +VALIDATESAVEBUF(*size) +} + +void +CGameLogic::Load(uint8* buf, uint32 size) +{ +INITSAVEBUF + NumAfterDeathStartPoints = ReadSaveBuf<uint32>(buf); + for (int i = 0; i < NUM_SHORTCUT_START_POINTS; i++) { + AfterDeathStartPoints[i].x = ReadSaveBuf<float>(buf); + AfterDeathStartPoints[i].y = ReadSaveBuf<float>(buf); + AfterDeathStartPoints[i].z = ReadSaveBuf<float>(buf); + AfterDeathStartPointOrientation[i] = ReadSaveBuf<float>(buf); + } +VALIDATESAVEBUF(size) } diff --git a/src/control/GameLogic.h b/src/control/GameLogic.h index 43e244a3..9b774cc7 100644 --- a/src/control/GameLogic.h +++ b/src/control/GameLogic.h @@ -1,13 +1,51 @@ #pragma once +class CAutomobile; + class CGameLogic { public: + enum { + SHORTCUT_NONE = 0, + SHORTCUT_INIT, + SHORTCUT_IDLE, + SHORTCUT_GETTING_IN, + SHORTCUT_TRANSITION, + SHORTCUT_ARRIVING, + SHORTCUT_GETTING_OUT + }; + static void InitAtStartOfGame(); static void PassTime(uint32 time); static void SortOutStreamingAndMemory(const CVector &pos); static void Update(); static void RestorePlayerStuffDuringResurrection(class CPlayerPed *pPlayerPed, CVector pos, float angle); + static void ClearShortCut(); + static void SetUpShortCut(CVector, float, CVector, float); + static void AbandonShortCutIfTaxiHasBeenMessedWith(); + static void AbandonShortCutIfPlayerMilesAway(); + static void UpdateShortCut(); + static void AddShortCutPointAfterDeath(CVector, float); + static void AddShortCutDropOffPointForMission(CVector, float); + static void RemoveShortCutDropOffPointForMission(); + static void AfterDeathArrestSetUpShortCutTaxi(); + + static void Save(uint8*, uint32*); + static void Load(uint8*, uint32); + static uint8 ActivePlayers; + static uint8 ShortCutState; + static CAutomobile* pShortCutTaxi; + static uint32 NumAfterDeathStartPoints; + static CVector ShortCutStart; + static float ShortCutStartOrientation; + static CVector ShortCutDestination; + static float ShortCutDestinationOrientation; + static uint32 ShortCutTimer; + static CVector AfterDeathStartPoints[NUM_SHORTCUT_START_POINTS]; + static float AfterDeathStartPointOrientation[NUM_SHORTCUT_START_POINTS]; + static CVector ShortCutDropOffForMission; + static float ShortCutDropOffOrientationForMission; + static bool MissionDropOffReadyToBeUsed; };
\ No newline at end of file diff --git a/src/control/PathFind.h b/src/control/PathFind.h index 7abc455a..e481f4c6 100644 --- a/src/control/PathFind.h +++ b/src/control/PathFind.h @@ -5,6 +5,8 @@ class CVehicle; class CPtrList; +#define LANE_WIDTH 5.0f + enum { NodeTypeExtern = 1, @@ -85,6 +87,8 @@ struct CPathNode float GetX(void) { return x/8.0f; } float GetY(void) { return y/8.0f; } float GetZ(void) { return z/8.0f; } + bool HasDivider(void) { return width != 0; } + float GetDividerWidth(void) { return width/(2*8.0f); } CPathNode *GetPrev(void); CPathNode *GetNext(void); void SetPrev(CPathNode *node); @@ -120,7 +124,7 @@ struct CCarPathLink float GetY(void) { return y/8.0f; } float GetDirX(void) { return dirX/100.0f; } float GetDirY(void) { return dirY/100.0f; } - float GetLaneOffset(void) { return width/80.0f; } + float GetLaneOffset(void) { return width/(2*8.0f*LANE_WIDTH); } float OneWayLaneOffset() { diff --git a/src/control/RoadBlocks.cpp b/src/control/RoadBlocks.cpp index a26e19f5..5d466be2 100644 --- a/src/control/RoadBlocks.cpp +++ b/src/control/RoadBlocks.cpp @@ -14,14 +14,18 @@ #include "Camera.h" #include "CarCtrl.h" #include "General.h" +#include "Object.h" + +//--MIAMI: file done #define ROADBLOCKDIST (90.0f) +#define ROADBLOCK_OBJECT_WIDTH (4.0f) int16 CRoadBlocks::NumRoadBlocks; int16 CRoadBlocks::RoadBlockNodes[NUMROADBLOCKS]; bool CRoadBlocks::InOrOut[NUMROADBLOCKS]; +CScriptRoadblock CRoadBlocks::aScriptRoadBlocks[NUM_SCRIPT_ROADBLOCKS]; -//--MIAMI: TODO void CRoadBlocks::Init(void) { @@ -43,7 +47,7 @@ CRoadBlocks::Init(void) } } - // TODO(MIAMI): script roadblocks + ClearScriptRoadBlocks(); } void @@ -83,14 +87,11 @@ CRoadBlocks::GenerateRoadBlockCopsForCar(CVehicle* pVehicle, int32 roadBlockType pCopPed->SetCurrentWeapon(WEAPONTYPE_COLT45); CPedPlacement::FindZCoorForPed(&posForZ); pCopPed->SetPosition(posForZ); - CVector vecSavedPos = pCopPed->GetPosition(); - pCopPed->m_matrix.SetRotate(0.0f, 0.0f, -HALFPI); - pCopPed->m_matrix.GetPosition() += vecSavedPos; + pCopPed->SetOrientation(0.0f, 0.0f, -HALFPI); pCopPed->m_bIsDisabledCop = true; pCopPed->SetIdle(); pCopPed->bKindaStayInSamePlace = true; pCopPed->bNotAllowedToDuck = false; -// pCopPed->m_nRoadblockNode = roadBlockNode; pCopPed->bCrouchWhenShooting = roadBlockType != 2; if (pEntityToAttack) { pCopPed->m_pPointGunAt = pEntityToAttack; @@ -105,99 +106,178 @@ CRoadBlocks::GenerateRoadBlockCopsForCar(CVehicle* pVehicle, int32 roadBlockType } } -//--MIAMI: TODO: implement this void CRoadBlocks::GenerateRoadBlocks(void) { - CMatrix offsetMatrix; + CMatrix tmp1, tmp2; + static int16 unk; uint32 frame = CTimer::GetFrameCounter() & 0xF; int16 nRoadblockNode = (int16)(NUMROADBLOCKS * frame) / 16; const int16 maxRoadBlocks = (int16)(NUMROADBLOCKS * (frame + 1)) / 16; for (; nRoadblockNode < Min(NumRoadBlocks, maxRoadBlocks); nRoadblockNode++) { - CVector2D vecDistance = FindPlayerCoors() - ThePaths.m_pathNodes[nRoadblockNode].GetPosition(); + int16 node = RoadBlockNodes[nRoadblockNode]; + CVector2D vecDistance = FindPlayerCoors() - ThePaths.m_pathNodes[node].GetPosition(); if (vecDistance.x > -ROADBLOCKDIST && vecDistance.x < ROADBLOCKDIST && vecDistance.y > -ROADBLOCKDIST && vecDistance.y < ROADBLOCKDIST && vecDistance.Magnitude() < ROADBLOCKDIST) { if (!InOrOut[nRoadblockNode]) { InOrOut[nRoadblockNode] = true; if (FindPlayerVehicle() && (CGeneral::GetRandomNumber() & 0x7F) < FindPlayerPed()->m_pWanted->m_RoadblockDensity) { -#ifndef MIAMI - CWanted *pPlayerWanted = FindPlayerPed()->m_pWanted; - float fMapObjectRadius = 2.0f * mapObject->GetColModel()->boundingBox.max.x; - int32 vehicleId = MI_POLICE; - if (pPlayerWanted->AreArmyRequired()) - vehicleId = MI_BARRACKS; - else if (pPlayerWanted->AreFbiRequired()) - vehicleId = MI_FBICAR; - else if (pPlayerWanted->AreSwatRequired()) - vehicleId = MI_ENFORCER; - if (!CStreaming::HasModelLoaded(vehicleId)) - vehicleId = MI_POLICE; - CColModel *pVehicleColModel = CModelInfo::GetModelInfo(vehicleId)->GetColModel(); - float fModelRadius = 2.0f * pVehicleColModel->boundingSphere.radius + 0.25f; - int16 radius = (int16)(fMapObjectRadius / fModelRadius); - if (radius > 0 && radius < 6) { - CVector2D vecDistanceToCamera = TheCamera.GetPosition() - mapObject->GetPosition(); - float fDotProduct = DotProduct2D(vecDistanceToCamera, mapObject->GetForward()); - float fOffset = 0.5f * fModelRadius * (float)(radius - 1); - for (int16 i = 0; i < radius; i++) { - uint8 nRoadblockType = fDotProduct < 0.0f; - if (CGeneral::GetRandomNumber() & 1) { - offsetMatrix.SetRotateZ(((CGeneral::GetRandomNumber() & 0xFF) - 128.0f) * 0.003f + HALFPI); - } - else { - nRoadblockType = !nRoadblockType; - offsetMatrix.SetRotateZ(((CGeneral::GetRandomNumber() & 0xFF) - 128.0f) * 0.003f - HALFPI); - } - if (ThePaths.m_objectFlags[RoadBlockObjects[nRoadblockNode]] & ObjectEastWest) - offsetMatrix.GetPosition() = CVector(0.0f, -fOffset, 0.6f); - else - offsetMatrix.GetPosition() = CVector(-fOffset, 0.0f, 0.6f); - CMatrix vehicleMatrix = mapObject->m_matrix * offsetMatrix; - float fModelRadius = CModelInfo::GetModelInfo(vehicleId)->GetColModel()->boundingSphere.radius - 0.25f; - int16 colliding = 0; - CWorld::FindObjectsKindaColliding(vehicleMatrix.GetPosition(), fModelRadius, 0, &colliding, 2, nil, false, true, true, false, false); - if (!colliding) { - CAutomobile *pVehicle = new CAutomobile(vehicleId, RANDOM_VEHICLE); - pVehicle->SetStatus(STATUS_ABANDONED); - // pVehicle->GetHeightAboveRoad(); // called but return value is ignored? - vehicleMatrix.GetPosition().z += fModelRadius - 0.6f; - pVehicle->m_matrix = vehicleMatrix; - pVehicle->PlaceOnRoadProperly(); - pVehicle->bIsStatic = false; - pVehicle->m_matrix.UpdateRW(); - pVehicle->m_nDoorLock = CARLOCK_UNLOCKED; - CCarCtrl::JoinCarWithRoadSystem(pVehicle); - pVehicle->bIsLocked = false; - pVehicle->AutoPilot.m_nCarMission = MISSION_NONE; - pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE; - pVehicle->AutoPilot.m_nCurrentLane = 0; - pVehicle->AutoPilot.m_nNextLane = 0; - pVehicle->AutoPilot.m_fMaxTrafficSpeed = 0.0f; - pVehicle->AutoPilot.m_nCruiseSpeed = 0.0f; - pVehicle->bExtendedRange = true; - if (pVehicle->UsesSiren(pVehicle->GetModelIndex()) && CGeneral::GetRandomNumber() & 1) - pVehicle->m_bSirenOrAlarm = true; - if (pVehicle->GetForward().z > 0.94f) { - CVisibilityPlugins::SetClumpAlpha(pVehicle->GetClump(), 0); - CWorld::Add(pVehicle); - pVehicle->bCreateRoadBlockPeds = true; - pVehicle->m_nRoadblockType = nRoadblockType; - pVehicle->m_nRoadblockNode = nRoadblockNode; - } - else { - delete pVehicle; - } - } - } + CCarPathLink* pLink1 = &ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[ThePaths.m_pathNodes[node].firstLink]]; + CCarPathLink* pLink2 = &ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[ThePaths.m_pathNodes[node].firstLink + 1]]; + int lanes = Min(pLink1->numRightLanes + pLink1->numLeftLanes, pLink2->numLeftLanes + pLink2->numRightLanes); + float length = LANE_WIDTH * (lanes + 1); + CVector forward(pLink2->GetY() - pLink1->GetY(), -(pLink2->GetX() - pLink1->GetX()), 0.0f); + forward.Normalise(); + if (ThePaths.m_pathNodes[node].HasDivider()) { + CreateRoadBlockBetween2Points( + ThePaths.m_pathNodes[node].GetPosition() + (length * 0.5f + ThePaths.m_pathNodes[node].GetDividerWidth()) * forward, + ThePaths.m_pathNodes[node].GetPosition() + ThePaths.m_pathNodes[node].GetDividerWidth() * forward); + CreateRoadBlockBetween2Points( + ThePaths.m_pathNodes[node].GetPosition() - ThePaths.m_pathNodes[node].GetDividerWidth() * forward, + ThePaths.m_pathNodes[node].GetPosition() - (length * 0.5f + ThePaths.m_pathNodes[node].GetDividerWidth()) * forward); + } + else { + CreateRoadBlockBetween2Points( + ThePaths.m_pathNodes[node].GetPosition() + (length * 0.5f) * forward, + ThePaths.m_pathNodes[node].GetPosition() - (length * 0.5f) * forward); } -#endif } } - } else { + } + else { InOrOut[nRoadblockNode] = false; } } + int i = CTimer::GetFrameCounter() & 0xF; + if (!aScriptRoadBlocks[i].m_bInUse) + return; + if ((aScriptRoadBlocks[i].GetPosition() - FindPlayerCoors()).Magnitude() < 100.0f) { + CreateRoadBlockBetween2Points(aScriptRoadBlocks[i].m_vInf, aScriptRoadBlocks[i].m_vSup); + aScriptRoadBlocks[i].m_bInUse = false; + } +} - // TODO(MIAMI): script roadblocks +void +CRoadBlocks::ClearScriptRoadBlocks(void) +{ + for (int i = 0; i < NUM_SCRIPT_ROADBLOCKS; i++) + aScriptRoadBlocks[i].m_bInUse = false; +} + +void +CRoadBlocks::RegisterScriptRoadBlock(CVector vInf, CVector vSup) +{ + int32 i; + for (i = 0; i < NUM_SCRIPT_ROADBLOCKS; i++) { + if (!aScriptRoadBlocks[i].m_bInUse) + break; + } + if (i == NUM_SCRIPT_ROADBLOCKS) + return; + aScriptRoadBlocks[i].m_bInUse = true; + aScriptRoadBlocks[i].m_vInf = vInf; + aScriptRoadBlocks[i].m_vSup = vSup; +} + +void +CRoadBlocks::CreateRoadBlockBetween2Points(CVector point1, CVector point2) +{ + CMatrix tmp; + CVector forward = (point2 - point1); + float distBetween = forward.Magnitude(); + CVector pos = (point1 + point2) / 2; + CVector right(forward.y, -forward.x, 0.0f); + forward.Normalise(); + right.Normalise(); + if (DotProduct(FindPlayerCoors() - pos, right) < 0.0f) { + right *= -1.0f; + } + int32 vehicleId = MI_POLICE; + if (FindPlayerPed()->m_pWanted->AreArmyRequired()) + vehicleId = MI_BARRACKS; + else if (FindPlayerPed()->m_pWanted->AreFbiRequired()) + vehicleId = MI_FBICAR; + else if (FindPlayerPed()->m_pWanted->AreSwatRequired()) + vehicleId = MI_ENFORCER; + if (!CStreaming::HasModelLoaded(vehicleId)) + vehicleId = MI_POLICE; + CColModel* pVehicleColModel = CModelInfo::GetModelInfo(vehicleId)->GetColModel(); + float fModelRadius = 2.0f * pVehicleColModel->boundingSphere.radius + 0.25f; + int16 numRoadblockVehicles = Min(6, (int16)(distBetween / fModelRadius)); + for (int16 i = 0; i < numRoadblockVehicles; i++) { + float offset = fModelRadius * (i - numRoadblockVehicles / 2); + tmp.SetTranslate(0.0f, 0.0f, 0.0f); + tmp.GetRight() = CVector(forward.y, -forward.x, 0.0f); + tmp.GetForward() = forward; + tmp.GetUp() = CVector(0.0f, 0.0f, 1.0f); + tmp.RotateZ(((CGeneral::GetRandomNumber() & 0xFF) - 128.0f) * 0.003f); + if (CGeneral::GetRandomNumber() & 1) + tmp.RotateZ(((CGeneral::GetRandomNumber() & 0xFF) - 128.0f) * 0.003f + 3.1416f); + tmp.SetTranslateOnly(offset * forward + pos); + tmp.GetPosition().z += 0.6f; + float fModelRadius = CModelInfo::GetModelInfo(vehicleId)->GetColModel()->boundingSphere.radius - 0.25f; + int16 colliding = 0; + CWorld::FindObjectsKindaColliding(tmp.GetPosition(), fModelRadius, 0, &colliding, 2, nil, false, true, true, false, false); + if (!colliding) { + CAutomobile* pVehicle = new CAutomobile(vehicleId, RANDOM_VEHICLE); + pVehicle->SetStatus(STATUS_ABANDONED); + // pVehicle->GetHeightAboveRoad(); // called but return value is ignored? + tmp.GetPosition().z += fModelRadius - 0.6f; + pVehicle->m_matrix = tmp; + pVehicle->PlaceOnRoadProperly(); + pVehicle->bIsStatic = false; + pVehicle->m_matrix.UpdateRW(); + pVehicle->m_nDoorLock = CARLOCK_UNLOCKED; + CCarCtrl::JoinCarWithRoadSystem(pVehicle); + pVehicle->bIsLocked = false; + pVehicle->AutoPilot.m_nCarMission = MISSION_NONE; + pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE; + pVehicle->AutoPilot.m_nNextLane = pVehicle->AutoPilot.m_nCurrentLane = 0; + pVehicle->AutoPilot.m_nCruiseSpeed = pVehicle->AutoPilot.m_fMaxTrafficSpeed = 0; + pVehicle->bExtendedRange = true; + if (pVehicle->UsesSiren(pVehicle->GetModelIndex()) && CGeneral::GetRandomNumber() & 1) + pVehicle->m_bSirenOrAlarm = true; + if (pVehicle->GetUp().z > 0.94f) { + CVisibilityPlugins::SetClumpAlpha(pVehicle->GetClump(), 0); + CWorld::Add(pVehicle); + pVehicle->bCreateRoadBlockPeds = true; + pVehicle->m_nRoadblockType = DotProduct(pVehicle->GetRight(), pVehicle->GetPosition() - FindPlayerCoors()) >= 0.0f; + pVehicle->m_nSetPieceExtendedRangeTime = CTimer::GetTimeInMilliseconds() + 7000; + } + else { + delete pVehicle; + } + } + } + int numBarriers = distBetween / ROADBLOCK_OBJECT_WIDTH; + CStreaming::RequestModel(MI_ROADWORKBARRIER1, STREAMFLAGS_DONT_REMOVE); + if (!CStreaming::HasModelLoaded(MI_ROADWORKBARRIER1)) + return; + for (int i = 0; i < numBarriers; i++) { + float offset = ROADBLOCK_OBJECT_WIDTH * (i - numBarriers / 2); + tmp.SetTranslate(0.0f, 0.0f, 0.0f); + tmp.GetRight() = CVector(forward.y, -forward.x, 0.0f); + tmp.GetForward() = forward; + tmp.GetUp() = CVector(0.0f, 0.0f, 1.0f); + tmp.RotateZ(((CGeneral::GetRandomNumber() & 0xFF) - 128.0f) * 0.003f); + tmp.SetTranslateOnly(5.0f * right + offset * forward + pos); + tmp.GetPosition().x += (CGeneral::GetRandomNumber() & 0xF) * 0.1f; + tmp.GetPosition().y += (CGeneral::GetRandomNumber() & 0xF) * 0.1f; + bool found; + tmp.GetPosition().z = CWorld::FindGroundZFor3DCoord(tmp.GetPosition().x, tmp.GetPosition().y, tmp.GetPosition().z + 2.0f, &found); + if (!found) + continue; + int16 colliding = 0; + CBaseModelInfo* pMI = CModelInfo::GetModelInfo(MI_ROADWORKBARRIER1); + tmp.GetPosition().z -= pMI->GetColModel()->boundingBox.min.z; + CWorld::FindObjectsKindaColliding(tmp.GetPosition(), pMI->GetColModel()->boundingSphere.radius, 0, &colliding, 2, nil, false, true, true, false, false); + if (colliding == 0) { + CObject* pObject = new CObject(MI_ROADWORKBARRIER1, true); + pObject->GetMatrix() = tmp; + pObject->ObjectCreatedBy = TEMP_OBJECT; + pObject->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 600000; + CWorld::Add(pObject); + } + } } diff --git a/src/control/RoadBlocks.h b/src/control/RoadBlocks.h index c8469ba5..ef614950 100644 --- a/src/control/RoadBlocks.h +++ b/src/control/RoadBlocks.h @@ -3,18 +3,28 @@ class CVehicle; +class CScriptRoadblock +{ +public: + CVector m_vInf; + CVector m_vSup; + bool m_bInUse; + CVector GetPosition() { return (m_vInf + m_vSup) / 2; } +}; + class CRoadBlocks { public: static int16 NumRoadBlocks; -#ifndef MIAMI - static int16 RoadBlockObjects[NUMROADBLOCKS]; -#else static int16 RoadBlockNodes[NUMROADBLOCKS]; -#endif static bool InOrOut[NUMROADBLOCKS]; + static CScriptRoadblock aScriptRoadBlocks[NUM_SCRIPT_ROADBLOCKS]; static void Init(void); static void GenerateRoadBlockCopsForCar(CVehicle* pVehicle, int32 roadBlockType); static void GenerateRoadBlocks(void); + + static void CreateRoadBlockBetween2Points(CVector, CVector); + static void RegisterScriptRoadBlock(CVector, CVector); + static void ClearScriptRoadBlocks(); }; diff --git a/src/control/Script.cpp b/src/control/Script.cpp index f3583cbe..bfc778ba 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -26,6 +26,7 @@ #include "Fire.h" #include "Frontend.h" #include "Gangs.h" +#include "GameLogic.h" #include "Garages.h" #include "General.h" #include "HandlingMgr.h" @@ -272,7 +273,7 @@ void CMissionCleanup::Process() CPed::nThreatReactionRangeMultiplier = 1; CPed::nEnterCarRangeMultiplier = 1; FindPlayerPed()->m_pWanted->m_fCrimeSensitivity = 1.0f; - //CRoadBlocks::ClearScriptRoadblocks() // TODO(MIAMI) + CRoadBlocks::ClearScriptRoadBlocks(); CRouteNode::Initialise(); if (!CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle) TheCamera.Restore(); @@ -300,7 +301,7 @@ void CMissionCleanup::Process() //DMAudio::ShutUpPlayerTalking(0); CVehicle::bDisableRemoteDetonation = false; CVehicle::bDisableRemoteDetonationOnContact = false; - //CGameLogic::ClearShortCut(); // TODO(MIAMI) + CGameLogic::ClearShortCut(); CTheScripts::RiotIntensity = 0; CTheScripts::StoreVehicleIndex = -1; CTheScripts::StoreVehicleWasRandom = true; @@ -6506,7 +6507,7 @@ int8 CRunningScript::ProcessCommands700To799(int32 command) ++CStats::MissionsPassed; CStats::CheckPointReachedSuccessfully(); CTheScripts::LastMissionPassedTime = CTimer::GetTimeInMilliseconds(); - //CGameLogic::RemoveShortCutDropOffPointForMission() // TODO(MIAMI) + CGameLogic::RemoveShortCutDropOffPointForMission(); return 0; } case COMMAND_SET_CHAR_RUNNING: @@ -7153,13 +7154,8 @@ int8 CRunningScript::ProcessCommands800To899(int32 command) CTheScripts::ReadTextLabelFromScript(&m_nIp, name); for (int i = 0; i < KEY_LENGTH_IN_SCRIPT; i++) name[i] = tolower(name[i]); - int mi = pPed->GetModelIndex(); - pPed->DeleteRwObject(); - if (pPed->IsPlayer()) - mi = 0; - CStreaming::RequestSpecialModel(mi, name, STREAMFLAGS_DEPENDENCY | STREAMFLAGS_SCRIPTOWNED); m_nIp += KEY_LENGTH_IN_SCRIPT; - CWorld::Remove(pPed); + pPed->Undress(name); return 0; } case COMMAND_DRESS_CHAR: @@ -7167,10 +7163,7 @@ int8 CRunningScript::ProcessCommands800To899(int32 command) CollectParameters(&m_nIp, 1); CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(pPed); - int mi = pPed->GetModelIndex(); - pPed->m_modelIndex = -1; - pPed->SetModelIndex(mi); - CWorld::Add(pPed); + pPed->Dress(); return 0; } /* @@ -9045,7 +9038,7 @@ int8 CRunningScript::ProcessCommands1000To1099(int32 command) pMissionScript->m_bIsMissionScript = true; pMissionScript->m_bMissionFlag = true; CTheScripts::bAlreadyRunningAMissionScript = true; - //CGameLogic::ClearShortcut(); // TODO(MIAMI) + CGameLogic::ClearShortCut(); return 0; } case COMMAND_SET_OBJECT_DRAW_LAST: @@ -10533,12 +10526,12 @@ int8 CRunningScript::ProcessCommands1200To1299(int32 command) case COMMAND_CREATE_SCRIPT_ROADBLOCK: { CollectParameters(&m_nIp, 6); - debug("CREATE_SCRIPT_ROADBLOCK not implemented\n"); // TODO(MIAMI) + CRoadBlocks::RegisterScriptRoadBlock(*(CVector*)&ScriptParams[0], *(CVector*)&ScriptParams[3]); return 0; } case COMMAND_CLEAR_ALL_SCRIPT_ROADBLOCKS: { - debug("CLEAR_ALL_SCRIPT_ROADBLOCKS not implemented\n"); // TODO(MIAMI) + CRoadBlocks::ClearScriptRoadBlocks(); return 0; } case COMMAND_SET_CHAR_OBJ_WALK_TO_CHAR: @@ -11440,11 +11433,13 @@ int8 CRunningScript::ProcessCommands1300To1399(int32 command) case COMMAND_SET_UP_TAXI_SHORTCUT: { CollectParameters(&m_nIp, 8); - debug("SET_UP_TAXI_SHORTCUT is not implemented\n"); // TODO(MIAMI) + CGameLogic::SetUpShortCut( + *(CVector*)&ScriptParams[0], *(float*)&ScriptParams[3], + *(CVector*)&ScriptParams[4], *(float*)&ScriptParams[7]); return 0; } case COMMAND_CLEAR_TAXI_SHORTCUT: - debug("CLEAR_TAXI_SHORTCUT is not implemented\n"); // TODO(MIAMI) + CGameLogic::ClearShortCut(); return 0; //case COMMAND_SET_CHAR_OBJ_GOTO_CAR_ON_FOOT: //case COMMAND_GET_CLOSEST_WATER_NODE: @@ -11910,13 +11905,13 @@ int8 CRunningScript::ProcessCommands1400To1499(int32 command) case COMMAND_SET_SHORTCUT_PICKUP_POINT: { CollectParameters(&m_nIp, 4); - debug("SET_SHORTCUT_PICKUP_POINT not implemented, skipping\n"); + CGameLogic::AddShortCutPointAfterDeath(*(CVector*)&ScriptParams[0], *(float*)&ScriptParams[3]); return 0; } case COMMAND_SET_SHORTCUT_DROPOFF_POINT_FOR_MISSION: { CollectParameters(&m_nIp, 4); - debug("SET_SHORTCUT_DROPOFF_POINT_FOR_MISSION not implemented, skipping"); + CGameLogic::AddShortCutDropOffPointForMission(*(CVector*)&ScriptParams[0], *(float*)&ScriptParams[3]); return 0; } case COMMAND_GET_RANDOM_ICE_CREAM_CUSTOMER_IN_AREA: @@ -11948,16 +11943,14 @@ int8 CRunningScript::ProcessCommands1400To1499(int32 command) ++CStats::MissionsPassed; CStats::CheckPointReachedSuccessfully(); CTheScripts::LastMissionPassedTime = CTimer::GetTimeInMilliseconds(); - // CGameLogic::RemoveShortCutDropOffPointForMission(); // TODO(MIAMI) + CGameLogic::RemoveShortCutDropOffPointForMission(); + return 0; case COMMAND_IS_PLAYER_IN_SHORTCUT_TAXI: { CollectParameters(&m_nIp, 1); - static bool bShowed = false; - if (!bShowed) { - debug("IS_PLAYER_IN_SHORTCUT_TAXI not implemented, default to FALSE\n"); - bShowed = true; - } - UpdateCompareFlag(false); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + assert(pPed); + UpdateCompareFlag(pPed->bInVehicle && pPed->m_pMyVehicle && pPed->m_pMyVehicle == CGameLogic::pShortCutTaxi); return 0; } case COMMAND_IS_CHAR_DUCKING: @@ -11980,6 +11973,7 @@ int8 CRunningScript::ProcessCommands1400To1499(int32 command) return 0; case COMMAND_IS_AUSTRALIAN_GAME: UpdateCompareFlag(false); // should we make some check? + return 0; case COMMAND_DISARM_CAR_BOMB: { CollectParameters(&m_nIp, 1); diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp index b65b60f3..d9cc5c32 100644 --- a/src/core/Camera.cpp +++ b/src/core/Camera.cpp @@ -3123,7 +3123,7 @@ CCamera::Fade(float timeout, int16 direction) void CCamera::SetFadeColour(uint8 r, uint8 g, uint8 b) { - m_FadeTargetIsSplashScreen = r == 0 && g == 0 && b == 0; + m_FadeTargetIsSplashScreen = r == 2 && g == 2 && b == 2; CDraw::FadeRed = r; CDraw::FadeGreen = g; CDraw::FadeBlue = b; diff --git a/src/core/Fire.cpp b/src/core/Fire.cpp index 933c73da..3752f1ba 100644 --- a/src/core/Fire.cpp +++ b/src/core/Fire.cpp @@ -15,6 +15,7 @@ #include "DamageManager.h" #include "Ped.h" #include "Fire.h" +#include "GameLogic.h" CFireManager gFireManager; @@ -59,6 +60,12 @@ CFire::ProcessFire(void) Extinguish(); return; } +#if defined GTAVC_JP_PATCH && !defined FIX_BUGS + if (m_pEntity == CGameLogic::pShortCutTaxi && CGameLogic::ShortCutState == CGameLogic::SHORTCUT_TRANSITION) { + Extinguish(); + return; + } +#endif if (ped->m_nMoveState != PEDMOVE_RUN) m_vecPos.z -= 1.0f; if (ped->bInVehicle && ped->m_pMyVehicle) { @@ -84,6 +91,12 @@ CFire::ProcessFire(void) Extinguish(); return; } +#ifdef FIX_BUGS + if (m_pEntity == CGameLogic::pShortCutTaxi && CGameLogic::ShortCutState == CGameLogic::SHORTCUT_TRANSITION) { + Extinguish(); + return; + } +#endif if (!m_bIsScriptFire) { fDamageVehicle = 1.2f * CTimer::GetTimeStep(); veh->InflictDamage((CVehicle *)m_pSource, WEAPONTYPE_FLAMETHROWER, fDamageVehicle); diff --git a/src/core/Game.cpp b/src/core/Game.cpp index 9a1c00a7..f401ca3f 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -523,6 +523,7 @@ void CGame::ShutDownForRestart(void) CTheScripts::UndoBuildingSwaps(); CTheScripts::UndoEntityInvisibilitySettings(); CWorld::ClearForRestart(); + CGameLogic::ClearShortCut(); CTimer::Shutdown(); CStreaming::FlushRequestList(); CStreaming::DeleteAllRwObjects(); diff --git a/src/core/Pad.h b/src/core/Pad.h index 46ed9b39..a1461575 100644 --- a/src/core/Pad.h +++ b/src/core/Pad.h @@ -10,6 +10,7 @@ enum { PLAYERCONTROL_DISABLED_20 = 32, // used on CPlayerInfo::MakePlayerSafe PLAYERCONTROL_DISABLED_40 = 64, // used on phone calls PLAYERCONTROL_DISABLED_80 = 128,// used on cutscenes + PLAYERCONTROL_SHORTCUT_TAXI = 256, }; class CControllerState @@ -150,10 +151,10 @@ public: int16 Phase; int16 Mode; int16 ShakeDur; + uint16 DisablePlayerControls; uint8 ShakeFreq; bool bHornHistory[HORNHISTORY_SIZE]; uint8 iCurrHornHistory; - uint8 DisablePlayerControls; int8 bApplyBrakes; char CheatString[12]; int32 LastTimeTouched; @@ -449,9 +450,9 @@ public: int16 GetRightStickY(void) { return NewState.RightStickY; } bool ArePlayerControlsDisabled(void) { return DisablePlayerControls != PLAYERCONTROL_ENABLED; } - void SetDisablePlayerControls(uint8 who) { DisablePlayerControls |= who; } - void SetEnablePlayerControls(uint8 who) { DisablePlayerControls &= ~who; } - bool IsPlayerControlsDisabledBy(uint8 who) { return DisablePlayerControls & who; } + void SetDisablePlayerControls(uint16 who) { DisablePlayerControls |= who; } + void SetEnablePlayerControls(uint16 who) { DisablePlayerControls &= ~who; } + bool IsPlayerControlsDisabledBy(uint16 who) { return DisablePlayerControls & who; } }; VALIDATE_SIZE(CPad, 0xFC); diff --git a/src/core/PlayerInfo.cpp b/src/core/PlayerInfo.cpp index 675fafb3..08c8ac36 100644 --- a/src/core/PlayerInfo.cpp +++ b/src/core/PlayerInfo.cpp @@ -146,6 +146,8 @@ CPlayerInfo::Clear(void) m_bDriveByAllowed = true; m_nPreviousTimeRewardedForExplosion = 0; m_nExplosionsSinceLastReward = 0; + m_nCurrentBustedAudio = 1; + m_nBustedAudioStatus = BUSTEDAUDIO_NONE; } void diff --git a/src/core/PlayerInfo.h b/src/core/PlayerInfo.h index e2e874e6..dfe6a53e 100644 --- a/src/core/PlayerInfo.h +++ b/src/core/PlayerInfo.h @@ -10,6 +10,13 @@ enum eWastedBustedState WBSTATE_FAILED_CRITICAL_MISSION, }; +enum eBustedAudioState : uint8 +{ + BUSTEDAUDIO_NONE, + BUSTEDAUDIO_LOADING, + BUSTEDAUDIO_DONE +}; + class CEntity; class CPed; class CVehicle; @@ -60,6 +67,8 @@ public: bool m_bGetOutOfJailFree; bool m_bGetOutOfHospitalFree; bool m_bDriveByAllowed; + eBustedAudioState m_nBustedAudioStatus; + int16 m_nCurrentBustedAudio; char m_aSkinName[32]; RwTexture *m_pSkinTexture; diff --git a/src/core/User.cpp b/src/core/User.cpp index 716d6393..56e37ac4 100644 --- a/src/core/User.cpp +++ b/src/core/User.cpp @@ -1,6 +1,6 @@ #include "common.h" - +#include "GameLogic.h" #include "Hud.h" #include "PlayerPed.h" #include "Replay.h" @@ -99,7 +99,7 @@ void CCurrentVehicle::Display() { wchar *text = nil; - if (m_pCurrentVehicle != nil) + if (m_pCurrentVehicle != nil && m_pCurrentVehicle != CGameLogic::pShortCutTaxi) text = TheText.Get(((CVehicleModelInfo*)CModelInfo::GetModelInfo(m_pCurrentVehicle->GetModelIndex()))->m_gameName); CHud::SetVehicleName(text); } diff --git a/src/core/config.h b/src/core/config.h index c90d3cbf..6744e888 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -115,6 +115,7 @@ enum Config { NUMSHOTINFOS = 100, NUMROADBLOCKS = 300, + NUM_SCRIPT_ROADBLOCKS = 16, NUMVISIBLEENTITIES = 2000, NUMINVISIBLEENTITIES = 150, @@ -136,7 +137,8 @@ enum Config { NUM_EXPLOSIONS = 48, - NUM_SETPIECES = 96 + NUM_SETPIECES = 96, + NUM_SHORTCUT_START_POINTS = 16 }; // We'll use this once we're ready to become independent of the game @@ -166,6 +168,7 @@ enum Config { #elif defined GTA_PC # define GTA3_1_1_PATCH //# define GTA3_STEAM_PATCH +//# define GTAVC_JP_PATCH # ifdef GTA_PS2_STUFF # define USE_PS2_RAND # define RANDOMSPLASH // use random splash as on PS2 diff --git a/src/math/Matrix.h b/src/math/Matrix.h index 1d26cc20..9979e701 100644 --- a/src/math/Matrix.h +++ b/src/math/Matrix.h @@ -255,6 +255,14 @@ public: m_matrix.at.y = 0.0f; m_matrix.at.z = 1.0f; } + void SetTranslateOnly(float x, float y, float z) { + m_matrix.pos.x = x; + m_matrix.pos.y = y; + m_matrix.pos.z = z; + } + void SetTranslateOnly(const CVector& pos) { + SetTranslateOnly(pos.x, pos.y, pos.z); + } }; diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index 687f9da1..406ac23f 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -60,6 +60,7 @@ #include "Streaming.h" #include "PedAttractor.h" #include "Debug.h" +#include "GameLogic.h" #define CAN_SEE_ENTITY_ANGLE_THRESHOLD DEGTORAD(60.0f) @@ -16228,6 +16229,12 @@ CPed::SetExitCar(CVehicle *veh, uint32 wantedDoorNode) return; } if (!someoneExitsFromOurExitDoor || m_nPedType == PEDTYPE_COP && veh->bIsBus) { +#if defined GTAVC_JP_PATCH || defined FIX_BUGS + if (veh->pDriver == this && !IsPlayer() && veh == CGameLogic::pShortCutTaxi) { + m_objective = OBJECTIVE_NONE; + return; + } +#endif // Again, unused... // CVector exitPos = GetPositionToOpenCarDoor(veh, optedDoorNode); bool thereIsRoom = veh->IsRoomForPedToLeaveCar(optedDoorNode, nil); @@ -18666,6 +18673,35 @@ CPed::CanBeDamagedByThisGangMember(CPed* who) return m_gangFlags & (1 << (uint8)(who->m_nPedType - PEDTYPE_GANG1)); } +void +CPed::Undress(const char* name) +{ + int mi = GetModelIndex(); + CAnimBlendAssociation* pAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_PHONE_OUT); + //if (pAnim) + // FinishTalkingOnMobileCB(pAnim, this); // TODO(MIAMI) + DeleteRwObject(); + if (m_nPedType == PEDTYPE_PLAYER1) + mi = MI_PLAYER; + CStreaming::RequestSpecialModel(mi, name, STREAMFLAGS_DEPENDENCY | STREAMFLAGS_SCRIPTOWNED); + CWorld::Remove(this); +} + +void +CPed::Dress(void) +{ + int mi = GetModelIndex(); + m_modelIndex = -1; + SetModelIndex(mi); + m_nPedState = PED_IDLE; + m_nLastPedState = PED_NONE; + m_objective = OBJECTIVE_NONE; + m_prevObjective = OBJECTIVE_NONE; + m_nWaitState = WAITSTATE_FALSE; + CWorld::Add(this); + m_headingRate = m_pedStats->m_headingChangeRate; +} + bool IsPedPointerValid_NotInWorld(CPed* pPed) { diff --git a/src/peds/Ped.h b/src/peds/Ped.h index 155e6cea..bbc5334b 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -916,6 +916,8 @@ public: void SetNewAttraction(CPedAttractor* pAttractor, const CVector& pos, float, float, int); void ClearWaitState(void); + void Undress(const char*); + void Dress(void); bool HasWeaponSlot(uint8 slot) { return m_weapons[slot].m_eWeaponType != WEAPONTYPE_UNARMED; } CWeapon& GetWeapon(uint8 slot) { return m_weapons[slot]; } diff --git a/src/render/Particle.h b/src/render/Particle.h index d254ef65..f2c3a459 100644 --- a/src/render/Particle.h +++ b/src/render/Particle.h @@ -97,4 +97,6 @@ public: static void HandleShootableBirdsStuff(CEntity *entity, CVector const&camPos); }; +extern bool clearWaterDrop; + VALIDATE_SIZE(CParticle, 0x58); diff --git a/src/save/GenericGameStorage.cpp b/src/save/GenericGameStorage.cpp index 839ad8b9..8ae3ffed 100644 --- a/src/save/GenericGameStorage.cpp +++ b/src/save/GenericGameStorage.cpp @@ -84,6 +84,7 @@ do {\ #define WriteSaveDataBlock(save_func)\ do {\ + size = 0;\ buf = work_buff;\ reserved = 0;\ MakeSpaceForSizeInBufferPointer(presize, buf, postsize);\ @@ -192,6 +193,7 @@ GenericSave(int file) // Save the rest WriteSaveDataBlock(CPools::SavePedPool); WriteSaveDataBlock(CGarages::Save); + WriteSaveDataBlock(CGameLogic::Save); WriteSaveDataBlock(CPools::SaveVehiclePool); WriteSaveDataBlock(CPools::SaveObjectPool); WriteSaveDataBlock(ThePaths.Save); @@ -306,6 +308,8 @@ GenericLoad() LoadSaveDataBlock(); ReadDataFromBlock("Loading Garages \n", CGarages::Load); LoadSaveDataBlock(); + ReadDataFromBlock("Loading GameLogic \n", CGameLogic::Load); + LoadSaveDataBlock(); ReadDataFromBlock("Loading Vehicles \n", CPools::LoadVehiclePool); LoadSaveDataBlock(); CProjectileInfo::RemoveAllProjectiles(); |