diff options
Diffstat (limited to 'src/control')
-rw-r--r-- | src/control/AutoPilot.cpp | 4 | ||||
-rw-r--r-- | src/control/AutoPilot.h | 14 | ||||
-rw-r--r-- | src/control/Bridge.cpp | 14 | ||||
-rw-r--r-- | src/control/CarAI.cpp | 264 | ||||
-rw-r--r-- | src/control/CarAI.h | 5 | ||||
-rw-r--r-- | src/control/CarCtrl.cpp | 1065 | ||||
-rw-r--r-- | src/control/CarCtrl.h | 64 | ||||
-rw-r--r-- | src/control/Curves.cpp | 18 | ||||
-rw-r--r-- | src/control/Garages.cpp | 880 | ||||
-rw-r--r-- | src/control/Garages.h | 90 | ||||
-rw-r--r-- | src/control/PathFind.cpp | 917 | ||||
-rw-r--r-- | src/control/PathFind.h | 162 | ||||
-rw-r--r-- | src/control/Pickups.cpp | 221 | ||||
-rw-r--r-- | src/control/Pickups.h | 13 | ||||
-rw-r--r-- | src/control/Record.cpp | 426 | ||||
-rw-r--r-- | src/control/Replay.cpp | 32 | ||||
-rw-r--r-- | src/control/Replay.h | 4 | ||||
-rw-r--r-- | src/control/Restart.cpp | 8 | ||||
-rw-r--r-- | src/control/RoadBlocks.cpp | 21 | ||||
-rw-r--r-- | src/control/RoadBlocks.h | 4 | ||||
-rw-r--r-- | src/control/SceneEdit.cpp | 2 | ||||
-rw-r--r-- | src/control/Script.cpp | 2011 | ||||
-rw-r--r-- | src/control/Script.h | 34 | ||||
-rw-r--r-- | src/control/ScriptCommands.h | 301 | ||||
-rw-r--r-- | src/control/TrafficLights.cpp | 9 |
25 files changed, 4080 insertions, 2503 deletions
diff --git a/src/control/AutoPilot.cpp b/src/control/AutoPilot.cpp index b1fce95f..da661b8c 100644 --- a/src/control/AutoPilot.cpp +++ b/src/control/AutoPilot.cpp @@ -6,6 +6,7 @@ #include "Curves.h" #include "PathFind.h" +//--MIAMI: done void CAutoPilot::ModifySpeed(float speed) { m_fMaxTrafficSpeed = Max(0.01f, speed); @@ -39,6 +40,7 @@ void CAutoPilot::ModifySpeed(float speed) #endif } +//--MIAMI: done void CAutoPilot::RemoveOnePathNode() { --m_nPathFindNodesCount; @@ -47,6 +49,7 @@ void CAutoPilot::RemoveOnePathNode() } #ifdef COMPATIBLE_SAVES +//--MIAMI: TODO void CAutoPilot::Save(uint8*& buf) { WriteSaveBuf<int32>(buf, m_nCurrentRouteNode); @@ -86,6 +89,7 @@ void CAutoPilot::Save(uint8*& buf) SkipSaveBuf(buf, 6); } +//--MIAMI: TODO void CAutoPilot::Load(uint8*& buf) { m_nCurrentRouteNode = ReadSaveBuf<int32>(buf); diff --git a/src/control/AutoPilot.h b/src/control/AutoPilot.h index 337a93c1..25feb72d 100644 --- a/src/control/AutoPilot.h +++ b/src/control/AutoPilot.h @@ -26,6 +26,13 @@ enum eCarMission : uint8 MISSION_BLOCKCAR_FARAWAY, MISSION_BLOCKCAR_CLOSE, MISSION_BLOCKCAR_HANDBRAKESTOP, + MISSION_HELI_FLYTOCOORS, + MISSION_ATTACKPLAYER, + MISSION_PLANE_FLYTOCOORS, + MISSION_HELI_LAND, + MISSION_SLOWLY_DRIVE_TOWARDS_PLAYER_1, + MISSION_SLOWLY_DRIVE_TOWARDS_PLAYER_2, + MISSION_BLOCKPLAYER_FORWARDANDBACK }; enum eCarTempAction : uint8 @@ -75,11 +82,14 @@ public: uint32 m_nTimeTempAction; float m_fMaxTrafficSpeed; uint8 m_nCruiseSpeed; + uint8 m_nCruiseSpeedMultiplierType; + float m_fCruiseSpeedMultiplier; uint8 m_bSlowedDownBecauseOfCars : 1; uint8 m_bSlowedDownBecauseOfPeds : 1; uint8 m_bStayInCurrentLevel : 1; uint8 m_bStayInFastLane : 1; uint8 m_bIgnorePathfinding : 1; + uint8 m_nSwitchDistance; CVector m_vecDestinationCoors; CPathNode *m_aPathFindNodesInfo[NUM_PATH_NODES_IN_AUTOPILOT]; int16 m_nPathFindNodesCount; @@ -109,6 +119,8 @@ public: m_nTimeToStartMission = CTimer::GetTimeInMilliseconds(); m_nAntiReverseTimer = m_nTimeToStartMission; m_bStayInFastLane = false; + m_nCruiseSpeedMultiplierType = 0; + m_fCruiseSpeedMultiplier = 1.0f; } void ModifySpeed(float); @@ -118,6 +130,8 @@ public: void Load(uint8*& buf); #endif + float GetCruiseSpeed(void) { return m_nCruiseSpeed * m_fCruiseSpeedMultiplier; } + }; VALIDATE_SIZE(CAutoPilot, 0x70); diff --git a/src/control/Bridge.cpp b/src/control/Bridge.cpp index e873062b..1e63cf30 100644 --- a/src/control/Bridge.cpp +++ b/src/control/Bridge.cpp @@ -23,6 +23,7 @@ uint32 CBridge::TimeOfBridgeBecomingOperational; void CBridge::Init() { +#ifdef GTA_BRIDGE FindBridgeEntities(); OldLift = -1.0f; if (pLiftPart && pWeight) @@ -35,10 +36,12 @@ void CBridge::Init() ThePaths.SetLinksBridgeLights(-330.0, -230.0, -700.0, -588.0, true); } +#endif } void CBridge::Update() { +#ifdef GTA_BRIDGE if (!pLiftPart || !pWeight) return; @@ -113,15 +116,21 @@ void CBridge::Update() ThePaths.SetLinksBridgeLights(-330.0, -230.0, -700.0, -588.0, true); else if (State == STATE_LIFT_PART_IS_DOWN && OldState == STATE_LIFT_PART_MOVING_DOWN) ThePaths.SetLinksBridgeLights(-330.0, -230.0, -700.0, -588.0, false); +#endif } bool CBridge::ShouldLightsBeFlashing() { +#ifdef GTA_BRIDGE return State != STATE_LIFT_PART_IS_DOWN; +#else + return false; +#endif } void CBridge::FindBridgeEntities() { +#ifdef GTA_BRIDGE pWeight = nil; pLiftRoad = nil; pLiftPart = nil; @@ -138,12 +147,17 @@ void CBridge::FindBridgeEntities() pWeight = entry; } } +#endif } bool CBridge::ThisIsABridgeObjectMovingUp(int index) { +#ifdef GTA_BRIDGE if (index != MI_BRIDGEROADSEGMENT && index != MI_BRIDGELIFT) return false; return State == STATE_LIFT_PART_ABOUT_TO_MOVE_UP || State == STATE_LIFT_PART_MOVING_UP; +#else + return false; +#endif } diff --git a/src/control/CarAI.cpp b/src/control/CarAI.cpp index b3fc85ae..a4406da9 100644 --- a/src/control/CarAI.cpp +++ b/src/control/CarAI.cpp @@ -13,6 +13,7 @@ #include "DMAudio.h" #include "Fire.h" #include "Pools.h" +#include "Population.h" #include "Timer.h" #include "TrafficLights.h" #include "Vehicle.h" @@ -21,16 +22,19 @@ #define DISTANCE_TO_SWITCH_DISTANCE_GOTO 20.0f +//--MIAMI: done float CCarAI::FindSwitchDistanceClose(CVehicle* pVehicle) { - return 30.0f; + return pVehicle->AutoPilot.m_nSwitchDistance; } +//--MIAMI: done float CCarAI::FindSwitchDistanceFarNormalVehicle(CVehicle* pVehicle) { return FindSwitchDistanceClose(pVehicle) + 5.0f; } +//--MIAMI: done float CCarAI::FindSwitchDistanceFar(CVehicle* pVehicle) { if (pVehicle->bIsLawEnforcer) @@ -38,6 +42,21 @@ float CCarAI::FindSwitchDistanceFar(CVehicle* pVehicle) return FindSwitchDistanceFarNormalVehicle(pVehicle); } +//--MIAMI: done +void CCarAI::BackToCruisingIfNoWantedLevel(CVehicle* pVehicle) +{ + if (FindPlayerPed()->m_pWanted->m_bIgnoredByEveryone || pVehicle->bIsLawEnforcer && + (FindPlayerPed()->m_pWanted->m_nWantedLevel == 0 || FindPlayerPed()->m_pWanted->m_bIgnoredByCops || CCullZones::NoPolice())) { + CCarCtrl::JoinCarWithRoadSystem(pVehicle); + pVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE; + pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS; + pVehicle->m_bSirenOrAlarm = false; + if (CCullZones::NoPolice()) + pVehicle->AutoPilot.m_nCarMission = MISSION_NONE; + } +} + +//--MIAMI: done void CCarAI::UpdateCarAI(CVehicle* pVehicle) { if (pVehicle->bIsLawEnforcer){ @@ -67,15 +86,7 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) if (pVehicle->UsesSiren(pVehicle->GetModelIndex())) pVehicle->m_bSirenOrAlarm = true; } - if (FindPlayerPed()->m_pWanted->m_bIgnoredByEveryone || pVehicle->bIsLawEnforcer && - (FindPlayerPed()->m_pWanted->m_nWantedLevel == 0 || FindPlayerPed()->m_pWanted->m_bIgnoredByCops || CCullZones::NoPolice())) { - CCarCtrl::JoinCarWithRoadSystem(pVehicle); - pVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE; - pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS; - pVehicle->m_bSirenOrAlarm = false; - if (CCullZones::NoPolice()) - pVehicle->AutoPilot.m_nCarMission = MISSION_NONE; - } + BackToCruisingIfNoWantedLevel(pVehicle); break; case MISSION_RAMPLAYER_CLOSE: if (FindSwitchDistanceFar(pVehicle) >= (FindPlayerCoors() - pVehicle->GetPosition()).Magnitude2D() || @@ -120,18 +131,9 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) pVehicle->m_bSirenOrAlarm = false; pVehicle->m_nCarHornTimer = 0; } - if (FindPlayerPed()->m_pWanted->m_bIgnoredByEveryone || pVehicle->bIsLawEnforcer && - (FindPlayerPed()->m_pWanted->m_nWantedLevel == 0 || FindPlayerPed()->m_pWanted->m_bIgnoredByCops || CCullZones::NoPolice())){ - CCarCtrl::JoinCarWithRoadSystem(pVehicle); - pVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE; - pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS; - pVehicle->m_bSirenOrAlarm = false; - if (CCullZones::NoPolice()) - pVehicle->AutoPilot.m_nCarMission = MISSION_NONE; - } - - else if (pVehicle->bIsLawEnforcer) + if (pVehicle->bIsLawEnforcer) MellowOutChaseSpeed(pVehicle); + BackToCruisingIfNoWantedLevel(pVehicle); break; case MISSION_BLOCKPLAYER_FARAWAY: if (FindSwitchDistanceClose(pVehicle) > (FindPlayerCoors() - pVehicle->GetPosition()).Magnitude2D() || @@ -140,20 +142,12 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) if (pVehicle->UsesSiren(pVehicle->GetModelIndex())) pVehicle->m_bSirenOrAlarm = true; } - if (FindPlayerPed()->m_pWanted->m_bIgnoredByEveryone || pVehicle->bIsLawEnforcer && - (FindPlayerPed()->m_pWanted->m_nWantedLevel == 0 || FindPlayerPed()->m_pWanted->m_bIgnoredByCops || CCullZones::NoPolice())) { - CCarCtrl::JoinCarWithRoadSystem(pVehicle); - pVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE; - pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS; - pVehicle->m_bSirenOrAlarm = false; - if (CCullZones::NoPolice()) - pVehicle->AutoPilot.m_nCarMission = MISSION_NONE; - } + BackToCruisingIfNoWantedLevel(pVehicle); break; case MISSION_BLOCKPLAYER_CLOSE: if (FindSwitchDistanceFar(pVehicle) >= (FindPlayerCoors() - pVehicle->GetPosition()).Magnitude2D() || pVehicle->AutoPilot.m_bIgnorePathfinding) { - if (FindPlayerVehicle() && FindPlayerVehicle()->GetMoveSpeed().Magnitude() < 0.05f) + if (FindPlayerVehicle() && FindPlayerVehicle()->GetMoveSpeed().Magnitude() < 0.04f) #ifdef FIX_BUGS pVehicle->m_nTimeBlocked += CTimer::GetTimeStepInMilliseconds(); #else @@ -162,7 +156,7 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) else pVehicle->m_nTimeBlocked = 0; if (!FindPlayerVehicle() || FindPlayerVehicle()->IsUpsideDown() || - FindPlayerVehicle()->GetMoveSpeed().Magnitude() < 0.05f && pVehicle->m_nTimeBlocked > TIME_COPS_WAIT_TO_EXIT_AFTER_STOPPING) { + FindPlayerVehicle()->GetMoveSpeed().Magnitude() < 0.04f && pVehicle->m_nTimeBlocked > TIME_COPS_WAIT_TO_EXIT_AFTER_STOPPING) { if (pVehicle->bIsLawEnforcer && (pVehicle->GetModelIndex() != MI_RHINO || pVehicle->m_randomSeed > 10000) && (FindPlayerCoors() - pVehicle->GetPosition()).Magnitude2D() < 10.0f) { @@ -178,20 +172,12 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) pVehicle->m_bSirenOrAlarm = false; pVehicle->m_nCarHornTimer = 0; } - if (FindPlayerPed()->m_pWanted->m_bIgnoredByEveryone || pVehicle->bIsLawEnforcer && - (FindPlayerPed()->m_pWanted->m_nWantedLevel == 0 || FindPlayerPed()->m_pWanted->m_bIgnoredByCops || CCullZones::NoPolice())) { - CCarCtrl::JoinCarWithRoadSystem(pVehicle); - pVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE; - pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS; - pVehicle->m_bSirenOrAlarm = false; - if (CCullZones::NoPolice()) - pVehicle->AutoPilot.m_nCarMission = MISSION_NONE; - } if (pVehicle->bIsLawEnforcer) MellowOutChaseSpeed(pVehicle); + BackToCruisingIfNoWantedLevel(pVehicle); break; case MISSION_GOTOCOORDS: - if ((pVehicle->AutoPilot.m_vecDestinationCoors - pVehicle->GetPosition()).Magnitude2D() < DISTANCE_TO_SWITCH_DISTANCE_GOTO || + if ((pVehicle->AutoPilot.m_vecDestinationCoors - pVehicle->GetPosition()).Magnitude2D() < FindSwitchDistanceClose(pVehicle) || pVehicle->AutoPilot.m_bIgnorePathfinding) pVehicle->AutoPilot.m_nCarMission = MISSION_GOTOCOORDS_STRAIGHT; break; @@ -203,6 +189,10 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) if (distance < 5.0f){ pVehicle->AutoPilot.m_nCarMission = MISSION_NONE; pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE; + if (pVehicle->bParking) { + TellOccupantsToLeaveCar(pVehicle); + pVehicle->bParking = false; + } } else if (distance > FindSwitchDistanceFarNormalVehicle(pVehicle) && !pVehicle->AutoPilot.m_bIgnorePathfinding && (CTimer::GetFrameCounter() & 7) == 0){ pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE; @@ -259,6 +249,10 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) if (distance < 1.0f) { pVehicle->AutoPilot.m_nCarMission = MISSION_NONE; pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE; + if (pVehicle->bParking) { + TellOccupantsToLeaveCar(pVehicle); + pVehicle->bParking = false; + } } else if (distance > FindSwitchDistanceFarNormalVehicle(pVehicle) && !pVehicle->AutoPilot.m_bIgnorePathfinding && (CTimer::GetFrameCounter() & 7) == 0) { pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE; @@ -278,23 +272,10 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) break; case MISSION_RAMCAR_CLOSE: if (pVehicle->AutoPilot.m_pTargetCar){ - if -#ifdef FIX_BUGS - (FindPlayerVehicle() == pVehicle->AutoPilot.m_pTargetCar && -#endif - (FindPlayerPed()->m_pWanted->m_bIgnoredByEveryone || pVehicle->bIsLawEnforcer && - (FindPlayerPed()->m_pWanted->m_nWantedLevel == 0 || FindPlayerPed()->m_pWanted->m_bIgnoredByCops || CCullZones::NoPolice())) -#ifdef FIX_BUGS - ) +#ifdef FIX_BUGS // btw fixed in SA + if (FindPlayerVehicle() == pVehicle->AutoPilot.m_pTargetCar) #endif - { - CCarCtrl::JoinCarWithRoadSystem(pVehicle); - pVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE; - pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS; - pVehicle->m_bSirenOrAlarm = false; - if (CCullZones::NoPolice()) - pVehicle->AutoPilot.m_nCarMission = MISSION_NONE; - } + BackToCruisingIfNoWantedLevel(pVehicle); if ((pVehicle->AutoPilot.m_pTargetCar->GetPosition() - pVehicle->GetPosition()).Magnitude2D() <= FindSwitchDistanceFar(pVehicle) || pVehicle->AutoPilot.m_bIgnorePathfinding){ if (pVehicle->GetHasCollidedWith(pVehicle->AutoPilot.m_pTargetCar)){ @@ -336,6 +317,40 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) pVehicle->AutoPilot.m_nCarMission = MISSION_NONE; } break; + case MISSION_ATTACKPLAYER: + if (pVehicle->bIsLawEnforcer) + MellowOutChaseSpeedBoat(pVehicle); + BackToCruisingIfNoWantedLevel(pVehicle); + break; + case MISSION_SLOWLY_DRIVE_TOWARDS_PLAYER_1: + if (((CVector2D)(pVehicle->AutoPilot.m_vecDestinationCoors) - pVehicle->GetPosition()).Magnitude() < 1.5f) + pVehicle->AutoPilot.m_nCarMission = MISSION_SLOWLY_DRIVE_TOWARDS_PLAYER_2; + BackToCruisingIfNoWantedLevel(pVehicle); + break; + case MISSION_SLOWLY_DRIVE_TOWARDS_PLAYER_2: + { + float distance = ((CVector2D)FindPlayerCoors() - pVehicle->GetPosition()).Magnitude(); + if (distance < 13.0f) { + TellOccupantsToLeaveCar(pVehicle); + pVehicle->AutoPilot.m_nCruiseSpeed = 0; + pVehicle->AutoPilot.m_nCarMission = MISSION_STOP_FOREVER; + } + if (distance > 70.0f || FindPlayerPed()->m_pWanted->m_bIgnoredByEveryone || + (FindPlayerPed()->m_pWanted->m_nWantedLevel == 0 || FindPlayerPed()->m_pWanted->m_bIgnoredByCops || CCullZones::NoPolice())) { + TellOccupantsToLeaveCar(pVehicle); + pVehicle->AutoPilot.m_nCruiseSpeed = 0; + pVehicle->AutoPilot.m_nCarMission = MISSION_STOP_FOREVER; + } + break; + } + case MISSION_BLOCKPLAYER_FORWARDANDBACK: + { + CVector2D diff = (CVector2D)FindPlayerCoors() - pVehicle->GetPosition(); + float distance = Max(0.001f, diff.Magnitude()); + if (!FindPlayerVehicle() || DotProduct2D(CVector2D(diff.x / distance, diff.y / distance), FindPlayerSpeed()) > 0.05f) + pVehicle->AutoPilot.m_nCarMission = MISSION_BLOCKPLAYER_CLOSE; + BackToCruisingIfNoWantedLevel(pVehicle); + } default: if (pVehicle->bIsLawEnforcer && FindPlayerPed()->m_pWanted->m_nWantedLevel > 0 && !CCullZones::NoPolice()){ if (ABS(FindPlayerCoors().x - pVehicle->GetPosition().x) > 10.0f || @@ -343,7 +358,7 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) pVehicle->AutoPilot.m_nCruiseSpeed = FindPoliceCarSpeedForWantedLevel(pVehicle); pVehicle->SetStatus(STATUS_PHYSICS); pVehicle->AutoPilot.m_nCarMission = - FindPoliceCarMissionForWantedLevel(); + pVehicle->GetVehicleAppearance() == VEHICLE_APPEARANCE_BOAT ? FindPoliceBoatMissionForWantedLevel() : FindPoliceCarMissionForWantedLevel(); pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE; pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; }else if (pVehicle->AutoPilot.m_nCarMission == MISSION_CRUISE){ @@ -364,6 +379,11 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) pVehicle->AutoPilot.m_nCruiseSpeed = 0; break; } + if (pVehicle->bIsLawEnforcer && FindPlayerPed()->m_pWanted->m_nWantedLevel >= 1 && CCullZones::PoliceAbandonCars()) { + TellOccupantsToLeaveCar(pVehicle); + pVehicle->AutoPilot.m_nCruiseSpeed = 0; + pVehicle->AutoPilot.m_nCarMission = MISSION_NONE; + } float flatSpeed = pVehicle->GetMoveSpeed().MagnitudeSqr2D(); if (flatSpeed > SQR(0.018f)){ pVehicle->AutoPilot.m_nTimeToStartMission = CTimer::GetTimeInMilliseconds(); @@ -372,9 +392,12 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) if (pVehicle->GetStatus() == STATUS_PHYSICS && pVehicle->AutoPilot.m_nTempAction == TEMPACT_NONE){ if (pVehicle->AutoPilot.m_nCarMission != MISSION_NONE){ if (pVehicle->AutoPilot.m_nCarMission != MISSION_STOP_FOREVER && + pVehicle->AutoPilot.m_nCarMission != MISSION_BLOCKPLAYER_HANDBRAKESTOP && pVehicle->AutoPilot.m_nCruiseSpeed != 0 && (pVehicle->VehicleCreatedBy != RANDOM_VEHICLE || pVehicle->AutoPilot.m_nCarMission != MISSION_CRUISE)){ if (pVehicle->AutoPilot.m_nDrivingStyle != DRIVINGSTYLE_STOP_FOR_CARS + && pVehicle->AutoPilot.m_nDrivingStyle != DRIVINGSTYLE_STOP_FOR_CARS_IGNORE_LIGHTS || + pVehicle->VehicleCreatedBy == MISSION_VEHICLE ) { if (CTimer::GetTimeInMilliseconds() - pVehicle->m_nLastTimeCollided > 500) pVehicle->AutoPilot.m_nAntiReverseTimer = CTimer::GetTimeInMilliseconds(); @@ -406,6 +429,13 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) pVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 400; } } + if (pVehicle->bIsLawEnforcer) { + if (pVehicle->AutoPilot.m_nCarMission == MISSION_RAMPLAYER_FARAWAY || + pVehicle->AutoPilot.m_nCarMission == MISSION_RAMPLAYER_CLOSE) { + if (FindPlayerVehicle() && FindPlayerVehicle()->GetVehicleAppearance() == VEHICLE_APPEARANCE_BIKE) + pVehicle->AutoPilot.m_nCarMission = MISSION_BLOCKPLAYER_FARAWAY; + } + } if (pVehicle->GetUp().z < 0.7f){ pVehicle->AutoPilot.m_nTempAction = TEMPACT_WAIT; pVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 1000; @@ -446,13 +476,43 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) if ((uint8)(pVehicle->m_randomSeed ^ CGeneral::GetRandomNumber()) == 0xAD) pVehicle->m_nCarHornTimer = 45; } + float target = 1.0f; + if (pVehicle->AutoPilot.m_nCarMission == MISSION_CRUISE) + target = CCarCtrl::FindSpeedMultiplierWithSpeedFromNodes(pVehicle->AutoPilot.m_nCruiseSpeedMultiplierType); + float change = CTimer::GetTimeStep() * 0.01f; + if (Abs(pVehicle->AutoPilot.m_fCruiseSpeedMultiplier - target) < change) + pVehicle->AutoPilot.m_fCruiseSpeedMultiplier = target; + else if (pVehicle->AutoPilot.m_fCruiseSpeedMultiplier > target) + pVehicle->AutoPilot.m_fCruiseSpeedMultiplier -= change; + else + pVehicle->AutoPilot.m_fCruiseSpeedMultiplier += change; + + if (pVehicle->bIsLawEnforcer && FindPlayerPed()->m_pWanted->m_nWantedLevel > 0) { + if (!FindPlayerVehicle() || + FindPlayerVehicle()->GetVehicleAppearance() == VEHICLE_APPEARANCE_CAR || + FindPlayerVehicle()->GetVehicleAppearance() == VEHICLE_APPEARANCE_BIKE) { + if (pVehicle->GetVehicleAppearance() == VEHICLE_APPEARANCE_BOAT) { + pVehicle->AutoPilot.m_nTempAction = TEMPACT_WAIT; + pVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 1000; + } + } + else if (FindPlayerVehicle()->GetVehicleAppearance() == VEHICLE_APPEARANCE_BOAT) { + if (pVehicle->GetVehicleAppearance() == VEHICLE_APPEARANCE_CAR || + pVehicle->GetVehicleAppearance() == VEHICLE_APPEARANCE_BIKE) { + pVehicle->AutoPilot.m_nTempAction = TEMPACT_WAIT; + pVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 1000; + } + } + } } +//--MIAMI: done void CCarAI::CarHasReasonToStop(CVehicle* pVehicle) { pVehicle->AutoPilot.m_nAntiReverseTimer = CTimer::GetTimeInMilliseconds(); } +//--MIAMI: done float CCarAI::GetCarToGoToCoors(CVehicle* pVehicle, CVector* pTarget) { if (pVehicle->AutoPilot.m_nCarMission != MISSION_GOTOCOORDS && pVehicle->AutoPilot.m_nCarMission != MISSION_GOTOCOORDS_STRAIGHT){ @@ -470,6 +530,16 @@ float CCarAI::GetCarToGoToCoors(CVehicle* pVehicle, CVector* pTarget) return (pVehicle->GetPosition() - *pTarget).Magnitude2D(); } +//--MIAMI: done +float CCarAI::GetCarToParkAtCoors(CVehicle* pVehicle, CVector* pTarget) +{ + GetCarToGoToCoors(pVehicle, pTarget); + pVehicle->bParking = true; + pVehicle->AutoPilot.m_nCruiseSpeed = 10; + return (pVehicle->GetPosition() - *pTarget).Magnitude2D(); +} + +//--MIAMI: TODO: MI_VICECHEE void CCarAI::AddPoliceCarOccupants(CVehicle* pVehicle) { if (pVehicle->bOccupantsHaveBeenGenerated) @@ -489,23 +559,38 @@ void CCarAI::AddPoliceCarOccupants(CVehicle* pVehicle) if (FindPlayerPed()->m_pWanted->m_nWantedLevel > 1) pVehicle->SetupPassenger(0); return; + case MI_PREDATOR: + pVehicle->SetUpDriver(); + return; + case MI_VICECHEE: + { + pVehicle->SetUpDriver()->bMiamiViceCop = true; + pVehicle->SetupPassenger(0)->bMiamiViceCop = true; + CPopulation::NumMiamiViceCops += 2; + CCarCtrl::MiamiViceCycle = (CCarCtrl::MiamiViceCycle + 1) % 4; + CCarCtrl::LastTimeMiamiViceGenerated = CTimer::GetTimeInMilliseconds(); + return; + } default: return; } } +//--MIAMI: done void CCarAI::AddAmbulanceOccupants(CVehicle* pVehicle) { pVehicle->SetUpDriver(); pVehicle->SetupPassenger(1); } +//--MIAMI: done void CCarAI::AddFiretruckOccupants(CVehicle* pVehicle) { pVehicle->SetUpDriver(); pVehicle->SetupPassenger(0); } +//--MIAMI: done void CCarAI::TellOccupantsToLeaveCar(CVehicle* pVehicle) { if (pVehicle->pDriver){ @@ -516,11 +601,32 @@ void CCarAI::TellOccupantsToLeaveCar(CVehicle* pVehicle) int timer = 100; for (int i = 0; i < pVehicle->m_nNumMaxPassengers; i++){ if (pVehicle->pPassengers[i]) { + pVehicle->pPassengers[i]->m_leaveCarTimer = timer; pVehicle->pPassengers[i]->SetObjective(OBJECTIVE_LEAVE_VEHICLE, pVehicle); + timer += CGeneral::GetRandomNumberInRange(200, 400); + } + } +} + +//--MIAMI: done +void CCarAI::TellOccupantsToFleeCar(CVehicle* pVehicle) +{ + if (pVehicle->pDriver && !pVehicle->pDriver->IsPlayer()) { + pVehicle->pDriver->SetObjective(OBJECTIVE_FLEE_TILL_SAFE); + if (pVehicle->GetModelIndex() != MI_FIRETRUCK && pVehicle->GetModelIndex() == MI_AMBULAN) + pVehicle->pDriver->Say(SOUND_PED_LEAVE_VEHICLE); + } + int timer = 100; + for (int i = 0; i < pVehicle->m_nNumMaxPassengers; i++) { + if (pVehicle->pPassengers[i]) { + pVehicle->pPassengers[i]->m_leaveCarTimer = timer; + pVehicle->pPassengers[i]->SetObjective(OBJECTIVE_FLEE_TILL_SAFE); + timer += CGeneral::GetRandomNumberInRange(200, 400); } } } +//--MIAMI: done void CCarAI::TellCarToRamOtherCar(CVehicle* pVehicle, CVehicle* pTarget) { pVehicle->AutoPilot.m_pTargetCar = pTarget; @@ -530,6 +636,7 @@ void CCarAI::TellCarToRamOtherCar(CVehicle* pVehicle, CVehicle* pTarget) pVehicle->AutoPilot.m_nCruiseSpeed = Max(6, pVehicle->AutoPilot.m_nCruiseSpeed); } +//--MIAMI: done void CCarAI::TellCarToBlockOtherCar(CVehicle* pVehicle, CVehicle* pTarget) { pVehicle->AutoPilot.m_pTargetCar = pTarget; @@ -539,6 +646,7 @@ void CCarAI::TellCarToBlockOtherCar(CVehicle* pVehicle, CVehicle* pTarget) pVehicle->AutoPilot.m_nCruiseSpeed = Max(6, pVehicle->AutoPilot.m_nCruiseSpeed); } +//--MIAMI: done eCarMission CCarAI::FindPoliceCarMissionForWantedLevel() { switch (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->m_nWantedLevel){ @@ -553,6 +661,22 @@ eCarMission CCarAI::FindPoliceCarMissionForWantedLevel() } } +//--MIAMI: done +eCarMission CCarAI::FindPoliceBoatMissionForWantedLevel() +{ + switch (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->m_nWantedLevel) { + case 0: + case 1: return MISSION_BLOCKPLAYER_FARAWAY; + case 2: + case 3: + case 4: + case 5: + case 6: return MISSION_ATTACKPLAYER; + default: return MISSION_BLOCKPLAYER_FARAWAY; + } +} + +//--MIAMI: done int32 CCarAI::FindPoliceCarSpeedForWantedLevel(CVehicle* pVehicle) { switch (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->m_nWantedLevel) { @@ -567,6 +691,7 @@ int32 CCarAI::FindPoliceCarSpeedForWantedLevel(CVehicle* pVehicle) } } +//--MIAMI: done void CCarAI::MellowOutChaseSpeed(CVehicle* pVehicle) { if (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->m_nWantedLevel == 1){ @@ -605,8 +730,27 @@ void CCarAI::MellowOutChaseSpeed(CVehicle* pVehicle) pVehicle->AutoPilot.m_nCruiseSpeed = 34; } } + if (!FindPlayerVehicle() && FindPlayerPed()->GetMoveSpeed().Magnitude() < 0.07f) { + if ((FindPlayerCoors() - pVehicle->GetPosition()).Magnitude() < 30.0f) + pVehicle->AutoPilot.m_nCruiseSpeed = Min(10, pVehicle->AutoPilot.m_nCruiseSpeed); + } +} + +//--MIAMI: done +void CCarAI::MellowOutChaseSpeedBoat(CVehicle* pVehicle) +{ + switch (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->m_nWantedLevel) { + case 0: pVehicle->AutoPilot.m_nCruiseSpeed = 8; break; + case 1: pVehicle->AutoPilot.m_nCruiseSpeed = 10; break; + case 2: pVehicle->AutoPilot.m_nCruiseSpeed = 15; break; + case 3: pVehicle->AutoPilot.m_nCruiseSpeed = 20; break; + case 4: pVehicle->AutoPilot.m_nCruiseSpeed = 25; break; + case 5: pVehicle->AutoPilot.m_nCruiseSpeed = 30; break; + case 6: pVehicle->AutoPilot.m_nCruiseSpeed = 40; break; + } } +//--MIAMI: done void CCarAI::MakeWayForCarWithSiren(CVehicle *pVehicle) { float flatSpeed = pVehicle->GetMoveSpeed().Magnitude2D(); @@ -629,6 +773,8 @@ void CCarAI::MakeWayForCarWithSiren(CVehicle *pVehicle) continue; if (vehicle == pVehicle) continue; + if (vehicle->AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_AVOID_CARS) + return; if (Abs(pVehicle->GetPosition().z - vehicle->GetPosition().z) >= 5.0f) continue; CVector2D distance = vehicle->GetPosition() - pVehicle->GetPosition(); diff --git a/src/control/CarAI.h b/src/control/CarAI.h index e88807c8..d4af1806 100644 --- a/src/control/CarAI.h +++ b/src/control/CarAI.h @@ -10,17 +10,22 @@ public: static float FindSwitchDistanceClose(CVehicle*); static float FindSwitchDistanceFarNormalVehicle(CVehicle*); static float FindSwitchDistanceFar(CVehicle*); + static void BackToCruisingIfNoWantedLevel(CVehicle*); static void UpdateCarAI(CVehicle*); static void CarHasReasonToStop(CVehicle*); static float GetCarToGoToCoors(CVehicle*, CVector*); + static float GetCarToParkAtCoors(CVehicle*, CVector*); static void AddPoliceCarOccupants(CVehicle*); static void AddAmbulanceOccupants(CVehicle*); static void AddFiretruckOccupants(CVehicle*); static void TellOccupantsToLeaveCar(CVehicle*); + static void TellOccupantsToFleeCar(CVehicle*); static void TellCarToRamOtherCar(CVehicle*, CVehicle*); static void TellCarToBlockOtherCar(CVehicle*, CVehicle*); static eCarMission FindPoliceCarMissionForWantedLevel(); + static eCarMission FindPoliceBoatMissionForWantedLevel(); static int32 FindPoliceCarSpeedForWantedLevel(CVehicle*); static void MellowOutChaseSpeed(CVehicle*); + static void MellowOutChaseSpeedBoat(CVehicle*); static void MakeWayForCarWithSiren(CVehicle *veh); }; diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp index cd86ce4c..920fba81 100644 --- a/src/control/CarCtrl.cpp +++ b/src/control/CarCtrl.cpp @@ -11,6 +11,7 @@ #include "Curves.h" #include "CutsceneMgr.h" #include "Gangs.h" +#include "Game.h" #include "Garages.h" #include "General.h" #include "IniFile.h" @@ -19,6 +20,7 @@ #include "Ped.h" #include "PlayerInfo.h" #include "PlayerPed.h" +#include "Population.h" #include "Wanted.h" #include "Pools.h" #include "Renderer.h" @@ -29,43 +31,54 @@ #include "VisibilityPlugins.h" #include "Vehicle.h" #include "Fire.h" +#include "WaterLevel.h" #include "World.h" #include "Zones.h" -#define DISTANCE_TO_SPAWN_ROADBLOCK_PEDS 51.0f -#define DISTANCE_TO_SCAN_FOR_DANGER 11.0f -#define SAFE_DISTANCE_TO_PED 3.0f -#define INFINITE_Z 1000000000.0f - -#define VEHICLE_HEIGHT_DIFF_TO_CONSIDER_WEAVING 4.0f -#define PED_HEIGHT_DIFF_TO_CONSIDER_WEAVING 4.0f -#define OBJECT_HEIGHT_DIFF_TO_CONSIDER_WEAVING 8.0f -#define WIDTH_COEF_TO_WEAVE_SAFELY 1.2f -#define OBJECT_WIDTH_TO_WEAVE 0.3f -#define PED_WIDTH_TO_WEAVE 0.8f - -#define PATH_DIRECTION_NONE 0 -#define PATH_DIRECTION_STRAIGHT 1 -#define PATH_DIRECTION_RIGHT 2 -#define PATH_DIRECTION_LEFT 4 - -#define ATTEMPTS_TO_FIND_NEXT_NODE 15 - -#define DISTANCE_TO_SWITCH_FROM_BLOCK_TO_STOP 5.0f -#define DISTANCE_TO_SWITCH_FROM_STOP_TO_BLOCK 10.0f -#define MAX_SPEED_TO_ACCOUNT_IN_INTERCEPTING 0.13f -#define DISTANCE_TO_NEXT_NODE_TO_CONSIDER_SLOWING_DOWN 40.0f -#define MAX_ANGLE_TO_STEER_AT_HIGH_SPEED 0.2f -#define MIN_SPEED_TO_START_LIMITING_STEER 0.45f -#define DISTANCE_TO_NEXT_NODE_TO_SELECT_NEW 5.0f -#define DISTANCE_TO_FACING_NEXT_NODE_TO_SELECT_NEW 8.0f -#define DEFAULT_MAX_STEER_ANGLE 0.5f -#define MIN_LOWERING_SPEED_COEFFICIENT 0.4f -#define MAX_ANGLE_FOR_SPEED_LIMITING 1.2f -#define MIN_ANGLE_FOR_SPEED_LIMITING 0.4f -#define MIN_ANGLE_FOR_SPEED_LIMITING_BETWEEN_NODES 0.1f -#define MIN_ANGLE_TO_APPLY_HANDBRAKE 0.7f -#define MIN_SPEED_TO_APPLY_HANDBRAKE 0.3f +#define DISTANCE_TO_SPAWN_ROADBLOCK_PEDS (51.0f) +#define DISTANCE_TO_SCAN_FOR_DANGER (14.0f) +#define SAFE_DISTANCE_TO_PED (3.0f) +#define INFINITE_Z (1000000000.0f) + +#define VEHICLE_HEIGHT_DIFF_TO_CONSIDER_WEAVING (4.0f) +#define PED_HEIGHT_DIFF_TO_CONSIDER_WEAVING (4.0f) +#define OBJECT_HEIGHT_DIFF_TO_CONSIDER_WEAVING (8.0f) +#define WIDTH_COEF_TO_WEAVE_SAFELY (1.2f) +#define OBJECT_WIDTH_TO_WEAVE (0.3f) +#define PED_WIDTH_TO_WEAVE (0.8f) + +#define PATH_DIRECTION_NONE (0) +#define PATH_DIRECTION_STRAIGHT (1) +#define PATH_DIRECTION_RIGHT (2) +#define PATH_DIRECTION_LEFT (4) + +#define ATTEMPTS_TO_FIND_NEXT_NODE (15) + +#define DISTANCE_TO_SWITCH_FROM_BLOCK_TO_STOP (5.0f) +#define DISTANCE_TO_SWITCH_FROM_STOP_TO_BLOCK (10.0f) +#define MAX_SPEED_TO_ACCOUNT_IN_INTERCEPTING (0.13f) +#define DISTANCE_TO_NEXT_NODE_TO_CONSIDER_SLOWING_DOWN (40.0f) +#define MAX_ANGLE_TO_STEER_AT_HIGH_SPEED (0.2f) +#define MIN_SPEED_TO_START_LIMITING_STEER (0.45f) +#define DISTANCE_TO_NEXT_NODE_TO_SELECT_NEW (5.0f) +#define DISTANCE_TO_FACING_NEXT_NODE_TO_SELECT_NEW (8.0f) +#define DEFAULT_MAX_STEER_ANGLE (0.5f) +#define MIN_LOWERING_SPEED_COEFFICIENT (0.4f) +#define MAX_ANGLE_FOR_SPEED_LIMITING (1.2f) +#define MIN_ANGLE_FOR_SPEED_LIMITING (0.4f) +#define MIN_ANGLE_FOR_SPEED_LIMITING_BETWEEN_NODES (0.1f) +#define MIN_ANGLE_TO_APPLY_HANDBRAKE (0.7f) +#define MIN_SPEED_TO_APPLY_HANDBRAKE (0.3f) + +#define PROBABILITY_OF_DEAD_PED_ACCIDENT (0.005f) +#define DISTANCE_BETWEEN_CAR_AND_DEAD_PED (6.0f) +#define PROBABILITY_OF_PASSENGER_IN_VEHICLE (0.125f) + +#define ONSCREEN_DESPAWN_RANGE (120.0f) +#define MINIMAL_DISTANCE_TO_SPAWN_ONSCREEN (100.0f) +#define REQUEST_ONSCREEN_DISTANCE ((ONSCREEN_DESPAWN_RANGE + MINIMAL_DISTANCE_TO_SPAWN_ONSCREEN) / 2) +#define OFFSCREEN_DESPAWN_RANGE (40.0f) +#define EXTENDED_RANGE_DESPAWN_MULTIPLIER (1.5f) int CCarCtrl::NumLawEnforcerCars; int CCarCtrl::NumAmbulancesOnDuty; @@ -81,23 +94,29 @@ int32 CCarCtrl::MaxNumberOfCarsInUse = 12; uint32 CCarCtrl::LastTimeLawEnforcerCreated; uint32 CCarCtrl::LastTimeFireTruckCreated; uint32 CCarCtrl::LastTimeAmbulanceCreated; +int32 CCarCtrl::MiamiViceCycle; +uint32 CCarCtrl::LastTimeMiamiViceGenerated; int32 CCarCtrl::TotalNumOfCarsOfRating[TOTAL_CUSTOM_CLASSES]; -int32 CCarCtrl::NextCarOfRating[TOTAL_CUSTOM_CLASSES]; int32 CCarCtrl::CarArrays[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY]; +int32 CCarCtrl::NumRequestsOfCarRating[TOTAL_CUSTOM_CLASSES]; +int32 CCarCtrl::NumOfLoadedCarsOfRating[TOTAL_CUSTOM_CLASSES]; +int32 CCarCtrl::CarFreqArrays[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY]; +int32 CCarCtrl::LoadedCarsArray[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY]; CVehicle* apCarsToKeep[MAX_CARS_TO_KEEP]; uint32 aCarsToKeepTime[MAX_CARS_TO_KEEP]; void CCarCtrl::GenerateRandomCars() { - if (CCutsceneMgr::IsRunning()) + if (CCutsceneMgr::IsRunning()) { + CountDownToCarsAtStart = 2; return; + } if (NumRandomCars < 30){ - if (CountDownToCarsAtStart == 0){ + if (CountDownToCarsAtStart == 0) GenerateOneRandomCar(); - } else if (--CountDownToCarsAtStart == 0) { - for (int i = 0; i < 50; i++) + for (int i = 0; i < 100; i++) GenerateOneRandomCar(); CTheCarGenerators::GenerateEvenIfPlayerIsCloseCounter = 20; } @@ -111,6 +130,7 @@ void CCarCtrl::GenerateOneRandomCar() { static int32 unk = 0; + bool bTopDownCamera = false; CPlayerInfo* pPlayer = &CWorld::Players[CWorld::PlayerInFocus]; CVector vecTargetPos = FindPlayerCentreOfWorld(CWorld::PlayerInFocus); CVector2D vecPlayerSpeed = FindPlayerSpeed(); @@ -125,7 +145,7 @@ CCarCtrl::GenerateOneRandomCar() int carClass; int carModel; if (pWanted->m_nWantedLevel > 1 && NumLawEnforcerCars < pWanted->m_MaximumLawEnforcerVehicles && - pWanted->m_CurrentCops < pWanted->m_MaxCops && ( + pWanted->m_CurrentCops < pWanted->m_MaxCops && !CGame::IsInInterior() && ( pWanted->m_nWantedLevel > 3 || pWanted->m_nWantedLevel > 2 && CTimer::GetTimeInMilliseconds() > LastTimeLawEnforcerCreated + 5000 || pWanted->m_nWantedLevel > 1 && CTimer::GetTimeInMilliseconds() > LastTimeLawEnforcerCreated + 8000)) { @@ -135,7 +155,7 @@ CCarCtrl::GenerateOneRandomCar() carModel = ChoosePoliceCarModel(); }else{ carModel = ChooseModel(&zone, &vecTargetPos, &carClass); - if (carClass == COPS && pWanted->m_nWantedLevel >= 1) + if (carClass == COPS && pWanted->m_nWantedLevel >= 1 || carModel < 0) /* All cop spawns with wanted level are handled by condition above. */ /* In particular it means that cop cars never spawn if player has wanted level of 1. */ return; @@ -159,8 +179,9 @@ CCarCtrl::GenerateOneRandomCar() /* Spawn essentially anywhere. */ frontX = frontY = 0.707f; /* 45 degrees */ angleLimit = -1.0f; + bTopDownCamera = true; invertAngleLimitTest = true; - preferredDistance = 40.0f; + preferredDistance = OFFSCREEN_DESPAWN_RANGE + 15.0f; /* BUG: testForCollision not initialized in original game. */ testForCollision = false; }else if (!pPlayerVehicle){ @@ -174,14 +195,14 @@ CCarCtrl::GenerateOneRandomCar() /* Forward to his current direction (camera direction). */ angleLimit = 0.707f; /* 45 degrees */ invertAngleLimitTest = true; - preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier; + preferredDistance = REQUEST_ONSCREEN_DISTANCE * TheCamera.GenerationDistMultiplier; break; case 1: /* Spawn a vehicle close to player to his side. */ /* Kinda not within camera angle. */ angleLimit = 0.707f; /* 45 degrees */ invertAngleLimitTest = false; - preferredDistance = 40.0f; + preferredDistance = OFFSCREEN_DESPAWN_RANGE; break; } }else if (fPlayerVehicleSpeed > 0.4f){ /* 72 km/h */ @@ -196,21 +217,21 @@ CCarCtrl::GenerateOneRandomCar() /* Spawn a vehicle in a very narrow gap in front of a player */ angleLimit = 0.85f; /* approx 30 degrees */ invertAngleLimitTest = true; - preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier; + preferredDistance = REQUEST_ONSCREEN_DISTANCE * TheCamera.GenerationDistMultiplier; break; case 2: /* Spawn a vehicle relatively far away from player. */ /* Forward to his current direction (camera direction). */ angleLimit = 0.707f; /* 45 degrees */ invertAngleLimitTest = true; - preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier; + preferredDistance = REQUEST_ONSCREEN_DISTANCE * TheCamera.GenerationDistMultiplier; break; case 3: /* Spawn a vehicle close to player to his side. */ /* Kinda not within camera angle. */ angleLimit = 0.707f; /* 45 degrees */ invertAngleLimitTest = false; - preferredDistance = 40.0f; + preferredDistance = OFFSCREEN_DESPAWN_RANGE; break; } }else if (fPlayerVehicleSpeed > 0.1f){ /* 18 km/h */ @@ -224,14 +245,14 @@ CCarCtrl::GenerateOneRandomCar() /* Spawn a vehicle in a very narrow gap in front of a player */ angleLimit = 0.85f; /* approx 30 degrees */ invertAngleLimitTest = true; - preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier; + preferredDistance = REQUEST_ONSCREEN_DISTANCE * TheCamera.GenerationDistMultiplier; break; case 1: /* Spawn a vehicle relatively far away from player. */ /* Forward to his current direction (camera direction). */ angleLimit = 0.707f; /* 45 degrees */ invertAngleLimitTest = true; - preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier; + preferredDistance = REQUEST_ONSCREEN_DISTANCE * TheCamera.GenerationDistMultiplier; break; case 2: case 3: @@ -239,7 +260,7 @@ CCarCtrl::GenerateOneRandomCar() /* Kinda not within camera angle. */ angleLimit = 0.707f; /* 45 degrees */ invertAngleLimitTest = false; - preferredDistance = 40.0f; + preferredDistance = OFFSCREEN_DESPAWN_RANGE; break; } }else{ @@ -254,14 +275,14 @@ CCarCtrl::GenerateOneRandomCar() /* Forward to his current direction (camera direction). */ angleLimit = 0.707f; /* 45 degrees */ invertAngleLimitTest = true; - preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier; + preferredDistance = REQUEST_ONSCREEN_DISTANCE * TheCamera.GenerationDistMultiplier; break; case 1: /* Spawn a vehicle close to player to his side. */ /* Kinda not within camera angle. */ angleLimit = 0.707f; /* 45 degrees */ invertAngleLimitTest = false; - preferredDistance = 40.0f; + preferredDistance = OFFSCREEN_DESPAWN_RANGE; break; } } @@ -269,17 +290,45 @@ CCarCtrl::GenerateOneRandomCar() preferredDistance, angleLimit, invertAngleLimitTest, &spawnPosition, &curNodeId, &nextNodeId, &positionBetweenNodes, carClass == COPS && pWanted->m_nWantedLevel >= 1)) return; + CPathNode* pCurNode = &ThePaths.m_pathNodes[curNodeId]; + CPathNode* pNextNode = &ThePaths.m_pathNodes[nextNodeId]; + bool bBoatGenerated = false; + if ((CGeneral::GetRandomNumber() & 0xF) > Min(pCurNode->spawnRate, pNextNode->spawnRate)) + return; + if (pCurNode->bWaterPath) { + bBoatGenerated = true; + if (carClass == COPS) { + carModel = MI_PREDATOR; + carClass = COPS_BOAT; + if (!CStreaming::HasModelLoaded(MI_PREDATOR)) { + CStreaming::RequestModel(MI_PREDATOR, STREAMFLAGS_DEPENDENCY); + return; + } + } + else { + int i; + carModel = -1; + for (i = 10; i > 0 && (carModel == -1 || !CStreaming::HasModelLoaded(carModel)); i--) { + carModel = ChooseBoatModel(ChooseBoatRating(&zone)); + } + if (i == 0) + return; + } + if (pCurNode->bOnlySmallBoats || pNextNode->bOnlySmallBoats) { + if (BoatWithTallMast(carModel)) + return; + } + } int16 colliding; - CWorld::FindObjectsKindaColliding(spawnPosition, 10.0f, true, &colliding, 2, nil, false, true, true, false, false); + CWorld::FindObjectsKindaColliding(spawnPosition, bBoatGenerated ? 40.0f : 10.0f, true, &colliding, 2, nil, false, true, true, false, false); if (colliding) /* If something is already present in spawn position, do not create vehicle*/ return; - if (!ThePaths.TestCoorsCloseness(vecTargetPos, false, spawnPosition)) + if (!bBoatGenerated && !ThePaths.TestCoorsCloseness(vecTargetPos, false, spawnPosition)) /* Testing if spawn position can reach target position via valid path. */ return; int16 idInNode = 0; - CPathNode* pCurNode = &ThePaths.m_pathNodes[curNodeId]; - CPathNode* pNextNode = &ThePaths.m_pathNodes[nextNodeId]; + while (idInNode < pCurNode->numLinks && ThePaths.ConnectedNode(idInNode + pCurNode->firstLink) != nextNodeId) idInNode++; @@ -287,48 +336,20 @@ CCarCtrl::GenerateOneRandomCar() CCarPathLink* pPathLink = &ThePaths.m_carPathLinks[connectionId]; int16 lanesOnCurrentRoad = pPathLink->pathNodeIndex == nextNodeId ? pPathLink->numLeftLanes : pPathLink->numRightLanes; CVehicleModelInfo* pModelInfo = (CVehicleModelInfo*)CModelInfo::GetModelInfo(carModel); - if (lanesOnCurrentRoad == 0 || pModelInfo->m_vehicleType == VEHICLE_TYPE_BIKE) + if (lanesOnCurrentRoad == 0) /* Not spawning vehicle if road is one way and intended direction is opposide to that way. */ - /* Also not spawning bikes but they don't exist in final game. */ return; - CAutomobile* pVehicle = new CAutomobile(carModel, RANDOM_VEHICLE); + CVehicle* pVehicle; + if (CModelInfo::IsBoatModel(carModel)) + pVehicle = new CBoat(carModel, RANDOM_VEHICLE); + else if (CModelInfo::IsBikeModel(carModel)) + return; // TODO(MIAMI): spawn bikes + else + pVehicle = new CAutomobile(carModel, RANDOM_VEHICLE); pVehicle->AutoPilot.m_nPrevRouteNode = 0; pVehicle->AutoPilot.m_nCurrentRouteNode = curNodeId; pVehicle->AutoPilot.m_nNextRouteNode = nextNodeId; switch (carClass) { - case POOR: - case RICH: - case EXEC: - case WORKER: - case SPECIAL: - case BIG: - case TAXI: - case MAFIA: - case TRIAD: - case DIABLO: - case YAKUZA: - case YARDIE: - case COLOMB: - case NINES: - case GANG8: - case GANG9: - { - pVehicle->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(9, 14); - if (carClass == EXEC) - pVehicle->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(12, 18); - else if (carClass == POOR || carClass == SPECIAL) - pVehicle->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(7, 10); - CVehicleModelInfo* pVehicleInfo = pVehicle->GetModelInfo(); - if (pVehicleInfo->GetColModel()->boundingBox.max.y - pVehicle->GetModelInfo()->GetColModel()->boundingBox.min.y > 10.0f || carClass == BIG) { - pVehicle->AutoPilot.m_nCruiseSpeed *= 3; - pVehicle->AutoPilot.m_nCruiseSpeed /= 4; - } - pVehicle->AutoPilot.m_fMaxTrafficSpeed = pVehicle->AutoPilot.m_nCruiseSpeed; - pVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE; - pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE; - pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS; - break; - } case COPS: pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE; if (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->m_nWantedLevel != 0){ @@ -345,16 +366,37 @@ CCarCtrl::GenerateOneRandomCar() if (carModel == MI_FBICAR){ pVehicle->m_currentColour1 = 0; pVehicle->m_currentColour2 = 0; - /* FBI cars are gray in carcols, but we want them black if they going after player. */ } + pVehicle->bCreatedAsPoliceVehicle = true; + break; + case COPS_BOAT: + pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE; + pVehicle->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(4.0f, 16.0f); + pVehicle->AutoPilot.m_fMaxTrafficSpeed = pVehicle->AutoPilot.m_nCruiseSpeed; + pVehicle->AutoPilot.m_nCarMission = CCarAI::FindPoliceBoatMissionForWantedLevel(); + pVehicle->bCreatedAsPoliceVehicle = true; + break; default: + pVehicle->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(9, 14); + if (carClass == EXEC) + pVehicle->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(12, 18); + else if (carClass == POOR) + pVehicle->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(7, 10); + if (pVehicle->GetColModel()->boundingBox.max.y - pVehicle->GetColModel()->boundingBox.min.y > 10.0f || carClass == BIG) { + pVehicle->AutoPilot.m_nCruiseSpeed *= 3; + pVehicle->AutoPilot.m_nCruiseSpeed /= 4; + } + pVehicle->AutoPilot.m_fMaxTrafficSpeed = pVehicle->AutoPilot.m_nCruiseSpeed; + pVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE; + pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE; + pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS; break; } if (pVehicle && pVehicle->GetModelIndex() == MI_MRWHOOP) pVehicle->m_bSirenOrAlarm = true; pVehicle->AutoPilot.m_nNextPathNodeInfo = connectionId; pVehicle->AutoPilot.m_nNextLane = pVehicle->AutoPilot.m_nCurrentLane = CGeneral::GetRandomNumber() % lanesOnCurrentRoad; - CColBox* boundingBox = &CModelInfo::GetModelInfo(pVehicle->GetModelIndex())->GetColModel()->boundingBox; + CBox* boundingBox = &CModelInfo::GetModelInfo(pVehicle->GetModelIndex())->GetColModel()->boundingBox; float carLength = 1.0f + (boundingBox->max.y - boundingBox->min.y) / 2; float distanceBetweenNodes = (pCurNode->GetPosition() - pNextNode->GetPosition()).Magnitude2D(); /* If car is so long that it doesn't fit between two car nodes, place it directly in the middle. */ @@ -393,11 +435,6 @@ CCarCtrl::GenerateOneRandomCar() pVehicle->GetRight() = CVector(forwardY, -forwardX, 0.0f); pVehicle->GetUp() = CVector(0.0f, 0.0f, 1.0f); - float currentPathLinkForwardX = pVehicle->AutoPilot.m_nCurrentDirection * ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nCurrentPathNodeInfo].GetDirX(); - float currentPathLinkForwardY = pVehicle->AutoPilot.m_nCurrentDirection * ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nCurrentPathNodeInfo].GetDirY(); - float nextPathLinkForwardX = pVehicle->AutoPilot.m_nNextDirection * ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nNextPathNodeInfo].GetDirX(); - float nextPathLinkForwardY = pVehicle->AutoPilot.m_nNextDirection * ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nNextPathNodeInfo].GetDirY(); - #ifdef FIX_BUGS CCarPathLink* pCurrentLink; CCarPathLink* pNextLink; @@ -492,6 +529,7 @@ CCarCtrl::GenerateOneRandomCar() pVehicle->AutoPilot.m_nTimeEnteredCurve = CTimer::GetTimeInMilliseconds() - (0.5f + positionBetweenNodes) * pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve; #endif + CVector directionCurrentLink(directionCurrentLinkX, directionCurrentLinkY, 0.0f); CVector directionNextLink(directionNextLinkX, directionNextLinkY, 0.0f); CVector positionIncludingCurve; @@ -513,62 +551,69 @@ CCarCtrl::GenerateOneRandomCar() float groundZ = INFINITE_Z; CColPoint colPoint; CEntity* pEntity; - if (CWorld::ProcessVerticalLine(finalPosition, 1000.0f, colPoint, pEntity, true, false, false, false, true, false, nil)) - groundZ = colPoint.point.z; - if (CWorld::ProcessVerticalLine(finalPosition, -1000.0f, colPoint, pEntity, true, false, false, false, true, false, nil)){ - if (ABS(colPoint.point.z - finalPosition.z) < ABS(groundZ - finalPosition.z)) + if (bBoatGenerated) { + if (!CWaterLevel::GetWaterLevel(finalPosition, &groundZ, true)) { + delete pVehicle; + return; + } + } + else { + if (CWorld::ProcessVerticalLine(finalPosition, 1000.0f, colPoint, pEntity, true, false, false, false, true, false, nil)) groundZ = colPoint.point.z; + if (CWorld::ProcessVerticalLine(finalPosition, -1000.0f, colPoint, pEntity, true, false, false, false, true, false, nil)) { + if (ABS(colPoint.point.z - finalPosition.z) < ABS(groundZ - finalPosition.z)) + groundZ = colPoint.point.z; + } } if (groundZ == INFINITE_Z || ABS(groundZ - finalPosition.z) > 7.0f) { /* Failed to find ground or too far from expected position. */ delete pVehicle; return; } - finalPosition.z = groundZ + pVehicle->GetHeightAboveRoad(); + if (CModelInfo::IsBoatModel(carModel)) { + finalPosition.z = groundZ; + pVehicle->bExtendedRange = true; + } + else + finalPosition.z = groundZ + pVehicle->GetHeightAboveRoad(); pVehicle->SetPosition(finalPosition); pVehicle->SetMoveSpeed(directionIncludingCurve / GAME_SPEED_TO_CARAI_SPEED); CVector2D speedDifferenceWithTarget = (CVector2D)pVehicle->GetMoveSpeed() - vecPlayerSpeed; CVector2D distanceToTarget = positionIncludingCurve - vecTargetPos; switch (carClass) { - case POOR: - case RICH: - case EXEC: - case WORKER: - case SPECIAL: - case BIG: - case TAXI: - case MAFIA: - case TRIAD: - case DIABLO: - case YAKUZA: - case YARDIE: - case COLOMB: - case NINES: - case GANG8: - case GANG9: - pVehicle->SetStatus(STATUS_SIMPLE); - break; case COPS: pVehicle->SetStatus((pVehicle->AutoPilot.m_nCarMission == MISSION_CRUISE) ? STATUS_SIMPLE : STATUS_PHYSICS); pVehicle->ChangeLawEnforcerState(1); break; + case COPS_BOAT: + pVehicle->ChangeLawEnforcerState(1); + pVehicle->SetStatus(STATUS_PHYSICS); + break; default: + bBoatGenerated ? pVehicle->SetStatus(STATUS_PHYSICS) : pVehicle->SetStatus(STATUS_SIMPLE); break; } CVisibilityPlugins::SetClumpAlpha(pVehicle->GetClump(), 0); if (!pVehicle->GetIsOnScreen()){ - if ((vecTargetPos - pVehicle->GetPosition()).Magnitude2D() > 50.0f) { + if ((vecTargetPos - pVehicle->GetPosition()).Magnitude2D() > OFFSCREEN_DESPAWN_RANGE * (pVehicle->bExtendedRange ? EXTENDED_RANGE_DESPAWN_MULTIPLIER : 1.0f)) { /* Too far away cars that are not visible aren't needed. */ delete pVehicle; return; } - }else if((vecTargetPos - pVehicle->GetPosition()).Magnitude2D() > TheCamera.GenerationDistMultiplier * 130.0f || - (vecTargetPos - pVehicle->GetPosition()).Magnitude2D() < TheCamera.GenerationDistMultiplier * 110.0f){ - delete pVehicle; - return; - }else if((TheCamera.GetPosition() - pVehicle->GetPosition()).Magnitude2D() < 90.0f * TheCamera.GenerationDistMultiplier){ - delete pVehicle; - return; + }else{ + if ((vecTargetPos - pVehicle->GetPosition()).Magnitude2D() > TheCamera.GenerationDistMultiplier * (pVehicle->bExtendedRange ? EXTENDED_RANGE_DESPAWN_MULTIPLIER : 1.0f) * ONSCREEN_DESPAWN_RANGE || + (vecTargetPos - pVehicle->GetPosition()).Magnitude2D() < TheCamera.GenerationDistMultiplier * MINIMAL_DISTANCE_TO_SPAWN_ONSCREEN) { + delete pVehicle; + return; + } + if ((TheCamera.GetPosition() - pVehicle->GetPosition()).Magnitude2D() < 82.5f * TheCamera.GenerationDistMultiplier || bTopDownCamera) { + delete pVehicle; + return; + } + if (pVehicle->GetModelIndex() == MI_MARQUIS) { // so marquis can only spawn if player doesn't see it? + delete pVehicle; + return; + } } CVehicleModelInfo* pVehicleModel = pVehicle->GetModelInfo(); float radiusToTest = pVehicleModel->GetColModel()->boundingSphere.radius; @@ -591,58 +636,152 @@ CCarCtrl::GenerateOneRandomCar() } pVehicleModel->AvoidSameVehicleColour(&pVehicle->m_currentColour1, &pVehicle->m_currentColour2); CWorld::Add(pVehicle); - if (carClass == COPS) + if (carClass == COPS || carClass == COPS_BOAT) CCarAI::AddPoliceCarOccupants(pVehicle); - else + else { pVehicle->SetUpDriver(); - if ((CGeneral::GetRandomNumber() & 0x3F) == 0){ /* 1/64 probability */ + int32 passengers = 0; + for (int i = 0; i < pVehicle->m_nNumMaxPassengers; i++) + passengers += (CGeneral::GetRandomNumberInRange(0.0f, 1.0f) < PROBABILITY_OF_PASSENGER_IN_VEHICLE) ? 1 : 0; + if (CModelInfo::IsCarModel(carModel) && (CModelInfo::GetModelInfo(carModel)->GetAnimFileIndex() == CAnimManager::GetAnimationBlockIndex("van") && passengers >= 1)) + passengers = 1; + for (int i = 0; i < passengers; i++) { + CPed* pPassenger = pVehicle->SetupPassenger(i); + if (pPassenger) { + ++CPopulation::ms_nTotalCarPassengerPeds; + pPassenger->bCarPassenger = true; + } + } + } + int nMadDrivers; + switch (pVehicle->GetVehicleAppearance()) { + case VEHICLE_APPEARANCE_BIKE: + nMadDrivers = 30; + break; + case VEHICLE_APPEARANCE_BOAT: + nMadDrivers = 40; + break; + default: + nMadDrivers = 6; + break; + } + if ((CGeneral::GetRandomNumber() & 0x7F) < nMadDrivers /* TODO(MIAMI): || mad drivers cheat */) { pVehicle->SetStatus(STATUS_PHYSICS); pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; pVehicle->AutoPilot.m_nCruiseSpeed += 10; } if (carClass == COPS) LastTimeLawEnforcerCreated = CTimer::GetTimeInMilliseconds(); + if (pVehicle->GetModelIndex() == MI_CADDY) { + pVehicle->SetStatus(STATUS_PHYSICS); + pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; + } + if (carClass == COPS && pVehicle->GetModelIndex() == MI_VICECHEE) { + CVehicleModelInfo* pVehicleModel = (CVehicleModelInfo*)CModelInfo::GetModelInfo(MI_VICECHEE); + switch (MiamiViceCycle) { + case 0: + pVehicleModel->SetVehicleColour(53, 77); + break; + case 1: + pVehicleModel->SetVehicleColour(15, 77); + break; + case 2: + pVehicleModel->SetVehicleColour(41, 77); + break; + case 3: + pVehicleModel->SetVehicleColour(61, 77); + break; + default: + break; + } + } + if (CGeneral::GetRandomNumberInRange(0.0f, 1.0f) >= (1 - PROBABILITY_OF_DEAD_PED_ACCIDENT)) { + if (CModelInfo::IsCarModel(pVehicle->GetModelIndex()) && !pVehicle->bIsLawEnforcer) { + if (CPopulation::AddDeadPedInFrontOfCar(pVehicle->GetPosition() + pVehicle->GetForward() * DISTANCE_BETWEEN_CAR_AND_DEAD_PED, pVehicle)) { + pVehicle->AutoPilot.m_nCruiseSpeed = 0; + pVehicle->SetMoveSpeed(0.0f, 0.0f, 0.0f); + for (int i = 0; i < pVehicle->m_nNumPassengers; i++) { + if (pVehicle->pPassengers[i]) { + pVehicle->pPassengers[i]->SetObjective(OBJECTIVE_LEAVE_VEHICLE, pVehicle); + pVehicle->pPassengers[i]->m_nLastPedState = PED_WANDER_PATH; + pVehicle->pPassengers[i]->m_vehicleInAccident = pVehicle; + pVehicle->pPassengers[i]->bDeadPedInFrontOfCar = true; + pVehicle->RegisterReference((CEntity**)&pVehicle->pPassengers[i]->m_vehicleInAccident); + } + } + if (pVehicle->pDriver) { + pVehicle->pDriver->SetObjective(OBJECTIVE_LEAVE_VEHICLE, pVehicle); + pVehicle->pDriver->m_nLastPedState = PED_WANDER_PATH; + pVehicle->pDriver->m_vehicleInAccident = pVehicle; + pVehicle->pDriver->bDeadPedInFrontOfCar = true; + pVehicle->RegisterReference((CEntity**)&pVehicle->pDriver->m_vehicleInAccident); + } + } + } + } +} + +bool +CCarCtrl::BoatWithTallMast(int32 mi) +{ + return mi == MI_RIO || mi == MI_TROPIC || mi == MI_MARQUIS; +} + +int32 +CCarCtrl::ChooseBoatModel(int32 rating) +{ + ++NumRequestsOfCarRating[rating]; + return ChooseCarModel(rating); +} + +int32 +CCarCtrl::ChooseBoatRating(CZoneInfo* pZoneInfo) +{ + int rnd = CGeneral::GetRandomNumberInRange(0, 1000); + for (int i = 0; i < NUM_BOAT_CLASSES - 1; i++) { + if (rnd < pZoneInfo->boatThreshold[i]) + return FIRST_BOAT_RATING + i; + } + return FIRST_BOAT_RATING + NUM_BOAT_CLASSES - 1; +} + +int32 +CCarCtrl::ChooseCarRating(CZoneInfo* pZoneInfo) +{ + int rnd = CGeneral::GetRandomNumberInRange(0, 1000); + for (int i = 0; i < NUM_CAR_CLASSES - 1; i++) { + if (rnd < pZoneInfo->carThreshold[i]) + return i; + } + return FIRST_CAR_RATING + NUM_CAR_CLASSES - 1; } int32 CCarCtrl::ChooseModel(CZoneInfo* pZone, CVector* pPos, int* pClass) { int32 model = -1; - while (model == -1 || !CStreaming::HasModelLoaded(model)){ + for (int i = 0; i < 10 && (model == -1 || !CStreaming::HasModelLoaded(model)); i++) { int rnd = CGeneral::GetRandomNumberInRange(0, 1000); - if (rnd < pZone->carThreshold[0]) - model = CCarCtrl::ChooseCarModel((*pClass = POOR)); - else if (rnd < pZone->carThreshold[1]) - model = CCarCtrl::ChooseCarModel((*pClass = RICH)); - else if (rnd < pZone->carThreshold[2]) - model = CCarCtrl::ChooseCarModel((*pClass = EXEC)); - else if (rnd < pZone->carThreshold[3]) - model = CCarCtrl::ChooseCarModel((*pClass = WORKER)); - else if (rnd < pZone->carThreshold[4]) - model = CCarCtrl::ChooseCarModel((*pClass = SPECIAL)); - else if (rnd < pZone->carThreshold[5]) - model = CCarCtrl::ChooseCarModel((*pClass = BIG)); - else if (rnd < pZone->copThreshold) - *pClass = COPS, model = CCarCtrl::ChoosePoliceCarModel(); - else if (rnd < pZone->gangThreshold[0]) - model = CCarCtrl::ChooseGangCarModel((*pClass = MAFIA) - MAFIA); - else if (rnd < pZone->gangThreshold[1]) - model = CCarCtrl::ChooseGangCarModel((*pClass = TRIAD) - MAFIA); - else if (rnd < pZone->gangThreshold[2]) - model = CCarCtrl::ChooseGangCarModel((*pClass = DIABLO) - MAFIA); - else if (rnd < pZone->gangThreshold[3]) - model = CCarCtrl::ChooseGangCarModel((*pClass = YAKUZA) - MAFIA); - else if (rnd < pZone->gangThreshold[4]) - model = CCarCtrl::ChooseGangCarModel((*pClass = YARDIE) - MAFIA); - else if (rnd < pZone->gangThreshold[5]) - model = CCarCtrl::ChooseGangCarModel((*pClass = COLOMB) - MAFIA); - else if (rnd < pZone->gangThreshold[6]) - model = CCarCtrl::ChooseGangCarModel((*pClass = NINES) - MAFIA); - else if (rnd < pZone->gangThreshold[7]) - model = CCarCtrl::ChooseGangCarModel((*pClass = GANG8) - MAFIA); - else if (rnd < pZone->gangThreshold[8]) - model = CCarCtrl::ChooseGangCarModel((*pClass = GANG9) - MAFIA); - else - model = CCarCtrl::ChooseCarModel((*pClass = TAXI)); + + if (rnd < pZone->copThreshold) { + *pClass = COPS; + model = ChoosePoliceCarModel(); + continue; + } + + int j; + for (j = 0; j < NUM_GANG_CAR_CLASSES; j++) { + if (rnd < pZone->gangThreshold[i]) { + *pClass = j + FIRST_GANG_CAR_RATING; + model = ChooseGangCarModel(j); + break; + } + } + + if (j != NUM_GANG_CAR_CLASSES) + continue; + + *pClass = ChooseCarRating(pZone); + model = ChooseCarModel(*pClass); } return model; } @@ -651,34 +790,86 @@ int32 CCarCtrl::ChooseCarModel(int32 vehclass) { int32 model = -1; - switch (vehclass) { - case POOR: - case RICH: - case EXEC: - case WORKER: - case SPECIAL: - case BIG: - case TAXI: - { - if (TotalNumOfCarsOfRating[vehclass] == 0) - debug("ChooseCarModel : No cars of type %d have been declared\n", vehclass); - model = CarArrays[vehclass][NextCarOfRating[vehclass]]; - int32 total = TotalNumOfCarsOfRating[vehclass]; - NextCarOfRating[vehclass] += CGeneral::GetRandomNumberInRange(1, total); - while (NextCarOfRating[vehclass] >= total) - NextCarOfRating[vehclass] -= total; - //NextCarOfRating[vehclass] %= total; - TotalNumOfCarsOfRating[vehclass] = total; /* why... */ - } - default: - break; - } - return model; + ++NumRequestsOfCarRating[vehclass]; + if (NumOfLoadedCarsOfRating[vehclass] == 0) + return -1; + int32 rnd = CGeneral::GetRandomNumberInRange(0, CarFreqArrays[vehclass][NumOfLoadedCarsOfRating[vehclass] - 1]); + int32 index = 0; + while (rnd > CarFreqArrays[vehclass][index]) + index++; + assert(LoadedCarsArray[vehclass][index]); + return LoadedCarsArray[vehclass][index]; +} + +void +CCarCtrl::AddToLoadedVehicleArray(int32 mi, int32 rating, int32 freq) +{ + LoadedCarsArray[rating][NumOfLoadedCarsOfRating[rating]] = mi; + assert(mi >= 130); + CarFreqArrays[rating][NumOfLoadedCarsOfRating[rating]] = freq; + if (NumOfLoadedCarsOfRating[rating]) + CarFreqArrays[rating][NumOfLoadedCarsOfRating[rating]] += CarFreqArrays[rating][NumOfLoadedCarsOfRating[rating] - 1]; + NumOfLoadedCarsOfRating[rating]++; +} + +void +CCarCtrl::RemoveFromLoadedVehicleArray(int mi, int32 rating) +{ + int index = 0; + while (LoadedCarsArray[rating][index] != -1) { + if (LoadedCarsArray[rating][index] == mi) + break; + index++; + } + assert(LoadedCarsArray[rating][index] == mi); + int32 freq = CarFreqArrays[rating][index]; + if (index > 0) + freq -= CarFreqArrays[rating][index - 1]; + while (LoadedCarsArray[rating][index + 1] != -1) { + LoadedCarsArray[rating][index] = LoadedCarsArray[rating][index + 1]; + CarFreqArrays[rating][index] = CarFreqArrays[rating][index + 1] - freq; + index++; + } + --NumOfLoadedCarsOfRating[rating]; +} + +int32 +CCarCtrl::ChooseCarModelToLoad(int rating) +{ + return CarArrays[rating][CGeneral::GetRandomNumberInRange(0, TotalNumOfCarsOfRating[rating])]; } int32 CCarCtrl::ChoosePoliceCarModel(void) { + if (FindPlayerPed()->m_pWanted->AreMiamiViceRequired() && +#ifdef FIX_BUGS + (CTimer::GetTimeInMilliseconds() > LastTimeMiamiViceGenerated + 120000 || LastTimeMiamiViceGenerated == 0) && +#else + CTimer::GetTimeInMilliseconds() > LastTimeMiamiViceGenerated + 120000 && +#endif + CStreaming::HasModelLoaded(MI_VICECHEE)) { + switch (MiamiViceCycle) { + case 0: + if (CStreaming::HasModelLoaded(MI_VICE1) && CStreaming::HasModelLoaded(MI_VICE2)) + return MI_VICECHEE; + break; + case 1: + if (CStreaming::HasModelLoaded(MI_VICE3) && CStreaming::HasModelLoaded(MI_VICE4)) + return MI_VICECHEE; + break; + case 2: + if (CStreaming::HasModelLoaded(MI_VICE5) && CStreaming::HasModelLoaded(MI_VICE6)) + return MI_VICECHEE; + break; + case 3: + if (CStreaming::HasModelLoaded(MI_VICE7) && CStreaming::HasModelLoaded(MI_VICE8)) + return MI_VICECHEE; + break; + default: + break; + } + } if (FindPlayerPed()->m_pWanted->AreSwatRequired() && CStreaming::HasModelLoaded(MI_ENFORCER) && CStreaming::HasModelLoaded(MI_POLICE)) @@ -698,8 +889,7 @@ CCarCtrl::ChoosePoliceCarModel(void) int32 CCarCtrl::ChooseGangCarModel(int32 gang) { - if (CStreaming::HasModelLoaded(MI_GANG01 + 2 * gang) && - CStreaming::HasModelLoaded(MI_GANG02 + 2 * gang)) + if (CGangs::HaveGangModelsLoaded(gang)) return CGangs::GetGangVehicleModel(gang); return -1; } @@ -707,6 +897,7 @@ CCarCtrl::ChooseGangCarModel(int32 gang) void CCarCtrl::AddToCarArray(int32 id, int32 vehclass) { + assert(TotalNumOfCarsOfRating[vehclass] < MAX_CAR_MODELS_IN_ARRAY); CarArrays[vehclass][TotalNumOfCarsOfRating[vehclass]++] = id; } @@ -728,6 +919,36 @@ CCarCtrl::RemoveDistantCars() } void +CCarCtrl::RemoveCarsIfThePoolGetsFull(void) +{ + if ((CTimer::GetFrameCounter() & 7) != 3) + return; + if (CPools::GetVehiclePool()->GetNoOfFreeSpaces() >= 8) + return; + int i = CPools::GetVehiclePool()->GetSize(); + float md = 999999.9f; + CVehicle* pClosestVehicle = nil; + while (i--) { + CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i); + if (!pVehicle) + continue; + if (IsThisVehicleInteresting(pVehicle) || pVehicle->bIsLocked) + continue; + if (!pVehicle->CanBeDeleted() || CCranes::IsThisCarBeingTargettedByAnyCrane(pVehicle)) + continue; + float distance = (TheCamera.GetPosition() - pVehicle->GetPosition()).Magnitude(); + if (distance < md) { + md = distance; + pClosestVehicle = pVehicle; + } + } + if (pClosestVehicle) { + CWorld::Remove(pClosestVehicle); + delete pClosestVehicle; + } +} + +void CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle) { CVector vecPlayerPos = FindPlayerCentreOfWorld(CWorld::PlayerInFocus); @@ -740,7 +961,7 @@ CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle) return; } float distanceToPlayer = (pVehicle->GetPosition() - vecPlayerPos).Magnitude2D(); - float threshold = 50.0f; + float threshold = OFFSCREEN_DESPAWN_RANGE; if (pVehicle->GetIsOnScreen() || TheCamera.Cams[TheCamera.ActiveCam].LookingLeft || TheCamera.Cams[TheCamera.ActiveCam].LookingRight || @@ -752,12 +973,14 @@ CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle) pVehicle->bIsLawEnforcer || pVehicle->bIsCarParkVehicle ){ - threshold = 130.0f * TheCamera.GenerationDistMultiplier; + threshold = ONSCREEN_DESPAWN_RANGE * TheCamera.GenerationDistMultiplier; } + if (TheCamera.GetForward().z < -0.9f) + threshold = 70.0f; if (pVehicle->bExtendedRange) - threshold *= 1.5f; + threshold *= EXTENDED_RANGE_DESPAWN_MULTIPLIER; if (distanceToPlayer > threshold && !CGarages::IsPointWithinHideOutGarage(pVehicle->GetPosition())){ - if (pVehicle->GetIsOnScreen() && CRenderer::IsEntityCullZoneVisible(pVehicle)) { + if (pVehicle->GetIsOnScreen()){ pVehicle->bFadeOut = true; }else{ CWorld::Remove(pVehicle); @@ -766,7 +989,8 @@ CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle) return; } } - if ((pVehicle->GetStatus() == STATUS_SIMPLE || pVehicle->GetStatus() == STATUS_PHYSICS && pVehicle->AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_STOP_FOR_CARS) && + if ((pVehicle->GetStatus() == STATUS_SIMPLE || pVehicle->GetStatus() == STATUS_PHYSICS && + (pVehicle->AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_STOP_FOR_CARS || pVehicle->AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_STOP_FOR_CARS_IGNORE_LIGHTS)) && CTimer::GetTimeInMilliseconds() - pVehicle->AutoPilot.m_nTimeToStartMission > 5000 && !pVehicle->GetIsOnScreen() && (pVehicle->GetPosition() - vecPlayerPos).Magnitude2D() > 25.0f && @@ -783,7 +1007,7 @@ CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle) if (pVehicle->GetStatus() != STATUS_WRECKED || pVehicle->m_nTimeOfDeath == 0) return; if (CTimer::GetTimeInMilliseconds() > pVehicle->m_nTimeOfDeath + 60000 && - !(pVehicle->GetIsOnScreen() && CRenderer::IsEntityCullZoneVisible(pVehicle)) ){ + !pVehicle->GetIsOnScreen()){ if ((pVehicle->GetPosition() - vecPlayerPos).MagnitudeSqr() > SQR(7.5f)){ if (!CGarages::IsPointWithinHideOutGarage(pVehicle->GetPosition())){ CWorld::Remove(pVehicle); @@ -807,6 +1031,16 @@ CCarCtrl::CountCarsOfType(int32 mi) return total; } +static CVector GetRandomOffsetForVehicle(CVehicle* pVehicle, bool bNext) +{ + CVector offset; + int32 seed = ((bNext ? pVehicle->AutoPilot.m_nNextPathNodeInfo : pVehicle->AutoPilot.m_nCurrentPathNodeInfo) + pVehicle->m_randomSeed) & 7; + offset.x = (seed - 3) * 0.009f; + offset.y = ((seed >> 3) - 3) * 0.009f; + offset.z = 0.0f; + return offset; +} + void CCarCtrl::UpdateCarOnRails(CVehicle* pVehicle) { @@ -839,8 +1073,12 @@ CCarCtrl::UpdateCarOnRails(CVehicle* pVehicle) pNextLink->GetX() + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY, pNextLink->GetY() - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX, 0.0f); - CVector directionCurrentLink(currentPathLinkForwardX, currentPathLinkForwardY, 0.0f); - CVector directionNextLink(nextPathLinkForwardX, nextPathLinkForwardY, 0.0f); + CVector directionCurrentLink = GetRandomOffsetForVehicle(pVehicle, false); + directionCurrentLink += CVector(currentPathLinkForwardX, currentPathLinkForwardY, 0.0f); + directionCurrentLink.Normalise(); + CVector directionNextLink = GetRandomOffsetForVehicle(pVehicle, true); + directionNextLink += CVector(nextPathLinkForwardX, nextPathLinkForwardY, 0.0f); + directionNextLink.Normalise(); CVector positionIncludingCurve; CVector directionIncludingCurve; CCurves::CalcCurvePoint( @@ -863,7 +1101,7 @@ CCarCtrl::FindMaximumSpeedForThisCarInTraffic(CVehicle* pVehicle) { if (pVehicle->AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_AVOID_CARS || pVehicle->AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_PLOUGH_THROUGH) - return pVehicle->AutoPilot.m_nCruiseSpeed; + return pVehicle->AutoPilot.GetCruiseSpeed(); float left = pVehicle->GetPosition().x - DISTANCE_TO_SCAN_FOR_DANGER; float right = pVehicle->GetPosition().x + DISTANCE_TO_SCAN_FOR_DANGER; float top = pVehicle->GetPosition().y - DISTANCE_TO_SCAN_FOR_DANGER; @@ -875,23 +1113,23 @@ CCarCtrl::FindMaximumSpeedForThisCarInTraffic(CVehicle* pVehicle) assert(xstart <= xend); assert(ystart <= yend); - float maxSpeed = pVehicle->AutoPilot.m_nCruiseSpeed; + float maxSpeed = pVehicle->AutoPilot.GetCruiseSpeed(); CWorld::AdvanceCurrentScanCode(); for (int y = ystart; y <= yend; y++){ for (int x = xstart; x <= xend; x++){ CSector* s = CWorld::GetSector(x, y); - SlowCarDownForCarsSectorList(s->m_lists[ENTITYLIST_VEHICLES], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.m_nCruiseSpeed); - SlowCarDownForCarsSectorList(s->m_lists[ENTITYLIST_VEHICLES_OVERLAP], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.m_nCruiseSpeed); - SlowCarDownForPedsSectorList(s->m_lists[ENTITYLIST_PEDS], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.m_nCruiseSpeed); - SlowCarDownForPedsSectorList(s->m_lists[ENTITYLIST_PEDS_OVERLAP], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.m_nCruiseSpeed); + SlowCarDownForCarsSectorList(s->m_lists[ENTITYLIST_VEHICLES], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.GetCruiseSpeed()); + SlowCarDownForCarsSectorList(s->m_lists[ENTITYLIST_VEHICLES_OVERLAP], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.GetCruiseSpeed()); + SlowCarDownForPedsSectorList(s->m_lists[ENTITYLIST_PEDS], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.GetCruiseSpeed()); + SlowCarDownForPedsSectorList(s->m_lists[ENTITYLIST_PEDS_OVERLAP], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.GetCruiseSpeed()); } } pVehicle->bWarnedPeds = true; if (pVehicle->AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_STOP_FOR_CARS) return maxSpeed; - return (maxSpeed + pVehicle->AutoPilot.m_nCruiseSpeed) / 2; + return (maxSpeed + pVehicle->AutoPilot.GetCruiseSpeed()) / 2; } void @@ -1093,8 +1331,8 @@ void CCarCtrl::SlowCarDownForOtherCar(CEntity* pOtherEntity, CVehicle* pVehicle, float proximityA = TestCollisionBetween2MovingRects(pOtherVehicle, pVehicle, projectionX, projectionY, &forwardA, &forwardB, 0); float proximityB = TestCollisionBetween2MovingRects(pVehicle, pOtherVehicle, -projectionX, -projectionY, &forwardB, &forwardA, 1); float minProximity = Min(proximityA, proximityB); - if (minProximity >= 0.0f && minProximity < 1.0f){ - minProximity = Max(0.0f, (minProximity - 0.2f) * 1.25f); + if (minProximity >= 0.0f && minProximity < 1.5f){ + minProximity = Max(0.0f, (minProximity - 0.2f) / 1.3f); pVehicle->AutoPilot.m_bSlowedDownBecauseOfCars = true; *pSpeed = Min(*pSpeed, minProximity * curSpeed); } @@ -1320,19 +1558,21 @@ void CCarCtrl::WeaveThroughCarsSectorList(CPtrList& lst, CVehicle* pVehicle, CPh void CCarCtrl::WeaveForOtherCar(CEntity* pOtherEntity, CVehicle* pVehicle, float* pAngleToWeaveLeft, float* pAngleToWeaveRight) { + CVehicle* pOtherCar = (CVehicle*)pOtherEntity; + if (pVehicle->bPartOfConvoy && pOtherCar->bPartOfConvoy) + return; if (pVehicle->AutoPilot.m_nCarMission == MISSION_RAMPLAYER_CLOSE && pOtherEntity == FindPlayerVehicle()) return; if (pVehicle->AutoPilot.m_nCarMission == MISSION_RAMCAR_CLOSE && pOtherEntity == pVehicle->AutoPilot.m_pTargetCar) return; - CVehicle* pOtherCar = (CVehicle*)pOtherEntity; CVector2D vecDiff = pOtherCar->GetPosition() - pVehicle->GetPosition(); float angleBetweenVehicles = CGeneral::GetATanOfXY(vecDiff.x, vecDiff.y); float distance = vecDiff.Magnitude(); if (distance < 1.0f) return; if (DotProduct2D(pVehicle->GetMoveSpeed() - pOtherCar->GetMoveSpeed(), vecDiff) * 110.0f - - pOtherCar->GetModelInfo()->GetColModel()->boundingSphere.radius - - pVehicle->GetModelInfo()->GetColModel()->boundingSphere.radius < distance) + pOtherCar->GetColModel()->boundingSphere.radius - + pVehicle->GetColModel()->boundingSphere.radius < distance) return; CVector2D forward = pVehicle->GetForward(); forward.Normalise(); @@ -1506,23 +1746,30 @@ bool CCarCtrl::PickNextNodeAccordingStrategy(CVehicle* pVehicle) return false; default: PickNextNodeRandomly(pVehicle); + if (ThePaths.GetNode(pVehicle->AutoPilot.m_nNextRouteNode)->bOnlySmallBoats && BoatWithTallMast(pVehicle->GetModelIndex())) + pVehicle->AutoPilot.m_nCruiseSpeed = 0; return false; } } void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle) { + if (pVehicle->m_nRouteSeed) + CGeneral::SetRandomSeed(pVehicle->m_nRouteSeed); int32 prevNode = pVehicle->AutoPilot.m_nCurrentRouteNode; int32 curNode = pVehicle->AutoPilot.m_nNextRouteNode; uint8 totalLinks = ThePaths.m_pathNodes[curNode].numLinks; CCarPathLink* pCurLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nNextPathNodeInfo]; -#ifdef FIX_BUGS - uint8 lanesOnCurrentPath = pCurLink->pathNodeIndex == curNode ? - pCurLink->numLeftLanes : pCurLink->numRightLanes; -#else - uint8 lanesOnCurrentPath = pCurLink->pathNodeIndex == curNode ? - pCurLink->numRightLanes : pCurLink->numLeftLanes; -#endif + uint8 lanesOnCurrentPath; + bool isOnOneWayRoad; + if (pCurLink->pathNodeIndex == curNode) { + lanesOnCurrentPath = pCurLink->numLeftLanes; + isOnOneWayRoad = pCurLink->numRightLanes == 0; + } + else { + lanesOnCurrentPath = pCurLink->numRightLanes; + isOnOneWayRoad = pCurLink->numLeftLanes == 0; + } uint8 allowedDirections = PATH_DIRECTION_NONE; uint8 nextLane = pVehicle->AutoPilot.m_nNextLane; if (nextLane == 0) @@ -1544,6 +1791,7 @@ void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle) CCarPathLink* pNextLink; CPathNode* pNextPathNode; bool goingAgainstOneWayRoad; + bool nextNodeIsOneWayRoad; uint8 direction; for(attempt = 0; attempt < ATTEMPTS_TO_FIND_NEXT_NODE; attempt++){ if (attempt != 0){ @@ -1553,7 +1801,7 @@ void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle) if ((!pNextPathNode->bDeadEnd || pPrevPathNode->bDeadEnd) && (!pNextPathNode->bDisabled || pPrevPathNode->bDisabled) && (!pNextPathNode->bBetweenLevels || pPrevPathNode->bBetweenLevels || !pVehicle->AutoPilot.m_bStayInCurrentLevel) && - !goingAgainstOneWayRoad) + !goingAgainstOneWayRoad && (!isOnOneWayRoad || !nextNodeIsOneWayRoad)) break; } } @@ -1563,9 +1811,10 @@ void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle) direction = FindPathDirection(prevNode, curNode, pVehicle->AutoPilot.m_nNextRouteNode); pNextLink = &ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[nextLink + pCurPathNode->firstLink]]; goingAgainstOneWayRoad = pNextLink->pathNodeIndex == curNode ? pNextLink->numRightLanes == 0 : pNextLink->numLeftLanes == 0; + nextNodeIsOneWayRoad = pNextLink->pathNodeIndex == curNode ? pNextLink->numLeftLanes == 0 : pNextLink->numRightLanes == 0; } if (attempt >= ATTEMPTS_TO_FIND_NEXT_NODE) { - /* If we failed 15 times, then remove dead end and current lane limitations */ + /* If we failed 15 times, then remove dead end, one way road and current lane limitations */ for (attempt = 0; attempt < ATTEMPTS_TO_FIND_NEXT_NODE; attempt++) { if (attempt != 0) { if (pVehicle->AutoPilot.m_nNextRouteNode != prevNode) { @@ -1646,6 +1895,7 @@ void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle) } if (pVehicle->AutoPilot.m_bStayInFastLane) pVehicle->AutoPilot.m_nNextLane = 0; +#ifdef FIX_BUGS CVector positionOnCurrentLinkIncludingLane( pCurLink->GetX() + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY, pCurLink->GetY() - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX, @@ -1654,6 +1904,16 @@ void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle) pNextLink->GetX() + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY, pNextLink->GetY() - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX, 0.0f); +#else + CVector positionOnCurrentLinkIncludingLane( + pCurLink->GetX() + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH), + pCurLink->GetY() - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX, + 0.0f); + CVector positionOnNextLinkIncludingLane( + pNextLink->GetX() + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY, + pNextLink->GetY() - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX, + 0.0f); +#endif float directionCurrentLinkX = pCurLink->GetDirX() * pVehicle->AutoPilot.m_nCurrentDirection; float directionCurrentLinkY = pCurLink->GetDirY() * pVehicle->AutoPilot.m_nCurrentDirection; float directionNextLinkX = pNextLink->GetDirX() * pVehicle->AutoPilot.m_nNextDirection; @@ -1704,74 +1964,57 @@ void CCarCtrl::PickNextNodeToChaseCar(CVehicle* pVehicle, float targetX, float t void CCarCtrl::PickNextNodeToChaseCar(CVehicle* pVehicle, float targetX, float targetY, CVehicle* pTarget) #endif { + if (pVehicle->m_nRouteSeed) + CGeneral::SetRandomSeed(pVehicle->m_nRouteSeed); int prevNode = pVehicle->AutoPilot.m_nCurrentRouteNode; int curNode = pVehicle->AutoPilot.m_nNextRouteNode; CPathNode* pPrevNode = &ThePaths.m_pathNodes[prevNode]; CPathNode* pCurNode = &ThePaths.m_pathNodes[curNode]; - CPathNode* pTargetNode; + CPathNode* pTargetNode[2]; int16 numNodes; float distanceToTargetNode; - if (pTarget && pTarget->m_pCurGroundEntity && - pTarget->m_pCurGroundEntity->IsBuilding() && - ((CBuilding*)pTarget->m_pCurGroundEntity)->GetIsATreadable() && - ((CTreadable*)pTarget->m_pCurGroundEntity)->m_nodeIndices[0][0] >= 0){ - CTreadable* pCurrentMapObject = (CTreadable*)pTarget->m_pCurGroundEntity; - int closestNode = -1; - float minDist = 100000.0f; - for (int i = 0; i < 12; i++){ - int node = pCurrentMapObject->m_nodeIndices[0][i]; - if (node < 0) - break; - float dist = (ThePaths.m_pathNodes[node].GetPosition() - pTarget->GetPosition()).Magnitude(); - if (dist < minDist){ - minDist = dist; - closestNode = node; - } - } - ThePaths.DoPathSearch(0, pCurNode->GetPosition(), curNode, + ThePaths.DoPathSearch(0, pCurNode->GetPosition(), curNode, #ifdef FIX_PATHFIND_BUG - CVector(targetX, targetY, targetZ), + CVector(targetX, targetY, targetZ), #else - CVector(targetX, targetY, 0.0f), + CVector(targetX, targetY, 0.0f), #endif - &pTargetNode, &numNodes, 1, pVehicle, &distanceToTargetNode, 999999.9f, closestNode); - }else - { - - ThePaths.DoPathSearch(0, pCurNode->GetPosition(), curNode, -#ifdef FIX_PATHFIND_BUG - CVector(targetX, targetY, targetZ), -#else - CVector(targetX, targetY, 0.0f), -#endif - &pTargetNode, &numNodes, 1, pVehicle, &distanceToTargetNode, 999999.9f, -1); - } + pTargetNode, &numNodes, 2, pVehicle, &distanceToTargetNode, 999999.9f, -1); int newNextNode; int nextLink; - if (numNodes != 1 || pTargetNode == pCurNode){ - float currentAngle = CGeneral::GetATanOfXY(targetX - pVehicle->GetPosition().x, targetY - pVehicle->GetPosition().y); - nextLink = 0; - float lowestAngleChange = 10.0f; - int numLinks = pCurNode->numLinks; - newNextNode = 0; - for (int i = 0; i < numLinks; i++){ - int conNode = ThePaths.ConnectedNode(i + pCurNode->firstLink); - if (conNode == prevNode && i > 1) - continue; - CPathNode* pTestNode = &ThePaths.m_pathNodes[conNode]; - float angle = CGeneral::GetATanOfXY(pTestNode->GetX() - pCurNode->GetX(), pTestNode->GetY() - pCurNode->GetY()); - angle = LimitRadianAngle(angle - currentAngle); - angle = ABS(angle); - if (angle < lowestAngleChange){ - lowestAngleChange = angle; - newNextNode = conNode; - nextLink = i; + if (numNodes != 1 && numNodes != 2 || pTargetNode[0] == pCurNode){ + if (numNodes != 2 || pTargetNode[1] == pCurNode) { + float currentAngle = CGeneral::GetATanOfXY(targetX - pVehicle->GetPosition().x, targetY - pVehicle->GetPosition().y); + nextLink = 0; + float lowestAngleChange = 10.0f; + int numLinks = pCurNode->numLinks; + newNextNode = 0; + for (int i = 0; i < numLinks; i++) { + int conNode = ThePaths.ConnectedNode(i + pCurNode->firstLink); + if (conNode == prevNode && i > 1) + continue; + CPathNode* pTestNode = &ThePaths.m_pathNodes[conNode]; + float angle = CGeneral::GetATanOfXY(pTestNode->GetX() - pCurNode->GetX(), pTestNode->GetY() - pCurNode->GetY()); + angle = LimitRadianAngle(angle - currentAngle); + angle = ABS(angle); + if (angle < lowestAngleChange) { + lowestAngleChange = angle; + newNextNode = conNode; + nextLink = i; + } } } - }else{ + else { + nextLink = 0; + newNextNode = pTargetNode[1] - ThePaths.m_pathNodes; + for (int i = pCurNode->firstLink; ThePaths.ConnectedNode(i) != newNextNode; i++, nextLink++) + ; + } + } + else { nextLink = 0; - newNextNode = pTargetNode - ThePaths.m_pathNodes; + newNextNode = pTargetNode[0] - ThePaths.m_pathNodes; for (int i = pCurNode->firstLink; ThePaths.ConnectedNode(i) != newNextNode; i++, nextLink++) ; } @@ -1791,11 +2034,11 @@ void CCarCtrl::PickNextNodeToChaseCar(CVehicle* pVehicle, float targetX, float t int8 lanesOnNextNode; if (curNode >= pVehicle->AutoPilot.m_nNextRouteNode) { pVehicle->AutoPilot.m_nNextDirection = 1; - lanesOnNextNode = pNextLink->numLeftLanes; + lanesOnNextNode = pNextLink->numRightLanes; } else { pVehicle->AutoPilot.m_nNextDirection = -1; - lanesOnNextNode = pNextLink->numRightLanes; + lanesOnNextNode = pNextLink->numLeftLanes; } float currentPathLinkForwardX = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->GetDirX(); float currentPathLinkForwardY = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->GetDirY(); @@ -1850,6 +2093,8 @@ void CCarCtrl::PickNextNodeToChaseCar(CVehicle* pVehicle, float targetX, float t bool CCarCtrl::PickNextNodeToFollowPath(CVehicle* pVehicle) { + if (pVehicle->m_nRouteSeed) + CGeneral::SetRandomSeed(pVehicle->m_nRouteSeed); int curNode = pVehicle->AutoPilot.m_nNextRouteNode; CPathNode* pCurNode = &ThePaths.m_pathNodes[curNode]; if (pVehicle->AutoPilot.m_nPathFindNodesCount == 0){ @@ -1942,6 +2187,7 @@ void CCarCtrl::Init(void) LastTimeAmbulanceCreated = 0; #ifdef FIX_BUGS LastTimeLawEnforcerCreated = 0; + LastTimeMiamiViceGenerated = 0; #endif bCarsGeneratedAroundCamera = false; CountDownToCarsAtStart = 2; @@ -1949,9 +2195,11 @@ void CCarCtrl::Init(void) for (int i = 0; i < MAX_CARS_TO_KEEP; i++) apCarsToKeep[i] = nil; for (int i = 0; i < TOTAL_CUSTOM_CLASSES; i++){ - for (int j = 0; j < MAX_CAR_MODELS_IN_ARRAY; j++) - CarArrays[i][j] = 0; - NextCarOfRating[i] = 0; + for (int j = 0; j < MAX_CAR_MODELS_IN_ARRAY; j++) { + LoadedCarsArray[i][j] = -1; + } + NumOfLoadedCarsOfRating[i] = 0; + NumRequestsOfCarRating[i] = 0; TotalNumOfCarsOfRating[i] = 0; } } @@ -1969,13 +2217,14 @@ void CCarCtrl::ReInit(void) LastTimeFireTruckCreated = 0; LastTimeAmbulanceCreated = 0; LastTimeLawEnforcerCreated = 0; + LastTimeMiamiViceGenerated = 0; #endif CountDownToCarsAtStart = 2; CarDensityMultiplier = 1.0f; for (int i = 0; i < MAX_CARS_TO_KEEP; i++) apCarsToKeep[i] = nil; for (int i = 0; i < TOTAL_CUSTOM_CLASSES; i++) - NextCarOfRating[i] = 0; + NumRequestsOfCarRating[i] = 0; } void CCarCtrl::DragCarToPoint(CVehicle* pVehicle, CVector* pPoint) @@ -2085,7 +2334,7 @@ void CCarCtrl::SteerAICarWithPhysics(CVehicle* pVehicle) pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE; break; case TEMPACT_HANDBRAKETURNLEFT: - swerve = -1.0f; // It seems like this should be swerve = 1.0f (fixed in VC) + swerve = 1.0f; accel = 0.0f; brake = 0.0f; handbrake = true; @@ -2093,7 +2342,7 @@ void CCarCtrl::SteerAICarWithPhysics(CVehicle* pVehicle) pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE; break; case TEMPACT_HANDBRAKETURNRIGHT: - swerve = 1.0f; // It seems like this should be swerve = -1.0f (fixed in VC) + swerve = -1.0f; accel = 0.0f; brake = 0.0f; handbrake = true; @@ -2204,6 +2453,9 @@ void CCarCtrl::SteerAICarWithPhysics_OnlyMission(CVehicle* pVehicle, float* pSwe SteerAICarWithPhysicsTryingToBlockTarget_Stop(pVehicle, FindPlayerCoors().x, FindPlayerCoors().y, FindPlayerSpeed().x, FindPlayerSpeed().y, pSwerve, pAccel, pBrake, pHandbrake); return; + case MISSION_WAITFORDELETION: + case MISSION_HELI_LAND: + return; case MISSION_GOTOCOORDS_STRAIGHT: case MISSION_GOTO_COORDS_STRAIGHT_ACCURATE: SteerAICarWithPhysicsHeadingForTarget(pVehicle, nil, @@ -2217,6 +2469,12 @@ void CCarCtrl::SteerAICarWithPhysics_OnlyMission(CVehicle* pVehicle, float* pSwe *pHandbrake = true; *pBrake = 0.5f; return; + case MISSION_GOTOCOORDS_ASTHECROWSWIMS: + SteerAIBoatWithPhysicsHeadingForTarget(pVehicle, + pVehicle->AutoPilot.m_vecDestinationCoors.x, pVehicle->AutoPilot.m_vecDestinationCoors.y, + pSwerve, pAccel, pBrake); + *pHandbrake = false; + return; case MISSION_RAMCAR_CLOSE: SteerAICarWithPhysicsHeadingForTarget(pVehicle, pVehicle->AutoPilot.m_pTargetCar, pVehicle->AutoPilot.m_pTargetCar->GetPosition().x, pVehicle->AutoPilot.m_pTargetCar->GetPosition().y, @@ -2238,26 +2496,93 @@ void CCarCtrl::SteerAICarWithPhysics_OnlyMission(CVehicle* pVehicle, float* pSwe pVehicle->AutoPilot.m_pTargetCar->GetMoveSpeed().y, pSwerve, pAccel, pBrake, pHandbrake); return; + case MISSION_HELI_FLYTOCOORS: + //SteerAIHeliTowardsTargetCoors((CAutomobile*)pVehicle); + return; + case MISSION_ATTACKPLAYER: + SteerAIBoatWithPhysicsAttackingPlayer(pVehicle, pSwerve, pAccel, pBrake, pHandbrake); + return; + case MISSION_PLANE_FLYTOCOORS: + //SteerAIPlaneTowardsTargetCoors((CAutomobile*)pVehicle); + return; + case MISSION_SLOWLY_DRIVE_TOWARDS_PLAYER_1: + SteerAICarWithPhysicsHeadingForTarget(pVehicle, nil, + pVehicle->AutoPilot.m_vecDestinationCoors.x, pVehicle->AutoPilot.m_vecDestinationCoors.y, + pSwerve, pAccel, pBrake, pHandbrake); + return; + case MISSION_SLOWLY_DRIVE_TOWARDS_PLAYER_2: + SteerAICarWithPhysicsHeadingForTarget(pVehicle, nil, FindPlayerCoors().x, FindPlayerCoors().y, + pSwerve, pAccel, pBrake, pHandbrake); + return; + case MISSION_BLOCKPLAYER_FORWARDANDBACK: + //SteerAICarBlockingPlayerForwardAndBack(pVehicle, pSwerve, pAccel, pBrake, pHandbrake); + return; default: + assert(0); return; } } -void CCarCtrl::SteerAIBoatWithPhysics(CBoat* pBoat) +void CCarCtrl::SteerAIBoatWithPhysicsHeadingForTarget(CVehicle* pVehicle, float targetX, float targetY, float* pSwerve, float* pAccel, float* pBrake) { - if (pBoat->AutoPilot.m_nCarMission == MISSION_GOTOCOORDS_ASTHECROWSWIMS){ - SteerAIBoatWithPhysicsHeadingForTarget(pBoat, - pBoat->AutoPilot.m_vecDestinationCoors.x, pBoat->AutoPilot.m_vecDestinationCoors.y, - &pBoat->m_fSteeringLeftRight, &pBoat->m_fAccelerate, &pBoat->m_fBrake); - }else if (pBoat->AutoPilot.m_nCarMission == MISSION_NONE){ - pBoat->m_fSteeringLeftRight = 0.0f; - pBoat->m_fAccelerate = 0.0f; - pBoat->m_fBrake = 0.0f; + CVector2D forward = pVehicle->GetForward(); + forward.Normalise(); + float angleToTarget = CGeneral::GetATanOfXY(targetX - pVehicle->GetPosition().x, targetY - pVehicle->GetPosition().y); + float angleForward = CGeneral::GetATanOfXY(forward.x, forward.y); + float steerAngle = LimitRadianAngle(angleToTarget - angleForward); + steerAngle = clamp(steerAngle, -DEFAULT_MAX_STEER_ANGLE, DEFAULT_MAX_STEER_ANGLE); +#ifdef FIX_BUGS + float speedTarget = pVehicle->AutoPilot.GetCruiseSpeed(); +#else + float speedTarget = pVehicle->AutoPilot.m_nCruiseSpeed; +#endif + float currentSpeed = pVehicle->GetMoveSpeed().Magnitude() * GAME_SPEED_TO_CARAI_SPEED; + float speedDiff = speedTarget - currentSpeed; + if (speedDiff <= 0.0f) { + speedDiff < -5.0f ? *pAccel = -0.2f : *pAccel = -0.1f; + steerAngle *= -1; + } + else if (speedDiff / currentSpeed > 0.25f) { + *pAccel = 1.0f; } - pBoat->m_fSteerAngle = pBoat->m_fSteeringLeftRight; - pBoat->m_fGasPedal = pBoat->m_fAccelerate; - pBoat->m_fBrakePedal = pBoat->m_fBrake; - pBoat->bIsHandbrakeOn = false; + else { + *pAccel = 1.0f - (0.25f - speedDiff / currentSpeed) * 4.0f; + } + *pBrake = 0.0f; + *pSwerve = steerAngle; +} + +void CCarCtrl::SteerAIBoatWithPhysicsAttackingPlayer(CVehicle* pVehicle, float* pSwerve, float* pAccel, float* pBrake, bool* pHandbrake) +{ + float distanceToPlayer = (FindPlayerCoors() - pVehicle->GetPosition()).Magnitude(); + float projection = Min(distanceToPlayer * 0.05f, 2.0f); + CVector2D forward = pVehicle->GetForward(); + forward.Normalise(); + CVector2D vecToProjection = FindPlayerCoors() + FindPlayerSpeed() * projection * GAME_SPEED_TO_CARAI_SPEED; + float angleToTarget = CGeneral::GetATanOfXY(vecToProjection.x - pVehicle->GetPosition().x, vecToProjection.y - pVehicle->GetPosition().y); + float angleForward = CGeneral::GetATanOfXY(forward.x, forward.y); + float steerAngle = LimitRadianAngle(angleToTarget - angleForward); +#ifdef FIX_BUGS + float speedTarget = pVehicle->AutoPilot.GetCruiseSpeed(); +#else + float speedTarget = pVehicle->AutoPilot.m_nCruiseSpeed; +#endif + float currentSpeed = pVehicle->GetMoveSpeed().Magnitude() * GAME_SPEED_TO_CARAI_SPEED; + float speedDiff = speedTarget - currentSpeed; + if (speedDiff <= 0.0f) { + speedDiff < -5.0f ? *pAccel = -0.2f : *pAccel = -0.1f; + } + else if (speedDiff / currentSpeed > 0.25f) { + *pAccel = 1.0f; + } + else { + *pAccel = 1.0f - (0.25f - speedDiff / currentSpeed) * 4.0f; + } + *pBrake = 0.0f; + *pSwerve = steerAngle; + *pHandbrake = false; + if (pVehicle->GetModelIndex() == MI_PREDATOR && distanceToPlayer < 40.0f && steerAngle < 0.15f) + pVehicle->FireFixedMachineGuns(); } float CCarCtrl::FindMaxSteerAngle(CVehicle* pVehicle) @@ -2265,6 +2590,50 @@ float CCarCtrl::FindMaxSteerAngle(CVehicle* pVehicle) return pVehicle->GetModelIndex() == MI_ENFORCER ? 0.7f : DEFAULT_MAX_STEER_ANGLE; } +void CCarCtrl::SteerAIHeliTowardsTargetCoors(CAutomobile* pHeli) +{ + if (pHeli->m_aWheelSpeed[1] < 0.22f) + pHeli->m_aWheelSpeed[1] += 0.001f; + if (pHeli->m_aWheelSpeed[1] < 0.22f) + return; + CVector2D vecToTarget = pHeli->AutoPilot.m_vecDestinationCoors - pHeli->GetPosition(); + float distanceToTarget = vecToTarget.Magnitude(); +#ifdef FIX_BUGS + float speed = pHeli->AutoPilot.GetCruiseSpeed() * 0.01f; +#else + float speed = pHeli->AutoPilot.m_nCruiseSpeed * 0.01f; +#endif + if (distanceToTarget >= 100.0f) + { + if (distanceToTarget > 75.0f) + speed *= 0.7f; + else if (distanceToTarget > 10.0f) + speed *= 0.4f; + else + speed *= 0.2f; + } + CVector2D vecAdvanceThisFrame = vecToTarget; + vecAdvanceThisFrame.Normalise(); + vecAdvanceThisFrame *= speed; + float resistance = Pow(0.997f, CTimer::GetTimeStep()); + pHeli->m_vecMoveSpeed.x *= resistance; + pHeli->m_vecMoveSpeed.y *= resistance; + vecAdvanceThisFrame -= pHeli->m_vecMoveSpeed; + CVector2D vecSpeedChange = vecAdvanceThisFrame - pHeli->m_vecMoveSpeed; + float vecSpeedChangeLength = vecSpeedChange.Magnitude(); + vecSpeedChange.Normalise(); + float changeMultiplier = 0.002f * CTimer::GetTimeStep(); + if (distanceToTarget < 5.0f) + changeMultiplier /= 5.0f; + if (vecSpeedChangeLength < changeMultiplier) + pHeli->AddToMoveSpeed(vecAdvanceThisFrame); + else + pHeli->AddToMoveSpeed(vecSpeedChange * changeMultiplier); + pHeli->SetPosition(pHeli->GetPosition() + CVector(CTimer::GetTimeStep() * pHeli->m_vecMoveSpeed.x, CTimer::GetTimeStep() * pHeli->m_vecMoveSpeed.y, 0.0f)); + assert(0); + // This is not finished yet. Heli fields in CAutomobile required +} + void CCarCtrl::SteerAICarWithPhysicsFollowPath(CVehicle* pVehicle, float* pSwerve, float* pAccel, float* pBrake, bool* pHandbrake) { CVector2D forward = pVehicle->GetForward(); @@ -2292,18 +2661,12 @@ void CCarCtrl::SteerAICarWithPhysicsFollowPath(CVehicle* pVehicle, float* pSwerv if (PickNextNodeAccordingStrategy(pVehicle)) { switch (pVehicle->AutoPilot.m_nCarMission){ case MISSION_GOTOCOORDS: - pVehicle->AutoPilot.m_nCarMission = MISSION_GOTOCOORDS_STRAIGHT; - *pSwerve = 0.0f; - *pAccel = 0.0f; - *pBrake = 0.0f; - *pHandbrake = false; + SteerAICarWithPhysicsHeadingForTarget(pVehicle, nil, pVehicle->AutoPilot.m_vecDestinationCoors.x, + pVehicle->AutoPilot.m_vecDestinationCoors.y, pSwerve, pAccel, pBrake, pHandbrake); return; case MISSION_GOTOCOORDS_ACCURATE: - pVehicle->AutoPilot.m_nCarMission = MISSION_GOTO_COORDS_STRAIGHT_ACCURATE; - *pSwerve = 0.0f; - *pAccel = 0.0f; - *pBrake = 0.0f; - *pHandbrake = false; + SteerAICarWithPhysicsHeadingForTarget(pVehicle, nil, pVehicle->AutoPilot.m_vecDestinationCoors.x, + pVehicle->AutoPilot.m_vecDestinationCoors.y, pSwerve, pAccel, pBrake, pHandbrake); return; default: break; } @@ -2340,6 +2703,7 @@ void CCarCtrl::SteerAICarWithPhysicsFollowPath(CVehicle* pVehicle, float* pSwerv switch (pVehicle->AutoPilot.m_nDrivingStyle) { case DRIVINGSTYLE_STOP_FOR_CARS: case DRIVINGSTYLE_SLOW_DOWN_FOR_CARS: + case DRIVINGSTYLE_STOP_FOR_CARS_IGNORE_LIGHTS: speedStyleMultiplier = FindMaximumSpeedForThisCarInTraffic(pVehicle) / pVehicle->AutoPilot.m_nCruiseSpeed; break; default: @@ -2445,6 +2809,7 @@ void CCarCtrl::SteerAICarWithPhysicsTryingToBlockTarget(CVehicle* pVehicle, floa pVehicle->AutoPilot.m_nCarMission = (pVehicle->AutoPilot.m_nCarMission == MISSION_BLOCKCAR_CLOSE) ? MISSION_BLOCKCAR_HANDBRAKESTOP : MISSION_BLOCKPLAYER_HANDBRAKESTOP; } + void CCarCtrl::SteerAICarWithPhysicsTryingToBlockTarget_Stop(CVehicle* pVehicle, float targetX, float targetY, float targetSpeedX, float targetSpeedY, float* pSwerve, float* pAccel, float* pBrake, bool* pHandbrake) { *pSwerve = 0.0f; @@ -2486,26 +2851,6 @@ void CCarCtrl::SteerAICarWithPhysicsTryingToBlockTarget_Stop(CVehicle* pVehicle, } } -void CCarCtrl::SteerAIBoatWithPhysicsHeadingForTarget(CBoat* pBoat, float targetX, float targetY, float* pSwerve, float* pAccel, float* pBrake) -{ - CVector2D forward(pBoat->GetForward()); - forward.Normalise(); - CVector2D distanceToTarget = CVector2D(targetX, targetY) - pBoat->GetPosition(); - float angleToTarget = CGeneral::GetATanOfXY(distanceToTarget.x, distanceToTarget.y); - float angleForward = CGeneral::GetATanOfXY(forward.x, forward.y); - float angleDiff = LimitRadianAngle(angleToTarget - angleForward); - angleDiff = Min(DEFAULT_MAX_STEER_ANGLE, Max(-DEFAULT_MAX_STEER_ANGLE, angleDiff)); - float currentSpeed = pBoat->GetMoveSpeed().Magnitude2D(); // +0.0f for some reason - float speedDiff = pBoat->AutoPilot.m_nCruiseSpeed - currentSpeed * 60.0f; - if (speedDiff > 0.0f){ - float accRemaining = speedDiff / pBoat->AutoPilot.m_nCruiseSpeed; - *pAccel = (accRemaining > 0.25f) ? 1.0f : 1.0f - (0.25f - accRemaining) * 4.0f; - }else - *pAccel = (speedDiff < -5.0f) ? -0.2f : -0.1f; - *pBrake = 0.0f; - *pSwerve = angleDiff; -} - void CCarCtrl::RegisterVehicleOfInterest(CVehicle* pVehicle) { @@ -2627,6 +2972,8 @@ bool CCarCtrl::JoinCarWithRoadSystemGotoCoors(CVehicle* pVehicle, CVector vecTar void CCarCtrl::FindLinksToGoWithTheseNodes(CVehicle* pVehicle) { + if (pVehicle->m_nRouteSeed) + CGeneral::SetRandomSeed(pVehicle->m_nRouteSeed); int nextLink; CPathNode* pCurNode = &ThePaths.m_pathNodes[pVehicle->AutoPilot.m_nCurrentRouteNode]; for (nextLink = 0; nextLink < 12; nextLink++) @@ -2640,11 +2987,21 @@ void CCarCtrl::FindLinksToGoWithTheseNodes(CVehicle* pVehicle) curLink = 0; curConnection = ThePaths.m_carPathConnections[pCurNode->firstLink]; }else{ - curConnection = pVehicle->AutoPilot.m_nNextPathNodeInfo; - while (curConnection == pVehicle->AutoPilot.m_nNextPathNodeInfo){ - curLink = CGeneral::GetRandomNumber() % pCurNode->numLinks; - curConnection = ThePaths.m_carPathConnections[curLink + pCurNode->firstLink]; + int closestLink = -1; + float md = 999999.9f; + + for (curLink = 0; curLink < pCurNode->numLinks; curLink++) { + int node = ThePaths.ConnectedNode(curLink + pCurNode->firstLink); + CPathNode* pNode = &ThePaths.m_pathNodes[node]; + if (node == pVehicle->AutoPilot.m_nNextRouteNode) + continue; + float dist = CCollision::DistToLine(&pCurNode->GetPosition(), &pNode->GetPosition(), &pVehicle->GetPosition()); + if (dist < md) { + md = dist; + closestLink = curLink; + } } + curConnection = ThePaths.m_carPathConnections[closestLink + pCurNode->firstLink]; } pVehicle->AutoPilot.m_nCurrentPathNodeInfo = curConnection; pVehicle->AutoPilot.m_nCurrentDirection = (ThePaths.ConnectedNode(curLink + pCurNode->firstLink) >= pVehicle->AutoPilot.m_nCurrentRouteNode) ? 1 : -1; @@ -2654,6 +3011,8 @@ void CCarCtrl::GenerateEmergencyServicesCar(void) { if (FindPlayerPed()->m_pWanted->m_nWantedLevel > 3) return; + if (CGame::IsInInterior()) + return; if (NumFiretrucksOnDuty + NumAmbulancesOnDuty + NumParkedCars + NumMissionCars + NumLawEnforcerCars + NumRandomCars > MaxNumberOfCarsInUse) return; @@ -2709,9 +3068,11 @@ bool CCarCtrl::GenerateOneEmergencyServicesCar(uint32 mi, CVector vecPos) if (ThePaths.NewGenerateCarCreationCoors(pPlayerPos.x, pPlayerPos.y, 0.707f, 0.707f, 120.0f, -1.0f, true, &spawnPos, &curNode, &nextNode, &posBetweenNodes, false)){ int16 colliding[2]; - CWorld::FindObjectsKindaColliding(spawnPos, 10.0f, true, colliding, 2, nil, false, true, true, false, false); - if (colliding[0] == 0) - created = true; + if (!ThePaths.GetNode(curNode)->bWaterPath) { + CWorld::FindObjectsKindaColliding(spawnPos, 10.0f, true, colliding, 2, nil, false, true, true, false, false); + if (colliding[0] == 0) + created = true; + } } attempts += 1; } @@ -2770,18 +3131,24 @@ void CCarCtrl::UpdateCarCount(CVehicle* pVehicle, bool remove) if (remove){ switch (pVehicle->VehicleCreatedBy){ case RANDOM_VEHICLE: - if (pVehicle->bIsLawEnforcer) - --NumLawEnforcerCars; - --NumRandomCars; + if (pVehicle->bIsLawEnforcer) { + if (--NumLawEnforcerCars < 0) + NumLawEnforcerCars = 0; + } + if (--NumRandomCars < 0) + NumRandomCars = 0; return; case MISSION_VEHICLE: - --NumMissionCars; + if (--NumMissionCars < 0) + NumMissionCars = 0; return; case PARKED_VEHICLE: - --NumParkedCars; + if (--NumParkedCars < 0) + NumParkedCars = 0; return; case PERMANENT_VEHICLE: - --NumPermanentCars;; + if (--NumPermanentCars < 0) + NumPermanentCars = 0; return; } } @@ -2799,7 +3166,7 @@ void CCarCtrl::UpdateCarCount(CVehicle* pVehicle, bool remove) ++NumParkedCars; return; case PERMANENT_VEHICLE: - ++NumPermanentCars;; + ++NumPermanentCars; return; } } @@ -2807,12 +3174,30 @@ void CCarCtrl::UpdateCarCount(CVehicle* pVehicle, bool remove) bool CCarCtrl::ThisRoadObjectCouldMove(int16 mi) { +#ifdef GTA_BRIDGE return mi == MI_BRIDGELIFT || mi == MI_BRIDGEROADSEGMENT; +#else + return false; +#endif } bool CCarCtrl::MapCouldMoveInThisArea(float x, float y) { +#ifdef GTA_BRIDGE // actually they forgot that in VC... // bridge moves up and down return x > -342.0f && x < -219.0f && y > -677.0f && y < -580.0f; +#else + return false; +#endif +} + +float CCarCtrl::FindSpeedMultiplierWithSpeedFromNodes(int8 type) +{ + switch (type) + { + case 1: return 1.5f; + case 2: return 2.0f; + } + return 1.0f; } diff --git a/src/control/CarCtrl.h b/src/control/CarCtrl.h index 457224fb..ed63a0e2 100644 --- a/src/control/CarCtrl.h +++ b/src/control/CarCtrl.h @@ -9,10 +9,11 @@ #define TIME_COPS_WAIT_TO_EXIT_AFTER_STOPPING 2500 class CZoneInfo; +class CAutomobile; enum{ MAX_CARS_TO_KEEP = 2, - MAX_CAR_MODELS_IN_ARRAY = 256, + MAX_CAR_MODELS_IN_ARRAY = 25, }; #define LANE_WIDTH 5.0f @@ -25,24 +26,37 @@ class CCarCtrl { public: enum eCarClass { - POOR = 0, + NORMAL = 0, + POOR, RICH, EXEC, WORKER, - SPECIAL, BIG, TAXI, - TOTAL_CUSTOM_CLASSES, - MAFIA, - TRIAD, - DIABLO, - YAKUZA, - YARDIE, - COLOMB, - NINES, - GANG8, + MOPED, + MOTORBIKE, + + LEISUREBOAT, + WORKERBOAT, + + COPS, + CUBAN, + HAITIAN, + STREET, + DIAZ, + BIKER, + SECURITY, + PLAYER, + GOLFERS, GANG9, - COPS + COPS_BOAT, + FIRST_CAR_RATING = NORMAL, + FIRST_BOAT_RATING = LEISUREBOAT, + FIRST_GANG_CAR_RATING = CUBAN, + NUM_CAR_CLASSES = MOTORBIKE - FIRST_CAR_RATING + 1, + NUM_BOAT_CLASSES = WORKERBOAT - FIRST_BOAT_RATING + 1, + NUM_GANG_CAR_CLASSES = GANG9 - FIRST_GANG_CAR_RATING + 1, + TOTAL_CUSTOM_CLASSES = NUM_CAR_CLASSES + NUM_BOAT_CLASSES }; static void SwitchVehicleToRealPhysics(CVehicle*); @@ -94,17 +108,29 @@ public: static float FindSpeedMultiplier(float, float, float, float); static void SteerAICarWithPhysics(CVehicle*); static void SteerAICarWithPhysics_OnlyMission(CVehicle*, float*, float*, float*, bool*); - static void SteerAIBoatWithPhysics(CBoat*); static float FindMaxSteerAngle(CVehicle*); static void SteerAICarWithPhysicsFollowPath(CVehicle*, float*, float*, float*, bool*); static void SteerAICarWithPhysicsHeadingForTarget(CVehicle*, CPhysical*, float, float, float*, float*, float*, bool*); static void SteerAICarWithPhysicsTryingToBlockTarget(CVehicle*, float, float, float, float, float*, float*, float*, bool*); static void SteerAICarWithPhysicsTryingToBlockTarget_Stop(CVehicle*, float, float, float, float, float*, float*, float*, bool*); - static void SteerAIBoatWithPhysicsHeadingForTarget(CBoat*, float, float, float*, float*, float*); static bool ThisRoadObjectCouldMove(int16); static void ClearInterestingVehicleList(); static void FindLinksToGoWithTheseNodes(CVehicle*); static bool GenerateOneEmergencyServicesCar(uint32, CVector); + static float FindSpeedMultiplierWithSpeedFromNodes(int8); + static int32 ChooseBoatModel(int32); + static int32 ChooseBoatRating(CZoneInfo* pZoneInfo); + static int32 ChooseCarRating(CZoneInfo* pZoneInfo); + static void AddToLoadedVehicleArray(int32 mi, int32 rating, int32 freq); + static void RemoveFromLoadedVehicleArray(int32 mi, int32 rating); + static int32 ChooseCarModelToLoad(int32 rating); + static bool BoatWithTallMast(int32 mi); + static void RemoveCarsIfThePoolGetsFull(void); + static void SteerAIBoatWithPhysicsHeadingForTarget(CVehicle*, float, float, float*, float*, float*); + static void SteerAIHeliTowardsTargetCoors(CAutomobile*); + static void SteerAIPlaneTowardsTargetCoors(CAutomobile*); + static void SteerAIBoatWithPhysicsAttackingPlayer(CVehicle*, float*, float*, float*, bool*); + static void SteerAICarBlockingPlayerForwardAndBack(CVehicle*, float*, float*, float*, bool*); static float GetPositionAlongCurrentCurve(CVehicle* pVehicle) { @@ -136,8 +162,14 @@ public: static uint32 LastTimeFireTruckCreated; static uint32 LastTimeAmbulanceCreated; static int32 TotalNumOfCarsOfRating[TOTAL_CUSTOM_CLASSES]; - static int32 NextCarOfRating[TOTAL_CUSTOM_CLASSES]; static int32 CarArrays[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY]; + + static int32 MiamiViceCycle; + static uint32 LastTimeMiamiViceGenerated; + static int32 NumRequestsOfCarRating[TOTAL_CUSTOM_CLASSES]; + static int32 NumOfLoadedCarsOfRating[TOTAL_CUSTOM_CLASSES]; + static int32 CarFreqArrays[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY]; + static int32 LoadedCarsArray[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY]; }; extern CVehicle* apCarsToKeep[MAX_CARS_TO_KEEP];
\ No newline at end of file diff --git a/src/control/Curves.cpp b/src/control/Curves.cpp index 0a01a7aa..31a2767a 100644 --- a/src/control/Curves.cpp +++ b/src/control/Curves.cpp @@ -11,7 +11,7 @@ float CCurves::CalcSpeedScaleFactor(CVector* pPoint1, CVector* pPoint2, float di if (dp > 0.9f) return distance + Abs((pPoint1->x * dir1Y - pPoint1->y * dir1X) - (pPoint2->x * dir1Y - pPoint2->y * dir1X)); else - return ((1.0f - dp) * 0.2f + 1.0f) * distance; + return ((1.0f - dp) * 0.25f + 1.0f) * distance; } void CCurves::CalcCurvePoint(CVector* pPos1, CVector* pPos2, CVector* pDir1, CVector* pDir2, float between, int32 timeOnCurve, CVector* pOutPos, CVector* pOutDir) @@ -19,7 +19,21 @@ void CCurves::CalcCurvePoint(CVector* pPos1, CVector* pPos2, CVector* pDir1, CVe float actualFactor = CalcSpeedScaleFactor(pPos1, pPos2, pDir1->x, pDir1->y, pDir2->x, pDir2->y); CVector2D dir1 = *pDir1 * actualFactor; CVector2D dir2 = *pDir2 * actualFactor; - float curveCoef = 0.5f - 0.5f * Cos(3.1415f * between); + float t1 = Abs(DotProduct2D(*pPos1 - *pPos2, *pDir1)); + float t2 = Abs(DotProduct2D(*pPos2 - *pPos1, *pDir2)); + float curveCoef; + if (t1 > t2) { + if (between < (t1 - t2) / (t1 + t2)) + curveCoef = 0.0f; + else + curveCoef = 0.5f - 0.5f * Cos(3.1415f * (t1 + t2) / (2 * t2) * (between - (t1 - t2) / (t1 + t2))); + } + else { + if (2 * t1 / (t1 + t2) < between) + curveCoef = 1.0f; + else + curveCoef = 0.5f - 0.5f * Cos(3.1415f * between * (t1 + t2) / (2 * t1)); + } *pOutPos = CVector( (pPos1->x + between * dir1.x) * (1.0f - curveCoef) + (pPos2->x - (1 - between) * dir2.x) * curveCoef, (pPos1->y + between * dir1.y) * (1.0f - curveCoef) + (pPos2->y - (1 - between) * dir2.y) * curveCoef, diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp index 5fc44974..a177343b 100644 --- a/src/control/Garages.cpp +++ b/src/control/Garages.cpp @@ -39,8 +39,8 @@ #define CRUSHER_CRANE_SPEED (0.005f) // Prices -#define BOMB_PRICE (1000) -#define RESPRAY_PRICE (1000) +#define BOMB_PRICE (500) +#define RESPRAY_PRICE (100) // Distances #define DISTANCE_TO_CALL_OFF_CHASE (10.0f) @@ -50,10 +50,10 @@ #define DISTANCE_TO_CLOSE_MISSION_GARAGE (30.0f) #define DISTANCE_TO_CLOSE_COLLECTSPECIFICCARS_GARAGE (25.0f) #define DISTANCE_TO_CLOSE_COLLECTCARS_GARAGE (40.0f) -#define DISTANCE_TO_CLOSE_HIDEOUT_GARAGE_ON_FOOT (2.2f) +#define DISTANCE_TO_CLOSE_HIDEOUT_GARAGE_ON_FOOT (3.2f) #define DISTANCE_TO_CLOSE_HIDEOUT_GARAGE_IN_CAR (15.0f) #define DISTANCE_TO_FORCE_CLOSE_HIDEOUT_GARAGE (70.0f) -#define DISTANCE_TO_OPEN_HIDEOUT_GARAGE_ON_FOOT (1.7f) +#define DISTANCE_TO_OPEN_HIDEOUT_GARAGE_ON_FOOT (2.8f) #define DISTANCE_TO_OPEN_HIDEOUT_GARAGE_IN_CAR (10.0f) #define DISTANCE_TO_SHOW_HIDEOUT_MESSAGE (5.0f) @@ -68,7 +68,7 @@ // Respray stuff #define FREE_RESPRAY_HEALTH_THRESHOLD (970.0f) #define NUM_PARTICLES_IN_RESPRAY (200) -#define RESPRAY_CENTERING_COEFFICIENT (0.75f) +#define RESPRAY_CENTERING_COEFFICIENT (0.4f) // Bomb stuff #define KGS_OF_EXPLOSIVES_IN_BOMB (10) @@ -81,8 +81,8 @@ // Collect cars stuff #define MAX_SPEED_TO_SHOW_COLLECTED_MESSAGE (0.03f) -#define IMPORT_REWARD (1000) -#define IMPORT_ALLCARS_REWARD (200000) +#define IMPORT_REWARD (500) +#define IMPORT_ALLCARS_REWARD (20500) // Crusher stuff #define CRUSHER_VEHICLE_TEST_SPAN (8) @@ -91,26 +91,23 @@ #define CRUSHER_REWARD_COEFFICIENT (1.0f/500000) // Hideout stuff -#define MAX_STORED_CARS_IN_INDUSTRIAL (1) -#define MAX_STORED_CARS_IN_COMMERCIAL (NUM_GARAGE_STORED_CARS) -#define MAX_STORED_CARS_IN_SUBURBAN (NUM_GARAGE_STORED_CARS) -#define LIMIT_CARS_IN_INDUSTRIAL (1) -#define LIMIT_CARS_IN_COMMERCIAL (2) -#define LIMIT_CARS_IN_SUBURBAN (3) #define HIDEOUT_DOOR_SPEED_COEFFICIENT (1.7f) #define TIME_BETWEEN_HIDEOUT_MESSAGES (18000) // Camera stuff -#define MARGIN_FOR_CAMERA_COLLECTCARS (1.3f) -#define MARGIN_FOR_CAMERA_DEFAULT (4.0f) +#define MARGIN_FOR_CAMERA_COLLECTCARS (0.5f) +#define MARGIN_FOR_CAMERA_DEFAULT (0.5f) const int32 gaCarsToCollectInCraigsGarages[TOTAL_COLLECTCARS_GARAGES][TOTAL_COLLECTCARS_CARS] = { - { MI_SECURICA, MI_MOONBEAM, MI_COACH, MI_FLATBED, MI_LINERUN, MI_TRASH, MI_PATRIOT, MI_MRWHOOP, MI_BLISTA, MI_MULE, MI_YANKEE, MI_BOBCAT, MI_DODO, MI_BUS, MI_RUMPO, MI_PONY }, - { MI_SENTINEL, MI_CHEETAH, MI_BANSHEE, MI_IDAHO, MI_INFERNUS, MI_TAXI, MI_KURUMA, MI_STRETCH, MI_PEREN, MI_STINGER, MI_MANANA, MI_LANDSTAL, MI_STALLION, MI_BFINJECT, MI_CABBIE, MI_ESPERANT }, - { MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_LANDSTAL, MI_CHEETAH, MI_TAXI, MI_ESPERANT, MI_SENTINEL, MI_IDAHO } + { MI_LANDSTAL, MI_IDAHO, MI_ESPERANT, MI_STALLION, MI_RANCHER, MI_BLISTAC }, + { MI_SABRE, MI_VIRGO, MI_SENTINEL, MI_STRETCH, MI_WASHING, MI_ADMIRAL }, + { MI_CHEETAH, MI_INFERNUS, MI_BANSHEE, MI_PHEONIX, MI_COMET, MI_STINGER }, + { MI_VOODOO, MI_CUBAN, MI_CADDY, MI_BAGGAGE, MI_MRWHOOP, MI_PIZZABOY } }; +const int32 gaCarsToCollectIn60Seconds[] = { MI_CHEETAH, MI_TAXI, MI_ESPERANT, MI_SENTINEL, MI_IDAHO }; // what is this? + int32 CGarages::BankVansCollected; bool CGarages::BombsAreFree; bool CGarages::RespraysAreFree; @@ -126,9 +123,7 @@ uint32 CGarages::MessageEndTime; uint32 CGarages::NumGarages; bool CGarages::PlayerInGarage; int32 CGarages::PoliceCarsCollected; -CStoredCar CGarages::aCarsInSafeHouse1[NUM_GARAGE_STORED_CARS]; -CStoredCar CGarages::aCarsInSafeHouse2[NUM_GARAGE_STORED_CARS]; -CStoredCar CGarages::aCarsInSafeHouse3[NUM_GARAGE_STORED_CARS]; +CStoredCar CGarages::aCarsInSafeHouses[TOTAL_HIDEOUT_GARAGES][CGarages::MAX_NUM_CARS_IN_HIDEOUT_GARAGE]; int32 CGarages::AudioEntity = AEHANDLE_NONE; CGarage CGarages::aGarages[NUM_GARAGES]; bool CGarages::bCamShouldBeOutisde; @@ -147,22 +142,15 @@ void CGarages::Init(void) for (int i = 0; i < TOTAL_COLLECTCARS_GARAGES; i++) CarTypesCollected[i] = 0; LastTimeHelpMessage = 0; - for (int i = 0; i < NUM_GARAGE_STORED_CARS; i++) - aCarsInSafeHouse1[i].Init(); - for (int i = 0; i < NUM_GARAGE_STORED_CARS; i++) - aCarsInSafeHouse2[i].Init(); - for (int i = 0; i < NUM_GARAGE_STORED_CARS; i++) - aCarsInSafeHouse3[i].Init(); + for (int i = 0; i < TOTAL_HIDEOUT_GARAGES; i++) { + for (int j = 0; j < MAX_NUM_CARS_IN_HIDEOUT_GARAGE; j++) + aCarsInSafeHouses[i][j].Init(); + } AudioEntity = DMAudio.CreateEntity(AUDIOTYPE_GARAGE, (void*)1); if (AudioEntity >= 0) DMAudio.SetEntityStatus(AudioEntity, 1); - AddOne( - CRUSHER_GARAGE_X1, CRUSHER_GARAGE_Y1, CRUSHER_GARAGE_Z1, - CRUSHER_GARAGE_X2, CRUSHER_GARAGE_Y2, CRUSHER_GARAGE_Z2, - GARAGE_CRUSHER, 0); } -#ifndef PS2 void CGarages::Shutdown(void) { NumGarages = 0; @@ -171,7 +159,6 @@ void CGarages::Shutdown(void) DMAudio.DestroyEntity(AudioEntity); AudioEntity = AEHANDLE_NONE; } -#endif void CGarages::Update(void) { @@ -199,19 +186,27 @@ void CGarages::Update(void) aGarages[GarageToBeTidied].TidyUpGarage(); } -int16 CGarages::AddOne(float X1, float Y1, float Z1, float X2, float Y2, float Z2, eGarageType type, int32 targetId) +int16 CGarages::AddOne(float X1, float Y1, float Z1, float X2, float Y2, float X3, float Y3, float Z2, eGarageType type, int32 targetId) { if (NumGarages >= NUM_GARAGES) { assert(0); return NumGarages++; } CGarage* pGarage = &aGarages[NumGarages]; - pGarage->m_fX1 = Min(X1, X2); - pGarage->m_fX2 = Max(X1, X2); - pGarage->m_fY1 = Min(Y1, Y2); - pGarage->m_fY2 = Max(Y1, Y2); - pGarage->m_fZ1 = Min(Z1, Z2); - pGarage->m_fZ2 = Max(Z1, Z2); + pGarage->m_fInfX = Min(Min(Min(X1, X2), X3), X2 + X3 - X1); + pGarage->m_fSupX = Max(Max(X1, X2), X3); + pGarage->m_fInfY = Min(Min(Min(Y1, Y2), Y3), Y2 + Y3 - Y1); + pGarage->m_fSupY = Max(Max(Y1, Y2), Y3); + pGarage->m_vecCorner1 = CVector(X1, Y1, Z1); + pGarage->m_fInfZ = Z1; + pGarage->m_vDir1 = CVector2D(X2 - X1, Y2 - Y1); + pGarage->m_vDir2 = CVector2D(X3 - X1, Y3 - Y1); + pGarage->m_fSupZ = Z2; + pGarage->m_nMaxStoredCars = NUM_GARAGE_STORED_CARS; + pGarage->m_fDir1Len = pGarage->m_vDir1.Magnitude(); + pGarage->m_fDir2Len = pGarage->m_vDir2.Magnitude(); + pGarage->m_vDir1 /= pGarage->m_fDir1Len; + pGarage->m_vDir2 /= pGarage->m_fDir2Len; pGarage->m_pDoor1 = nil; pGarage->m_pDoor2 = nil; pGarage->m_fDoor1Z = Z1; @@ -258,6 +253,17 @@ int16 CGarages::AddOne(float X1, float Y1, float Z1, float X2, float Y2, float Z case GARAGE_FOR_SCRIPT_TO_OPEN_AND_CLOSE: case GARAGE_KEEPS_OPENING_FOR_SPECIFIC_CAR: case GARAGE_MISSION_KEEPCAR_REMAINCLOSED: + case GARAGE_COLLECTCARS_4: + case GARAGE_FOR_SCRIPT_TO_OPEN_FOR_CAR: + case GARAGE_HIDEOUT_FOUR: + case GARAGE_HIDEOUT_FIVE: + case GARAGE_HIDEOUT_SIX: + case GARAGE_HIDEOUT_SEVEN: + case GARAGE_HIDEOUT_EIGHT: + case GARAGE_HIDEOUT_NINE: + case GARAGE_HIDEOUT_TEN: + case GARAGE_HIDEOUT_ELEVEN: + case GARAGE_HIDEOUT_TWELVE: pGarage->m_eGarageState = GS_FULLYCLOSED; pGarage->m_fDoorPos = 0.0f; break; @@ -311,10 +317,10 @@ void CGarage::Update() TheCamera.pToGarageWeAreInForHackAvoidFirstPerson = this; if (pVehicle->GetModelIndex() == MI_MRWHOOP) { if (pVehicle->IsWithinArea( - m_fX1 - DISTANCE_FOR_MRWHOOP_HACK, - m_fY1 + DISTANCE_FOR_MRWHOOP_HACK, - m_fX2 - DISTANCE_FOR_MRWHOOP_HACK, - m_fY2 + DISTANCE_FOR_MRWHOOP_HACK)) { + m_fInfX - DISTANCE_FOR_MRWHOOP_HACK, + m_fInfY - DISTANCE_FOR_MRWHOOP_HACK, + m_fSupX + DISTANCE_FOR_MRWHOOP_HACK, + m_fSupY + DISTANCE_FOR_MRWHOOP_HACK)) { TheCamera.pToGarageWeAreIn = this; CGarages::bCamShouldBeOutisde = true; } @@ -332,7 +338,7 @@ void CGarage::Update() case GARAGE_RESPRAY: switch (m_eGarageState) { case GS_OPENED: - if (IsStaticPlayerCarEntirelyInside() && !IsAnyOtherCarTouchingGarage(FindPlayerVehicle())) { + if (IsStaticPlayerCarEntirelyInside()) { if (CGarages::IsCarSprayable(FindPlayerVehicle())) { if (CWorld::Players[CWorld::PlayerInFocus].m_nMoney >= RESPRAY_PRICE || CGarages::RespraysAreFree) { m_eGarageState = GS_CLOSING; @@ -354,13 +360,15 @@ void CGarage::Update() if (FindPlayerVehicle()) { if (CalcDistToGarageRectangleSquared(FindPlayerVehicle()->GetPosition().x, FindPlayerVehicle()->GetPosition().y) < SQR(DISTANCE_TO_ACTIVATE_GARAGE)) CWorld::CallOffChaseForArea( - m_fX1 - DISTANCE_TO_CALL_OFF_CHASE, - m_fY1 - DISTANCE_TO_CALL_OFF_CHASE, - m_fX2 + DISTANCE_TO_CALL_OFF_CHASE, - m_fY2 + DISTANCE_TO_CALL_OFF_CHASE); + m_fInfX - DISTANCE_TO_CALL_OFF_CHASE, + m_fInfY - DISTANCE_TO_CALL_OFF_CHASE, + m_fSupX + DISTANCE_TO_CALL_OFF_CHASE, + m_fSupY + DISTANCE_TO_CALL_OFF_CHASE); } break; case GS_CLOSING: + if (FindPlayerVehicle()) + ThrowCarsNearDoorOutOfGarage(FindPlayerVehicle()); m_fDoorPos = Max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == 0.0f) { m_eGarageState = GS_FULLYCLOSED; @@ -376,19 +384,20 @@ void CGarage::Update() #endif ((CAutomobile*)(FindPlayerVehicle()))->m_fFireBlowUpTimer = 0.0f; CWorld::CallOffChaseForArea( - m_fX1 - DISTANCE_TO_CALL_OFF_CHASE, - m_fY1 - DISTANCE_TO_CALL_OFF_CHASE, - m_fX2 + DISTANCE_TO_CALL_OFF_CHASE, - m_fY2 + DISTANCE_TO_CALL_OFF_CHASE); + m_fInfX - DISTANCE_TO_CALL_OFF_CHASE, + m_fInfY - DISTANCE_TO_CALL_OFF_CHASE, + m_fSupX + DISTANCE_TO_CALL_OFF_CHASE, + m_fSupY + DISTANCE_TO_CALL_OFF_CHASE); break; case GS_FULLYCLOSED: if (CTimer::GetTimeInMilliseconds() > m_nTimeToStartAction) { m_eGarageState = GS_OPENING; DMAudio.PlayFrontEndSound(SOUND_GARAGE_OPENING, 1); bool bTakeMoney = false; - if (FindPlayerPed()->m_pWanted->m_nWantedLevel != 0) + if (FindPlayerPed()->m_pWanted->m_nWantedLevel != 0) { bTakeMoney = true; - FindPlayerPed()->m_pWanted->Reset(); + FindPlayerPed()->m_pWanted->Suspend(); + } CPad::GetPad(0)->SetEnablePlayerControls(PLAYERCONTROL_GARAGE); FindPlayerPed()->m_pWanted->m_bIgnoredByCops = true; #ifdef FIX_BUGS @@ -396,18 +405,29 @@ void CGarage::Update() #else bool bChangedColour; #endif - if (FindPlayerVehicle() && FindPlayerVehicle()->IsCar()) { + if (FindPlayerVehicle() && (FindPlayerVehicle()->IsCar() || FindPlayerVehicle()->IsBike())) { if (FindPlayerVehicle()->m_fHealth < FREE_RESPRAY_HEALTH_THRESHOLD) bTakeMoney = true; FindPlayerVehicle()->m_fHealth = 1000.0f; - ((CAutomobile*)(FindPlayerVehicle()))->m_fFireBlowUpTimer = 0.0f; - ((CAutomobile*)(FindPlayerVehicle()))->Fix(); + if (FindPlayerVehicle()->IsCar()) { + ((CAutomobile*)(FindPlayerVehicle()))->m_fFireBlowUpTimer = 0.0f; + ((CAutomobile*)(FindPlayerVehicle()))->Fix(); + } + else { + // TODO(MIAMI): Bike Fix + } + FindPlayerVehicle()->m_nDoorLock = CARLOCK_UNLOCKED; + ++CStats::Sprayings; if (FindPlayerVehicle()->GetUp().z < 0.0f) { FindPlayerVehicle()->GetUp() = -FindPlayerVehicle()->GetUp(); FindPlayerVehicle()->GetRight() = -FindPlayerVehicle()->GetRight(); } bChangedColour = false; +#ifdef FIX_BUGS + if (!FindPlayerVehicle()->IsCar() || !((CAutomobile*)(FindPlayerVehicle()))->bFixedColour) { +#else if (!((CAutomobile*)(FindPlayerVehicle()))->bFixedColour) { +#endif uint8 colour1, colour2; uint16 attempt; FindPlayerVehicle()->GetModelInfo()->ChooseVehicleColour(colour1, colour2); @@ -422,16 +442,9 @@ void CGarage::Update() if (bChangedColour) { for (int i = 0; i < NUM_PARTICLES_IN_RESPRAY; i++) { CVector pos; -#ifdef FIX_BUGS - pos.x = CGeneral::GetRandomNumberInRange(m_fX1 + 0.5f, m_fX2 - 0.5f); - pos.y = CGeneral::GetRandomNumberInRange(m_fY1 + 0.5f, m_fY2 - 0.5f); + pos.x = CGeneral::GetRandomNumberInRange(m_fInfX + 0.5f, m_fSupX - 0.5f); + pos.y = CGeneral::GetRandomNumberInRange(m_fInfY + 0.5f, m_fSupY - 0.5f); pos.z = CGeneral::GetRandomNumberInRange(m_fDoor1Z - 3.0f, m_fDoor1Z + 1.0f); -#else - // wtf is this - pos.x = m_fX1 + 0.5f + (uint8)(CGeneral::GetRandomNumber()) / 256.0f * (m_fX2 - m_fX1 - 1.0f); - pos.y = m_fY1 + 0.5f + (uint8)(CGeneral::GetRandomNumber()) / 256.0f * (m_fY2 - m_fY1 - 1.0f); - pos.z = m_fDoor1Z - 3.0f + (uint8)(CGeneral::GetRandomNumber()) / 256.0f * 4.0f; -#endif CParticle::AddParticle(PARTICLE_GARAGEPAINT_SPRAY, pos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, CVehicleModelInfo::ms_vehicleColourTable[colour1]); } } @@ -439,8 +452,10 @@ void CGarage::Update() CenterCarInGarage(FindPlayerVehicle()); } if (bTakeMoney) { - if (!CGarages::RespraysAreFree) + if (!CGarages::RespraysAreFree) { CWorld::Players[CWorld::PlayerInFocus].m_nMoney = Max(0, CWorld::Players[CWorld::PlayerInFocus].m_nMoney - RESPRAY_PRICE); + CStats::AutoPaintingBudget += RESPRAY_PRICE; + } CGarages::TriggerMessage("GA_2", -1, 4000, -1); // New engine and paint job. The cops won't recognize you! } else if (bChangedColour) { @@ -452,10 +467,10 @@ void CGarage::Update() m_bResprayHappened = true; } CWorld::CallOffChaseForArea( - m_fX1 - DISTANCE_TO_CALL_OFF_CHASE, - m_fY1 - DISTANCE_TO_CALL_OFF_CHASE, - m_fX2 + DISTANCE_TO_CALL_OFF_CHASE, - m_fY2 + DISTANCE_TO_CALL_OFF_CHASE); + m_fInfX - DISTANCE_TO_CALL_OFF_CHASE, + m_fInfY - DISTANCE_TO_CALL_OFF_CHASE, + m_fSupX + DISTANCE_TO_CALL_OFF_CHASE, + m_fSupY + DISTANCE_TO_CALL_OFF_CHASE); break; case GS_OPENING: m_fDoorPos = Min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep()); @@ -480,12 +495,8 @@ void CGarage::Update() case GARAGE_BOMBSHOP3: switch (m_eGarageState) { case GS_OPENED: - if (IsStaticPlayerCarEntirelyInside() && !IsAnyOtherCarTouchingGarage(FindPlayerVehicle())) { -#ifdef FIX_BUGS // FindPlayerVehicle() can never be NULL here because IsStaticPlayerCarEntirelyInside() is true, and there is no IsCar() check - if (FindPlayerVehicle()->IsCar() && ((CAutomobile*)FindPlayerVehicle())->m_bombType) { -#else - if (!FindPlayerVehicle() || ((CAutomobile*)FindPlayerVehicle())->m_bombType) { -#endif + if (IsStaticPlayerCarEntirelyInside()) { + if (!FindPlayerVehicle() || FindPlayerVehicle()->m_bombType) { CGarages::TriggerMessage("GA_5", -1, 4000, -1); //"Your car is already fitted with a bomb" m_eGarageState = GS_OPENEDCONTAINSCAR; DMAudio.PlayFrontEndSound(SOUND_GARAGE_BOMB_ALREADY_SET, 1); @@ -503,6 +514,8 @@ void CGarage::Update() } break; case GS_CLOSING: + if (FindPlayerVehicle()) + ThrowCarsNearDoorOutOfGarage(FindPlayerVehicle()); m_fDoorPos = Max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == 0.0f) { m_eGarageState = GS_FULLYCLOSED; @@ -510,62 +523,69 @@ void CGarage::Update() DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f); } UpdateDoorsHeight(); + if (m_eGarageType == GARAGE_BOMBSHOP3) + CStreaming::RequestModel(MI_BOMB, STREAMFLAGS_DONT_REMOVE); break; case GS_FULLYCLOSED: if (CTimer::GetTimeInMilliseconds() > m_nTimeToStartAction) { - switch (m_eGarageType) { - case GARAGE_BOMBSHOP1: DMAudio.PlayFrontEndSound(SOUND_GARAGE_BOMB1_SET, 1); break; - case GARAGE_BOMBSHOP2: DMAudio.PlayFrontEndSound(SOUND_GARAGE_BOMB2_SET, 1); break; - case GARAGE_BOMBSHOP3: DMAudio.PlayFrontEndSound(SOUND_GARAGE_BOMB3_SET, 1); break; + if (m_eGarageType != GARAGE_BOMBSHOP3 || CStreaming::HasModelLoaded(MI_BOMB)) { + switch (m_eGarageType) { + case GARAGE_BOMBSHOP1: DMAudio.PlayFrontEndSound(SOUND_GARAGE_BOMB1_SET, 1); break; + case GARAGE_BOMBSHOP2: DMAudio.PlayFrontEndSound(SOUND_GARAGE_BOMB2_SET, 1); break; + case GARAGE_BOMBSHOP3: DMAudio.PlayFrontEndSound(SOUND_GARAGE_BOMB3_SET, 1); break; default: break; - } - m_eGarageState = GS_OPENING; - if (!CGarages::BombsAreFree) - CWorld::Players[CWorld::PlayerInFocus].m_nMoney = Max(0, CWorld::Players[CWorld::PlayerInFocus].m_nMoney - BOMB_PRICE); - if (FindPlayerVehicle() && FindPlayerVehicle()->IsCar()) { - ((CAutomobile*)(FindPlayerVehicle()))->m_bombType = CGarages::GetBombTypeForGarageType(m_eGarageType); - ((CAutomobile*)(FindPlayerVehicle()))->m_pBombRigger = FindPlayerPed(); - if (m_eGarageType == GARAGE_BOMBSHOP3) - CGarages::GivePlayerDetonator(); - CStats::KgsOfExplosivesUsed += KGS_OF_EXPLOSIVES_IN_BOMB; - } + } + m_eGarageState = GS_OPENING; + if (!CGarages::BombsAreFree) + CWorld::Players[CWorld::PlayerInFocus].m_nMoney = Max(0, CWorld::Players[CWorld::PlayerInFocus].m_nMoney - BOMB_PRICE); + if (FindPlayerVehicle() && (FindPlayerVehicle()->IsCar() || FindPlayerVehicle()->IsBike())) { + FindPlayerVehicle()->m_bombType = CGarages::GetBombTypeForGarageType(m_eGarageType); + FindPlayerVehicle()->m_pBombRigger = FindPlayerPed(); + if (m_eGarageType == GARAGE_BOMBSHOP3) + CGarages::GivePlayerDetonator(); + CStats::KgsOfExplosivesUsed += KGS_OF_EXPLOSIVES_IN_BOMB; + } #ifdef DETECT_PAD_INPUT_SWITCH - int16 Mode = CPad::IsAffectedByController ? CPad::GetPad(0)->Mode : 0; + int16 Mode = CPad::IsAffectedByController ? CPad::GetPad(0)->Mode : 0; #else - int16 Mode = CPad::GetPad(0)->Mode; + int16 Mode = CPad::GetPad(0)->Mode; #endif - switch (m_eGarageType) { - case GARAGE_BOMBSHOP1: - switch (Mode) { - case 0: - case 1: - case 2: - CHud::SetHelpMessage(TheText.Get("GA_6"), false); // Arm with ~h~~k~~PED_FIREWEAPON~ button~w~. Bomb will go off when engine is started. - break; - case 3: - CHud::SetHelpMessage(TheText.Get("GA_6B"), false); // Arm with ~h~~k~~PED_FIREWEAPON~ button~w~. Bomb will go off when engine is started. + switch (m_eGarageType) { + case GARAGE_BOMBSHOP1: + switch (Mode) { + case 0: + case 1: + case 2: + CHud::SetHelpMessage(TheText.Get("GA_6"), false); // Arm with ~h~~k~~PED_FIREWEAPON~ button~w~. Bomb will go off when engine is started. + break; + case 3: + CHud::SetHelpMessage(TheText.Get("GA_6B"), false); // Arm with ~h~~k~~PED_FIREWEAPON~ button~w~. Bomb will go off when engine is started. + break; + } break; - } - break; - case GARAGE_BOMBSHOP2: - switch (Mode) { - case 0: - case 1: - case 2: - CHud::SetHelpMessage(TheText.Get("GA_7"), false); // Park it, prime it by pressing the ~h~~k~~PED_FIREWEAPON~ button~w~ and LEG IT! + case GARAGE_BOMBSHOP2: + switch (Mode) { + case 0: + case 1: + case 2: + CHud::SetHelpMessage(TheText.Get("GA_7"), false); // Park it, prime it by pressing the ~h~~k~~PED_FIREWEAPON~ button~w~ and LEG IT! + break; + case 3: + CHud::SetHelpMessage(TheText.Get("GA_7B"), false); // Park it, prime it by pressing the ~h~~k~~PED_FIREWEAPON~ button~w~ and LEG IT! + break; + } break; - case 3: - CHud::SetHelpMessage(TheText.Get("GA_7B"), false); // Park it, prime it by pressing the ~h~~k~~PED_FIREWEAPON~ button~w~ and LEG IT! + case GARAGE_BOMBSHOP3: + CHud::SetHelpMessage(TheText.Get("GA_8"), false); // Use the detonator to activate the bomb. break; - } - break; - case GARAGE_BOMBSHOP3: - CHud::SetHelpMessage(TheText.Get("GA_8"), false); // Use the detonator to activate the bomb. - break; default: break; + } + CPad::GetPad(0)->SetEnablePlayerControls(PLAYERCONTROL_GARAGE); + FindPlayerPed()->m_pWanted->m_bIgnoredByCops = false; + } + else { + CStreaming::RequestModel(MI_BOMB, STREAMFLAGS_DONT_REMOVE); } - CPad::GetPad(0)->SetEnablePlayerControls(PLAYERCONTROL_GARAGE); - FindPlayerPed()->m_pWanted->m_bIgnoredByCops = false; } break; case GS_OPENING: @@ -604,6 +624,8 @@ void CGarage::Update() } break; case GS_CLOSING: + if (m_pTarget) + ThrowCarsNearDoorOutOfGarage(m_pTarget); m_fDoorPos = Max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == 0.0f) { DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f); @@ -648,92 +670,10 @@ void CGarage::Update() } break; case GARAGE_COLLECTSPECIFICCARS: - switch (m_eGarageState) { - case GS_OPENED: - if (FindPlayerVehicle() && m_nTargetModelIndex == FindPlayerVehicle()->GetModelIndex()) { - m_pTarget = FindPlayerVehicle(); - m_pTarget->RegisterReference((CEntity**)&m_pTarget); - } - if (!FindPlayerVehicle()) { - if (m_pTarget && IsEntityEntirelyInside3D(m_pTarget, 0.0f) && !IsAnyOtherCarTouchingGarage(m_pTarget)) { - if (IsEntityEntirelyOutside(FindPlayerPed(), 2.0f)) { - CPad::GetPad(0)->SetDisablePlayerControls(PLAYERCONTROL_GARAGE); - FindPlayerPed()->m_pWanted->m_bIgnoredByCops = true; - m_eGarageState = GS_CLOSING; - } - } - else if (Abs(FindPlayerCoors().x - GetGarageCenterX()) > DISTANCE_TO_CLOSE_COLLECTSPECIFICCARS_GARAGE || - Abs(FindPlayerCoors().y - GetGarageCenterY()) > DISTANCE_TO_CLOSE_COLLECTSPECIFICCARS_GARAGE) { - m_eGarageState = GS_CLOSING; - m_pTarget = nil; - } - } - break; - case GS_CLOSING: - m_fDoorPos = Max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep()); - if (m_fDoorPos == 0.0f) { - m_eGarageState = GS_FULLYCLOSED; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f); - if (m_pTarget) { - DestroyVehicleAndDriverAndPassengers(m_pTarget); - m_pTarget = nil; - CPad::GetPad(0)->SetEnablePlayerControls(PLAYERCONTROL_GARAGE); - FindPlayerPed()->m_pWanted->m_bIgnoredByCops = false; - int16 reward; - switch (m_nTargetModelIndex) { - case MI_POLICE: - reward = REWARD_FOR_FIRST_POLICE_CAR * (MAX_POLICE_CARS_TO_COLLECT - CGarages::PoliceCarsCollected++) / MAX_POLICE_CARS_TO_COLLECT; - break; - case MI_SECURICA: - reward = REWARD_FOR_FIRST_BANK_VAN * (MAX_BANK_VANS_TO_COLLECT - CGarages::BankVansCollected++) / MAX_BANK_VANS_TO_COLLECT; - break; -#ifdef FIX_BUGS // not possible though - default: - reward = 0; - break; -#endif - } - if (reward > 0) { - CWorld::Players[CWorld::PlayerInFocus].m_nMoney += reward; - CGarages::TriggerMessage("GA_10", reward, 4000, -1); // Nice one. Here's your $~1~ - DMAudio.PlayFrontEndSound(SOUND_GARAGE_VEHICLE_ACCEPTED, 1); - } - else { - CGarages::TriggerMessage("GA_11", -1, 4000, -1); // We got these wheels already. It's worthless to us! - DMAudio.PlayFrontEndSound(SOUND_GARAGE_VEHICLE_DECLINED, 1); - } - } - } - UpdateDoorsHeight(); - break; - case GS_FULLYCLOSED: - if (FindPlayerVehicle() && m_nTargetModelIndex == FindPlayerVehicle()->GetModelIndex()) { - if (CalcDistToGarageRectangleSquared(FindPlayerVehicle()->GetPosition().x, FindPlayerVehicle()->GetPosition().y) < SQR(DISTANCE_TO_ACTIVATE_GARAGE)) - m_eGarageState = GS_OPENING; - } - break; - case GS_OPENING: - if (FindPlayerVehicle() && m_nTargetModelIndex == FindPlayerVehicle()->GetModelIndex()) { - m_pTarget = FindPlayerVehicle(); - m_pTarget->RegisterReference((CEntity**)&m_pTarget); - } - m_fDoorPos = Min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep()); - if (m_fDoorPos == m_fDoorHeight) { - m_eGarageState = GS_OPENED; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f); - } - UpdateDoorsHeight(); - break; - //case GS_OPENEDCONTAINSCAR: - //case GS_CLOSEDCONTAINSCAR: - //case GS_AFTERDROPOFF: - default: - break; - } - break; case GARAGE_COLLECTCARS_1: case GARAGE_COLLECTCARS_2: case GARAGE_COLLECTCARS_3: + case GARAGE_COLLECTCARS_4: switch (m_eGarageState) { case GS_OPENED: if (FindPlayerVehicle() && DoesCraigNeedThisCar(FindPlayerVehicle()->GetModelIndex())) { @@ -766,6 +706,8 @@ void CGarage::Update() } break; case GS_CLOSING: + if (m_pTarget) + ThrowCarsNearDoorOutOfGarage(m_pTarget); m_fDoorPos = Max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == 0.0f) { m_eGarageState = GS_FULLYCLOSED; @@ -853,75 +795,6 @@ void CGarage::Update() } break; case GARAGE_CRUSHER: - switch (m_eGarageState) { - case GS_OPENED: - { - int i = CPools::GetVehiclePool()->GetSize() * (CTimer::GetFrameCounter() % CRUSHER_VEHICLE_TEST_SPAN) / CRUSHER_VEHICLE_TEST_SPAN; - int end = CPools::GetVehiclePool()->GetSize() * (CTimer::GetFrameCounter() % CRUSHER_VEHICLE_TEST_SPAN + 1) / CRUSHER_VEHICLE_TEST_SPAN; - for (; i < end; i++) { - CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i); - if (!pVehicle) - continue; - if (pVehicle->IsCar() && IsEntityEntirelyInside3D(pVehicle, 0.0f)) { - m_eGarageState = GS_CLOSING; - m_pTarget = pVehicle; - m_pTarget->RegisterReference((CEntity**)&m_pTarget); - } - } - break; - } - case GS_CLOSING: - if (m_pTarget) { - m_fDoorPos = Max(0.0f, m_fDoorPos - CRUSHER_CRANE_SPEED * CTimer::GetTimeStep()); - if (m_fDoorPos < TWOPI / 5) { - m_pTarget->bUsesCollision = false; - m_pTarget->bAffectedByGravity = false; - m_pTarget->SetMoveSpeed(0.0f, 0.0f, 0.0f); - } - else { - m_pTarget->SetMoveSpeed(m_pTarget->GetMoveSpeed() * Pow(0.8f, CTimer::GetTimeStep())); - } - if (m_fDoorPos == 0.0f) { - CGarages::CrushedCarId = CPools::GetVehiclePool()->GetIndex(m_pTarget); - float reward = Min(CRUSHER_MAX_REWARD, CRUSHER_MIN_REWARD + m_pTarget->pHandling->nMonetaryValue * m_pTarget->m_fHealth * CRUSHER_REWARD_COEFFICIENT); - CWorld::Players[CWorld::PlayerInFocus].m_nMoney += reward; - DestroyVehicleAndDriverAndPassengers(m_pTarget); - ++CStats::CarsCrushed; - m_pTarget = nil; - m_eGarageState = GS_AFTERDROPOFF; - m_nTimeToStartAction = CTimer::GetTimeInMilliseconds() + TIME_TO_CRUSH_CAR; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f); - } - } - else - m_eGarageState = GS_OPENING; - UpdateCrusherAngle(); - break; - case GS_AFTERDROPOFF: - if (CTimer::GetTimeInMilliseconds() <= m_nTimeToStartAction) { - UpdateCrusherShake((myrand() & 0xFF - 128) * 0.0002f, (myrand() & 0xFF - 128) * 0.0002f); - } - else { - UpdateCrusherShake(0.0f, 0.0f); - m_eGarageState = GS_OPENING; - } - break; - case GS_OPENING: - m_fDoorPos = Min(HALFPI, m_fDoorPos + CTimer::GetTimeStep() * CRUSHER_CRANE_SPEED); - if (m_fDoorPos == HALFPI) { - m_eGarageState = GS_OPENED; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f); - } - UpdateCrusherAngle(); - break; - //case GS_FULLYCLOSED: - //case GS_CLOSEDCONTAINSCAR: - //case GS_OPENEDCONTAINSCAR: - default: - break; - } - if (!FindPlayerVehicle() && (CTimer::GetFrameCounter() & 0x1F) == 0x17 && IsEntityEntirelyInside(FindPlayerPed())) - FindPlayerPed()->InflictDamage(nil, WEAPONTYPE_RAMMEDBYCAR, 300.0f, PEDPIECE_TORSO, 0); break; case GARAGE_MISSION_KEEPCAR: case GARAGE_MISSION_KEEPCAR_REMAINCLOSED: @@ -940,6 +813,8 @@ void CGarage::Update() } break; case GS_CLOSING: + if (m_pTarget) + ThrowCarsNearDoorOutOfGarage(m_pTarget); m_fDoorPos = Max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == 0.0f) { DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f); @@ -1035,6 +910,15 @@ void CGarage::Update() case GARAGE_HIDEOUT_ONE: case GARAGE_HIDEOUT_TWO: case GARAGE_HIDEOUT_THREE: + case GARAGE_HIDEOUT_FOUR: + case GARAGE_HIDEOUT_FIVE: + case GARAGE_HIDEOUT_SIX: + case GARAGE_HIDEOUT_SEVEN: + case GARAGE_HIDEOUT_EIGHT: + case GARAGE_HIDEOUT_NINE: + case GARAGE_HIDEOUT_TEN: + case GARAGE_HIDEOUT_ELEVEN: + case GARAGE_HIDEOUT_TWELVE: switch (m_eGarageState) { case GS_OPENED: { @@ -1047,7 +931,7 @@ void CGarage::Update() m_eGarageState = GS_CLOSING; else if (FindPlayerVehicle() && CountCarsWithCenterPointWithinGarage(FindPlayerVehicle()) >= - CGarages::FindMaxNumStoredCarsForGarage(m_eGarageType)) { + FindMaxNumStoredCarsForGarage()) { m_eGarageState = GS_CLOSING; } else if (distance > SQR(DISTANCE_TO_FORCE_CLOSE_HIDEOUT_GARAGE)) { @@ -1063,12 +947,7 @@ void CGarage::Update() else if (m_fDoorPos == 0.0f) { DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f); m_eGarageState = GS_FULLYCLOSED; - switch (m_eGarageType) { - case GARAGE_HIDEOUT_ONE: StoreAndRemoveCarsForThisHideout(CGarages::aCarsInSafeHouse1, MAX_STORED_CARS_IN_INDUSTRIAL); break; - case GARAGE_HIDEOUT_TWO: StoreAndRemoveCarsForThisHideout(CGarages::aCarsInSafeHouse2, MAX_STORED_CARS_IN_COMMERCIAL); break; - case GARAGE_HIDEOUT_THREE: StoreAndRemoveCarsForThisHideout(CGarages::aCarsInSafeHouse3, MAX_STORED_CARS_IN_SUBURBAN); break; - default: break; - } + StoreAndRemoveCarsForThisHideout(CGarages::aCarsInSafeHouses[CGarages::FindSafeHouseIndexForGarageType(m_eGarageType)], NUM_GARAGE_STORED_CARS); } UpdateDoorsHeight(); break; @@ -1077,30 +956,19 @@ void CGarage::Update() float distance = CalcDistToGarageRectangleSquared(FindPlayerCoors().x, FindPlayerCoors().y); if (distance < SQR(DISTANCE_TO_OPEN_HIDEOUT_GARAGE_ON_FOOT) || distance < SQR(DISTANCE_TO_OPEN_HIDEOUT_GARAGE_IN_CAR) && FindPlayerVehicle()) { - if (FindPlayerVehicle() && CGarages::CountCarsInHideoutGarage(m_eGarageType) >= CGarages::FindMaxNumStoredCarsForGarage(m_eGarageType)) { + if (FindPlayerVehicle() && CGarages::CountCarsInHideoutGarage(m_eGarageType) >= FindMaxNumStoredCarsForGarage()) { if (m_pDoor1) { if (((CVector2D)FindPlayerVehicle()->GetPosition() - (CVector2D)m_pDoor1->GetPosition()).MagnitudeSqr() < SQR(DISTANCE_TO_SHOW_HIDEOUT_MESSAGE) && CTimer::GetTimeInMilliseconds() - CGarages::LastTimeHelpMessage > TIME_BETWEEN_HIDEOUT_MESSAGES) { - CHud::SetHelpMessage(TheText.Get("GA_21"), false); // You cannot store any more cars in this garage. - CGarages::LastTimeHelpMessage = CTimer::GetTimeInMilliseconds(); + if (FindPlayerVehicle()->GetVehicleAppearance() != VEHICLE_APPEARANCE_HELI && FindPlayerVehicle()->GetVehicleAppearance() != VEHICLE_APPEARANCE_PLANE) { + CHud::SetHelpMessage(TheText.Get("GA_21"), false); // You cannot store any more cars in this garage. + CGarages::LastTimeHelpMessage = CTimer::GetTimeInMilliseconds(); + } } } } - else { -#ifdef FIX_BUGS - bool bCreatedAllCars = false; -#else - bool bCreatedAllCars; -#endif - switch (m_eGarageType) { - case GARAGE_HIDEOUT_ONE: bCreatedAllCars = RestoreCarsForThisHideout(CGarages::aCarsInSafeHouse1); break; - case GARAGE_HIDEOUT_TWO: bCreatedAllCars = RestoreCarsForThisHideout(CGarages::aCarsInSafeHouse2); break; - case GARAGE_HIDEOUT_THREE: bCreatedAllCars = RestoreCarsForThisHideout(CGarages::aCarsInSafeHouse3); break; - default: break; - } - if (bCreatedAllCars) - m_eGarageState = GS_OPENING; - } + else if (RestoreCarsForThisHideout(CGarages::aCarsInSafeHouses[CGarages::FindSafeHouseIndexForGarageType(m_eGarageType)])) + m_eGarageState = GS_OPENING; } break; } @@ -1130,6 +998,8 @@ void CGarage::Update() } break; case GS_CLOSING: + if (m_pTarget) + ThrowCarsNearDoorOutOfGarage(m_pTarget); m_fDoorPos = Max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == 0.0f) { m_eGarageState = GS_FULLYCLOSED; @@ -1162,11 +1032,64 @@ void CGarage::Update() break; //case GARAGE_COLLECTORSITEMS: //case GARAGE_60SECONDS: + case GARAGE_FOR_SCRIPT_TO_OPEN_FOR_CAR: + switch (m_eGarageState) { + case GS_OPENED: + if (m_pTarget && IsEntityEntirelyInside3D(m_pTarget, 0.0f) && !IsAnyCarBlockingDoor() && IsPlayerOutsideGarage()) { + CPad::GetPad(0)->SetDisablePlayerControls(PLAYERCONTROL_GARAGE); + m_eGarageState = GS_CLOSING; + m_bClosingWithoutTargetCar = false; + } + case GS_CLOSING: + m_fDoorPos = Max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep()); + if (m_fDoorPos == 0.0f) { + m_eGarageState = GS_FULLYCLOSED; + DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f); + CPad::GetPad(0)->SetEnablePlayerControls(PLAYERCONTROL_GARAGE); + } + case GS_FULLYCLOSED: + break; + case GS_OPENING: + m_fDoorPos = Min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep()); + if (m_fDoorPos == m_fDoorHeight) { + m_eGarageState = GS_OPENED; + DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f); + } + UpdateDoorsHeight(); + break; + //case GS_OPENEDCONTAINSCAR: + //case GS_CLOSEDCONTAINSCAR: + //case GS_AFTERDROPOFF: + default: + break; + } default: break; } } +void CGarage::ThrowCarsNearDoorOutOfGarage(CVehicle* pException) +{ + uint32 i = CPools::GetVehiclePool()->GetSize(); + while (i--) { + CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i); + if (!pVehicle || pVehicle == pException) + continue; + if (!IsEntityTouching3D(pVehicle)) + continue; + CColModel* pColModel = pVehicle->GetColModel(); + for (int i = 0; i < pColModel->numSpheres; i++) { + CVector pos = pVehicle->GetMatrix() * pColModel->spheres[i].center; + float radius = pColModel->spheres[i].radius; + if (!IsPointInsideGarage(pos, 0.0f)) { + CVector vecDirectionAway(pVehicle->GetPosition().x - GetGarageCenterX(), pVehicle->GetPosition().y - GetGarageCenterY(), 0.0f); + vecDirectionAway.Normalise(); + pVehicle->AddToMoveSpeed(vecDirectionAway * CTimer::GetTimeStepInSeconds()); + } + } + } +} + bool CGarage::IsStaticPlayerCarEntirelyInside() { if (!FindPlayerVehicle()) @@ -1178,8 +1101,8 @@ bool CGarage::IsStaticPlayerCarEntirelyInside() if (FindPlayerPed()->m_objective == OBJECTIVE_LEAVE_VEHICLE) return false; CVehicle* pVehicle = FindPlayerVehicle(); - if (pVehicle->GetPosition().x < m_fX1 || pVehicle->GetPosition().x > m_fX2 || - pVehicle->GetPosition().y < m_fY1 || pVehicle->GetPosition().y > m_fY2) + if (pVehicle->GetPosition().x < m_fInfX || pVehicle->GetPosition().x > m_fSupX || + pVehicle->GetPosition().y < m_fInfY || pVehicle->GetPosition().y > m_fSupY) return false; if (Abs(pVehicle->GetSpeed().x) > 0.01f || Abs(pVehicle->GetSpeed().y) > 0.01f || @@ -1190,35 +1113,58 @@ bool CGarage::IsStaticPlayerCarEntirelyInside() return IsEntityEntirelyInside3D(pVehicle, 0.0f); } -bool CGarage::IsEntityEntirelyInside(CEntity * pEntity) +bool CGarage::IsPointInsideGarage(CVector pos) { - if (pEntity->GetPosition().x < m_fX1 || pEntity->GetPosition().x > m_fX2 || - pEntity->GetPosition().y < m_fY1 || pEntity->GetPosition().y > m_fY2) + // is it IsPointInsideGarage(pos, 0.0f)? + if (pos.z < m_fInfZ) + return false; + if (pos.z > m_fSupZ) + return false; + CVector2D vecToTarget((CVector2D)pos - m_vecCorner1); + float dp = DotProduct2D(m_vDir1, vecToTarget); + if (dp < 0.0f) + return false; + if (m_fDir1Len < dp) + return false; + dp = DotProduct2D(m_vDir2, vecToTarget); + if (dp < 0.0f) + return false; + if (m_fDir2Len < dp) + return false; + return true; +} + +bool CGarage::IsPointInsideGarage(CVector pos, float m_fMargin) +{ + if (pos.z < m_fInfZ - m_fMargin) + return false; + if (pos.z > m_fSupZ + m_fMargin) + return false; + CVector2D vecToTarget((CVector2D)pos - m_vecCorner1); + float dp = DotProduct2D(m_vDir1, vecToTarget); + if (dp < -m_fMargin) + return false; + if (m_fDir1Len + m_fMargin < dp) + return false; + dp = DotProduct2D(m_vDir2, vecToTarget); + if (dp < -m_fMargin) + return false; + if (m_fDir2Len + m_fMargin < dp) return false; - CColModel* pColModel = pEntity->GetColModel(); - for (int i = 0; i < pColModel->numSpheres; i++) { - CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center; - float radius = pColModel->spheres[i].radius; - if (pos.x - radius < m_fX1 || pos.x + radius > m_fX2 || - pos.y - radius < m_fY1 || pos.y + radius > m_fY2) - return false; - } return true; } bool CGarage::IsEntityEntirelyInside3D(CEntity * pEntity, float fMargin) { - if (pEntity->GetPosition().x < m_fX1 - fMargin || pEntity->GetPosition().x > m_fX2 + fMargin || - pEntity->GetPosition().y < m_fY1 - fMargin || pEntity->GetPosition().y > m_fY2 + fMargin || - pEntity->GetPosition().z < m_fZ1 - fMargin || pEntity->GetPosition().z > m_fZ2 + fMargin) + if (pEntity->GetPosition().x < m_fInfX - fMargin || pEntity->GetPosition().x > m_fSupX + fMargin || + pEntity->GetPosition().y < m_fInfY - fMargin || pEntity->GetPosition().y > m_fSupY + fMargin || + pEntity->GetPosition().z < m_fInfZ - fMargin || pEntity->GetPosition().z > m_fSupZ + fMargin) return false; CColModel* pColModel = pEntity->GetColModel(); for (int i = 0; i < pColModel->numSpheres; i++) { CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center; float radius = pColModel->spheres[i].radius; - if (pos.x + radius < m_fX1 - fMargin || pos.x - radius > m_fX2 + fMargin || - pos.y + radius < m_fY1 - fMargin || pos.y - radius > m_fY2 + fMargin || - pos.z + radius < m_fZ1 - fMargin || pos.z - radius > m_fZ2 + fMargin) + if (!IsPointInsideGarage(pos, fMargin - radius)) return false; } return true; @@ -1226,15 +1172,14 @@ bool CGarage::IsEntityEntirelyInside3D(CEntity * pEntity, float fMargin) bool CGarage::IsEntityEntirelyOutside(CEntity * pEntity, float fMargin) { - if (pEntity->GetPosition().x > m_fX1 - fMargin && pEntity->GetPosition().x < m_fX2 + fMargin && - pEntity->GetPosition().y > m_fY1 - fMargin && pEntity->GetPosition().y < m_fY2 + fMargin) + if (pEntity->GetPosition().x > m_fInfX - fMargin && pEntity->GetPosition().x < m_fSupX + fMargin && + pEntity->GetPosition().y > m_fInfY - fMargin && pEntity->GetPosition().y < m_fSupY + fMargin) return false; CColModel* pColModel = pEntity->GetColModel(); for (int i = 0; i < pColModel->numSpheres; i++) { CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center; float radius = pColModel->spheres[i].radius; - if (pos.x + radius > m_fX1 - fMargin && pos.x - radius < m_fX2 + fMargin && - pos.y + radius > m_fY1 - fMargin && pos.y - radius < m_fY2 + fMargin) + if (IsPointInsideGarage(pos, fMargin + radius)) return false; } return true; @@ -1243,8 +1188,15 @@ bool CGarage::IsEntityEntirelyOutside(CEntity * pEntity, float fMargin) bool CGarage::IsGarageEmpty() { int16 num; - CWorld::FindObjectsIntersectingCube(CVector(m_fX1, m_fY1, m_fZ1), CVector(m_fX2, m_fY2, m_fZ2), &num, 2, nil, false, true, true, false, false); - return num == 0; + CEntity* pEntities[16]; + CWorld::FindObjectsIntersectingCube(CVector(m_fInfX, m_fInfY, m_fInfZ), CVector(m_fSupX, m_fSupY, m_fSupZ), &num, 16, pEntities, false, true, true, false, false); + if (num <= 0) + return true; + for (int i = 0; i < 16; i++) { + if (IsEntityTouching3D(pEntities[i])) + return false; + } + return true; } bool CGarage::IsPlayerOutsideGarage() @@ -1257,20 +1209,18 @@ bool CGarage::IsPlayerOutsideGarage() bool CGarage::IsEntityTouching3D(CEntity * pEntity) { float radius = pEntity->GetBoundRadius(); - if (pEntity->GetPosition().x - radius < m_fX1 || pEntity->GetPosition().x + radius > m_fX2 || - pEntity->GetPosition().y - radius < m_fY1 || pEntity->GetPosition().y + radius > m_fY2 || - pEntity->GetPosition().z - radius < m_fZ1 || pEntity->GetPosition().z + radius > m_fZ2) + if (pEntity->GetPosition().x - radius < m_fInfX || pEntity->GetPosition().x + radius > m_fSupX || + pEntity->GetPosition().y - radius < m_fInfY || pEntity->GetPosition().y + radius > m_fSupY || + pEntity->GetPosition().z - radius < m_fInfZ || pEntity->GetPosition().z + radius > m_fSupZ) return false; CColModel* pColModel = pEntity->GetColModel(); for (int i = 0; i < pColModel->numSpheres; i++) { CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center; radius = pColModel->spheres[i].radius; - if (pos.x + radius > m_fX1 && pos.x - radius < m_fX2 && - pos.y + radius > m_fY1 && pos.y - radius < m_fY2 && - pos.z + radius > m_fZ1 && pos.z - radius < m_fZ2) - return false; + if (IsPointInsideGarage(pos, radius)) + return true; } - return true; + return false; } bool CGarage::EntityHasASphereWayOutsideGarage(CEntity * pEntity, float fMargin) @@ -1279,9 +1229,7 @@ bool CGarage::EntityHasASphereWayOutsideGarage(CEntity * pEntity, float fMargin) for (int i = 0; i < pColModel->numSpheres; i++) { CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center; float radius = pColModel->spheres[i].radius; - if (pos.x + radius + fMargin < m_fX1 || pos.x - radius - fMargin > m_fX2 || - pos.y + radius + fMargin < m_fY1 || pos.y - radius - fMargin > m_fY2 || - pos.z + radius + fMargin < m_fZ1 || pos.z - radius - fMargin > m_fZ2) + if (!IsPointInsideGarage(pos, fMargin + radius)) return true; } return false; @@ -1300,9 +1248,7 @@ bool CGarage::IsAnyOtherCarTouchingGarage(CVehicle * pException) for (int i = 0; i < pColModel->numSpheres; i++) { CVector pos = pVehicle->GetMatrix() * pColModel->spheres[i].center; float radius = pColModel->spheres[i].radius; - if (pos.x + radius > m_fX1 && pos.x - radius < m_fX2 && - pos.y + radius > m_fY1 && pos.y - radius < m_fY2 && - pos.z + radius > m_fZ1 && pos.z - radius < m_fZ2) + if (IsPointInsideGarage(pos, radius)) return true; } } @@ -1322,9 +1268,7 @@ bool CGarage::IsAnyOtherPedTouchingGarage(CPed * pException) for (int i = 0; i < pColModel->numSpheres; i++) { CVector pos = pPed->GetMatrix() * pColModel->spheres[i].center; float radius = pColModel->spheres[i].radius; - if (pos.x + radius > m_fX1 && pos.x - radius < m_fX2 && - pos.y + radius > m_fY1 && pos.y - radius < m_fY2 && - pos.z + radius > m_fZ1 && pos.z - radius < m_fZ2) + if (IsPointInsideGarage(pos, radius)) return true; } } @@ -1344,9 +1288,7 @@ bool CGarage::IsAnyCarBlockingDoor() for (int i = 0; i < pColModel->numSpheres; i++) { CVector pos = pVehicle->GetMatrix() * pColModel->spheres[i].center; float radius = pColModel->spheres[i].radius; - if (pos.x + radius < m_fX1 || pos.x - radius > m_fX2 || - pos.y + radius < m_fY1 || pos.y - radius > m_fY2 || - pos.z + radius < m_fZ1 || pos.z - radius > m_fZ2) + if (!IsPointInsideGarage(pos, radius)) return true; } } @@ -1361,9 +1303,7 @@ int32 CGarage::CountCarsWithCenterPointWithinGarage(CEntity * pException) CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i); if (!pVehicle || pVehicle == pException) continue; - if (pVehicle->GetPosition().x > m_fX1 && pVehicle->GetPosition().x < m_fX2 && - pVehicle->GetPosition().y > m_fY1 && pVehicle->GetPosition().y < m_fY2 && - pVehicle->GetPosition().z > m_fZ1 && pVehicle->GetPosition().z < m_fZ2) + if (IsPointInsideGarage(pVehicle->GetPosition())) total++; } return total; @@ -1378,9 +1318,7 @@ void CGarage::RemoveCarsBlockingDoorNotInside() continue; if (!IsEntityTouching3D(pVehicle)) continue; - if (pVehicle->GetPosition().x < m_fX1 || pVehicle->GetPosition().x > m_fX2 || - pVehicle->GetPosition().y < m_fY1 || pVehicle->GetPosition().y > m_fY2 || - pVehicle->GetPosition().z < m_fZ1 || pVehicle->GetPosition().z > m_fZ2) { + if (!IsPointInsideGarage(pVehicle->GetPosition())) { if (pVehicle->bIsLocked && pVehicle->CanBeDeleted()) { CWorld::Remove(pVehicle); delete pVehicle; @@ -1399,7 +1337,7 @@ void CGarages::PrintMessages() CFont::SetBackgroundOff(); CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(50.0f)); CFont::SetCentreOn(); - CFont::SetFontStyle(FONT_LOCALE(FONT_BANK)); + CFont::SetFontStyle(FONT_LOCALE(FONT_BANK)); // TODO(MIAMI): redo it CFont::SetColor(CRGBA(0, 0, 0, 255)); #if defined(PS2) || defined (FIX_BUGS) @@ -1412,7 +1350,7 @@ void CGarages::PrintMessages() if (MessageNumberInString < 0) { CFont::PrintString(SCREEN_WIDTH / 2 - SCREEN_SCALE_X(2.0f), y_offset - SCREEN_SCALE_Y(2.0f), TheText.Get(MessageIDString)); - CFont::SetColor(CRGBA(89, 115, 150, 255)); + CFont::SetColor(CRGBA(27, 89, 130, 255)); CFont::PrintString(SCREEN_WIDTH / 2, y_offset, TheText.Get(MessageIDString)); } else { @@ -1420,7 +1358,7 @@ void CGarages::PrintMessages() CFont::PrintString(SCREEN_WIDTH / 2 + SCREEN_SCALE_X(2.0f), y_offset - SCREEN_SCALE_Y(40.0f) + SCREEN_SCALE_Y(2.0f), gUString); - CFont::SetColor(CRGBA(89, 115, 150, 255)); + CFont::SetColor(CRGBA(27, 89, 130, 255)); CFont::PrintString(SCREEN_WIDTH / 2, y_offset - SCREEN_SCALE_Y(40.0f), gUString); } } @@ -1428,7 +1366,7 @@ void CGarages::PrintMessages() CMessages::InsertNumberInString(TheText.Get(MessageIDString), MessageNumberInString, MessageNumberInString2, -1, -1, -1, -1, gUString); CFont::PrintString(SCREEN_WIDTH / 2 + SCREEN_SCALE_X(2.0f), y_offset - SCREEN_SCALE_Y(40.0f) + SCREEN_SCALE_Y(2.0f), gUString); - CFont::SetColor(CRGBA(89, 115, 150, 255)); + CFont::SetColor(CRGBA(27, 89, 130, 255)); CFont::PrintString(SCREEN_WIDTH / 2, y_offset - SCREEN_SCALE_Y(40.0f), gUString); } } @@ -1458,15 +1396,27 @@ void CGarage::UpdateDoorsHeight() RefreshDoorPointers(false); if (m_pDoor1) { m_pDoor1->GetMatrix().GetPosition().z = m_fDoorPos + m_fDoor1Z; - if (m_bRotatedDoor) + if (m_bRotatedDoor) { + CVector pos; + pos.x = m_fDoor1X + m_fDoorPos * m_pDoor1->GetForward().y * 5.0f / 6.0f; + pos.y = m_fDoor1Y - m_fDoorPos * m_pDoor1->GetForward().x * 5.0f / 6.0f; + pos.z = m_pDoor1->GetPosition().z; + m_pDoor1->SetPosition(pos); BuildRotatedDoorMatrix(m_pDoor1, m_fDoorPos / m_fDoorHeight); + } m_pDoor1->GetMatrix().UpdateRW(); m_pDoor1->UpdateRwFrame(); } if (m_pDoor2) { m_pDoor2->GetMatrix().GetPosition().z = m_fDoorPos + m_fDoor2Z; - if (m_bRotatedDoor) + if (m_bRotatedDoor) { + CVector pos; + pos.x = m_fDoor2X + m_fDoorPos * m_pDoor2->GetForward().y * 5.0f / 6.0f; + pos.y = m_fDoor2Y - m_fDoorPos * m_pDoor2->GetForward().x * 5.0f / 6.0f; + pos.z = m_pDoor2->GetPosition().z; + m_pDoor2->SetPosition(pos); BuildRotatedDoorMatrix(m_pDoor2, m_fDoorPos / m_fDoorHeight); + } m_pDoor2->GetMatrix().UpdateRW(); m_pDoor2->UpdateRwFrame(); } @@ -1568,6 +1518,7 @@ void CGarages::SetTargetCarForMissonGarage(int16 garage, CVehicle * pVehicle) assert(garage >= 0 && garage < NUM_GARAGES); if (pVehicle) { aGarages[garage].m_pTarget = pVehicle; + aGarages[garage].m_pTarget->RegisterReference((CEntity**)&aGarages[garage].m_pTarget); if (aGarages[garage].m_eGarageState == GS_CLOSEDCONTAINSCAR) aGarages[garage].m_eGarageState = GS_FULLYCLOSED; } @@ -1619,11 +1570,9 @@ bool CGarages::HasThisCarBeenCollected(int16 garage, uint8 id) bool CGarage::DoesCraigNeedThisCar(int32 mi) { - if (mi == MI_CORPSE) - mi = MI_MANANA; int ct = CGarages::GetCarsCollectedIndexForGarageType(m_eGarageType); for (int i = 0; i < TOTAL_COLLECTCARS_CARS; i++) { - if (mi == gaCarsToCollectInCraigsGarages[ct][i]) + if (mi == gaCarsToCollectInCraigsGarages[ct][i] || (gaCarsToCollectInCraigsGarages[ct][i] == MI_CHEETAH && mi == MI_VICECHEE)) return (CGarages::CarTypesCollected[ct] & BIT(i)) == 0; } return false; @@ -1631,11 +1580,9 @@ bool CGarage::DoesCraigNeedThisCar(int32 mi) bool CGarage::HasCraigCollectedThisCar(int32 mi) { - if (mi == MI_CORPSE) - mi = MI_MANANA; int ct = CGarages::GetCarsCollectedIndexForGarageType(m_eGarageType); for (int i = 0; i < TOTAL_COLLECTCARS_CARS; i++) { - if (mi == gaCarsToCollectInCraigsGarages[ct][i]) + if (mi == gaCarsToCollectInCraigsGarages[ct][i] || (gaCarsToCollectInCraigsGarages[ct][i] == MI_CHEETAH && mi == MI_VICECHEE)) return CGarages::CarTypesCollected[ct] & BIT(i); } return false; @@ -1643,12 +1590,10 @@ bool CGarage::HasCraigCollectedThisCar(int32 mi) bool CGarage::MarkThisCarAsCollectedForCraig(int32 mi) { - if (mi == MI_CORPSE) - mi = MI_MANANA; int ct = CGarages::GetCarsCollectedIndexForGarageType(m_eGarageType); int index; for (index = 0; index < TOTAL_COLLECTCARS_CARS; index++) { - if (mi == gaCarsToCollectInCraigsGarages[ct][index]) + if (mi == gaCarsToCollectInCraigsGarages[ct][index] || (gaCarsToCollectInCraigsGarages[ct][index] == MI_CHEETAH && mi == MI_VICECHEE)) break; } if (index >= TOTAL_COLLECTCARS_CARS) @@ -1681,16 +1626,16 @@ void CGarage::CloseThisGarage() float CGarage::CalcDistToGarageRectangleSquared(float X, float Y) { float distX, distY; - if (X < m_fX1) - distX = m_fX1 - X; - else if (X > m_fX2) - distX = X - m_fX2; + if (X < m_fInfX) + distX = m_fInfX - X; + else if (X > m_fSupX) + distX = X - m_fSupX; else distX = 0.0f; - if (Y < m_fY1) - distY = m_fY1 - Y; - else if (Y > m_fY2) - distY = Y - m_fY2; + if (Y < m_fInfY) + distY = m_fInfY - Y; + else if (Y > m_fSupY) + distY = Y - m_fSupY; else distY = 0.0f; return SQR(distX) + SQR(distY); @@ -1711,10 +1656,10 @@ void CGarage::FindDoorsEntities() { m_pDoor1 = nil; m_pDoor2 = nil; - int xstart = Max(0, CWorld::GetSectorIndexX(m_fX1)); - int xend = Min(NUMSECTORS_X - 1, CWorld::GetSectorIndexX(m_fX2)); - int ystart = Max(0, CWorld::GetSectorIndexY(m_fY1)); - int yend = Min(NUMSECTORS_Y - 1, CWorld::GetSectorIndexY(m_fY2)); + int xstart = Max(0, CWorld::GetSectorIndexX(m_fInfX)); + int xend = Min(NUMSECTORS_X - 1, CWorld::GetSectorIndexX(m_fSupX)); + int ystart = Max(0, CWorld::GetSectorIndexY(m_fInfY)); + int yend = Min(NUMSECTORS_Y - 1, CWorld::GetSectorIndexY(m_fSupY)); assert(xstart <= xend); assert(ystart <= yend); @@ -1729,20 +1674,22 @@ void CGarage::FindDoorsEntities() FindDoorsEntitiesSectorList(s->m_lists[ENTITYLIST_DUMMIES_OVERLAP], true); } } - if (!m_pDoor1 || !m_pDoor2) - return; - if (m_pDoor1->GetModelIndex() == MI_CRUSHERBODY || m_pDoor1->GetModelIndex() == MI_CRUSHERLID) - return; - CVector2D vecDoor1ToGarage(m_pDoor1->GetPosition().x - GetGarageCenterX(), m_pDoor1->GetPosition().y - GetGarageCenterY()); - CVector2D vecDoor2ToGarage(m_pDoor2->GetPosition().x - GetGarageCenterX(), m_pDoor2->GetPosition().y - GetGarageCenterY()); - if (DotProduct2D(vecDoor1ToGarage, vecDoor2ToGarage) > 0.0f) { - if (vecDoor1ToGarage.MagnitudeSqr() >= vecDoor2ToGarage.MagnitudeSqr()) { - m_pDoor1 = m_pDoor2; - m_bDoor1IsDummy = m_bDoor2IsDummy; + if (m_pDoor1 && m_pDoor2) { + CVector2D vecDoor1ToGarage(m_pDoor1->GetPosition().x - GetGarageCenterX(), m_pDoor1->GetPosition().y - GetGarageCenterY()); + CVector2D vecDoor2ToGarage(m_pDoor2->GetPosition().x - GetGarageCenterX(), m_pDoor2->GetPosition().y - GetGarageCenterY()); + if (DotProduct2D(vecDoor1ToGarage, vecDoor2ToGarage) > 0.0f) { + if (vecDoor1ToGarage.MagnitudeSqr() >= vecDoor2ToGarage.MagnitudeSqr()) { + m_pDoor1 = m_pDoor2; + m_bDoor1IsDummy = m_bDoor2IsDummy; + } + m_pDoor2 = nil; + m_bDoor2IsDummy = false; } - m_pDoor2 = nil; - m_bDoor2IsDummy = false; } + if (m_pDoor1) + m_pDoor1->bUsesCollision = true; + if (m_pDoor2) + m_pDoor2->bUsesCollision = true; } void CGarage::FindDoorsEntitiesSectorList(CPtrList& list, bool dummy) @@ -1755,29 +1702,8 @@ void CGarage::FindDoorsEntitiesSectorList(CPtrList& list, bool dummy) pEntity->m_scanCode = CWorld::GetCurrentScanCode(); if (!pEntity || !CGarages::IsModelIndexADoor(pEntity->GetModelIndex())) continue; - if (Abs(pEntity->GetPosition().x - GetGarageCenterX()) >= DISTANCE_TO_CONSIDER_DOOR_FOR_GARAGE) - continue; - if (Abs(pEntity->GetPosition().y - GetGarageCenterY()) >= DISTANCE_TO_CONSIDER_DOOR_FOR_GARAGE) - continue; - if (pEntity->GetModelIndex() == MI_CRUSHERBODY) { - m_pDoor1 = pEntity; - m_bDoor1IsDummy = dummy; - // very odd pool operations, they could have used GetJustIndex - if (dummy) - m_bDoor1PoolIndex = (CPools::GetDummyPool()->GetIndex((CDummy*)pEntity)) & 0x7F; - else - m_bDoor1PoolIndex = (CPools::GetObjectPool()->GetIndex((CObject*)pEntity)) & 0x7F; - continue; - } - if (pEntity->GetModelIndex() == MI_CRUSHERLID) { - m_pDoor2 = pEntity; - m_bDoor2IsDummy = dummy; - if (dummy) - m_bDoor2PoolIndex = (CPools::GetDummyPool()->GetIndex((CDummy*)pEntity)) & 0x7F; - else - m_bDoor2PoolIndex = (CPools::GetObjectPool()->GetIndex((CObject*)pEntity)) & 0x7F; + if (!IsPointInsideGarage(pEntity->GetPosition(), 2.0f)) continue; - } if (!m_pDoor1) { m_pDoor1 = pEntity; m_bDoor1IsDummy = dummy; @@ -1812,6 +1738,8 @@ void CGarages::SetGarageDoorToRotate(int16 garage) aGarages[garage].m_bRotatedDoor = true; aGarages[garage].m_fDoorHeight /= 2.0f; aGarages[garage].m_fDoorHeight -= 0.1f; + aGarages[garage].m_fDoorPos = Min(aGarages[garage].m_fDoorHeight, aGarages[garage].m_fDoorPos); + aGarages[garage].UpdateDoorsHeight(); } void CGarages::SetLeaveCameraForThisGarage(int16 garage) @@ -1854,15 +1782,12 @@ CVehicle* CStoredCar::RestoreCar() if (!CStreaming::HasModelLoaded(m_nModelIndex)) return nil; CVehicleModelInfo::SetComponentsToUse(m_nVariationA, m_nVariationB); -#ifdef FIX_BUGS CVehicle* pVehicle; if (CModelInfo::IsBoatModel(m_nModelIndex)) pVehicle = new CBoat(m_nModelIndex, RANDOM_VEHICLE); + // else if bike - TODO(MIAMI) else pVehicle = new CAutomobile(m_nModelIndex, RANDOM_VEHICLE); -#else - CVehicle* pVehicle = new CAutomobile(m_nModelIndex, RANDOM_VEHICLE); -#endif pVehicle->SetPosition(m_vecPos); pVehicle->SetStatus(STATUS_ABANDONED); pVehicle->GetForward() = m_vecAngle; @@ -1896,9 +1821,7 @@ void CGarage::StoreAndRemoveCarsForThisHideout(CStoredCar* aCars, int32 nMax) CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i); if (!pVehicle) continue; - if (pVehicle->GetPosition().x > m_fX1 && pVehicle->GetPosition().x < m_fX2 && - pVehicle->GetPosition().y > m_fY1 && pVehicle->GetPosition().y < m_fY2 && - pVehicle->GetPosition().z > m_fZ1 && pVehicle->GetPosition().z < m_fZ2) { + if (IsPointInsideGarage(pVehicle->GetPosition())) { if (pVehicle->VehicleCreatedBy != MISSION_VEHICLE) { if (index < Max(NUM_GARAGE_STORED_CARS, nMax) && !EntityHasASphereWayOutsideGarage(pVehicle, 1.0f)) aCars[index++].StoreCar(pVehicle); @@ -1940,17 +1863,12 @@ bool CGarages::IsPointInAGarageCameraZone(CVector point) case GARAGE_COLLECTCARS_1: case GARAGE_COLLECTCARS_2: case GARAGE_COLLECTCARS_3: - if (aGarages[i].m_fX1 - MARGIN_FOR_CAMERA_COLLECTCARS <= point.x && - aGarages[i].m_fX2 + MARGIN_FOR_CAMERA_COLLECTCARS >= point.x && - aGarages[i].m_fY1 - MARGIN_FOR_CAMERA_COLLECTCARS <= point.y && - aGarages[i].m_fY2 + MARGIN_FOR_CAMERA_COLLECTCARS >= point.y) + case GARAGE_COLLECTCARS_4: + if (aGarages[i].IsPointInsideGarage(point, MARGIN_FOR_CAMERA_COLLECTCARS)) return true; break; default: - if (aGarages[i].m_fX1 - MARGIN_FOR_CAMERA_DEFAULT <= point.x && - aGarages[i].m_fX2 + MARGIN_FOR_CAMERA_DEFAULT >= point.x && - aGarages[i].m_fY1 - MARGIN_FOR_CAMERA_DEFAULT <= point.y && - aGarages[i].m_fY2 + MARGIN_FOR_CAMERA_DEFAULT >= point.y) + if (aGarages[i].IsPointInsideGarage(point, MARGIN_FOR_CAMERA_DEFAULT)) return true; break; } @@ -1981,9 +1899,7 @@ void CGarage::TidyUpGarage() CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i); if (!pVehicle || !pVehicle->IsCar()) continue; - if (pVehicle->GetPosition().x > m_fX1 && pVehicle->GetPosition().x < m_fX2 && - pVehicle->GetPosition().y > m_fY1 && pVehicle->GetPosition().y < m_fY2 && - pVehicle->GetPosition().z > m_fZ1 && pVehicle->GetPosition().z < m_fZ2) { + if (IsPointInsideGarage(pVehicle->GetPosition())) { if (pVehicle->GetStatus() == STATUS_WRECKED || pVehicle->GetUp().z < 0.5f) { CWorld::Remove(pVehicle); delete pVehicle; @@ -2007,11 +1923,8 @@ void CGarage::TidyUpGarageClose() for (int i = 0; i < pColModel->numSpheres; i++) { CVector pos = pVehicle->GetMatrix() * pColModel->spheres[i].center; float radius = pColModel->spheres[i].radius; - if (pos.x + radius < m_fX1 || pos.x - radius > m_fX2 || - pos.y + radius < m_fY1 || pos.y - radius > m_fY2 || - pos.z + radius < m_fZ1 || pos.z - radius > m_fZ2) { + if (!IsPointInsideGarage(pos, radius)) bRemove = true; - } } } else @@ -2054,6 +1967,17 @@ void CGarage::PlayerArrestedOrDied() case GARAGE_FOR_SCRIPT_TO_OPEN_AND_CLOSE: case GARAGE_KEEPS_OPENING_FOR_SPECIFIC_CAR: case GARAGE_MISSION_KEEPCAR_REMAINCLOSED: + case GARAGE_COLLECTCARS_4: + case GARAGE_FOR_SCRIPT_TO_OPEN_FOR_CAR: + case GARAGE_HIDEOUT_FOUR: + case GARAGE_HIDEOUT_FIVE: + case GARAGE_HIDEOUT_SIX: + case GARAGE_HIDEOUT_SEVEN: + case GARAGE_HIDEOUT_EIGHT: + case GARAGE_HIDEOUT_NINE: + case GARAGE_HIDEOUT_TEN: + case GARAGE_HIDEOUT_ELEVEN: + case GARAGE_HIDEOUT_TWELVE: switch (m_eGarageState) { case GS_OPENED: case GS_CLOSING: @@ -2105,36 +2029,19 @@ void CGarage::CenterCarInGarage(CVehicle* pVehicle) pVehicle->GetMatrix().GetPosition().x += offsetX * RESPRAY_CENTERING_COEFFICIENT / distance; pVehicle->GetMatrix().GetPosition().y += offsetY * RESPRAY_CENTERING_COEFFICIENT / distance; } - if (!IsEntityEntirelyInside3D(pVehicle, 0.1f)) + if (!IsEntityEntirelyInside3D(pVehicle, 0.3f)) pVehicle->SetPosition(pos); } void CGarages::CloseHideOutGaragesBeforeSave() { for (int i = 0; i < NUM_GARAGES; i++) { - if (aGarages[i].m_eGarageType != GARAGE_HIDEOUT_ONE && - aGarages[i].m_eGarageType != GARAGE_HIDEOUT_TWO && - aGarages[i].m_eGarageType != GARAGE_HIDEOUT_THREE) + if (!IsThisGarageTypeSafehouse(aGarages[i].m_eGarageType)) continue; - if (aGarages[i].m_eGarageState != GS_FULLYCLOSED && - (aGarages[i].m_eGarageType != GARAGE_HIDEOUT_ONE || !aGarages[i].IsAnyCarBlockingDoor())) { + if (aGarages[i].m_eGarageState != GS_FULLYCLOSED) { aGarages[i].m_eGarageState = GS_FULLYCLOSED; - switch (aGarages[i].m_eGarageType) { - case GARAGE_HIDEOUT_ONE: - aGarages[i].StoreAndRemoveCarsForThisHideout(aCarsInSafeHouse1, NUM_GARAGE_STORED_CARS); - aGarages[i].RemoveCarsBlockingDoorNotInside(); - break; - case GARAGE_HIDEOUT_TWO: - aGarages[i].StoreAndRemoveCarsForThisHideout(aCarsInSafeHouse2, NUM_GARAGE_STORED_CARS); - aGarages[i].RemoveCarsBlockingDoorNotInside(); - break; - case GARAGE_HIDEOUT_THREE: - aGarages[i].StoreAndRemoveCarsForThisHideout(aCarsInSafeHouse3, NUM_GARAGE_STORED_CARS); - aGarages[i].RemoveCarsBlockingDoorNotInside(); - break; - default: - break; - } + aGarages[i].StoreAndRemoveCarsForThisHideout(aCarsInSafeHouses[FindSafeHouseIndexForGarageType(aGarages[i].m_eGarageType)], NUM_GARAGE_STORED_CARS); + aGarages[i].RemoveCarsBlockingDoorNotInside(); } aGarages[i].m_fDoorPos = 0.0f; aGarages[i].UpdateDoorsHeight(); @@ -2145,36 +2052,11 @@ int32 CGarages::CountCarsInHideoutGarage(eGarageType type) { int32 total = 0; for (int i = 0; i < NUM_GARAGE_STORED_CARS; i++) { - switch (type) { - case GARAGE_HIDEOUT_ONE: - total += (aCarsInSafeHouse1[i].HasCar()); - break; - case GARAGE_HIDEOUT_TWO: - total += (aCarsInSafeHouse2[i].HasCar()); - break; - case GARAGE_HIDEOUT_THREE: - total += (aCarsInSafeHouse3[i].HasCar()); - break; - default: break; - } + total += aCarsInSafeHouses[FindSafeHouseIndexForGarageType(type)][i].HasCar(); } return total; } -int32 CGarages::FindMaxNumStoredCarsForGarage(eGarageType type) -{ - switch (type) { - case GARAGE_HIDEOUT_ONE: - return LIMIT_CARS_IN_INDUSTRIAL; - case GARAGE_HIDEOUT_TWO: - return LIMIT_CARS_IN_COMMERCIAL; - case GARAGE_HIDEOUT_THREE: - return LIMIT_CARS_IN_SUBURBAN; - default: break; - } - return 0; -} - bool CGarages::IsPointWithinHideOutGarage(Const CVector& point) { for (int i = 0; i < NUM_GARAGES; i++) { @@ -2182,9 +2064,7 @@ bool CGarages::IsPointWithinHideOutGarage(Const CVector& point) case GARAGE_HIDEOUT_ONE: case GARAGE_HIDEOUT_TWO: case GARAGE_HIDEOUT_THREE: - if (point.x > aGarages[i].m_fX1 && point.x < aGarages[i].m_fX2 && - point.y > aGarages[i].m_fY1 && point.y < aGarages[i].m_fY2 && - point.z > aGarages[i].m_fZ1 && point.z < aGarages[i].m_fZ2) + if (aGarages[i].IsPointInsideGarage(point)) return true; default: break; } @@ -2199,9 +2079,7 @@ bool CGarages::IsPointWithinAnyGarage(Const CVector& point) case GARAGE_NONE: continue; default: - if (point.x > aGarages[i].m_fX1 && point.x < aGarages[i].m_fX2 && - point.y > aGarages[i].m_fY1 && point.y < aGarages[i].m_fY2 && - point.z > aGarages[i].m_fZ1 && point.z < aGarages[i].m_fZ2) + if (aGarages[i].IsPointInsideGarage(point)) return true; } } @@ -2238,6 +2116,7 @@ void CGarages::SetAllDoorsBackToOriginalHeight() } } +// TODO(MIAMI) void CGarages::Save(uint8 * buf, uint32 * size) { #ifdef FIX_GARAGE_SIZE @@ -2257,9 +2136,9 @@ void CGarages::Save(uint8 * buf, uint32 * size) WriteSaveBuf(buf, CarTypesCollected[i]); WriteSaveBuf(buf, LastTimeHelpMessage); for (int i = 0; i < NUM_GARAGE_STORED_CARS; i++) { - WriteSaveBuf(buf, aCarsInSafeHouse1[i]); - WriteSaveBuf(buf, aCarsInSafeHouse2[i]); - WriteSaveBuf(buf, aCarsInSafeHouse3[i]); + for (int j = 0; j < TOTAL_HIDEOUT_GARAGES; j++) { + WriteSaveBuf(buf, aCarsInSafeHouses[j][i]); + } } for (int i = 0; i < NUM_GARAGES; i++) WriteSaveBuf(buf, aGarages[i]); @@ -2287,6 +2166,7 @@ const CStoredCar &CStoredCar::operator=(const CStoredCar & other) return *this; } +//TODO(MIAMI) void CGarages::Load(uint8* buf, uint32 size) { #ifdef FIX_GARAGE_SIZE @@ -2306,9 +2186,9 @@ void CGarages::Load(uint8* buf, uint32 size) CarTypesCollected[i] = ReadSaveBuf<uint32>(buf); LastTimeHelpMessage = ReadSaveBuf<uint32>(buf); for (int i = 0; i < NUM_GARAGE_STORED_CARS; i++) { - aCarsInSafeHouse1[i] = ReadSaveBuf<CStoredCar>(buf); - aCarsInSafeHouse2[i] = ReadSaveBuf<CStoredCar>(buf); - aCarsInSafeHouse3[i] = ReadSaveBuf<CStoredCar>(buf); + for (int j = 0; j < TOTAL_HIDEOUT_GARAGES; j++) { + aCarsInSafeHouses[j][i] = ReadSaveBuf<CStoredCar>(buf); + } } for (int i = 0; i < NUM_GARAGES; i++) { aGarages[i] = ReadSaveBuf<CGarage>(buf); @@ -2335,8 +2215,7 @@ void CGarages::Load(uint8* buf, uint32 size) bool CGarages::IsModelIndexADoor(uint32 id) { - return id == MI_GARAGEDOOR1 || - id == MI_GARAGEDOOR2 || + return id == MI_GARAGEDOOR2 || id == MI_GARAGEDOOR3 || id == MI_GARAGEDOOR4 || id == MI_GARAGEDOOR5 || @@ -2350,7 +2229,6 @@ CGarages::IsModelIndexADoor(uint32 id) id == MI_GARAGEDOOR14 || id == MI_GARAGEDOOR15 || id == MI_GARAGEDOOR16 || - id == MI_GARAGEDOOR17 || id == MI_GARAGEDOOR18 || id == MI_GARAGEDOOR19 || id == MI_GARAGEDOOR20 || @@ -2359,13 +2237,5 @@ CGarages::IsModelIndexADoor(uint32 id) id == MI_GARAGEDOOR23 || id == MI_GARAGEDOOR24 || id == MI_GARAGEDOOR25 || - id == MI_GARAGEDOOR26 || - id == MI_GARAGEDOOR27 || - id == MI_GARAGEDOOR28 || - id == MI_GARAGEDOOR29 || - id == MI_GARAGEDOOR30 || - id == MI_GARAGEDOOR31 || - id == MI_GARAGEDOOR32 || - id == MI_CRUSHERBODY || - id == MI_CRUSHERLID; + id == MI_GARAGEDOOR26; } diff --git a/src/control/Garages.h b/src/control/Garages.h index 00020eb3..c5bede2b 100644 --- a/src/control/Garages.h +++ b/src/control/Garages.h @@ -42,12 +42,24 @@ enum eGarageType : int8 GARAGE_FOR_SCRIPT_TO_OPEN_AND_CLOSE, GARAGE_KEEPS_OPENING_FOR_SPECIFIC_CAR, GARAGE_MISSION_KEEPCAR_REMAINCLOSED, + GARAGE_COLLECTCARS_4, + GARAGE_FOR_SCRIPT_TO_OPEN_FOR_CAR, + GARAGE_HIDEOUT_FOUR, + GARAGE_HIDEOUT_FIVE, + GARAGE_HIDEOUT_SIX, + GARAGE_HIDEOUT_SEVEN, + GARAGE_HIDEOUT_EIGHT, + GARAGE_HIDEOUT_NINE, + GARAGE_HIDEOUT_TEN, + GARAGE_HIDEOUT_ELEVEN, + GARAGE_HIDEOUT_TWELVE }; enum { - TOTAL_COLLECTCARS_GARAGES = GARAGE_COLLECTCARS_3 - GARAGE_COLLECTCARS_1 + 1, - TOTAL_COLLECTCARS_CARS = 16 + TOTAL_COLLECTCARS_GARAGES = 4, + TOTAL_HIDEOUT_GARAGES = 12, + TOTAL_COLLECTCARS_CARS = 6 }; class CStoredCar @@ -83,6 +95,7 @@ class CGarage { eGarageType m_eGarageType; eGarageState m_eGarageState; + uint8 m_nMaxStoredCars; bool field_2; // unused bool m_bClosingWithoutTargetCar; bool m_bDeactivated; @@ -97,12 +110,17 @@ class CGarage bool m_bRecreateDoorOnNextRefresh; bool m_bRotatedDoor; bool m_bCameraFollowsPlayer; - float m_fX1; - float m_fX2; - float m_fY1; - float m_fY2; - float m_fZ1; - float m_fZ2; + CVector2D m_vecCorner1; + float m_fInfZ; + CVector2D m_vDir1; + CVector2D m_vDir2; + float m_fSupZ; + float m_fDir1Len; + float m_fDir2Len; + float m_fInfX; + float m_fSupX; + float m_fInfY; + float m_fSupY; float m_fDoorPos; float m_fDoorHeight; float m_fDoor1X; @@ -123,8 +141,8 @@ class CGarage bool IsClosed() { return m_eGarageState == GS_FULLYCLOSED; } bool IsUsed() { return m_eGarageType != GARAGE_NONE; } void Update(); - float GetGarageCenterX() { return (m_fX1 + m_fX2) / 2; } - float GetGarageCenterY() { return (m_fY1 + m_fY2) / 2; } + float GetGarageCenterX() { return (m_fInfX + m_fSupX) / 2; } + float GetGarageCenterY() { return (m_fInfY + m_fSupY) / 2; } bool IsFar() { #ifdef FIX_BUGS @@ -142,7 +160,6 @@ class CGarage void UpdateDoorsHeight(); bool IsEntityEntirelyInside3D(CEntity*, float); bool IsEntityEntirelyOutside(CEntity*, float); - bool IsEntityEntirelyInside(CEntity*); float CalcDistToGarageRectangleSquared(float, float); float CalcSmallestDistToGarageDoorSquared(float, float); bool IsAnyOtherCarTouchingGarage(CVehicle* pException); @@ -167,17 +184,22 @@ class CGarage void FindDoorsEntitiesSectorList(CPtrList&, bool); void PlayerArrestedOrDied(); + bool IsPointInsideGarage(CVector); + bool IsPointInsideGarage(CVector, float); + void ThrowCarsNearDoorOutOfGarage(CVehicle*); + + int32 FindMaxNumStoredCarsForGarage() { return Max(NUM_GARAGE_STORED_CARS, m_nMaxStoredCars); } + friend class CGarages; friend class cAudioManager; friend class CCamera; }; -VALIDATE_SIZE(CGarage, 140); - class CGarages { enum { - MESSAGE_LENGTH = 8 + MESSAGE_LENGTH = 8, + MAX_NUM_CARS_IN_HIDEOUT_GARAGE = 4 }; static int32 BankVansCollected; static bool BombsAreFree; @@ -195,9 +217,7 @@ class CGarages static bool PlayerInGarage; static int32 PoliceCarsCollected; static CGarage aGarages[NUM_GARAGES]; - static CStoredCar aCarsInSafeHouse1[NUM_GARAGE_STORED_CARS]; - static CStoredCar aCarsInSafeHouse2[NUM_GARAGE_STORED_CARS]; - static CStoredCar aCarsInSafeHouse3[NUM_GARAGE_STORED_CARS]; + static CStoredCar aCarsInSafeHouses[TOTAL_HIDEOUT_GARAGES][MAX_NUM_CARS_IN_HIDEOUT_GARAGE]; static int32 AudioEntity; static bool bCamShouldBeOutisde; @@ -208,7 +228,7 @@ public: #endif static void Update(void); - static int16 AddOne(float X1, float Y1, float Z1, float X2, float Y2, float Z2, eGarageType type, int32 targetId); + static int16 AddOne(float X1, float Y1, float Z1, float X2, float Y2, float X3, float Y3, float Z2, eGarageType type, int32 targetId); static void ChangeGarageType(int16, eGarageType, int32); static void PrintMessages(void); static void TriggerMessage(const char* text, int16, uint16 time, int16); @@ -240,15 +260,45 @@ public: static bool IsModelIndexADoor(uint32 id); static void SetFreeBombs(bool bValue) { BombsAreFree = bValue; } static void SetFreeResprays(bool bValue) { RespraysAreFree = bValue; } + static void SetMaxNumStoredCarsForGarage(int16 garage, uint8 num) { aGarages[garage].m_nMaxStoredCars = num; } private: static bool IsCarSprayable(CVehicle*); static float FindDoorHeightForMI(int32); static void CloseHideOutGaragesBeforeSave(void); static int32 CountCarsInHideoutGarage(eGarageType); - static int32 FindMaxNumStoredCarsForGarage(eGarageType); static int32 GetBombTypeForGarageType(eGarageType type) { return type - GARAGE_BOMBSHOP1 + 1; } - static int32 GetCarsCollectedIndexForGarageType(eGarageType type) { return type - GARAGE_COLLECTCARS_1; } + static int32 GetCarsCollectedIndexForGarageType(eGarageType type) + { + switch (type) { + case GARAGE_COLLECTCARS_1: return 0; + case GARAGE_COLLECTCARS_2: return 1; + case GARAGE_COLLECTCARS_3: return 2; + case GARAGE_COLLECTCARS_4: return 3; + default: assert(0); + } + return 0; + } + static int32 FindSafeHouseIndexForGarageType(eGarageType type) + { + switch (type) { + case GARAGE_HIDEOUT_ONE: return 0; + case GARAGE_HIDEOUT_TWO: return 1; + case GARAGE_HIDEOUT_THREE: return 2; + case GARAGE_HIDEOUT_FOUR: return 3; + case GARAGE_HIDEOUT_FIVE: return 4; + case GARAGE_HIDEOUT_SIX: return 5; + case GARAGE_HIDEOUT_SEVEN: return 6; + case GARAGE_HIDEOUT_EIGHT: return 7; + case GARAGE_HIDEOUT_NINE: return 8; + case GARAGE_HIDEOUT_TEN: return 9; + case GARAGE_HIDEOUT_ELEVEN: return 10; + case GARAGE_HIDEOUT_TWELVE: return 11; + default: assert(0); + } + return -1; + } + static bool IsThisGarageTypeSafehouse(eGarageType type) { return FindSafeHouseIndexForGarageType(type) >= 0; } friend class cAudioManager; friend class CGarage; diff --git a/src/control/PathFind.cpp b/src/control/PathFind.cpp index ee15b82f..4a948032 100644 --- a/src/control/PathFind.cpp +++ b/src/control/PathFind.cpp @@ -18,21 +18,21 @@ CPathFind ThePaths; #define MIN_PED_ROUTE_DISTANCE 23.8f -#define NUMTEMPNODES 4000 -#define NUMDETACHED_CARS 100 -#define NUMDETACHED_PEDS 50 +#define NUMTEMPNODES 5000 +#define NUMDETACHED_CARS 1024 +#define NUMDETACHED_PEDS 1214 +#define NUMTEMPEXTERNALNODES 4600 -// object flags: -// 1 UseInRoadBlock -// 2 east/west road(?) - CPathInfoForObject *InfoForTileCars; CPathInfoForObject *InfoForTilePeds; -// unused -CTempDetachedNode *DetachedNodesCars; -CTempDetachedNode *DetachedNodesPeds; +CPathInfoForObject *DetachedInfoForTileCars; +CPathInfoForObject *DetachedInfoForTilePeds; +CTempNodeExternal *TempExternalNodes; +int32 NumTempExternalNodes; +int32 NumDetachedPedNodeGroups; +int32 NumDetachedCarNodeGroups; bool CPedPath::CalcPedRoute(int8 pathType, CVector position, CVector destination, CVector *pointPoses, int16 *pointsFound, int16 maxPoints) @@ -197,7 +197,7 @@ CPedPath::AddBlockadeSectorList(CPtrList& list, CPedPathNode(*pathNodes)[40], CV void CPedPath::AddBlockade(CEntity *pEntity, CPedPathNode(*pathNodes)[40], CVector *pPosition) { - const CColBox& boundingBox = pEntity->GetColModel()->boundingBox; + const CBox& boundingBox = pEntity->GetColModel()->boundingBox; const float fBoundMaxY = boundingBox.max.y + 0.3f; const float fBoundMinY = boundingBox.min.y - 0.3f; const float fBoundMaxX = boundingBox.max.x + 0.3f; @@ -227,6 +227,27 @@ CPedPath::AddBlockade(CEntity *pEntity, CPedPathNode(*pathNodes)[40], CVector *p } } +//--MIAMI: done +// Make sure all externals link TO an internal +void +CPathInfoForObject::SwapConnectionsToBeRightWayRound(void) +{ + int e, i; + CPathInfoForObject *tile = this; + + for(e = 0; e < 12; e++) + if(tile[e].type == NodeTypeExtern && tile[e].next < 0) + for(i = 0; i < 12; i++) + if(tile[i].type == NodeTypeIntern && tile[i].next == e){ + tile[e].next = i; + tile[i].next = -1; + bool tmp = !!tile[e].crossing; + tile[e].crossing = tile[i].crossing; + tile[i].crossing = tmp; + } +} + +//--MIAMI: done void CPathFind::Init(void) { @@ -237,11 +258,13 @@ CPathFind::Init(void) m_numConnections = 0; m_numCarPathLinks = 0; unk = 0; + NumTempExternalNodes = 0; for(i = 0; i < NUM_PATHNODES; i++) m_pathNodes[i].distance = MAX_DIST; } +//--MIAMI: done void CPathFind::AllocatePathFindInfoMem(int16 numPathGroups) { @@ -250,93 +273,172 @@ CPathFind::AllocatePathFindInfoMem(int16 numPathGroups) delete[] InfoForTilePeds; InfoForTilePeds = nil; - // NB: MIAMI doesn't use numPathGroups here but hardcodes 4500 - InfoForTileCars = new CPathInfoForObject[12*numPathGroups]; - memset(InfoForTileCars, 0, 12*numPathGroups*sizeof(CPathInfoForObject)); - InfoForTilePeds = new CPathInfoForObject[12*numPathGroups]; - memset(InfoForTilePeds, 0, 12*numPathGroups*sizeof(CPathInfoForObject)); - - // unused - delete[] DetachedNodesCars; - DetachedNodesCars = nil; - delete[] DetachedNodesPeds; - DetachedNodesPeds = nil; - DetachedNodesCars = new CTempDetachedNode[NUMDETACHED_CARS]; - memset(DetachedNodesCars, 0, NUMDETACHED_CARS*sizeof(CTempDetachedNode)); - DetachedNodesPeds = new CTempDetachedNode[NUMDETACHED_PEDS]; - memset(DetachedNodesPeds, 0, NUMDETACHED_PEDS*sizeof(CTempDetachedNode)); + // NB: MIAMI doesn't use numPathGroups here but hardcodes PATHNODESIZE + InfoForTileCars = new CPathInfoForObject[12*PATHNODESIZE]; + memset(InfoForTileCars, 0, 12*PATHNODESIZE*sizeof(CPathInfoForObject)); + InfoForTilePeds = new CPathInfoForObject[12*PATHNODESIZE]; + memset(InfoForTilePeds, 0, 12*PATHNODESIZE*sizeof(CPathInfoForObject)); + + delete[] DetachedInfoForTileCars; + DetachedInfoForTileCars = nil; + delete[] DetachedInfoForTilePeds; + DetachedInfoForTilePeds = nil; + DetachedInfoForTileCars = new CPathInfoForObject[12*NUMDETACHED_CARS]; + memset(DetachedInfoForTileCars, 0, 12*NUMDETACHED_CARS*sizeof(CPathInfoForObject)); + DetachedInfoForTilePeds = new CPathInfoForObject[12*NUMDETACHED_PEDS]; + memset(DetachedInfoForTilePeds, 0, 12*NUMDETACHED_PEDS*sizeof(CPathInfoForObject)); + + TempExternalNodes = new CTempNodeExternal[NUMTEMPEXTERNALNODES]; + memset(TempExternalNodes, 0, NUMTEMPEXTERNALNODES*sizeof(CTempNodeExternal)); + NumTempExternalNodes = 0; + NumDetachedPedNodeGroups = 0; + NumDetachedCarNodeGroups = 0; } +//--MIAMI: done void CPathFind::RegisterMapObject(CTreadable *mapObject) { m_mapObjects[m_numMapObjects++] = mapObject; } +//--MIAMI: done void -CPathFind::StoreNodeInfoPed(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, int16 width, bool crossing) +CPathFind::StoreNodeInfoPed(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, float width, bool crossing, uint8 spawnRate) { - int i, j; + int i; i = id*12 + node; InfoForTilePeds[i].type = type; InfoForTilePeds[i].next = next; - InfoForTilePeds[i].x = x; - InfoForTilePeds[i].y = y; - InfoForTilePeds[i].z = z; + InfoForTilePeds[i].x = x/16.0f; + InfoForTilePeds[i].y = y/16.0f; + InfoForTilePeds[i].z = z/16.0f; + InfoForTilePeds[i].width = 8.0f*Min(width, 15.0f); InfoForTilePeds[i].numLeftLanes = 0; InfoForTilePeds[i].numRightLanes = 0; InfoForTilePeds[i].crossing = crossing; - - if(type) - for(i = 0; i < node; i++){ - j = id*12 + i; - if(x == InfoForTilePeds[j].x && y == InfoForTilePeds[j].y){ - printf("^^^^^^^^^^^^^ AARON IS TOO CHICKEN TO EAT MEAT!\n"); - printf("Several ped nodes on one road segment have identical coordinates (%d==%d && %d==%d)\n", - x, InfoForTilePeds[j].x, y, InfoForTilePeds[j].y); - printf("Modelindex of cullprit: %d\n\n", id); - } - } + InfoForTilePeds[i].speedLimit = 0; + InfoForTilePeds[i].roadBlock = false; + InfoForTilePeds[i].disabled = false; + InfoForTilePeds[i].waterPath = false; + InfoForTilePeds[i].onlySmallBoats = false; + InfoForTilePeds[i].betweenLevels = false; + InfoForTilePeds[i].spawnRate = Min(spawnRate, 15); + + if(node == 11) + InfoForTilePeds[id*12].SwapConnectionsToBeRightWayRound(); } +//--MIAMI: done void -CPathFind::StoreNodeInfoCar(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, int16 width, int8 numLeft, int8 numRight) +CPathFind::StoreNodeInfoCar(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, float width, int8 numLeft, int8 numRight, + bool disabled, bool betweenLevels, uint8 speedLimit, bool roadBlock, bool waterPath, uint8 spawnRate) { - int i, j; + int i; i = id*12 + node; InfoForTileCars[i].type = type; InfoForTileCars[i].next = next; - InfoForTileCars[i].x = x; - InfoForTileCars[i].y = y; - InfoForTileCars[i].z = z; + InfoForTileCars[i].x = x/16.0f; + InfoForTileCars[i].y = y/16.0f; + InfoForTileCars[i].z = z/16.0f; + InfoForTilePeds[i].width = 8.0f*Min(width, 15.0f); InfoForTileCars[i].numLeftLanes = numLeft; InfoForTileCars[i].numRightLanes = numRight; + InfoForTilePeds[i].crossing = false; + InfoForTilePeds[i].speedLimit = 0; + InfoForTilePeds[i].roadBlock = false; + InfoForTilePeds[i].disabled = false; + InfoForTilePeds[i].waterPath = false; + InfoForTilePeds[i].onlySmallBoats = false; + InfoForTilePeds[i].betweenLevels = false; + InfoForTilePeds[i].spawnRate = Min(spawnRate, 15); + + if(node == 11) + InfoForTileCars[id*12].SwapConnectionsToBeRightWayRound(); +} + +//--MIAMI: done +void +CPathFind::StoreDetachedNodeInfoPed(int32 node, int8 type, int32 next, float x, float y, float z, float width, bool crossing, + bool disabled, bool betweenLevels, uint8 spawnRate) +{ + int i; + if(NumDetachedPedNodeGroups >= NUMDETACHED_PEDS) + return; - if(type) - for(i = 0; i < node; i++){ - j = id*12 + i; - if(x == InfoForTileCars[j].x && y == InfoForTileCars[j].y){ - printf("^^^^^^^^^^^^^ AARON IS TOO CHICKEN TO EAT MEAT!\n"); - printf("Several car nodes on one road segment have identical coordinates (%d==%d && %d==%d)\n", - x, InfoForTileCars[j].x, y, InfoForTileCars[j].y); - printf("Modelindex of cullprit: %d\n\n", id); - } - } + i = NumDetachedPedNodeGroups*12 + node; + DetachedInfoForTilePeds[i].type = type; + DetachedInfoForTilePeds[i].next = next; + DetachedInfoForTilePeds[i].x = x/16.0f; + DetachedInfoForTilePeds[i].y = y/16.0f; + DetachedInfoForTilePeds[i].z = z/16.0f; + DetachedInfoForTilePeds[i].width = 8.0f*Min(width, 31.0f); + DetachedInfoForTilePeds[i].numLeftLanes = 0; + DetachedInfoForTilePeds[i].numRightLanes = 0; + DetachedInfoForTilePeds[i].crossing = crossing; + DetachedInfoForTilePeds[i].speedLimit = 0; + DetachedInfoForTilePeds[i].roadBlock = false; + DetachedInfoForTilePeds[i].disabled = disabled; + DetachedInfoForTilePeds[i].waterPath = false; + DetachedInfoForTilePeds[i].onlySmallBoats = false; + DetachedInfoForTilePeds[i].betweenLevels = betweenLevels; + DetachedInfoForTilePeds[i].spawnRate = Min(spawnRate, 15); + + if(node == 11){ + DetachedInfoForTilePeds[NumDetachedPedNodeGroups*12].SwapConnectionsToBeRightWayRound(); + NumDetachedPedNodeGroups++; + } } +//--MIAMI: done void -CPathFind::CalcNodeCoors(int16 x, int16 y, int16 z, int id, CVector *out) +CPathFind::StoreDetachedNodeInfoCar(int32 node, int8 type, int32 next, float x, float y, float z, float width, int8 numLeft, int8 numRight, + bool disabled, bool betweenLevels, uint8 speedLimit, bool roadBlock, bool waterPath, uint8 spawnRate, bool onlySmallBoats) +{ + int i; + + if(NumDetachedCarNodeGroups >= NUMDETACHED_CARS) + return; + + i = NumDetachedCarNodeGroups*12 + node; + DetachedInfoForTileCars[i].type = type; + DetachedInfoForTileCars[i].next = next; + DetachedInfoForTileCars[i].x = x/16.0f; + DetachedInfoForTileCars[i].y = y/16.0f; + DetachedInfoForTileCars[i].z = z/16.0f; + DetachedInfoForTileCars[i].width = 8.0f*Min(width, 15.0f); + DetachedInfoForTileCars[i].numLeftLanes = numLeft; + DetachedInfoForTileCars[i].numRightLanes = numRight; + DetachedInfoForTileCars[i].crossing = false; + DetachedInfoForTileCars[i].speedLimit = speedLimit; + DetachedInfoForTileCars[i].roadBlock = roadBlock; + DetachedInfoForTileCars[i].disabled = disabled; + DetachedInfoForTileCars[i].waterPath = waterPath; + DetachedInfoForTileCars[i].onlySmallBoats = onlySmallBoats; + DetachedInfoForTileCars[i].betweenLevels = betweenLevels; + DetachedInfoForTileCars[i].spawnRate = Min(spawnRate, 15); + + if(node == 11){ + DetachedInfoForTileCars[NumDetachedCarNodeGroups*12].SwapConnectionsToBeRightWayRound(); + NumDetachedCarNodeGroups++; + } +} + +//--MIAMI: done +void +CPathFind::CalcNodeCoors(float x, float y, float z, int id, CVector *out) { CVector pos; - pos.x = x / 16.0f; - pos.y = y / 16.0f; - pos.z = z / 16.0f; + pos.x = x; + pos.y = y; + pos.z = z; *out = m_mapObjects[id]->GetMatrix() * pos; } +//--MIAMI: done bool CPathFind::LoadPathFindData(void) { @@ -344,26 +446,22 @@ CPathFind::LoadPathFindData(void) return false; } +//--MIAMI: done void CPathFind::PreparePathData(void) { - int i, j, k; - int numExtern, numIntern, numLanes; - float maxX, maxY; + int i, j; + int numExtern, numIntern; CTempNode *tempNodes; printf("PreparePathData\n"); if(!CPathFind::LoadPathFindData() && // empty InfoForTileCars && InfoForTilePeds && - DetachedNodesCars && DetachedNodesPeds - ){ + DetachedInfoForTileCars && DetachedInfoForTilePeds && TempExternalNodes){ tempNodes = new CTempNode[NUMTEMPNODES]; m_numConnections = 0; - for(i = 0; i < PATHNODESIZE; i++) - m_pathNodes[i].unkBits = 0; - for(i = 0; i < PATHNODESIZE; i++){ numExtern = 0; numIntern = 0; @@ -377,6 +475,19 @@ CPathFind::PreparePathData(void) printf("ILLEGAL BLOCK. MORE THAN 1 INTERNALS AND NOT 2 EXTERNALS (Modelindex:%d)\n", i); } + int numExternDetached, numInternDetached; + for(i = 0; i < NUMDETACHED_CARS; i++){ + numExternDetached = 0; + numInternDetached = 0; + for(j = 0; j < 12; j++){ + if(DetachedInfoForTileCars[i*12 + j].type == NodeTypeExtern) + numExternDetached++; + if(DetachedInfoForTilePeds[i*12 + j].type == NodeTypeIntern) + numInternDetached++; + } + // no diagnostic here + } + for(i = 0; i < PATHNODESIZE; i++) for(j = 0; j < 12; j++) if(InfoForTileCars[i*12 + j].type == NodeTypeExtern){ @@ -388,52 +499,24 @@ CPathFind::PreparePathData(void) if(InfoForTileCars[i*12 + j].numLeftLanes + InfoForTileCars[i*12 + j].numRightLanes <= 0) printf("ILLEGAL BLOCK. NO LANES IN NODE (Obj:%d)\n", i); } + for(i = 0; i < NUMDETACHED_CARS; i++) + for(j = 0; j < 12; j++) + if(DetachedInfoForTileCars[i*12 + j].type == NodeTypeExtern){ + // MI:%d here but no argument for it + if(DetachedInfoForTileCars[i*12 + j].numLeftLanes < 0) + printf("ILLEGAL BLOCK. NEGATIVE NUMBER OF LANES (Obj:%d)\n", i); + if(DetachedInfoForTileCars[i*12 + j].numRightLanes < 0) + printf("ILLEGAL BLOCK. NEGATIVE NUMBER OF LANES (Obj:%d)\n", i); + if(DetachedInfoForTileCars[i*12 + j].numLeftLanes + DetachedInfoForTileCars[i*12 + j].numRightLanes <= 0) + printf("ILLEGAL BLOCK. NO LANES IN NODE (Obj:%d)\n", i); + } m_numPathNodes = 0; - PreparePathDataForType(PATH_CAR, tempNodes, InfoForTileCars, 1.0f, DetachedNodesCars, NUMDETACHED_CARS); + PreparePathDataForType(PATH_CAR, tempNodes, InfoForTileCars, 1.0f, DetachedInfoForTileCars, NumDetachedCarNodeGroups); m_numCarPathNodes = m_numPathNodes; - PreparePathDataForType(PATH_PED, tempNodes, InfoForTilePeds, 1.0f, DetachedNodesPeds, NUMDETACHED_PEDS); + PreparePathDataForType(PATH_PED, tempNodes, InfoForTilePeds, 1.0f, DetachedInfoForTilePeds, NumDetachedPedNodeGroups); m_numPedPathNodes = m_numPathNodes - m_numCarPathNodes; - // TODO: figure out what exactly is going on here - // Some roads seem to get a west/east flag - for(i = 0; i < m_numMapObjects; i++){ - numExtern = 0; - numIntern = 0; - numLanes = 0; - maxX = 0.0f; - maxY = 0.0f; - for(j = 0; j < 12; j++){ - k = i*12 + j; - if(InfoForTileCars[k].type == NodeTypeExtern){ - numExtern++; - if(InfoForTileCars[k].numLeftLanes + InfoForTileCars[k].numRightLanes > numLanes) - numLanes = InfoForTileCars[k].numLeftLanes + InfoForTileCars[k].numRightLanes; - maxX = Max(maxX, Abs(InfoForTileCars[k].x)); - maxY = Max(maxY, Abs(InfoForTileCars[k].y)); - }else if(InfoForTileCars[k].type == NodeTypeIntern) - numIntern++; - } - - if(numIntern == 1 && numExtern == 2){ - if(numLanes < 4){ - if((i & 7) == 4){ // WHAT? - m_objectFlags[i] |= UseInRoadBlock; - if(maxX > maxY) - m_objectFlags[i] |= ObjectEastWest; - else - m_objectFlags[i] &= ~ObjectEastWest; - } - }else{ - m_objectFlags[i] |= UseInRoadBlock; - if(maxX > maxY) - m_objectFlags[i] |= ObjectEastWest; - else - m_objectFlags[i] &= ~ObjectEastWest; - } - } - } - delete[] tempNodes; CountFloodFillGroups(PATH_CAR); @@ -444,14 +527,17 @@ CPathFind::PreparePathData(void) delete[] InfoForTilePeds; InfoForTilePeds = nil; - delete[] DetachedNodesCars; - DetachedNodesCars = nil; - delete[] DetachedNodesPeds; - DetachedNodesPeds = nil; + delete[] DetachedInfoForTileCars; + DetachedInfoForTileCars = nil; + delete[] DetachedInfoForTilePeds; + DetachedInfoForTilePeds = nil; + delete[] TempExternalNodes; + TempExternalNodes = nil; } printf("Done with PreparePathData\n"); } +//--MIAMI: done /* String together connected nodes in a list by a flood fill algorithm */ void CPathFind::CountFloodFillGroups(uint8 type) @@ -494,8 +580,8 @@ CPathFind::CountFloodFillGroups(uint8 type) if(node->numLinks == 0){ if(type == PATH_CAR) - printf("Single car node: %f %f %f (%d)\n", - node->GetX(), node->GetY(), node->GetZ(), m_mapObjects[node->objectIndex]->GetModelIndex()); + printf("Single car node: %f %f %f\n", + node->GetX(), node->GetY(), node->GetZ()); else printf("Single ped node: %f %f %f\n", node->GetX(), node->GetY(), node->GetZ()); @@ -523,34 +609,31 @@ CPathFind::CountFloodFillGroups(uint8 type) int32 TempListLength; +//--MIAMI: done void CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoForObject *objectpathinfo, - float maxdist, CTempDetachedNode *detachednodes, int numDetached) + float maxdist, CPathInfoForObject *detachednodes, int numDetached) { static CVector CoorsXFormed; - int i, j, k, l; + int i, j, k; int l1, l2; int start; float posx, posy; float dx, dy, mag; float nearestDist; int nearestId; - int next; int oldNumPathNodes, oldNumLinks; float dist; int iseg, jseg; - int istart, jstart; int done, cont; int tileStart; oldNumPathNodes = m_numPathNodes; oldNumLinks = m_numConnections; -#define OBJECTINDEX(n) (m_pathNodes[(n)].objectIndex) - // Initialize map objects - for(i = 0; i < m_numMapObjects; i++) - for(j = 0; j < 12; j++) - m_mapObjects[i]->m_nodeIndices[type][j] = -1; +#define OBJECTINDEX(n) (mapObjIndices[(n)]) + int16 *mapObjIndices = new int16[NUM_PATHNODES]; + NumTempExternalNodes = 0; // Calculate internal nodes, store them and connect them to defining object for(i = 0; i < m_numMapObjects; i++){ @@ -566,89 +649,125 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor &CoorsXFormed); m_pathNodes[m_numPathNodes].SetPosition(CoorsXFormed); OBJECTINDEX(m_numPathNodes) = i; - m_pathNodes[m_numPathNodes].unkBits = 1; - m_mapObjects[i]->m_nodeIndices[type][j] = m_numPathNodes; + m_pathNodes[m_numPathNodes].width = objectpathinfo[start + j].width; + m_pathNodes[m_numPathNodes].speedLimit = objectpathinfo[start + j].speedLimit; + m_pathNodes[m_numPathNodes].spawnRate = objectpathinfo[start + j].spawnRate; + m_pathNodes[m_numPathNodes].bUseInRoadBlock = objectpathinfo[start + j].roadBlock; + m_pathNodes[m_numPathNodes].bDisabled = objectpathinfo[start + j].disabled; + m_pathNodes[m_numPathNodes].bWaterPath = objectpathinfo[start + j].waterPath; + m_pathNodes[m_numPathNodes].bOnlySmallBoats = objectpathinfo[start + j].onlySmallBoats; + m_pathNodes[m_numPathNodes].bBetweenLevels = objectpathinfo[start + j].betweenLevels; m_numPathNodes++; } + else if(objectpathinfo[start + j].type == NodeTypeExtern){ + CalcNodeCoors( + objectpathinfo[start + j].x, + objectpathinfo[start + j].y, + objectpathinfo[start + j].z, + i, + &CoorsXFormed); + TempExternalNodes[NumTempExternalNodes].pos = CoorsXFormed; + assert(objectpathinfo[start + j].next >= 0); + TempExternalNodes[NumTempExternalNodes].next = tileStart + objectpathinfo[start + j].next; + TempExternalNodes[NumTempExternalNodes].numLeftLanes = objectpathinfo[start + j].numLeftLanes; + TempExternalNodes[NumTempExternalNodes].numRightLanes = objectpathinfo[start + j].numRightLanes; + TempExternalNodes[NumTempExternalNodes].width = objectpathinfo[start + j].width; + TempExternalNodes[NumTempExternalNodes].isCross = !!objectpathinfo[start + j].crossing; + NumTempExternalNodes++; + } } } + // Same thing for detached nodes + for(i = 0; i < numDetached; i++){ + tileStart = m_numPathNodes; + start = 12*i; + for(j = 0; j < 12; j++){ + if(detachednodes[start + j].type == NodeTypeIntern){ + CVector pos; + pos.x = detachednodes[start + j].x; + pos.y = detachednodes[start + j].y; + pos.z = detachednodes[start + j].z; + m_pathNodes[m_numPathNodes].SetPosition(pos); + mapObjIndices[m_numPathNodes] = -(i+1); + m_pathNodes[m_numPathNodes].width = detachednodes[start + j].width; + m_pathNodes[m_numPathNodes].speedLimit = detachednodes[start + j].speedLimit; + m_pathNodes[m_numPathNodes].spawnRate = detachednodes[start + j].spawnRate; + m_pathNodes[m_numPathNodes].bUseInRoadBlock = detachednodes[start + j].roadBlock; + m_pathNodes[m_numPathNodes].bDisabled = detachednodes[start + j].disabled; + m_pathNodes[m_numPathNodes].bWaterPath = detachednodes[start + j].waterPath; + m_pathNodes[m_numPathNodes].bOnlySmallBoats = detachednodes[start + j].onlySmallBoats; + m_pathNodes[m_numPathNodes].bBetweenLevels = detachednodes[start + j].betweenLevels; + m_numPathNodes++; + }else if(detachednodes[start + j].type == NodeTypeExtern){ + TempExternalNodes[NumTempExternalNodes].pos.x = detachednodes[start + j].x; + TempExternalNodes[NumTempExternalNodes].pos.y = detachednodes[start + j].y; + TempExternalNodes[NumTempExternalNodes].pos.z = detachednodes[start + j].z; + assert(detachednodes[start + j].next >= 0); + TempExternalNodes[NumTempExternalNodes].next = tileStart + detachednodes[start + j].next; + TempExternalNodes[NumTempExternalNodes].numLeftLanes = detachednodes[start + j].numLeftLanes; + TempExternalNodes[NumTempExternalNodes].numRightLanes = detachednodes[start + j].numRightLanes; + TempExternalNodes[NumTempExternalNodes].width = detachednodes[start + j].width; + TempExternalNodes[NumTempExternalNodes].isCross = !!detachednodes[start + j].crossing; + NumTempExternalNodes++; + } + } + } // Insert external nodes into TempList TempListLength = 0; - for(i = 0; i < m_numMapObjects; i++){ - start = 12 * m_mapObjects[i]->GetModelIndex(); - for(j = 0; j < 12; j++){ - if(objectpathinfo[start + j].type != NodeTypeExtern) + for(i = 0; i < NumTempExternalNodes; i++){ + // find closest unconnected node + nearestId = -1; + nearestDist = maxdist; + for(k = 0; k < TempListLength; k++){ + if(tempnodes[k].linkState != 1) continue; - CalcNodeCoors( - objectpathinfo[start + j].x, - objectpathinfo[start + j].y, - objectpathinfo[start + j].z, - i, - &CoorsXFormed); - - // find closest unconnected node - nearestId = -1; - nearestDist = maxdist; - for(k = 0; k < TempListLength; k++){ - if(tempnodes[k].linkState != 1) - continue; - dx = tempnodes[k].pos.x - CoorsXFormed.x; - if(Abs(dx) < nearestDist){ - dy = tempnodes[k].pos.y - CoorsXFormed.y; - if(Abs(dy) < nearestDist){ - nearestDist = Max(Abs(dx), Abs(dy)); - nearestId = k; - } + dx = tempnodes[k].pos.x - TempExternalNodes[i].pos.x; + if(Abs(dx) < nearestDist){ + dy = tempnodes[k].pos.y - TempExternalNodes[i].pos.y; + if(Abs(dy) < nearestDist){ + nearestDist = Max(Abs(dx), Abs(dy)); + nearestId = k; } } + } - if(nearestId < 0){ - // None found, add this one to temp list - tempnodes[TempListLength].pos = CoorsXFormed; - next = objectpathinfo[start + j].next; - if(next < 0){ - // no link from this node, find link to this node - next = 0; - for(k = start; j != objectpathinfo[k].next; k++) - next++; - } - // link to connecting internal node - tempnodes[TempListLength].link1 = m_mapObjects[i]->m_nodeIndices[type][next]; - if(type == PATH_CAR){ - tempnodes[TempListLength].numLeftLanes = objectpathinfo[start + j].numLeftLanes; - tempnodes[TempListLength].numRightLanes = objectpathinfo[start + j].numRightLanes; - } - tempnodes[TempListLength++].linkState = 1; - }else{ - // Found nearest, connect it to our neighbour - next = objectpathinfo[start + j].next; - if(next < 0){ - // no link from this node, find link to this node - next = 0; - for(k = start; j != objectpathinfo[k].next; k++) - next++; - } - tempnodes[nearestId].link2 = m_mapObjects[i]->m_nodeIndices[type][next]; - tempnodes[nearestId].linkState = 2; - - // collapse this node with nearest we found - dx = m_pathNodes[tempnodes[nearestId].link1].GetX() - m_pathNodes[tempnodes[nearestId].link2].GetX(); - dy = m_pathNodes[tempnodes[nearestId].link1].GetY() - m_pathNodes[tempnodes[nearestId].link2].GetY(); - tempnodes[nearestId].pos = (tempnodes[nearestId].pos + CoorsXFormed)*0.5f; - mag = Sqrt(dx*dx + dy*dy); - tempnodes[nearestId].dirX = dx/mag; - tempnodes[nearestId].dirY = dy/mag; - // do something when number of lanes doesn't agree - if(type == PATH_CAR) - if(tempnodes[nearestId].numLeftLanes != 0 && tempnodes[nearestId].numRightLanes != 0 && - (objectpathinfo[start + j].numLeftLanes == 0 || objectpathinfo[start + j].numRightLanes == 0)){ - // why switch left and right here? - tempnodes[nearestId].numLeftLanes = objectpathinfo[start + j].numRightLanes; - tempnodes[nearestId].numRightLanes = objectpathinfo[start + j].numLeftLanes; - } + if(nearestId < 0){ + // None found, add this one to temp list + tempnodes[TempListLength].pos = TempExternalNodes[i].pos; + // link to connecting internal node + tempnodes[TempListLength].link1 = TempExternalNodes[i].next; + if(type == PATH_CAR){ + tempnodes[TempListLength].numLeftLanes = TempExternalNodes[i].numLeftLanes; + tempnodes[TempListLength].numRightLanes = TempExternalNodes[i].numRightLanes; } + tempnodes[TempListLength].width = TempExternalNodes[i].width; + tempnodes[TempListLength].isCross = TempExternalNodes[i].isCross; + tempnodes[TempListLength++].linkState = 1; + }else{ + // Found nearest, connect it to our neighbour + tempnodes[nearestId].link2 = TempExternalNodes[i].next; + tempnodes[nearestId].linkState = 2; + + // collapse this node with nearest we found + dx = m_pathNodes[tempnodes[nearestId].link1].GetX() - m_pathNodes[tempnodes[nearestId].link2].GetX(); + dy = m_pathNodes[tempnodes[nearestId].link1].GetY() - m_pathNodes[tempnodes[nearestId].link2].GetY(); + tempnodes[nearestId].pos = (tempnodes[nearestId].pos + TempExternalNodes[i].pos)*0.5f; + mag = Sqrt(dx*dx + dy*dy); + tempnodes[nearestId].dirX = dx/mag * 100; + tempnodes[nearestId].dirY = dy/mag * 100; + tempnodes[nearestId].width = Max(tempnodes[nearestId].width, TempExternalNodes[i].width); + if(TempExternalNodes[i].isCross) + tempnodes[nearestId].isCross = true; // TODO: is this guaranteed to be false otherwise? + // do something when number of lanes doesn't agree + if(type == PATH_CAR) + if(tempnodes[nearestId].numLeftLanes != 0 && tempnodes[nearestId].numRightLanes != 0 && + (TempExternalNodes[i].numLeftLanes == 0 || TempExternalNodes[i].numRightLanes == 0)){ + // why switch left and right here? + tempnodes[nearestId].numLeftLanes = TempExternalNodes[i].numRightLanes; + tempnodes[nearestId].numRightLanes = TempExternalNodes[i].numLeftLanes; + } } } @@ -673,27 +792,30 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor continue; dist = (m_pathNodes[i].GetPosition() - m_pathNodes[ConnectedNode(m_numConnections)].GetPosition()).Magnitude(); - m_distances[m_numConnections] = dist; - m_connectionFlags[m_numConnections].flags = 0; + m_distances[m_numConnections] = Min(dist, 255); + if(tempnodes[j].isCross) + m_connections[j] |= 0x8000; // crosses road flag if(type == PATH_CAR){ // IMPROVE: use a goto here // Find existing car path link for(k = 0; k < m_numCarPathLinks; k++){ - if(m_carPathLinks[k].dir.x == tempnodes[j].dirX && - m_carPathLinks[k].dir.y == tempnodes[j].dirY && - m_carPathLinks[k].pos.x == tempnodes[j].pos.x && - m_carPathLinks[k].pos.y == tempnodes[j].pos.y){ + if(m_carPathLinks[k].dirX == tempnodes[j].dirX && + m_carPathLinks[k].dirY == tempnodes[j].dirY && + m_carPathLinks[k].x == (int)(tempnodes[j].pos.x*8.0f) && + m_carPathLinks[k].y == (int)(tempnodes[j].pos.y*8.0f)){ m_carPathConnections[m_numConnections] = k; k = m_numCarPathLinks; } } // k is m_numCarPathLinks+1 if we found one if(k == m_numCarPathLinks){ - m_carPathLinks[m_numCarPathLinks].dir.x = tempnodes[j].dirX; - m_carPathLinks[m_numCarPathLinks].dir.y = tempnodes[j].dirY; - m_carPathLinks[m_numCarPathLinks].pos.x = tempnodes[j].pos.x; - m_carPathLinks[m_numCarPathLinks].pos.y = tempnodes[j].pos.y; + m_carPathLinks[m_numCarPathLinks].dirX = tempnodes[j].dirX; + m_carPathLinks[m_numCarPathLinks].dirY = tempnodes[j].dirY; + m_carPathLinks[m_numCarPathLinks].x = tempnodes[j].pos.x*8.0f; + m_carPathLinks[m_numCarPathLinks].y = tempnodes[j].pos.y*8.0f; + m_carPathLinks[m_numCarPathLinks].flag1 = false; + m_carPathLinks[m_numCarPathLinks].width = tempnodes[j].width; m_carPathLinks[m_numCarPathLinks].pathNodeIndex = i; m_carPathLinks[m_numCarPathLinks].numLeftLanes = tempnodes[j].numLeftLanes; m_carPathLinks[m_numCarPathLinks].numRightLanes = tempnodes[j].numRightLanes; @@ -707,6 +829,18 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor m_numConnections++; } + CPathInfoForObject *tile; + if(mapObjIndices[i] < 0){ + if(type == PATH_CAR) + tile = &DetachedInfoForTileCars[12 * (-1 - mapObjIndices[i])]; + else + tile = &DetachedInfoForTilePeds[12 * (-1 - mapObjIndices[i])]; + }else{ + if(type == PATH_CAR) + tile = &InfoForTileCars[12 * m_mapObjects[mapObjIndices[i]]->GetModelIndex()]; + else + tile = &InfoForTilePeds[12 * m_mapObjects[mapObjIndices[i]]->GetModelIndex()]; + } // Find i inside path segment iseg = 0; @@ -714,7 +848,6 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor if(OBJECTINDEX(j) == OBJECTINDEX(i)) iseg++; - istart = 12 * m_mapObjects[m_pathNodes[i].objectIndex]->GetModelIndex(); // Add links to other internal nodes for(j = Max(oldNumPathNodes, i-12); j < Min(m_numPathNodes, i+12); j++){ if(OBJECTINDEX(i) != OBJECTINDEX(j) || i == j) @@ -722,14 +855,13 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor // N.B.: in every path segment, the externals have to be at the end jseg = j-i + iseg; - jstart = 12 * m_mapObjects[m_pathNodes[j].objectIndex]->GetModelIndex(); - if(objectpathinfo[istart + iseg].next == jseg || - objectpathinfo[jstart + jseg].next == iseg){ + if(tile[iseg].next == jseg || + tile[jseg].next == iseg){ // Found a link between i and jConnectionSetCrossesRoad // NB this clears the flags in MIAMI m_connections[m_numConnections] = j; dist = (m_pathNodes[i].GetPosition() - m_pathNodes[j].GetPosition()).Magnitude(); - m_distances[m_numConnections] = dist; + m_distances[m_numConnections] = Min(dist, 255); if(type == PATH_CAR){ posx = (m_pathNodes[i].GetX() + m_pathNodes[j].GetX())*0.5f; @@ -739,6 +871,7 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor mag = Sqrt(dx*dx + dy*dy); dx /= mag; dy /= mag; + int width = Max(m_pathNodes[i].width, m_pathNodes[j].width); if(i < j){ dx = -dx; dy = -dy; @@ -746,20 +879,22 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor // IMPROVE: use a goto here // Find existing car path link for(k = 0; k < m_numCarPathLinks; k++){ - if(m_carPathLinks[k].dir.x == dx && - m_carPathLinks[k].dir.y == dy && - m_carPathLinks[k].pos.x == posx && - m_carPathLinks[k].pos.y == posy){ + if(m_carPathLinks[k].dirX == (int)(dx*100.0f) && + m_carPathLinks[k].dirY == (int)(dy*100.0f) && + m_carPathLinks[k].x == (int)(posx*8.0f) && + m_carPathLinks[k].y == (int)(posy*8.0f)){ m_carPathConnections[m_numConnections] = k; k = m_numCarPathLinks; } } // k is m_numCarPathLinks+1 if we found one if(k == m_numCarPathLinks){ - m_carPathLinks[m_numCarPathLinks].dir.x = dx; - m_carPathLinks[m_numCarPathLinks].dir.y = dy; - m_carPathLinks[m_numCarPathLinks].pos.x = posx; - m_carPathLinks[m_numCarPathLinks].pos.y = posy; + m_carPathLinks[m_numCarPathLinks].dirX = dx*100.0f; + m_carPathLinks[m_numCarPathLinks].dirY = dy*100.0f; + m_carPathLinks[m_numCarPathLinks].x = posx*8.0f; + m_carPathLinks[m_numCarPathLinks].y = posy*8.0f; + m_carPathLinks[m_numCarPathLinks].flag1 = false; + m_carPathLinks[m_numCarPathLinks].width = width; m_carPathLinks[m_numCarPathLinks].pathNodeIndex = i; m_carPathLinks[m_numCarPathLinks].numLeftLanes = -1; m_carPathLinks[m_numCarPathLinks].numRightLanes = -1; @@ -769,11 +904,9 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor } }else{ // Crosses road - if(objectpathinfo[istart + iseg].next == jseg && objectpathinfo[istart + iseg].crossing || - objectpathinfo[jstart + jseg].next == iseg && objectpathinfo[jstart + jseg].crossing) - m_connectionFlags[m_numConnections].bCrossesRoad = true; - else - m_connectionFlags[m_numConnections].bCrossesRoad = false; + if(tile[iseg].next == jseg && tile[iseg].crossing || + tile[jseg].next == iseg && tile[jseg].crossing) + m_connections[m_numConnections] |= 0x8000; // crosses road flag } m_pathNodes[i].numLinks++; @@ -786,7 +919,7 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor done = 0; // Set number of lanes for all nodes somehow // very strange code - for(k = 0; !done && k < 10; k++){ + for(k = 0; !done && k < 12; k++){ done = 1; for(i = 0; i < m_numPathNodes; i++){ if(m_pathNodes[i].numLinks != 2) @@ -794,33 +927,50 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor l1 = m_carPathConnections[m_pathNodes[i].firstLink]; l2 = m_carPathConnections[m_pathNodes[i].firstLink+1]; - if(m_carPathLinks[l1].numLeftLanes == -1 && - m_carPathLinks[l2].numLeftLanes != -1){ + int8 l1Left = m_carPathLinks[l1].numLeftLanes; + int8 l1Right = m_carPathLinks[l1].numRightLanes; + int8 l2Left = m_carPathLinks[l2].numLeftLanes; + int8 l2Right = m_carPathLinks[l2].numRightLanes; + int8 *l1Leftp, *l1Rightp; + int8 *l2Leftp, *l2Rightp; + if(m_carPathLinks[l1].pathNodeIndex == i){ + l1Leftp = &l1Left; + l1Rightp = &l1Right; + }else{ + l1Leftp = &l1Right; + l1Rightp = &l1Left; + } + if(m_carPathLinks[l2].pathNodeIndex == i){ + l2Leftp = &l2Left; + l2Rightp = &l2Right; + }else{ + l2Leftp = &l2Right; + l2Rightp = &l2Left; + } + if(*l1Leftp == -1 && *l2Rightp != -1){ + *l1Leftp = *l2Rightp; done = 0; - if(m_carPathLinks[l2].pathNodeIndex == i){ - // why switch left and right here? - m_carPathLinks[l1].numLeftLanes = m_carPathLinks[l2].numRightLanes; - m_carPathLinks[l1].numRightLanes = m_carPathLinks[l2].numLeftLanes; - }else{ - m_carPathLinks[l1].numLeftLanes = m_carPathLinks[l2].numLeftLanes; - m_carPathLinks[l1].numRightLanes = m_carPathLinks[l2].numRightLanes; - } - m_carPathLinks[l1].pathNodeIndex = i; - }else if(m_carPathLinks[l1].numLeftLanes != -1 && - m_carPathLinks[l2].numLeftLanes == -1){ + } + if(*l1Rightp == -1 && *l2Leftp != -1){ + *l1Rightp = *l2Leftp; done = 0; - if(m_carPathLinks[l1].pathNodeIndex == i){ - // why switch left and right here? - m_carPathLinks[l2].numLeftLanes = m_carPathLinks[l1].numRightLanes; - m_carPathLinks[l2].numRightLanes = m_carPathLinks[l1].numLeftLanes; - }else{ - m_carPathLinks[l2].numLeftLanes = m_carPathLinks[l1].numLeftLanes; - m_carPathLinks[l2].numRightLanes = m_carPathLinks[l1].numRightLanes; - } - m_carPathLinks[l2].pathNodeIndex = i; - }else if(m_carPathLinks[l1].numLeftLanes == -1 && - m_carPathLinks[l2].numLeftLanes == -1) + } + if(*l2Leftp == -1 && *l1Rightp != -1){ + *l2Leftp = *l1Rightp; + done = 0; + } + if(*l2Rightp == -1 && *l1Leftp != -1){ + *l2Rightp = *l1Leftp; + done = 0; + } + if(*l1Leftp == -1 && *l2Rightp == -1) done = 0; + if(*l2Leftp == -1 && *l1Rightp == -1) + done = 0; + m_carPathLinks[l1].numLeftLanes = l1Left; + m_carPathLinks[l1].numRightLanes = l1Right; + m_carPathLinks[l2].numLeftLanes = l2Left; + m_carPathLinks[l2].numRightLanes = l2Right; } } @@ -828,10 +978,10 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor for(i = 0; i < m_numPathNodes; i++) for(j = 0; j < m_pathNodes[i].numLinks; j++){ k = m_carPathConnections[m_pathNodes[i].firstLink + j]; - if(m_carPathLinks[k].numLeftLanes < 0) - m_carPathLinks[k].numLeftLanes = 1; - if(m_carPathLinks[k].numRightLanes < 0) - m_carPathLinks[k].numRightLanes = 1; + if(m_carPathLinks[k].numLeftLanes == -1) + m_carPathLinks[k].numLeftLanes = 0; + if(m_carPathLinks[k].numRightLanes == -1) + m_carPathLinks[k].numRightLanes = 0; } } @@ -840,8 +990,6 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor do{ cont = 0; for(i = 0; i < m_numPathNodes; i++){ - m_pathNodes[i].bDisabled = false; - m_pathNodes[i].bBetweenLevels = false; // See if node is a dead end, if so, we're not done yet if(!m_pathNodes[i].bDeadEnd){ k = 0; @@ -874,23 +1022,14 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor m_connections[j] = node-1; } - // Also in treadables - for(j = 0; j < m_numMapObjects; j++) - for(k = 0; k < 12; k++){ - if(m_mapObjects[j]->m_nodeIndices[PATH_PED][k] == i){ - // remove this one - for(l = k; l < 12-1; l++) - m_mapObjects[j]->m_nodeIndices[PATH_PED][l] = m_mapObjects[j]->m_nodeIndices[PATH_PED][l+1]; - m_mapObjects[j]->m_nodeIndices[PATH_PED][11] = -1; - }else if(m_mapObjects[j]->m_nodeIndices[PATH_PED][k] > i) - m_mapObjects[j]->m_nodeIndices[PATH_PED][k]--; - } - i--; m_numPathNodes--; } + + delete[] mapObjIndices; } +//--MIAMI: done float CPathFind::CalcRoadDensity(float x, float y) { @@ -907,21 +1046,13 @@ CPathFind::CalcRoadDensity(float x, float y) next = m_carPathConnections[m_pathNodes[i].firstLink + j]; density += m_carPathLinks[next].numLeftLanes * dist; density += m_carPathLinks[next].numRightLanes * dist; - - if(m_carPathLinks[next].numLeftLanes < 0) - printf("Link from object %d to %d (MIs)\n", - m_mapObjects[m_pathNodes[i].objectIndex]->GetModelIndex(), - m_mapObjects[m_pathNodes[ConnectedNode(m_pathNodes[i].firstLink + j)].objectIndex]->GetModelIndex()); - if(m_carPathLinks[next].numRightLanes < 0) - printf("Link from object %d to %d (MIs)\n", - m_mapObjects[m_pathNodes[i].objectIndex]->GetModelIndex(), - m_mapObjects[m_pathNodes[ConnectedNode(m_pathNodes[i].firstLink + j)].objectIndex]->GetModelIndex()); } } } return density/2500.0f; } +//--MIAMI: done bool CPathFind::TestForPedTrafficLight(CPathNode *n1, CPathNode *n2) { @@ -932,6 +1063,7 @@ CPathFind::TestForPedTrafficLight(CPathNode *n1, CPathNode *n2) return false; } +//--MIAMI: done bool CPathFind::TestCrossesRoad(CPathNode *n1, CPathNode *n2) { @@ -942,6 +1074,7 @@ CPathFind::TestCrossesRoad(CPathNode *n1, CPathNode *n2) return false; } +//--MIAMI: done void CPathFind::AddNodeToList(CPathNode *node, int32 listId) { @@ -954,6 +1087,7 @@ CPathFind::AddNodeToList(CPathNode *node, int32 listId) node->distance = listId; } +//--MIAMI: done void CPathFind::RemoveNodeFromList(CPathNode *node) { @@ -962,6 +1096,7 @@ CPathFind::RemoveNodeFromList(CPathNode *node) node->GetNext()->SetPrev(node->GetPrev()); } +//--MIAMI: done void CPathFind::RemoveBadStartNode(CVector pos, CPathNode **nodes, int16 *n) { @@ -975,6 +1110,7 @@ CPathFind::RemoveBadStartNode(CVector pos, CPathNode **nodes, int16 *n) } } +#ifdef GTA_BRIDGE void CPathFind::SetLinksBridgeLights(float x1, float x2, float y1, float y2, bool enable) { @@ -986,7 +1122,9 @@ CPathFind::SetLinksBridgeLights(float x1, float x2, float y1, float y2, bool ena m_carPathLinks[i].bBridgeLights = enable; } } +#endif +//--MIAMI: done void CPathFind::SwitchOffNodeAndNeighbours(int32 nodeId, bool disable) { @@ -1002,6 +1140,7 @@ CPathFind::SwitchOffNodeAndNeighbours(int32 nodeId, bool disable) } } +//--MIAMI: done void CPathFind::SwitchRoadsOffInArea(float x1, float x2, float y1, float y2, float z1, float z2, bool disable) { @@ -1017,6 +1156,7 @@ CPathFind::SwitchRoadsOffInArea(float x1, float x2, float y1, float y2, float z1 } } +//--MIAMI: done void CPathFind::SwitchPedRoadsOffInArea(float x1, float x2, float y1, float y2, float z1, float z2, bool disable) { @@ -1032,6 +1172,7 @@ CPathFind::SwitchPedRoadsOffInArea(float x1, float x2, float y1, float y2, float } } +//--MIAMI: unused (still needed for script here) void CPathFind::SwitchRoadsInAngledArea(float x1, float y1, float z1, float x2, float y2, float z2, float length, uint8 type, uint8 mode) { @@ -1083,6 +1224,7 @@ CPathFind::SwitchRoadsInAngledArea(float x1, float y1, float z1, float x2, float } } +//--MIAMI: unused (still needed for script here) void CPathFind::MarkRoadsBetweenLevelsNodeAndNeighbours(int32 nodeId) { @@ -1098,6 +1240,7 @@ CPathFind::MarkRoadsBetweenLevelsNodeAndNeighbours(int32 nodeId) } } +//--MIAMI: unused (still needed for script here) void CPathFind::MarkRoadsBetweenLevelsInArea(float x1, float x2, float y1, float y2, float z1, float z2) { @@ -1112,6 +1255,7 @@ CPathFind::MarkRoadsBetweenLevelsInArea(float x1, float x2, float y1, float y2, } } +//--MIAMI: unused (still needed for script here) void CPathFind::PedMarkRoadsBetweenLevelsInArea(float x1, float x2, float y1, float y2, float z1, float z2) { @@ -1126,8 +1270,9 @@ CPathFind::PedMarkRoadsBetweenLevelsInArea(float x1, float x2, float y1, float y } } +//--MIAMI: done int32 -CPathFind::FindNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bool ignoreDisabled, bool ignoreBetweenLevels) +CPathFind::FindNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bool ignoreDisabled, bool ignoreBetweenLevels, bool ignoreFlagB4, bool bWaterPath) { int i; int firstNode, lastNode; @@ -1149,22 +1294,20 @@ CPathFind::FindNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bo for(i = firstNode; i < lastNode; i++){ if(ignoreDisabled && m_pathNodes[i].bDisabled) continue; if(ignoreBetweenLevels && m_pathNodes[i].bBetweenLevels) continue; - switch(m_pathNodes[i].unkBits){ - case 1: - case 2: - dist = Abs(m_pathNodes[i].GetX() - coors.x) + - Abs(m_pathNodes[i].GetY() - coors.y) + - 3.0f*Abs(m_pathNodes[i].GetZ() - coors.z); - if(dist < closestDist){ - closestDist = dist; - closestNode = i; - } - break; + if(ignoreFlagB4 && m_pathNodes[i].flagB4) continue; + if(bWaterPath != m_pathNodes[i].bWaterPath) continue; + dist = Abs(m_pathNodes[i].GetX() - coors.x) + + Abs(m_pathNodes[i].GetY() - coors.y) + + 3.0f*Abs(m_pathNodes[i].GetZ() - coors.z); + if(dist < closestDist){ + closestDist = dist; + closestNode = i; } } return closestDist < distLimit ? closestNode : -1; } +//--MIAMI: done int32 CPathFind::FindNodeClosestToCoorsFavourDirection(CVector coors, uint8 type, float dirX, float dirY) { @@ -1187,27 +1330,23 @@ CPathFind::FindNodeClosestToCoorsFavourDirection(CVector coors, uint8 type, floa } for(i = firstNode; i < lastNode; i++){ - switch(m_pathNodes[i].unkBits){ - case 1: - case 2: - dX = m_pathNodes[i].GetX() - coors.x; - dY = m_pathNodes[i].GetY() - coors.y; - dist = Abs(dX) + Abs(dY) + - 3.0f*Abs(m_pathNodes[i].GetZ() - coors.z); + dX = m_pathNodes[i].GetX() - coors.x; + dY = m_pathNodes[i].GetY() - coors.y; + dist = Abs(dX) + Abs(dY) + + 3.0f*Abs(m_pathNodes[i].GetZ() - coors.z); + if(dist < closestDist){ + NormalizeXY(dX, dY); + dist -= (dX*dirX + dY*dirY - 1.0f)*20.0f; if(dist < closestDist){ - NormalizeXY(dX, dY); - dist -= (dX*dirX + dY*dirY - 1.0f)*20.0f; - if(dist < closestDist){ - closestDist = dist; - closestNode = i; - } + closestDist = dist; + closestNode = i; } - break; } } return closestNode; } +//--MIAMI: done float CPathFind::FindNodeOrientationForCarPlacement(int32 nodeId) { @@ -1219,6 +1358,7 @@ CPathFind::FindNodeOrientationForCarPlacement(int32 nodeId) return RADTODEG(dir.Heading()); } +//--MIAMI: unused (still needed for script here) float CPathFind::FindNodeOrientationForCarPlacementFacingDestination(int32 nodeId, float x, float y, bool towards) { @@ -1262,6 +1402,8 @@ CPathFind::FindNodeOrientationForCarPlacementFacingDestination(int32 nodeId, flo return RADTODEG(dir.Heading()); } +// no "New" in MIAMI +//--MIAMI: TODO bool CPathFind::NewGenerateCarCreationCoors(float x, float y, float dirX, float dirY, float spawnDist, float angleLimit, bool forward, CVector *pPosition, int32 *pNode1, int32 *pNode2, float *pPositionBetweenNodes, bool ignoreDisabled) { @@ -1277,14 +1419,14 @@ CPathFind::NewGenerateCarCreationCoors(float x, float y, float dirX, float dirY, if(m_pathNodes[node1].bDisabled && !ignoreDisabled) continue; dist1 = Distance2D(m_pathNodes[node1].GetPosition(), x, y); - if(dist1 < spawnDist + 60.0f){ - d1 = dist1 - spawnDist; + if(dist1 < Max(spawnDist + 70.0f, spawnDist * 1.7f)){ + d1 = m_pathNodes[node1].bWaterPath ? (dist1 - spawnDist * 1.5f) : (dist1 - spawnDist); for(j = 0; j < m_pathNodes[node1].numLinks; j++){ node2 = ConnectedNode(m_pathNodes[node1].firstLink + j); if(m_pathNodes[node2].bDisabled && !ignoreDisabled) continue; dist2 = Distance2D(m_pathNodes[node2].GetPosition(), x, y); - d2 = dist2 - spawnDist; + d2 = m_pathNodes[node2].bWaterPath ? (dist2 - spawnDist * 1.5f) : (dist2 - spawnDist); if(d1*d2 < 0.0f){ // nodes are on different sides of spawn distance float f2 = Abs(d1)/(Abs(d1) + Abs(d2)); @@ -1316,6 +1458,7 @@ CPathFind::NewGenerateCarCreationCoors(float x, float y, float dirX, float dirY, return false; } +//--MIAMI: TODO bool CPathFind::GeneratePedCreationCoors(float x, float y, float minDist, float maxDist, float minDistOffScreen, float maxDistOffScreen, CVector *pPosition, int32 *pNode1, int32 *pNode2, float *pPositionBetweenNodes, CMatrix *camMatrix) { @@ -1375,42 +1518,7 @@ CPathFind::GeneratePedCreationCoors(float x, float y, float minDist, float maxDi return false; } -CTreadable* -CPathFind::FindRoadObjectClosestToCoors(CVector coors, uint8 type) -{ - int i, j, k; - int node1, node2; - CTreadable *closestMapObj = nil; - float closestDist = 10000.0f; - - for(i = 0; i < m_numMapObjects; i++){ - CTreadable *mapObj = m_mapObjects[i]; - if(mapObj->m_nodeIndices[type][0] < 0) - continue; - CVector vDist = mapObj->GetPosition() - coors; - float fDist = Abs(vDist.x) + Abs(vDist.y) + Abs(vDist.z); - if(fDist < 200.0f || fDist < closestDist) - for(j = 0; j < 12; j++){ - node1 = mapObj->m_nodeIndices[type][j]; - if(node1 < 0) - break; - // FIX: game uses ThePaths here explicitly - for(k = 0; k < m_pathNodes[node1].numLinks; k++){ - node2 = ConnectedNode(m_pathNodes[node1].firstLink + k); - float lineDist = CCollision::DistToLine(&m_pathNodes[node1].GetPosition(), &m_pathNodes[node2].GetPosition(), &coors); - if(lineDist < closestDist){ - closestDist = lineDist; - if((coors - m_pathNodes[node1].GetPosition()).MagnitudeSqr() < (coors - m_pathNodes[node2].GetPosition()).MagnitudeSqr()) - closestMapObj = m_mapObjects[m_pathNodes[node1].objectIndex]; - else - closestMapObj = m_mapObjects[m_pathNodes[node2].objectIndex]; - } - } - } - } - return closestMapObj; -} - +//--MIAMI: done void CPathFind::FindNextNodeWandering(uint8 type, CVector coors, CPathNode **lastNode, CPathNode **nextNode, uint8 curDir, uint8 *nextDir) { @@ -1418,19 +1526,8 @@ CPathFind::FindNextNodeWandering(uint8 type, CVector coors, CPathNode **lastNode CPathNode *node; if(lastNode == nil || (node = *lastNode) == nil || (coors - (*lastNode)->GetPosition()).MagnitudeSqr() > 7.0f){ - // need to find the node we're coming from - node = nil; - CTreadable *obj = FindRoadObjectClosestToCoors(coors, type); - float nodeDist = 1000000000.0f; - for(i = 0; i < 12; i++){ - if(obj->m_nodeIndices[type][i] < 0) - break; - float dist = (coors - m_pathNodes[obj->m_nodeIndices[type][i]].GetPosition()).MagnitudeSqr(); - if(dist < nodeDist){ - nodeDist = dist; - node = &m_pathNodes[obj->m_nodeIndices[type][i]]; - } - } + int32 nodeIdx = FindNodeClosestToCoors(coors, type, 999999.88f); + node = &m_pathNodes[nodeIdx]; } CVector2D vCurDir(Sin(curDir*PI/4.0f), Cos(curDir * PI / 4.0f)); @@ -1486,8 +1583,9 @@ CPathFind::FindNextNodeWandering(uint8 type, CVector coors, CPathNode **lastNode } } -static CPathNode *apNodesToBeCleared[4995]; +static CPathNode *apNodesToBeCleared[6525]; +//--MIAMI: done void CPathFind::DoPathSearch(uint8 type, CVector start, int32 startNodeId, CVector target, CPathNode **nodes, int16 *pNumNodes, int16 maxNumNodes, CVehicle *vehicle, float *pDist, float distLimit, int32 targetNodeId) { @@ -1503,42 +1601,22 @@ CPathFind::DoPathSearch(uint8 type, CVector start, int32 startNodeId, CVector ta } // Find start - int numPathsToTry; - CTreadable *startObj; - if(startNodeId < 0){ - if(vehicle == nil || (startObj = vehicle->m_treadable[type]) == nil) - startObj = FindRoadObjectClosestToCoors(start, type); - numPathsToTry = 0; - for(i = 0; i < 12; i++){ - if(startObj->m_nodeIndices[type][i] < 0) - break; - if(m_pathNodes[startObj->m_nodeIndices[type][i]].group == m_pathNodes[targetNodeId].group) - numPathsToTry++; - } - }else{ - numPathsToTry = 1; - startObj = m_mapObjects[m_pathNodes[startNodeId].objectIndex]; - } - if(numPathsToTry == 0) { + if(startNodeId < 0) + startNodeId = FindNodeClosestToCoors(start, type, 999999.88f); + if(startNodeId < 0) { *pNumNodes = 0; if(pDist) *pDist = 100000.0f; return; } - - if(startNodeId < 0){ - // why only check node 0? - if(m_pathNodes[startObj->m_nodeIndices[type][0]].group != - m_pathNodes[targetNodeId].group) { - *pNumNodes = 0; - if(pDist) *pDist = 100000.0f; - return; - } - }else{ - if(m_pathNodes[startNodeId].group != m_pathNodes[targetNodeId].group) { - *pNumNodes = 0; - if(pDist) *pDist = 100000.0f; - return; - } + if(startNodeId == targetNodeId){ + *pNumNodes = 0; + if(pDist) *pDist = 0.0f; + return; + } + if(m_pathNodes[startNodeId].group != m_pathNodes[targetNodeId].group) { + *pNumNodes = 0; + if(pDist) *pDist = 100000.0f; + return; } for(i = 0; i < ARRAY_SIZE(m_searchNodes); i++) @@ -1550,14 +1628,11 @@ CPathFind::DoPathSearch(uint8 type, CVector start, int32 startNodeId, CVector ta // Dijkstra's algorithm // Find distances int numPathsFound = 0; - if(startNodeId < 0 && m_mapObjects[m_pathNodes[targetNodeId].objectIndex] == startObj) - numPathsFound++; - for(i = 0; numPathsFound < numPathsToTry; i = (i+1) & 0x1FF){ + for(i = 0; numPathsFound == 0; i = (i+1) & 0x1FF){ CPathNode *node; for(node = m_searchNodes[i].GetNext(); node; node = node->GetNext()){ - if(m_mapObjects[node->objectIndex] == startObj && - (startNodeId < 0 || node == &m_pathNodes[startNodeId])) - numPathsFound++; + if(node == &m_pathNodes[startNodeId]) + numPathsFound = 1; for(j = 0; j < node->numLinks; j++){ int next = ConnectedNode(node->firstLink + j); @@ -1577,34 +1652,12 @@ CPathFind::DoPathSearch(uint8 type, CVector start, int32 startNodeId, CVector ta // Find out whence to start tracing back CPathNode *curNode; - if(startNodeId < 0){ - int minDist = MAX_DIST; - *pNumNodes = 1; - for(i = 0; i < 12; i++){ - if(startObj->m_nodeIndices[type][i] < 0) - break; - int dist = (m_pathNodes[startObj->m_nodeIndices[type][i]].GetPosition() - start).Magnitude(); - if(m_pathNodes[startObj->m_nodeIndices[type][i]].distance + dist < minDist){ - minDist = m_pathNodes[startObj->m_nodeIndices[type][i]].distance + dist; - curNode = &m_pathNodes[startObj->m_nodeIndices[type][i]]; - } - } - if(maxNumNodes == 0){ - *pNumNodes = 0; - }else{ - nodes[0] = curNode; - *pNumNodes = 1; - } - if(pDist) - *pDist = minDist; - }else - { - curNode = &m_pathNodes[startNodeId]; - *pNumNodes = 0; - if(pDist) - *pDist = m_pathNodes[startNodeId].distance; - } + curNode = &m_pathNodes[startNodeId]; + *pNumNodes = 0; + if(pDist) + *pDist = m_pathNodes[startNodeId].distance; + nodes[(*pNumNodes)++] = curNode; // Trace back to target and update list of nodes while(*pNumNodes < maxNumNodes && curNode != &m_pathNodes[targetNodeId]) for(i = 0; i < curNode->numLinks; i++){ @@ -1618,13 +1671,13 @@ CPathFind::DoPathSearch(uint8 type, CVector start, int32 startNodeId, CVector ta for(i = 0; i < numNodesToBeCleared; i++) apNodesToBeCleared[i]->distance = MAX_DIST; - return; } static CPathNode *pNodeList[32]; static int16 DummyResult; static int16 DummyResult2; +//--MIAMI: done bool CPathFind::TestCoorsCloseness(CVector target, uint8 type, CVector start) { @@ -1635,11 +1688,12 @@ CPathFind::TestCoorsCloseness(CVector target, uint8 type, CVector start) else DoPathSearch(type, start, -1, target, nil, &DummyResult2, 0, nil, &dist, 50.0f, -1); if(type == PATH_CAR) - return dist < 160.0f; + return dist < 150.0f; else return dist < 100.0f; } +//--MIAMI: done void CPathFind::Save(uint8 *buf, uint32 *size) { @@ -1661,6 +1715,7 @@ CPathFind::Save(uint8 *buf, uint32 *size) buf[i/8 + n] &= ~(1 << i%8); } +//--MIAMI: done void CPathFind::Load(uint8 *buf, uint32 size) { @@ -1805,3 +1860,23 @@ CPathFind::DisplayPathData(void) } } } + +CPathNode* +CPathFind::GetNode(int16 index) +{ + if(index < 0) + return nil; + if(index < ARRAY_SIZE(ThePaths.m_searchNodes)) + return &ThePaths.m_searchNodes[index]; + return &ThePaths.m_pathNodes[index - ARRAY_SIZE(ThePaths.m_searchNodes)]; +} +int16 +CPathFind::GetIndex(CPathNode *node) +{ + if(node == nil) + return -1; + if(node >= &ThePaths.m_searchNodes[0] && node < &ThePaths.m_searchNodes[ARRAY_SIZE(ThePaths.m_searchNodes)]) + return node - ThePaths.m_searchNodes; + else + return (node - ThePaths.m_pathNodes) + ARRAY_SIZE(ThePaths.m_searchNodes); +} diff --git a/src/control/PathFind.h b/src/control/PathFind.h index bbfdf7b7..7abc455a 100644 --- a/src/control/PathFind.h +++ b/src/control/PathFind.h @@ -9,9 +9,6 @@ enum { NodeTypeExtern = 1, NodeTypeIntern = 2, - - UseInRoadBlock = 1, - ObjectEastWest = 2, }; enum @@ -56,31 +53,42 @@ public: struct CPathNode { - CVector pos; - CPathNode *prev; - CPathNode *next; + int16 prevIndex; + int16 nextIndex; + int16 x; + int16 y; + int16 z; int16 distance; // in path search - int16 objectIndex; int16 firstLink; - uint8 numLinks; + int8 width; + int8 group; - uint8 unkBits : 2; + uint8 numLinks : 4; uint8 bDeadEnd : 1; uint8 bDisabled : 1; uint8 bBetweenLevels : 1; - - int8 group; - - CVector &GetPosition(void) { return pos; } - void SetPosition(const CVector &p) { pos = p; } - float GetX(void) { return pos.x; } - float GetY(void) { return pos.y; } - float GetZ(void) { return pos.z; } - - CPathNode *GetPrev(void) { return prev; } - CPathNode *GetNext(void) { return next; } - void SetPrev(CPathNode *node) { prev = node; } - void SetNext(CPathNode *node) { next = node; } + uint8 bUseInRoadBlock : 1; + + uint8 bWaterPath : 1; + uint8 bOnlySmallBoats : 1; + uint8 flagB4 : 1; // where is this set? + uint8 speedLimit : 2; + //uint8 flagB20 : 1; + //uint8 flagB40 : 1; + //uint8 flagB80 : 1; + + uint8 spawnRate : 4; + uint8 flagsC : 4; + + CVector GetPosition(void) { return CVector(x/8.0f, y/8.0f, z/8.0f); } + void SetPosition(const CVector &p) { x = p.x*8.0f; y = p.y*8.0f; z = p.z*8.0f; } + float GetX(void) { return x/8.0f; } + float GetY(void) { return y/8.0f; } + float GetZ(void) { return z/8.0f; } + CPathNode *GetPrev(void); + CPathNode *GetNext(void); + void SetPrev(CPathNode *node); + void SetNext(CPathNode *node); }; union CConnectionFlags @@ -94,22 +102,25 @@ union CConnectionFlags struct CCarPathLink { - CVector2D pos; - CVector2D dir; + int16 x; + int16 y; int16 pathNodeIndex; - int8 numLeftLanes; - int8 numRightLanes; - uint8 trafficLightType; - - uint8 bBridgeLights : 1; - // more? - - CVector2D &GetPosition(void) { return pos; } - CVector2D &GetDirection(void) { return dir; } - float GetX(void) { return pos.x; } - float GetY(void) { return pos.y; } - float GetDirX(void) { return dir.x; } - float GetDirY(void) { return dir.y; } + int8 dirX; + int8 dirY; + int8 numLeftLanes : 3; + int8 numRightLanes : 3; + uint8 flag1 : 1; + uint8 trafficLightType : 2; + uint8 bBridgeLights : 1; // at least in LCS... + int8 width; + + CVector2D GetPosition(void) { return CVector2D(x/8.0f, y/8.0f); } + CVector2D GetDirection(void) { return CVector2D(dirX/100.0f, dirY/100.0f); } + float GetX(void) { return x/8.0f; } + 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 OneWayLaneOffset() { @@ -117,21 +128,33 @@ struct CCarPathLink return 0.5f - 0.5f * numRightLanes; if (numRightLanes == 0) return 0.5f - 0.5f * numLeftLanes; - return 0.5f; + return 0.5f + GetLaneOffset(); } }; // This is what we're reading from the files, only temporary struct CPathInfoForObject { - int16 x; - int16 y; - int16 z; + float x; + float y; + float z; int8 type; int8 next; int8 numLeftLanes; int8 numRightLanes; + int8 speedLimit; + int8 width; + uint8 crossing : 1; + uint8 onlySmallBoats : 1; + uint8 roadBlock : 1; + uint8 disabled : 1; + uint8 waterPath : 1; + uint8 betweenLevels : 1; + + uint8 spawnRate : 4; + + void SwapConnectionsToBeRightWayRound(void); }; extern CPathInfoForObject *InfoForTileCars; extern CPathInfoForObject *InfoForTilePeds; @@ -139,18 +162,25 @@ extern CPathInfoForObject *InfoForTilePeds; struct CTempNode { CVector pos; - float dirX; - float dirY; + int8 dirX; // *100 + int8 dirY; int16 link1; int16 link2; int8 numLeftLanes; int8 numRightLanes; + int8 width; + bool isCross; int8 linkState; }; -struct CTempDetachedNode // unused +struct CTempNodeExternal // made up name { - uint8 foo[20]; + CVector pos; + int16 next; + int8 numLeftLanes; + int8 numRightLanes; + int8 width; + bool isCross; }; class CPathFind @@ -159,10 +189,8 @@ public: CPathNode m_pathNodes[NUM_PATHNODES]; CCarPathLink m_carPathLinks[NUM_CARPATHLINKS]; CTreadable *m_mapObjects[NUM_MAPOBJECTS]; - uint8 m_objectFlags[NUM_MAPOBJECTS]; - int16 m_connections[NUM_PATHCONNECTIONS]; - int16 m_distances[NUM_PATHCONNECTIONS]; - CConnectionFlags m_connectionFlags[NUM_PATHCONNECTIONS]; + uint16 m_connections[NUM_PATHCONNECTIONS]; // and flags + uint8 m_distances[NUM_PATHCONNECTIONS]; int16 m_carPathConnections[NUM_PATHCONNECTIONS]; int32 m_numPathNodes; @@ -178,14 +206,19 @@ public: void Init(void); void AllocatePathFindInfoMem(int16 numPathGroups); void RegisterMapObject(CTreadable *mapObject); - void StoreNodeInfoPed(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, int16 width, bool crossing); - void StoreNodeInfoCar(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, int16 width, int8 numLeft, int8 numRight); - void CalcNodeCoors(int16 x, int16 y, int16 z, int32 id, CVector *out); + void StoreNodeInfoPed(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, float width, bool crossing, uint8 spawnRate); + void StoreNodeInfoCar(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, float width, int8 numLeft, int8 numRight, + bool disabled, bool betweenLevels, uint8 speedLimit, bool roadBlock, bool waterPath, uint8 spawnRate); + void StoreDetachedNodeInfoPed(int32 node, int8 type, int32 next, float x, float y, float z, float width, bool crossing, + bool disabled, bool betweenLevels, uint8 spawnRate); + void StoreDetachedNodeInfoCar(int32 node, int8 type, int32 next, float x, float y, float z, float width, int8 numLeft, int8 numRight, + bool disabled, bool betweenLevels, uint8 speedLimit, bool roadBlock, bool waterPath, uint8 spawnRate, bool unk); + void CalcNodeCoors(float x, float y, float z, int32 id, CVector *out); bool LoadPathFindData(void); void PreparePathData(void); void CountFloodFillGroups(uint8 type); void PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoForObject *objectpathinfo, - float maxdist, CTempDetachedNode *detachednodes, int32 numDetached); + float maxdist, CPathInfoForObject *detachednodes, int32 numDetached); bool IsPathObject(int id) { return id < PATHNODESIZE && (InfoForTileCars[id*12].type != 0 || InfoForTilePeds[id*12].type != 0); } @@ -203,30 +236,37 @@ public: void MarkRoadsBetweenLevelsNodeAndNeighbours(int32 nodeId); void MarkRoadsBetweenLevelsInArea(float x1, float x2, float y1, float y2, float z1, float z2); void PedMarkRoadsBetweenLevelsInArea(float x1, float x2, float y1, float y2, float z1, float z2); - int32 FindNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bool ignoreDisabled = false, bool ignoreBetweenLevels = false); +// TODO(MIAMI): check callers for new arguments + int32 FindNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bool ignoreDisabled = false, bool ignoreBetweenLevels = false, bool ignoreFlagB4 = false, bool bWaterPath = false); int32 FindNodeClosestToCoorsFavourDirection(CVector coors, uint8 type, float dirX, float dirY); float FindNodeOrientationForCarPlacement(int32 nodeId); float FindNodeOrientationForCarPlacementFacingDestination(int32 nodeId, float x, float y, bool towards); bool NewGenerateCarCreationCoors(float x, float y, float dirX, float dirY, float spawnDist, float angleLimit, bool forward, CVector *pPosition, int32 *pNode1, int32 *pNode2, float *pPositionBetweenNodes, bool ignoreDisabled = false); bool GeneratePedCreationCoors(float x, float y, float minDist, float maxDist, float minDistOffScreen, float maxDistOffScreen, CVector *pPosition, int32 *pNode1, int32 *pNode2, float *pPositionBetweenNodes, CMatrix *camMatrix); - CTreadable *FindRoadObjectClosestToCoors(CVector coors, uint8 type); void FindNextNodeWandering(uint8, CVector, CPathNode**, CPathNode**, uint8, uint8*); void DoPathSearch(uint8 type, CVector start, int32 startNodeId, CVector target, CPathNode **nodes, int16 *numNodes, int16 maxNumNodes, CVehicle *vehicle, float *dist, float distLimit, int32 forcedTargetNode); bool TestCoorsCloseness(CVector target, uint8 type, CVector start); void Save(uint8 *buf, uint32 *size); void Load(uint8 *buf, uint32 size); - uint16 ConnectedNode(int id) { return m_connections[id]; } - bool ConnectionCrossesRoad(int id) { return m_connectionFlags[id].bCrossesRoad; } - bool ConnectionHasTrafficLight(int id) { return m_connectionFlags[id].bTrafficLight; } - void ConnectionSetTrafficLight(int id) { m_connectionFlags[id].bTrafficLight = true; } + + CPathNode *GetNode(int16 index); + int16 GetIndex(CPathNode *node); + + uint16 ConnectedNode(int id) { return m_connections[id] & 0x3FFF; } + bool ConnectionCrossesRoad(int id) { return !!(m_connections[id] & 0x8000); } + bool ConnectionHasTrafficLight(int id) { return !!(m_connections[id] & 0x4000); } + void ConnectionSetTrafficLight(int id) { m_connections[id] |= 0x4000; } void DisplayPathData(void); }; -VALIDATE_SIZE(CPathFind, 0x49bf4); - extern CPathFind ThePaths; +inline CPathNode *CPathNode::GetPrev(void) { return ThePaths.GetNode(prevIndex); } +inline CPathNode *CPathNode::GetNext(void) { return ThePaths.GetNode(nextIndex); } +inline void CPathNode::SetPrev(CPathNode *node) { prevIndex = ThePaths.GetIndex(node); } +inline void CPathNode::SetNext(CPathNode *node) { nextIndex = ThePaths.GetIndex(node); } + extern bool gbShowPedPaths; extern bool gbShowCarPaths; extern bool gbShowCarPathsLinks; diff --git a/src/control/Pickups.cpp b/src/control/Pickups.cpp index 32bffa17..b5e20e41 100644 --- a/src/control/Pickups.cpp +++ b/src/control/Pickups.cpp @@ -44,15 +44,58 @@ uint32 CPickups::StaticCamStartTime; tPickupMessage CPickups::aMessages[NUMPICKUPMESSAGES]; -// 20 ?! Some Miami leftover? (Originally at 0x5ED8D4) +// TODO(Miami) uint16 AmmoForWeapon[20] = { 0, 1, 45, 125, 25, 150, 300, 25, 5, 250, 5, 5, 0, 500, 0, 100, 0, 0, 0, 0 }; -uint16 AmmoForWeapon_OnStreet[20] = { 0, 1, 9, 25, 5, 30, 60, 5, 1, 50, 1, 1, 0, 200, 0, 100, 0, 0, 0, 0 }; +uint16 AmmoForWeapon_OnStreet[WEAPONTYPE_TOTALWEAPONS] = { + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 4, + 4, + 4, + 4, + 34, + 16, + 100, + 60, + 60, + 60, + 60, + 60, + 20, + 4, + 14, + 1, + 400, +}; uint16 CostOfWeapon[20] = { 0, 10, 250, 800, 1500, 3000, 5000, 10000, 25000, 25000, 2000, 2000, 0, 50000, 0, 3000, 0, 0, 0, 0 }; -uint8 aWeaponReds[] = { 255, 0, 128, 255, 255, 0, 255, 0, 128, 128, 255, 255, 128, 0, 255, 0 }; -uint8 aWeaponGreens[] = { 0, 255, 128, 255, 0, 255, 128, 255, 0, 255, 255, 0, 255, 0, 255, 0 }; -uint8 aWeaponBlues[] = { 0, 0, 255, 0, 255, 255, 0, 128, 255, 0, 255, 0, 128, 255, 0, 0 }; -float aWeaponScale[] = { 1.0f, 2.0f, 1.5f, 1.0f, 1.0f, 1.5f, 1.0f, 2.0f, 1.0f, 2.0f, 2.5f, 1.0f, 1.0f, 1.0f, 1.0f }; +// TODO(Miami): Those are all placeholders!! +uint8 aWeaponReds[] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 0, 128, 255, 255, 0, 255, 0, 128, 128, 255, +255, 255, 255, 255, 255, 255, 255, 255, +255, 128, 0, 255, 0 }; +uint8 aWeaponGreens[] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +0, 255, 128, 255, 0, 255, 128, 255, 0, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, +0, 255, 0, 255, 0 }; +uint8 aWeaponBlues[] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +0, 0, 255, 0, 255, 255, 0, 128, 255, 0, 255, +255, 255, 255, 255, 255, 255, 255, 255, +0, 128, 255, 0, 0 }; +float aWeaponScale[] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, +2.0f, 1.5f, 1.0f, 1.0f, 1.5f, 1.0f, 2.0f, 1.0f, 2.0f, 2.5f, 1.0f, +1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, +1.0f, 1.0f, 1.0f, 1.0f }; void CPickup::RemoveKeepType() @@ -129,12 +172,12 @@ CPickup::GiveUsAPickUpObject(int32 handle) } bool -CPickup::CanBePickedUp(CPlayerPed *player) +CPickup::CanBePickedUp(CPlayerPed *player, int playerId) { assert(m_pObject != nil); bool cannotBePickedUp = - (m_pObject->GetModelIndex() == MI_PICKUP_BODYARMOUR && player->m_fArmour > 99.5f) - || (m_pObject->GetModelIndex() == MI_PICKUP_HEALTH && player->m_fHealth > 99.5f) + (m_pObject->GetModelIndex() == MI_PICKUP_BODYARMOUR && player->m_fArmour > CWorld::Players[playerId].m_nMaxArmour - 0.5f) + || (m_pObject->GetModelIndex() == MI_PICKUP_HEALTH && player->m_fHealth > CWorld::Players[playerId].m_nMaxHealth - 0.5f) || (m_pObject->GetModelIndex() == MI_PICKUP_BRIBE && player->m_pWanted->m_nWantedLevel == 0) || (m_pObject->GetModelIndex() == MI_PICKUP_KILLFRENZY && (CTheScripts::IsPlayerOnAMission() || CDarkel::FrenzyOnGoing() || !CGame::nastyGame)); return !cannotBePickedUp; @@ -190,7 +233,7 @@ CPickup::Update(CPlayerPed *player, CVehicle *vehicle, int playerId) } // if we didn't then we've got nothing to do - if (isPickupTouched && CanBePickedUp(player)) { + if (isPickupTouched && CanBePickedUp(player, playerId)) { CPad::GetPad(0)->StartShake(120, 100); switch (m_eType) { @@ -380,6 +423,30 @@ CPickups::Init(void) CollectedPickUpIndex = 0; } +// --MIAMI: Done +bool +CPickups::TestForPickupsInBubble(CVector pos, float range) +{ + for (int i = 0; i < NUMPICKUPS; i++) { + if ((aPickUps[i].m_vecPos - pos).Magnitude() < range) + return true; + } + return false; +} + +// --MIAMI: Done +bool +CPickups::TryToMerge_WeaponType(CVector pos, eWeaponType weapon, uint8 type, uint32 quantity, bool unused) { + for (int i = 0; i < NUMPICKUPS; i++) { + if (aPickUps[i].m_eType == type && aPickUps[i].m_eModelIndex == ModelForWeapon(weapon)) + if ((aPickUps[i].m_vecPos - pos).Magnitude() < 7.5f) { + aPickUps[i].m_nQuantity += quantity; + return true; + } + } + return false; +} + bool CPickups::IsPickUpPickedUp(int32 pickupId) { @@ -430,14 +497,14 @@ CPickups::GivePlayerGoodiesWithPickUpMI(int16 modelIndex, int playerIndex) DMAudio.PlayFrontEndSound(SOUND_PICKUP_ADRENALINE, 0); return true; } else if (modelIndex == MI_PICKUP_BODYARMOUR) { - player->m_fArmour = 100.0f; + player->m_fArmour = CWorld::Players[playerIndex].m_nMaxArmour; DMAudio.PlayFrontEndSound(SOUND_PICKUP_ARMOUR, 0); return true; } else if (modelIndex == MI_PICKUP_INFO) { DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0); return true; } else if (modelIndex == MI_PICKUP_HEALTH) { - player->m_fHealth = 100.0f; + player->m_fHealth = CWorld::Players[playerIndex].m_nMaxHealth; DMAudio.PlayFrontEndSound(SOUND_PICKUP_HEALTH, 0); return true; } else if (modelIndex == MI_PICKUP_BONUS) { @@ -486,7 +553,7 @@ CPickups::RemovePickUp(int32 pickupIndex) } int32 -CPickups::GenerateNewOne(CVector pos, uint32 modelIndex, uint8 type, uint32 quantity) +CPickups::GenerateNewOne(CVector pos, uint32 modelIndex, uint8 type, uint32 quantity, uint32 rate, bool highPriority, wchar* pText) { bool bFreeFound = false; int32 slot = 0; @@ -561,53 +628,22 @@ CPickups::GetNewUniquePickupIndex(int32 slot) return slot | (aPickUps[slot].m_nIndex << 16); } +// --MIAMI: Done int32 CPickups::ModelForWeapon(eWeaponType weaponType) { - switch (weaponType) - { - case WEAPONTYPE_BASEBALLBAT: return MI_BASEBALL_BAT; - case WEAPONTYPE_COLT45: return MI_COLT; - case WEAPONTYPE_UZI: return MI_UZI; - case WEAPONTYPE_SHOTGUN: return MI_SHOTGUN; - case WEAPONTYPE_AK47: return MI_AK47; - case WEAPONTYPE_M16: return MI_M16; - case WEAPONTYPE_SNIPERRIFLE: return MI_SNIPER; - case WEAPONTYPE_ROCKETLAUNCHER: return MI_ROCKETLAUNCHER; - case WEAPONTYPE_FLAMETHROWER: return MI_FLAMETHROWER; - case WEAPONTYPE_MOLOTOV: return MI_MOLOTOV; - case WEAPONTYPE_GRENADE: return MI_GRENADE; - default: break; - } - return 0; + return CWeaponInfo::GetWeaponInfo(weaponType)->m_nModelId; } +// --MIAMI: Done eWeaponType CPickups::WeaponForModel(int32 model) { if (model == MI_PICKUP_BODYARMOUR) return WEAPONTYPE_ARMOUR; - switch (model) - { - case MI_GRENADE: return WEAPONTYPE_GRENADE; - case MI_AK47: return WEAPONTYPE_AK47; - case MI_BASEBALL_BAT: return WEAPONTYPE_BASEBALLBAT; - case MI_COLT: return WEAPONTYPE_COLT45; - case MI_MOLOTOV: return WEAPONTYPE_MOLOTOV; - case MI_ROCKETLAUNCHER: return WEAPONTYPE_ROCKETLAUNCHER; - case MI_SHOTGUN: return WEAPONTYPE_SHOTGUN; - case MI_SNIPER: return WEAPONTYPE_SNIPERRIFLE; - case MI_UZI: return WEAPONTYPE_UZI; - case MI_MISSILE: return WEAPONTYPE_UNARMED; - case MI_M16: return WEAPONTYPE_M16; - case MI_FLAMETHROWER: return WEAPONTYPE_FLAMETHROWER; - } - return WEAPONTYPE_UNARMED; -} - -int32 -CPickups::FindColourIndexForWeaponMI(int32 model) -{ - return WeaponForModel(model) - 1; + if (model == MI_PICKUP_HEALTH) return WEAPONTYPE_HEALTH; + if (model == MI_PICKUP_ADRENALINE) return WEAPONTYPE_ARMOUR; + if (model == -1) return WEAPONTYPE_UNARMED; + return (eWeaponType)((CWeaponModelInfo*)CModelInfo::GetModelInfo(model))->GetWeaponInfo(); } void @@ -685,15 +721,15 @@ CPickups::DoPickUpEffects(CEntity *entity) int16 colorId; if (entity->GetModelIndex() == MI_PICKUP_ADRENALINE || entity->GetModelIndex() == MI_PICKUP_CAMERA) - colorId = 11; + colorId = WEAPONTYPE_LAST_WEAPONTYPE; else if (entity->GetModelIndex() == MI_PICKUP_BODYARMOUR || entity->GetModelIndex() == MI_PICKUP_BRIBE) - colorId = 12; + colorId = WEAPONTYPE_LAST_WEAPONTYPE + 1; else if (entity->GetModelIndex() == MI_PICKUP_INFO || entity->GetModelIndex() == MI_PICKUP_KILLFRENZY) - colorId = 13; + colorId = WEAPONTYPE_LAST_WEAPONTYPE + 2; else if (entity->GetModelIndex() == MI_PICKUP_HEALTH || entity->GetModelIndex() == MI_PICKUP_BONUS) - colorId = 14; + colorId = WEAPONTYPE_LAST_WEAPONTYPE + 3; else - colorId = FindColourIndexForWeaponMI(entity->GetModelIndex()); + colorId = WeaponForModel(entity->GetModelIndex()); assert(colorId >= 0); @@ -1126,45 +1162,6 @@ CPacManPickups::Update() void CPacManPickups::GeneratePMPickUps(CVector pos, float scrambleMult, int16 count, uint8 type) { - int i = 0; - while (count > 0) { - while (aPMPickUps[i].m_eType != PACMAN_NONE) - i++; - - bool bPickupCreated = false; - while (!bPickupCreated) { - CVector newPos = pos; - CColPoint colPoint; - CEntity *pRoad; - uint16 nRand = CGeneral::GetRandomNumber(); - newPos.x += ((nRand & 0xFF) - 128) * scrambleMult / 128.0f; - newPos.y += (((nRand >> 8) & 0xFF) - 128) * scrambleMult / 128.0f; - newPos.z = 1000.0f; - if (CWorld::ProcessVerticalLine(newPos, -1000.0f, colPoint, pRoad, true, false, false, false, true, false, nil) && pRoad->IsBuilding() && ((CBuilding*)pRoad)->GetIsATreadable()) { - newPos.z = 0.7f + colPoint.point.z; - aPMPickUps[i].m_eType = type; - aPMPickUps[i].m_vecPosn = newPos; - CObject *obj = new CObject(MI_BULLION, true); - if (obj != nil) { - obj->ObjectCreatedBy = MISSION_OBJECT; - obj->SetPosition(aPMPickUps[i].m_vecPosn); - obj->SetOrientation(0.0f, 0.0f, -HALFPI); - obj->GetMatrix().UpdateRW(); - obj->UpdateRwFrame(); - - obj->bAffectedByGravity = false; - obj->bExplosionProof = true; - obj->bUsesCollision = false; - obj->bIsPickup = false; - CWorld::Add(obj); - } - aPMPickUps[i].m_pObject = obj; - bPickupCreated = true; - } - } - count--; - } - bPMActive = true; } // diablo porn mission pickups @@ -1281,40 +1278,6 @@ static const CVector aRacePoints1[] = { void CPacManPickups::GeneratePMPickUpsForRace(int32 race) { - const CVector *pPos = nil; - int i = 0; - - if (race == 0) pPos = aRacePoints1; // there's only one available - assert(pPos != nil); - - while (!pPos->IsZero()) { - while (aPMPickUps[i].m_eType != PACMAN_NONE) - i++; - - aPMPickUps[i].m_eType = PACMAN_RACE; - aPMPickUps[i].m_vecPosn = *(pPos++); - if (race == 0) { - CObject* obj = new CObject(MI_DONKEYMAG, true); - if (obj != nil) { - obj->ObjectCreatedBy = MISSION_OBJECT; - - obj->SetPosition(aPMPickUps[i].m_vecPosn); - obj->SetOrientation(0.0f, 0.0f, -HALFPI); - obj->GetMatrix().UpdateRW(); - obj->UpdateRwFrame(); - - obj->bAffectedByGravity = false; - obj->bExplosionProof = true; - obj->bUsesCollision = false; - obj->bIsPickup = false; - - CWorld::Add(obj); - } - aPMPickUps[i].m_pObject = obj; - } else - aPMPickUps[i].m_pObject = nil; - } - bPMActive = true; } void diff --git a/src/control/Pickups.h b/src/control/Pickups.h index b05f5db7..810f3dff 100644 --- a/src/control/Pickups.h +++ b/src/control/Pickups.h @@ -8,6 +8,7 @@ enum ePickupType : uint8 PICKUP_ON_STREET, PICKUP_ONCE, PICKUP_ONCE_TIMEOUT, + PICKUP_ONCE_TIMEOUT_SLOW, PICKUP_COLLECTABLE1, PICKUP_IN_SHOP_OUT_OF_STOCK, PICKUP_MONEY, @@ -18,6 +19,9 @@ enum ePickupType : uint8 PICKUP_FLOATINGPACKAGE, PICKUP_FLOATINGPACKAGE_FLOATING, PICKUP_ON_STREET_SLOW, + PICKUP_ASSET_REVENUE, + PICKUP_PROPERTY_LOCKED, + PICKUP_PROPERTY_FORSALE, PICKUP_NUMOFTYPES }; @@ -42,7 +46,7 @@ public: bool Update(CPlayerPed *player, CVehicle *vehicle, int playerId); private: bool IsMine() { return m_eType >= PICKUP_MINE_INACTIVE && m_eType <= PICKUP_FLOATINGPACKAGE_FLOATING; } - inline bool CanBePickedUp(CPlayerPed *player); + inline bool CanBePickedUp(CPlayerPed *player, int playerId); void RemoveKeepType(); void Remove(); }; @@ -73,7 +77,7 @@ public: static void DoMoneyEffects(CEntity *ent); static void DoMineEffects(CEntity *ent); static void DoPickUpEffects(CEntity *ent); - static int32 GenerateNewOne(CVector pos, uint32 modelIndex, uint8 type, uint32 quantity); + static int32 GenerateNewOne(CVector pos, uint32 modelIndex, uint8 type, uint32 quantity, uint32 rate = 0, bool highPriority = false, wchar* pText = nil); static int32 GenerateNewOne_WeaponType(CVector pos, eWeaponType weaponType, uint8 type, uint32 quantity); static void RemovePickUp(int32 pickupIndex); static void RemoveAllFloatingPickups(); @@ -81,11 +85,12 @@ public: static bool IsPickUpPickedUp(int32 pickupId); static int32 ModelForWeapon(eWeaponType weaponType); static enum eWeaponType WeaponForModel(int32 model); - static int32 FindColourIndexForWeaponMI(int32 model); static int32 GetActualPickupIndex(int32 index); static int32 GetNewUniquePickupIndex(int32 slot); static void PassTime(uint32 time); static bool GivePlayerGoodiesWithPickUpMI(int16 modelIndex, int playerIndex); + static bool TestForPickupsInBubble(CVector pos, float range); + static bool TryToMerge_WeaponType(CVector pos, eWeaponType weapon, uint8 type, uint32 quantity, bool unused); static void Load(uint8 *buf, uint32 size); static void Save(uint8 *buf, uint32 *size); @@ -99,7 +104,7 @@ public: }; extern uint16 AmmoForWeapon[20]; -extern uint16 AmmoForWeapon_OnStreet[20]; +extern uint16 AmmoForWeapon_OnStreet[WEAPONTYPE_TOTALWEAPONS]; extern uint16 CostOfWeapon[20]; enum ePacmanPickupType diff --git a/src/control/Record.cpp b/src/control/Record.cpp index d086543f..5e6c7cdb 100644 --- a/src/control/Record.cpp +++ b/src/control/Record.cpp @@ -11,513 +11,97 @@ #include "World.h" uint16 CRecordDataForGame::RecordingState; -uint8* CRecordDataForGame::pDataBuffer; -uint8* CRecordDataForGame::pDataBufferPointer; -int CRecordDataForGame::FId; -tGameBuffer CRecordDataForGame::pDataBufferForFrame; - -#define MEMORY_FOR_GAME_RECORD (150000) void CRecordDataForGame::Init(void) { RecordingState = STATE_NONE; - delete[] pDataBuffer; - pDataBufferPointer = nil; - pDataBuffer = nil; -#ifndef GTA_PS2 // this stuff is not present on PS2 - FId = CFileMgr::OpenFile("playback.dat", "r"); - if (FId <= 0) { - if ((FId = CFileMgr::OpenFile("record.dat", "r")) <= 0) - RecordingState = STATE_NONE; - else { - CFileMgr::CloseFile(FId); - FId = CFileMgr::OpenFileForWriting("record.dat"); - RecordingState = STATE_RECORD; - } - } - else { - RecordingState = STATE_PLAYBACK; - } - if (RecordingState == STATE_PLAYBACK) { - pDataBufferPointer = new uint8[MEMORY_FOR_GAME_RECORD]; - pDataBuffer = pDataBufferPointer; - pDataBuffer[CFileMgr::Read(FId, (char*)pDataBufferPointer, MEMORY_FOR_GAME_RECORD) + 8] = (uint8)-1; - CFileMgr::CloseFile(FId); - } -#else - RecordingState = STATE_NONE; // second time to make sure -#endif } void CRecordDataForGame::SaveOrRetrieveDataForThisFrame(void) { - switch (RecordingState) { - case STATE_RECORD: - { - pDataBufferForFrame.m_fTimeStep = CTimer::GetTimeStep(); - pDataBufferForFrame.m_nTimeInMilliseconds = CTimer::GetTimeInMilliseconds(); - pDataBufferForFrame.m_nSizeOfPads[0] = 0; - pDataBufferForFrame.m_nSizeOfPads[1] = 0; - pDataBufferForFrame.m_nChecksum = CalcGameChecksum(); - uint8* pController1 = PackCurrentPadValues(pDataBufferForFrame.m_ControllerBuffer, &CPad::GetPad(0)->OldState, &CPad::GetPad(0)->NewState); - pDataBufferForFrame.m_nSizeOfPads[0] = (pController1 - pDataBufferForFrame.m_ControllerBuffer) / 2; - uint8* pController2 = PackCurrentPadValues(pController1, &CPad::GetPad(1)->OldState, &CPad::GetPad(1)->NewState); - pDataBufferForFrame.m_nSizeOfPads[1] = (pController2 - pController1) / 2; - uint8* pEndPtr = pController2; - if ((pDataBufferForFrame.m_nSizeOfPads[0] + pDataBufferForFrame.m_nSizeOfPads[1]) & 1) - pEndPtr += 2; - CFileMgr::Write(FId, (char*)&pDataBufferForFrame, pEndPtr - (uint8*)&pDataBufferForFrame); - break; - } - case STATE_PLAYBACK: - if (pDataBufferPointer[8] == (uint8)-1) - CPad::GetPad(0)->NewState.Clear(); - else { - tGameBuffer* pData = (tGameBuffer*)pDataBufferPointer; - CTimer::SetTimeInMilliseconds(pData->m_nTimeInMilliseconds); - CTimer::SetTimeStep(pData->m_fTimeStep); - uint8 size1 = pData->m_nSizeOfPads[0]; - uint8 size2 = pData->m_nSizeOfPads[1]; - pDataBufferPointer = (uint8*)&pData->m_ControllerBuffer; - pDataBufferPointer = UnPackCurrentPadValues(pDataBufferPointer, size1, &CPad::GetPad(0)->NewState); - pDataBufferPointer = UnPackCurrentPadValues(pDataBufferPointer, size2, &CPad::GetPad(1)->NewState); - if ((size1 + size2) & 1) - pDataBufferPointer += 2; - if (pData->m_nChecksum != CalcGameChecksum()) - printf("Playback out of sync\n"); - } - } } -#define PROCESS_BUTTON_STATE_STORE(buf, os, ns, field, id) \ - do { \ - if (os->field != ns->field){ \ - *buf++ = id; \ - *buf++ = ns->field; \ - } \ - } while (0); - uint8* CRecordDataForGame::PackCurrentPadValues(uint8* buf, CControllerState* os, CControllerState* ns) { - PROCESS_BUTTON_STATE_STORE(buf, os, ns, LeftStickX, 0); - PROCESS_BUTTON_STATE_STORE(buf, os, ns, LeftStickY, 1); - PROCESS_BUTTON_STATE_STORE(buf, os, ns, RightStickX, 2); - PROCESS_BUTTON_STATE_STORE(buf, os, ns, RightStickY, 3); - PROCESS_BUTTON_STATE_STORE(buf, os, ns, LeftShoulder1, 4); - PROCESS_BUTTON_STATE_STORE(buf, os, ns, LeftShoulder2, 5); - PROCESS_BUTTON_STATE_STORE(buf, os, ns, RightShoulder1, 6); - PROCESS_BUTTON_STATE_STORE(buf, os, ns, RightShoulder2, 7); - PROCESS_BUTTON_STATE_STORE(buf, os, ns, DPadUp, 8); - PROCESS_BUTTON_STATE_STORE(buf, os, ns, DPadDown, 9); - PROCESS_BUTTON_STATE_STORE(buf, os, ns, DPadLeft, 10); - PROCESS_BUTTON_STATE_STORE(buf, os, ns, DPadRight, 11); - PROCESS_BUTTON_STATE_STORE(buf, os, ns, Start, 12); - PROCESS_BUTTON_STATE_STORE(buf, os, ns, Select, 13); - PROCESS_BUTTON_STATE_STORE(buf, os, ns, Square, 14); - PROCESS_BUTTON_STATE_STORE(buf, os, ns, Triangle, 15); - PROCESS_BUTTON_STATE_STORE(buf, os, ns, Cross, 16); - PROCESS_BUTTON_STATE_STORE(buf, os, ns, Circle, 17); - PROCESS_BUTTON_STATE_STORE(buf, os, ns, LeftShock, 18); - PROCESS_BUTTON_STATE_STORE(buf, os, ns, RightShock, 19); - return buf; + return nil; } -#undef PROCESS_BUTTON_STATE_STORE - -#define PROCESS_BUTTON_STATE_RESTORE(buf, state, field, id) case id: state->field = *buf++; break; uint8* CRecordDataForGame::UnPackCurrentPadValues(uint8* buf, uint8 total, CControllerState* state) { - for (uint8 i = 0; i < total; i++) { - switch (*buf++) { - PROCESS_BUTTON_STATE_RESTORE(buf, state, LeftStickX, 0); - PROCESS_BUTTON_STATE_RESTORE(buf, state, LeftStickY, 1); - PROCESS_BUTTON_STATE_RESTORE(buf, state, RightStickX, 2); - PROCESS_BUTTON_STATE_RESTORE(buf, state, RightStickY, 3); - PROCESS_BUTTON_STATE_RESTORE(buf, state, LeftShoulder1, 4); - PROCESS_BUTTON_STATE_RESTORE(buf, state, LeftShoulder2, 5); - PROCESS_BUTTON_STATE_RESTORE(buf, state, RightShoulder1, 6); - PROCESS_BUTTON_STATE_RESTORE(buf, state, RightShoulder2, 7); - PROCESS_BUTTON_STATE_RESTORE(buf, state, DPadUp, 8); - PROCESS_BUTTON_STATE_RESTORE(buf, state, DPadDown, 9); - PROCESS_BUTTON_STATE_RESTORE(buf, state, DPadLeft, 10); - PROCESS_BUTTON_STATE_RESTORE(buf, state, DPadRight, 11); - PROCESS_BUTTON_STATE_RESTORE(buf, state, Start, 12); - PROCESS_BUTTON_STATE_RESTORE(buf, state, Select, 13); - PROCESS_BUTTON_STATE_RESTORE(buf, state, Square, 14); - PROCESS_BUTTON_STATE_RESTORE(buf, state, Triangle, 15); - PROCESS_BUTTON_STATE_RESTORE(buf, state, Cross, 16); - PROCESS_BUTTON_STATE_RESTORE(buf, state, Circle, 17); - PROCESS_BUTTON_STATE_RESTORE(buf, state, LeftShock, 18); - PROCESS_BUTTON_STATE_RESTORE(buf, state, RightShock, 19); - } - } - return buf; + return nil; } -#undef PROCESS_BUTTON_STATE_RESTORE - uint16 CRecordDataForGame::CalcGameChecksum(void) { - uint32 checksum = 0; - int i = CPools::GetPedPool()->GetSize(); - while (i--) { - CPed* pPed = CPools::GetPedPool()->GetSlot(i); - if (!pPed) - continue; - checksum ^= pPed->GetModelIndex() ^ *(uint32*)&pPed->GetPosition().z ^ *(uint32*)&pPed->GetPosition().y ^ *(uint32*)&pPed->GetPosition().x; - } - i = CPools::GetVehiclePool()->GetSize(); - while (i--) { - CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i); - if (!pVehicle) - continue; - checksum ^= pVehicle->GetModelIndex() ^ *(uint32*)&pVehicle->GetPosition().z ^ *(uint32*)&pVehicle->GetPosition().y ^ *(uint32*)&pVehicle->GetPosition().x; - } - return checksum ^ checksum >> 16; + return 0; } uint8 CRecordDataForChase::Status; -int CRecordDataForChase::PositionChanges; -uint8 CRecordDataForChase::CurrentCar; -CAutomobile* CRecordDataForChase::pChaseCars[NUM_CHASE_CARS]; -uint32 CRecordDataForChase::AnimStartTime; -float CRecordDataForChase::AnimTime; -CCarStateEachFrame* CRecordDataForChase::pBaseMemForCar[NUM_CHASE_CARS]; -float CRecordDataForChase::TimeMultiplier; -int CRecordDataForChase::FId2; - -#define CHASE_SCENE_LENGTH_IN_SECONDS (80) -#define CHASE_SCENE_FRAMES_PER_SECOND (15) // skipping every second frame -#define CHASE_SCENE_FRAMES_IN_RECORDING (CHASE_SCENE_LENGTH_IN_SECONDS * CHASE_SCENE_FRAMES_PER_SECOND) -#define CHASE_SCENE_LENGTH_IN_FRAMES (CHASE_SCENE_FRAMES_IN_RECORDING * 2) void CRecordDataForChase::Init(void) { Status = STATE_NONE; - PositionChanges = 0; - CurrentCar = 0; - for (int i = 0; i < NUM_CHASE_CARS; i++) - pChaseCars[i] = nil; - AnimStartTime = 0; } void CRecordDataForChase::SaveOrRetrieveDataForThisFrame(void) { - switch (Status) { - case STATE_NONE: - return; - case STATE_RECORD: - { - if ((CTimer::GetFrameCounter() & 1) == 0) - StoreInfoForCar(pChaseCars[CurrentCar], &pBaseMemForCar[CurrentCar][CTimer::GetFrameCounter() / 2]); - if (CTimer::GetFrameCounter() < CHASE_SCENE_LENGTH_IN_FRAMES * 2) - return; - CFileMgr::SetDir("data\\paths"); - sprintf(gString, "chase%d.dat", CurrentCar); - int fid = CFileMgr::OpenFileForWriting(gString); - uint32 fs = CHASE_SCENE_LENGTH_IN_FRAMES * sizeof(CCarStateEachFrame); - printf("FileSize:%d\n", fs); - CFileMgr::Write(fid, (char*)pBaseMemForCar[CurrentCar], fs); - CFileMgr::CloseFile(fid); - CFileMgr::SetDir(""); - sprintf(gString, "car%d.max", CurrentCar); - int fid2 = CFileMgr::OpenFileForWriting(gString); - for (int i = 0; i < CHASE_SCENE_FRAMES_IN_RECORDING; i++) { - // WTF? Was it ever used? -#ifdef FIX_BUGS - CCarStateEachFrame* pState = pBaseMemForCar[CurrentCar]; -#else - CCarStateEachFrame* pState = (CCarStateEachFrame*)pChaseCars[CurrentCar]; -#endif - CVector right = CVector(pState->rightX, pState->rightY, pState->rightZ) / INT8_MAX; - CVector forward = CVector(pState->forwardX, pState->forwardY, pState->forwardZ) / INT8_MAX; - CVector up = CrossProduct(right, forward); - sprintf(gString, "%f %f %f\n", pState->pos.x, pState->pos.y, pState->pos.z); - CFileMgr::Write(fid2, gString, strlen(gString) - 1); - sprintf(gString, "%f %f %f\n", right.x, right.y, right.z); - CFileMgr::Write(fid2, gString, strlen(gString) - 1); - sprintf(gString, "%f %f %f\n", forward.x, forward.y, forward.z); - CFileMgr::Write(fid2, gString, strlen(gString) - 1); - sprintf(gString, "%f %f %f\n", up.x, up.y, up.z); - CFileMgr::Write(fid2, gString, strlen(gString) - 1); - } - CFileMgr::CloseFile(fid2); - } - case STATE_PLAYBACK: - case STATE_PLAYBACK_BEFORE_RECORDING: - case STATE_PLAYBACK_INIT: - break; - } } -struct tCoors { - CVector pos; - float angle; -}; - -// I guess developer was filling this with actual data before running the game -tCoors NewCoorsForRecordedCars[7]; - void CRecordDataForChase::SaveOrRetrieveCarPositions(void) { - switch (Status) { - case STATE_NONE: - return; - case STATE_RECORD: - case STATE_PLAYBACK_BEFORE_RECORDING: - for (int i = 0; i < NUM_CHASE_CARS; i++) { - if (i != CurrentCar && CTimer::GetFrameCounter()) { - RestoreInfoForCar(pChaseCars[i], &pBaseMemForCar[i][CTimer::GetFrameCounter() / 2], false); - pChaseCars[i]->GetMatrix().UpdateRW(); - pChaseCars[i]->UpdateRwFrame(); - } - } - if (Status == STATE_PLAYBACK_BEFORE_RECORDING && CTimer::GetFrameCounter()) { - RestoreInfoForCar(pChaseCars[CurrentCar], &pBaseMemForCar[CurrentCar][CTimer::GetFrameCounter() / 2], false); - pChaseCars[CurrentCar]->GetMatrix().UpdateRW(); - pChaseCars[CurrentCar]->UpdateRwFrame(); - } - if (CPad::GetPad(0)->GetLeftShockJustDown() && CPad::GetPad(0)->GetRightShockJustDown()) { - if (!CPad::GetPad(0)->GetRightShockJustDown()) { - pChaseCars[CurrentCar]->SetPosition(NewCoorsForRecordedCars[PositionChanges].pos); - pChaseCars[CurrentCar]->SetMoveSpeed(0.0f, 0.0f, 0.0f); - pChaseCars[CurrentCar]->GetMatrix().SetRotateZOnly(DEGTORAD(NewCoorsForRecordedCars[PositionChanges].angle)); - ++PositionChanges; - } - if (Status == STATE_PLAYBACK_BEFORE_RECORDING) { - Status = STATE_RECORD; - pChaseCars[CurrentCar]->SetStatus(STATUS_PLAYER); - } - } - break; - case STATE_PLAYBACK_INIT: - Status = STATE_PLAYBACK; - break; - case STATE_PLAYBACK: - { - TimeMultiplier += CTimer::GetTimeStepNonClippedInSeconds(); - float EndOfFrameTime = CHASE_SCENE_FRAMES_PER_SECOND * Min(CHASE_SCENE_LENGTH_IN_SECONDS, TimeMultiplier); - for (int i = 0; i < NUM_CHASE_CARS; i++) { - if (!pBaseMemForCar[i]) - continue; - if (!pChaseCars[i]) - continue; - if (EndOfFrameTime < CHASE_SCENE_FRAMES_IN_RECORDING - 1) { - int FlooredEOFTime = EndOfFrameTime; - RestoreInfoForCar(pChaseCars[i], &pBaseMemForCar[i][FlooredEOFTime], false); - CMatrix tmp; - float dp = EndOfFrameTime - FlooredEOFTime; - RestoreInfoForMatrix(tmp, &pBaseMemForCar[i][FlooredEOFTime + 1]); - pChaseCars[i]->GetRight() += (tmp.GetRight() - pChaseCars[i]->GetRight()) * dp; - pChaseCars[i]->GetForward() += (tmp.GetForward() - pChaseCars[i]->GetForward()) * dp; - pChaseCars[i]->GetUp() += (tmp.GetUp() - pChaseCars[i]->GetUp()) * dp; - pChaseCars[i]->GetMatrix().GetPosition() += (tmp.GetPosition() - pChaseCars[i]->GetPosition()) * dp; - } - else{ - RestoreInfoForCar(pChaseCars[i], &pBaseMemForCar[i][CHASE_SCENE_FRAMES_IN_RECORDING - 1], true); - if (i == 0) - pChaseCars[i]->GetMatrix().GetPosition().z += 0.2f; - } - pChaseCars[i]->GetMatrix().UpdateRW(); - pChaseCars[i]->UpdateRwFrame(); - pChaseCars[i]->RemoveAndAdd(); - } - break; - } - } } void CRecordDataForChase::StoreInfoForCar(CAutomobile* pCar, CCarStateEachFrame* pState) { - pState->rightX = INT8_MAX * pCar->GetRight().x; - pState->rightY = INT8_MAX * pCar->GetRight().y; - pState->rightZ = INT8_MAX * pCar->GetRight().z; - pState->forwardX = INT8_MAX * pCar->GetForward().x; - pState->forwardY = INT8_MAX * pCar->GetForward().y; - pState->forwardZ = INT8_MAX * pCar->GetForward().z; - pState->pos = pCar->GetPosition(); - pState->velX = 0.5f * INT16_MAX * pCar->GetMoveSpeed().x; - pState->velY = 0.5f * INT16_MAX * pCar->GetMoveSpeed().y; - pState->velZ = 0.5f * INT16_MAX * pCar->GetMoveSpeed().z; - pState->wheel = 20 * pCar->m_fSteerAngle; - pState->gas = 100 * pCar->m_fGasPedal; - pState->brake = 100 * pCar->m_fBrakePedal; - pState->handbrake = pCar->bIsHandbrakeOn; } void CRecordDataForChase::RestoreInfoForMatrix(CMatrix& matrix, CCarStateEachFrame* pState) { - matrix.GetRight() = CVector(pState->rightX, pState->rightY, pState->rightZ) / INT8_MAX; - matrix.GetForward() = CVector(pState->forwardX, pState->forwardY, pState->forwardZ) / INT8_MAX; - matrix.GetUp() = CrossProduct(matrix.GetRight(), matrix.GetForward()); - matrix.GetPosition() = pState->pos; } void CRecordDataForChase::RestoreInfoForCar(CAutomobile* pCar, CCarStateEachFrame* pState, bool stop) { - CVector oldPos = pCar->GetPosition(); - RestoreInfoForMatrix(pCar->GetMatrix(), pState); - pCar->SetMoveSpeed(CVector(pState->velX, pState->velY, pState->velZ) / INT16_MAX / 0.5f); - pCar->SetTurnSpeed(0.0f, 0.0f, 0.0f); - pCar->m_fSteerAngle = pState->wheel / 20.0f; - pCar->m_fGasPedal = pState->gas / 100.0f; - pCar->m_fBrakePedal = pState->brake / 100.0f; - pCar->bIsHandbrakeOn = pState->handbrake; - if ((oldPos - pCar->GetPosition()).Magnitude() > 15.0f) { - if (pCar == pChaseCars[14]) { - pCar->m_currentColour1 = 58; - pCar->m_currentColour2 = 1; - } - else - pCar->GetModelInfo()->ChooseVehicleColour(pCar->m_currentColour1, pCar->m_currentColour2); - } - pCar->m_fHealth = Min(pCar->m_fHealth, 500.0f); - if (stop) { - pCar->m_fGasPedal = 0.0f; - pCar->m_fBrakePedal = 0.0f; - pCar->SetMoveSpeed(0.0f, 0.0f, 0.0f); - pCar->bIsHandbrakeOn = false; - } } void CRecordDataForChase::ProcessControlCars(void) { - if (Status != STATE_PLAYBACK) - return; - for (int i = 0; i < NUM_CHASE_CARS; i++) { - if (pChaseCars[i]) - pChaseCars[i]->ProcessControl(); - } } -#if (defined(GTA_PS2) || defined(FIX_BUGS)) bool CRecordDataForChase::ShouldThisPadBeLeftAlone(uint8 pad) { - // may be wrong - if (Status == STATE_NONE || Status == STATE_PLAYBACK) - return false; - return pad != 0; + return false; } -#endif void CRecordDataForChase::GiveUsACar(int32 mi, CVector pos, float angle, CAutomobile** ppCar, uint8 colour1, uint8 colour2) { - CStreaming::RequestModel(mi, STREAMFLAGS_DEPENDENCY); - CStreaming::LoadAllRequestedModels(false); - if (!CStreaming::HasModelLoaded(mi)) - return; - CAutomobile* pCar = new CAutomobile(mi, MISSION_VEHICLE); - pCar->SetPosition(pos); - pCar->SetStatus(STATUS_PLAYER_PLAYBACKFROMBUFFER); - pCar->GetMatrix().SetRotateZOnly(DEGTORAD(angle)); - pCar->pDriver = nil; - pCar->m_currentColour1 = colour1; - pCar->m_currentColour2 = colour2; - CWorld::Add(pCar); - *ppCar = pCar; } void RemoveUnusedCollision(void) { - static const char* dontDeleteArray[] = { - "rd_SrRoad2A50", "rd_SrRoad2A20", "rd_CrossRda1w22", "rd_CrossRda1rw22", - "road_broadway02", "road_broadway01", "com_21way5", "com_21way50", - "cm1waycrosscom", "com_21way20", "com_21way10", "road_broadway04", - "com_rvroads52", "com_roadsrv", "com_roadkb23", "com_roadkb22" - }; - for (int i = 0; i < ARRAY_SIZE(dontDeleteArray); i++) - CModelInfo::GetModelInfo(dontDeleteArray[i], nil)->GetColModel()->level = LEVEL_NONE; - CModelInfo::RemoveColModelsFromOtherLevels(LEVEL_NONE); - for (int i = 0; i < ARRAY_SIZE(dontDeleteArray); i++) - CModelInfo::GetModelInfo(dontDeleteArray[i], nil)->GetColModel()->level = LEVEL_COMMERCIAL; } void CRecordDataForChase::StartChaseScene(float startTime) { - char filename[28]; - SetUpCarsForChaseScene(); - Status = STATE_PLAYBACK; - AnimTime = startTime; - AnimStartTime = CTimer::GetTimeInMilliseconds(); - RemoveUnusedCollision(); - CStreaming::RemoveIslandsNotUsed(LEVEL_SUBURBAN); - CGame::TidyUpMemory(true, true); - CStreaming::ImGonnaUseStreamingMemory(); - CFileMgr::SetDir("data\\paths"); - for (int i = 0; i < NUM_CHASE_CARS; i++) { - if (!pChaseCars[i]) { - pBaseMemForCar[i] = nil; - continue; - } - sprintf(filename, "chase%d.dat", i); - FId2 = CFileMgr::OpenFile(filename, "rb"); - if (FId2 <= 0) { - pBaseMemForCar[i] = nil; - continue; - } - pBaseMemForCar[i] = new CCarStateEachFrame[CHASE_SCENE_FRAMES_IN_RECORDING]; - for (int j = 0; j < CHASE_SCENE_FRAMES_IN_RECORDING; j++) { - CFileMgr::Read(FId2, (char*)&pBaseMemForCar[i][j], sizeof(CCarStateEachFrame)); - CFileMgr::Seek(FId2, sizeof(CCarStateEachFrame), 1); - } - CFileMgr::CloseFile(FId2); - } - CFileMgr::SetDir(""); - CStreaming::IHaveUsedStreamingMemory(); - TimeMultiplier = 0.0f; } void CRecordDataForChase::CleanUpChaseScene(void) { - if (Status != STATE_PLAYBACK_INIT && Status != STATE_PLAYBACK) - return; - Status = STATE_NONE; - CleanUpCarsForChaseScene(); - for (int i = 0; i < NUM_CHASE_CARS; i++) { - if (pBaseMemForCar[i]) { - delete[] pBaseMemForCar[i]; - pBaseMemForCar[i] = nil; - } - } } void CRecordDataForChase::SetUpCarsForChaseScene(void) { - GiveUsACar(MI_POLICE, CVector(273.54221f, -1167.1907f, 24.880601f), 63.0f, &pChaseCars[0], 2, 1); - GiveUsACar(MI_ENFORCER, CVector(231.1783f, -1388.8322f, 25.978201f), 90.0f, &pChaseCars[1], 2, 1); - GiveUsACar(MI_TAXI, CVector(184.3156f, -1473.251f, 25.978201f), 0.0f, &pChaseCars[4], 6, 6); - GiveUsACar(MI_CHEETAH, CVector(173.8868f, -1377.6514f, 25.978201f), 0.0f, &pChaseCars[6], 4, 5); - GiveUsACar(MI_STINGER, CVector(102.5946f, -943.93628f, 25.9781f), 270.0f, &pChaseCars[7], 53, 53); - GiveUsACar(MI_CHEETAH, CVector(-177.7157f, -862.18652f, 25.978201f), 155.0f, &pChaseCars[10], 41, 1); - GiveUsACar(MI_STINGER, CVector(-170.56979f, -889.02362f, 25.978201f), 154.0f, &pChaseCars[11], 10, 10); - GiveUsACar(MI_KURUMA, CVector(402.60809f, -917.49628f, 37.381001f), 90.0f, &pChaseCars[14], 34, 1); - GiveUsACar(MI_TAXI, CVector(-33.496201f, -938.4563f, 25.9781f), 266.0f, &pChaseCars[16], 6, 6); - GiveUsACar(MI_KURUMA, CVector(49.363098f, -987.60498f, 25.9781f), 0.0f, &pChaseCars[18], 51, 1); - GiveUsACar(MI_TAXI, CVector(179.0049f, -1154.6686f, 25.9781f), 0.0f, &pChaseCars[19], 6, 76); - GiveUsACar(MI_RUMPO, CVector(-28.9762f, -1031.3367f, 25.990601f), 242.0f, &pChaseCars[2], 1, 75); - GiveUsACar(MI_PATRIOT, CVector(114.1564f, -796.69379f, 24.978201f), 180.0f, &pChaseCars[3], 0, 0); } void CRecordDataForChase::CleanUpCarsForChaseScene(void) { - for (int i = 0; i < NUM_CHASE_CARS; i++) - RemoveCarFromChase(i); } void CRecordDataForChase::RemoveCarFromChase(int32 i) { - if (!pChaseCars[i]) - return; - CWorld::Remove(pChaseCars[i]); - delete pChaseCars[i]; - pChaseCars[i] = nil; } CVehicle* CRecordDataForChase::TurnChaseCarIntoScriptCar(int32 i) { - CVehicle* pVehicle = pChaseCars[i]; - pChaseCars[i] = nil; - pVehicle->SetStatus(STATUS_PHYSICS); - return pVehicle; + return nil; } diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp index 707f1d87..28b999f8 100644 --- a/src/control/Replay.cpp +++ b/src/control/Replay.cpp @@ -17,6 +17,7 @@ #include "ModelInfo.h" #include "Object.h" #include "Pad.h" +#include "PedAttractor.h" #include "Phones.h" #include "Pickups.h" #include "Plane.h" @@ -47,7 +48,7 @@ CAutomobile *CReplay::pBuf1; uint8 *CReplay::pBuf2; CPlayerPed *CReplay::pBuf3; uint8 *CReplay::pBuf4; -CCutsceneHead *CReplay::pBuf5; +CCutsceneObject *CReplay::pBuf5; uint8 *CReplay::pBuf6; CPtrNode *CReplay::pBuf7; uint8 *CReplay::pBuf8; @@ -510,8 +511,12 @@ void CReplay::ProcessPedUpdate(CPed *ped, float interpolation, CAddressInReplayB } RetrievePedAnimation(ped, &pp->anim_state); ped->RemoveWeaponModel(-1); - if (pp->weapon_model != (uint8)-1) - ped->AddWeaponModel(pp->weapon_model); + if (pp->weapon_model != (uint16)-1) { + if (CStreaming::HasModelLoaded(pp->weapon_model)) + ped->AddWeaponModel(pp->weapon_model); + else + CStreaming::RequestModel(pp->weapon_model, 0); + } CWorld::Remove(ped); CWorld::Add(ped); buffer->m_nOffset += sizeof(tPedUpdatePacket); @@ -835,13 +840,14 @@ bool CReplay::PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, flo CStreaming::RequestModel(mi, 0); } else { +// TODO(MIAMI): don't hardcode model indices if (mi == MI_DEADDODO || mi == MI_AIRTRAIN) { new_v = new(vp->index << 8) CPlane(mi, 2); } else if (mi == MI_TRAIN) { new_v = new(vp->index << 8) CTrain(mi, 2); } - else if (mi == MI_CHOPPER || mi == MI_ESCAPE) { + else if (mi == MI_CHOPPER) { new_v = new(vp->index << 8) CHeli(mi, 2); } else if (CModelInfo::IsBoatModel(mi)){ @@ -1115,6 +1121,14 @@ void CReplay::StoreStuffInMem(void) for (int i = 0; i < NUMPLAYERS; i++) nHandleOfPlayerPed[i] = CPools::GetPedPool()->GetIndex(CWorld::Players[i].m_pPed); #endif + int i = CPools::GetPedPool()->GetSize(); + while (--i >= 0) { + CPed* ped = CPools::GetPedPool()->GetSlot(i); + if (!ped) + continue; + if (ped->m_attractor) + GetPedAttractorManager()->DeRegisterPed(ped, ped->m_attractor); + } CPools::GetVehiclePool()->Store(pBuf0, pBuf1); CPools::GetPedPool()->Store(pBuf2, pBuf3); CPools::GetObjectPool()->Store(pBuf4, pBuf5); @@ -1210,6 +1224,16 @@ void CReplay::RestoreStuffFromMem(void) ped->m_audioEntityId = DMAudio.CreateEntity(AUDIOTYPE_PHYSICAL, ped); DMAudio.SetEntityStatus(ped->m_audioEntityId, true); CPopulation::UpdatePedCount((ePedType)ped->m_nPedType, false); + for (int j = 0; j < TOTAL_WEAPON_SLOTS; j++) { + int mi1 = CWeaponInfo::GetWeaponInfo(ped->m_weapons[j].m_eWeaponType)->m_nModelId; + if (mi1 != -1) + CStreaming::RequestModel(mi1, STREAMFLAGS_DEPENDENCY); + int mi2 = CWeaponInfo::GetWeaponInfo(ped->m_weapons[j].m_eWeaponType)->m_nModel2Id; + if (mi2 != -1) + CStreaming::RequestModel(mi2, STREAMFLAGS_DEPENDENCY); + CStreaming::LoadAllRequestedModels(false); + ped->m_weapons[j].Initialise(ped->m_weapons[j].m_eWeaponType, ped->m_weapons[j].m_nAmmoTotal); + } if (ped->m_wepModelID >= 0) ped->AddWeaponModel(ped->m_wepModelID); } diff --git a/src/control/Replay.h b/src/control/Replay.h index 66bee3bf..b369c13d 100644 --- a/src/control/Replay.h +++ b/src/control/Replay.h @@ -176,7 +176,7 @@ class CReplay CStoredAnimationState anim_state; CCompressedMatrixNotAligned matrix; int8 assoc_group_id; - uint8 weapon_model; + uint16 weapon_model; }; VALIDATE_SIZE(tPedUpdatePacket, 40); @@ -214,7 +214,7 @@ private: static uint8* pBuf2; static CPlayerPed* pBuf3; static uint8* pBuf4; - static CCutsceneHead* pBuf5; + static CCutsceneObject* pBuf5; static uint8* pBuf6; static CPtrNode* pBuf7; static uint8* pBuf8; diff --git a/src/control/Restart.cpp b/src/control/Restart.cpp index 5a322cdb..64cabf5d 100644 --- a/src/control/Restart.cpp +++ b/src/control/Restart.cpp @@ -80,13 +80,13 @@ CRestart::FindClosestHospitalRestartPoint(const CVector &pos, CVector *outPos, f return; } - eLevelName curlevel = CTheZones::FindZoneForPoint(pos); + eLevelName curlevel = CTheZones::GetLevelFromPosition(&pos); float fMinDist = 16000000.0f; int closestPoint = NUM_RESTART_POINTS; // find closest point on this level for (int i = 0; i < NumberOfHospitalRestarts; i++) { - if (CTheZones::FindZoneForPoint(HospitalRestartPoints[i]) == (OverrideHospitalLevel != LEVEL_NONE ? OverrideHospitalLevel : curlevel)) { + if (CTheZones::GetLevelFromPosition(&HospitalRestartPoints[i]) == (OverrideHospitalLevel != LEVEL_NONE ? OverrideHospitalLevel : curlevel)) { float dist = (pos - HospitalRestartPoints[i]).MagnitudeSqr(); if (fMinDist >= dist) { fMinDist = dist; @@ -127,13 +127,13 @@ CRestart::FindClosestPoliceRestartPoint(const CVector &pos, CVector *outPos, flo return; } - eLevelName curlevel = CTheZones::FindZoneForPoint(pos); + eLevelName curlevel = CTheZones::GetLevelFromPosition(&pos); float fMinDist = 16000000.0f; int closestPoint = NUM_RESTART_POINTS; // find closest point on this level for (int i = 0; i < NumberOfPoliceRestarts; i++) { - if (CTheZones::FindZoneForPoint(PoliceRestartPoints[i]) == (OverridePoliceStationLevel != LEVEL_NONE ? OverridePoliceStationLevel : curlevel)) { + if (CTheZones::GetLevelFromPosition(&PoliceRestartPoints[i]) == (OverridePoliceStationLevel != LEVEL_NONE ? OverridePoliceStationLevel : curlevel)) { float dist = (pos - PoliceRestartPoints[i]).MagnitudeSqr(); if (fMinDist >= dist) { fMinDist = dist; diff --git a/src/control/RoadBlocks.cpp b/src/control/RoadBlocks.cpp index 572f8134..0261cd4a 100644 --- a/src/control/RoadBlocks.cpp +++ b/src/control/RoadBlocks.cpp @@ -15,22 +15,23 @@ #include "CarCtrl.h" #include "General.h" -#define ROADBLOCKDIST (80.0f) +#define ROADBLOCKDIST (90.0f) int16 CRoadBlocks::NumRoadBlocks; -int16 CRoadBlocks::RoadBlockObjects[NUMROADBLOCKS]; +int16 CRoadBlocks::RoadBlockNodes[NUMROADBLOCKS]; bool CRoadBlocks::InOrOut[NUMROADBLOCKS]; +//--MIAMI: TODO void CRoadBlocks::Init(void) { int i; NumRoadBlocks = 0; - for (i = 0; i < ThePaths.m_numMapObjects; i++) { - if (ThePaths.m_objectFlags[i] & UseInRoadBlock) { + for(i = 0; i < ThePaths.m_numCarPathNodes; i++){ + if(ThePaths.m_pathNodes[i].bUseInRoadBlock && ThePaths.m_pathNodes[i].numLinks == 2){ if (NumRoadBlocks < NUMROADBLOCKS) { InOrOut[NumRoadBlocks] = true; - RoadBlockObjects[NumRoadBlocks] = i; + RoadBlockNodes[NumRoadBlocks] = i; NumRoadBlocks++; } else { #ifndef MASTER @@ -41,6 +42,8 @@ CRoadBlocks::Init(void) } } } + + // TODO(MIAMI): script roadblocks } void @@ -102,6 +105,7 @@ CRoadBlocks::GenerateRoadBlockCopsForCar(CVehicle* pVehicle, int32 roadBlockType } } +//--MIAMI: TODO: implement this void CRoadBlocks::GenerateRoadBlocks(void) { @@ -110,14 +114,14 @@ CRoadBlocks::GenerateRoadBlocks(void) int16 nRoadblockNode = (int16)(NUMROADBLOCKS * frame) / 16; const int16 maxRoadBlocks = (int16)(NUMROADBLOCKS * (frame + 1)) / 16; for (; nRoadblockNode < Min(NumRoadBlocks, maxRoadBlocks); nRoadblockNode++) { - CTreadable *mapObject = ThePaths.m_mapObjects[RoadBlockObjects[nRoadblockNode]]; - CVector2D vecDistance = FindPlayerCoors() - mapObject->GetPosition(); + CVector2D vecDistance = FindPlayerCoors() - ThePaths.m_pathNodes[nRoadblockNode].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; @@ -187,10 +191,13 @@ CRoadBlocks::GenerateRoadBlocks(void) } } } +#endif } } } else { InOrOut[nRoadblockNode] = false; } } + + // TODO(MIAMI): script roadblocks } diff --git a/src/control/RoadBlocks.h b/src/control/RoadBlocks.h index 0f0c1882..439fd6e7 100644 --- a/src/control/RoadBlocks.h +++ b/src/control/RoadBlocks.h @@ -7,7 +7,11 @@ class CRoadBlocks { public: static int16 NumRoadBlocks; +#ifndef MIAMI static int16 RoadBlockObjects[NUMROADBLOCKS]; +#else + static int16 RoadBlockNodes[NUMROADBLOCKS]; +#endif static bool InOrOut[NUMROADBLOCKS]; static void Init(void); diff --git a/src/control/SceneEdit.cpp b/src/control/SceneEdit.cpp index be8c5519..f7dcaa3c 100644 --- a/src/control/SceneEdit.cpp +++ b/src/control/SceneEdit.cpp @@ -88,7 +88,7 @@ static int32 NextValidModelId(int32 mi, int32 step) continue; if (pInfo->GetModelType() == MITYPE_PED #ifdef FIX_BUGS - && !(i >= MI_SPECIAL01 && i <= MI_SPECIAL04) + && !(i >= MI_SPECIAL01 && i <= MI_SPECIAL21) #endif || pInfo->GetModelType() == MITYPE_VEHICLE && #ifdef FIX_BUGS diff --git a/src/control/Script.cpp b/src/control/Script.cpp index e8aa3266..1ea68dd3 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -13,6 +13,7 @@ #include "CarGen.h" #include "CivilianPed.h" #include "Clock.h" +#include "ColStore.h" #include "CopPed.h" #include "Coronas.h" #include "Cranes.h" @@ -53,15 +54,20 @@ #include "Remote.h" #include "Replay.h" #include "Restart.h" +#include "RoadBlocks.h" #include "RpAnimBlend.h" #include "Rubbish.h" +#include "SimpleModelInfo.h" #include "Shadows.h" #include "SpecialFX.h" +#include "Sprite.h" #include "Stats.h" #include "Streaming.h" #include "Text.h" +#include "Timecycle.h" #include "TxdStore.h" #include "User.h" +#include "VisibilityPlugins.h" #include "WaterLevel.h" #include "Weather.h" #include "World.h" @@ -69,7 +75,7 @@ #include "main.h" #define PICKUP_PLACEMENT_OFFSET 0.5f -#define PED_FIND_Z_OFFSET 5.0f +#define PED_FIND_Z_OFFSET 10.0f #define SPHERE_MARKER_R 0 #define SPHERE_MARKER_G 128 @@ -88,13 +94,10 @@ uint8 CTheScripts::ScriptSpace[SIZE_SCRIPT_SPACE]; CRunningScript CTheScripts::ScriptsArray[MAX_NUM_SCRIPTS]; -int32 CTheScripts::BaseBriefIdForContact[MAX_NUM_CONTACTS]; -int32 CTheScripts::OnAMissionForContactFlag[MAX_NUM_CONTACTS]; intro_text_line CTheScripts::IntroTextLines[MAX_NUM_INTRO_TEXT_LINES]; intro_script_rectangle CTheScripts::IntroRectangles[MAX_NUM_INTRO_RECTANGLES]; CSprite2d CTheScripts::ScriptSprites[MAX_NUM_SCRIPT_SRPITES]; script_sphere_struct CTheScripts::ScriptSphereArray[MAX_NUM_SCRIPT_SPHERES]; -tCollectiveData CTheScripts::CollectiveArray[MAX_NUM_COLLECTIVES]; tUsedObject CTheScripts::UsedObjectArray[MAX_NUM_USED_OBJECTS]; int32 CTheScripts::MultiScriptArray[MAX_NUM_MISSION_SCRIPTS]; tBuildingSwap CTheScripts::BuildingSwapArray[MAX_NUM_BUILDING_SWAPS]; @@ -115,8 +118,6 @@ uint16 CTheScripts::NumberOfMissionScripts; uint32 CTheScripts::LargestMissionScriptSize; uint32 CTheScripts::MainScriptSize; uint8 CTheScripts::FailCurrentMission; -uint8 CTheScripts::CountdownToMakePlayerUnsafe; -uint8 CTheScripts::DelayMakingPlayerUnsafeThisTime; uint16 CTheScripts::NumScriptDebugLines; uint16 CTheScripts::NumberOfIntroRectanglesThisFrame; uint16 CTheScripts::NumberOfIntroTextLinesThisFrame; @@ -127,6 +128,11 @@ CStuckCarCheck CTheScripts::StuckCars; uint16 CTheScripts::CommandsExecuted; uint16 CTheScripts::ScriptsUpdated; int32 ScriptParams[32]; +uint8 CTheScripts::RiotIntensity; +uint32 CTheScripts::LastMissionPassedTime; +uint16 CTheScripts::NumberOfExclusiveMissionScripts; +bool CTheScripts::bPlayerHasMetDebbieHarry; +bool CTheScripts::bPlayerIsInTheStatium; const uint32 CRunningScript::nSaveStructSize = @@ -170,10 +176,46 @@ void CMissionCleanup::AddEntityToList(int32 id, uint8 type) m_nCount++; } +static void PossiblyWakeThisEntity(CPhysical* pEntity) +{ + if (!pEntity->bIsStaticWaitingForCollision) + return; + if (CColStore::HasCollisionLoaded(pEntity->GetPosition())) { + pEntity->bIsStaticWaitingForCollision = false; + if (!pEntity->IsStatic()) + pEntity->AddToMovingList(); + } +} + void CMissionCleanup::RemoveEntityFromList(int32 id, uint8 type) { for (int i = 0; i < MAX_CLEANUP; i++){ if (m_sEntities[i].type == type && m_sEntities[i].id == id){ + switch (m_sEntities[i].type) { + case CLEANUP_CAR: + { + CVehicle* v = CPools::GetVehiclePool()->GetAt(m_sEntities[i].id); + if (v) + PossiblyWakeThisEntity(v); + break; + } + case CLEANUP_CHAR: + { + CPed* p = CPools::GetPedPool()->GetAt(m_sEntities[i].id); + if (p) + PossiblyWakeThisEntity(p); + break; + } + case CLEANUP_OBJECT: + { + CObject* o = CPools::GetObjectPool()->GetAt(m_sEntities[i].id); + if (o) + PossiblyWakeThisEntity(o); + break; + } + default: + break; + } m_sEntities[i].id = 0; m_sEntities[i].type = CLEANUP_UNUSED; m_nCount--; @@ -181,14 +223,70 @@ void CMissionCleanup::RemoveEntityFromList(int32 id, uint8 type) } } +void CMissionCleanup::CheckIfCollisionHasLoadedForMissionObject() +{ + for (int i = 0; i < MAX_CLEANUP; i++) { + switch (m_sEntities[i].type) { + case CLEANUP_CAR: + { + CVehicle* v = CPools::GetVehiclePool()->GetAt(m_sEntities[i].id); + if (v) + PossiblyWakeThisEntity(v); + break; + } + case CLEANUP_CHAR: + { + CPed* p = CPools::GetPedPool()->GetAt(m_sEntities[i].id); + if (p) + PossiblyWakeThisEntity(p); + break; + } + case CLEANUP_OBJECT: + { + CObject* o = CPools::GetObjectPool()->GetAt(m_sEntities[i].id); + if (o) + PossiblyWakeThisEntity(o); + break; + } + default: + break; + } + } +} + +CPhysical* CMissionCleanup::DoesThisEntityWaitForCollision(int i) +{ + if (m_sEntities[i].type == CLEANUP_CAR) { + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(m_sEntities[i].id); + if (pVehicle && pVehicle->GetStatus() != STATUS_WRECKED) + return pVehicle; + } + else if (m_sEntities[i].type == CLEANUP_CHAR) { + CPed* pPed = CPools::GetPedPool()->GetAt(m_sEntities[i].id); + if (pPed && !pPed->DyingOrDead()) + return pPed; + } + return nil; +} + void CMissionCleanup::Process() { CPopulation::m_AllRandomPedsThisType = -1; CPopulation::PedDensityMultiplier = 1.0f; CCarCtrl::CarDensityMultiplier = 1.0f; + CPed::nThreatReactionRangeMultiplier = 1; + CPed::nEnterCarRangeMultiplier = 1; FindPlayerPed()->m_pWanted->m_fCrimeSensitivity = 1.0f; - TheCamera.Restore(); + //CRoadBlocks::ClearScriptRoadblocks() // TODO(MIAMI) + CRouteNode::Initialise(); + if (!CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle) + TheCamera.Restore(); TheCamera.SetWideScreenOff(); + // TODO(MIAMI) + //CSpecialFX::bLiftCam = false; + //CSpecialFX::bVideoCam = false; + //CTimeCycle::StopExtraColour(0); + // TODO(MIAMI): change this to loop when it supports parameters DMAudio.ClearMissionAudio(); CWeather::ReleaseWeather(); for (int i = 0; i < NUM_OF_SPECIAL_CHARS; i++) @@ -197,11 +295,18 @@ void CMissionCleanup::Process() CStreaming::SetMissionDoesntRequireModel(MI_CUTOBJ01 + i); CStreaming::ms_disableStreaming = false; CHud::m_ItemToFlash = -1; - CHud::SetHelpMessage(nil, false); + CHud::SetHelpMessage(nil, false); // TODO(MIAMI): third parameter is false CUserDisplay::OnscnTimer.m_bDisabled = false; + CTheScripts::RemoveScriptTextureDictionary(); CWorld::Players[0].m_pPed->m_pWanted->m_bIgnoredByCops = false; CWorld::Players[0].m_pPed->m_pWanted->m_bIgnoredByEveryone = false; CWorld::Players[0].MakePlayerSafe(false); + //TODO(MIAMI): drunkenness, enable drive by + //DMAudio::ShutUpPlayerTalking(0); + CVehicle::bDisableRemoteDetonation = false; + //CVehicle::bDisableRemoteDetonationOnContact = false; // TODO(MIAMI) + //CGameLogic::ClearShortCut(); // TODO(MIAMI) + CTheScripts::RiotIntensity = 0; CTheScripts::StoreVehicleIndex = -1; CTheScripts::StoreVehicleWasRandom = true; CTheScripts::UpsideDownCars.Init(); @@ -391,11 +496,11 @@ bool CStuckCarCheck::HasCarBeenStuckForAWhile(int32 id) void CRunningScript::CollectParameters(uint32* pIp, int16 total) { for (int16 i = 0; i < total; i++){ - float tmp; uint16 varIndex; switch (CTheScripts::Read1ByteFromScript(pIp)) { case ARGUMENT_INT32: + case ARGUMENT_FLOAT: ScriptParams[i] = CTheScripts::Read4BytesFromScript(pIp); break; case ARGUMENT_GLOBALVAR: @@ -414,10 +519,6 @@ void CRunningScript::CollectParameters(uint32* pIp, int16 total) case ARGUMENT_INT16: ScriptParams[i] = CTheScripts::Read2BytesFromScript(pIp); break; - case ARGUMENT_FLOAT: - tmp = CTheScripts::ReadFloatFromScript(pIp); - ScriptParams[i] = *(int32*)&tmp; - break; default: assert(0); break; @@ -428,7 +529,6 @@ void CRunningScript::CollectParameters(uint32* pIp, int16 total) int32 CRunningScript::CollectNextParameterWithoutIncreasingPC(uint32 ip) { uint32* pIp = &ip; - float tmp; switch (CTheScripts::Read1ByteFromScript(pIp)) { case ARGUMENT_INT32: @@ -442,8 +542,7 @@ int32 CRunningScript::CollectNextParameterWithoutIncreasingPC(uint32 ip) case ARGUMENT_INT16: return CTheScripts::Read2BytesFromScript(pIp); case ARGUMENT_FLOAT: - tmp = CTheScripts::ReadFloatFromScript(pIp); - return *(int32*)&tmp; + return CTheScripts::Read4BytesFromScript(pIp); default: assert(0); } @@ -504,9 +603,12 @@ void CRunningScript::Init() } #ifdef USE_DEBUG_SCRIPT_LOADER + +const char* scriptfile = "main.scm"; + int open_script() { - static int scriptToLoad = 0; + static int scriptToLoad = 1; #ifdef _WIN32 if (GetAsyncKeyState('G') & 0x8000) @@ -517,11 +619,11 @@ int open_script() scriptToLoad = 2; #endif switch (scriptToLoad) { - case 0: return CFileMgr::OpenFile("main.scm", "rb"); - case 1: return CFileMgr::OpenFile("main_freeroam.scm", "rb"); - case 2: return CFileMgr::OpenFile("main_d.scm", "rb"); + case 0: scriptfile = "main.scm"; break; + case 1: scriptfile = "freeroam_miami.scm"; break; + case 2: scriptfile = "main_d.scm"; break; } - return CFileMgr::OpenFile("main.scm", "rb"); + return CFileMgr::OpenFile(scriptfile, "rb"); } #endif @@ -549,14 +651,7 @@ void CTheScripts::Init() StoreVehicleIndex = -1; StoreVehicleWasRandom = true; OnAMissionFlag = 0; - for (int i = 0; i < MAX_NUM_CONTACTS; i++){ - BaseBriefIdForContact[i] = 0; - OnAMissionForContactFlag[i] = 0; - } - for (int i = 0; i < MAX_NUM_COLLECTIVES; i++){ - CollectiveArray[i].index = -1; - CollectiveArray[i].unk_data = 0; - } + LastMissionPassedTime = (uint32)-1; NextFreeCollectiveIndex = 0; LastRandomPedId = -1; for (int i = 0; i < MAX_NUM_USED_OBJECTS; i++){ @@ -570,15 +665,17 @@ void CTheScripts::Init() bUsingAMultiScriptFile = true; for (int i = 0; i < MAX_NUM_MISSION_SCRIPTS; i++) MultiScriptArray[i] = 0; + NumberOfExclusiveMissionScripts = 0; NumberOfMissionScripts = 0; LargestMissionScriptSize = 0; MainScriptSize = 0; ReadMultiScriptFileOffsetsFromScript(); FailCurrentMission = 0; - CountdownToMakePlayerUnsafe = 0; DbgFlag = false; - DelayMakingPlayerUnsafeThisTime = 1; NumScriptDebugLines = 0; + RiotIntensity = 0; + bPlayerHasMetDebbieHarry = false; + bPlayerIsInTheStatium = false; for (int i = 0; i < MAX_NUM_SCRIPT_SPHERES; i++){ ScriptSphereArray[i].m_bInUse = false; ScriptSphereArray[i].m_Index = 1; @@ -599,6 +696,7 @@ void CTheScripts::Init() IntroRectangles[i].m_sColor = CRGBA(255, 255, 255, 255); } NumberOfIntroRectanglesThisFrame = 0; + RemoveScriptTextureDictionary(); for (int i = 0; i < MAX_NUM_BUILDING_SWAPS; i++){ BuildingSwapArray[i].m_pBuilding = nil; BuildingSwapArray[i].m_nNewModel = -1; @@ -608,6 +706,15 @@ void CTheScripts::Init() InvisibilitySettingArray[i] = nil; } +void CTheScripts::RemoveScriptTextureDictionary() +{ + for (int i = 0; i < ARRAY_SIZE(CTheScripts::ScriptSprites); i++) + CTheScripts::ScriptSprites[i].Delete(); + int slot = CTxdStore::FindTxdSlot("script"); + if (slot != -1) + CTxdStore::RemoveTxd(slot); +} + void CRunningScript::RemoveScriptFromList(CRunningScript** ppScript) { if (prev) @@ -647,13 +754,10 @@ void CTheScripts::Process() float timeStep = CTimer::GetTimeStepInMilliseconds(); UpsideDownCars.UpdateTimers(); StuckCars.Process(); + MissionCleanup.CheckIfCollisionHasLoadedForMissionObject(); DrawScriptSpheres(); if (FailCurrentMission) --FailCurrentMission; - if (CountdownToMakePlayerUnsafe){ - if (--CountdownToMakePlayerUnsafe == 0) - CWorld::Players[0].MakePlayerSafe(false); - } if (UseTextCommands){ for (int i = 0; i < MAX_NUM_INTRO_TEXT_LINES; i++) IntroTextLines[i].Reset(); @@ -737,15 +841,16 @@ int8 CRunningScript::ProcessOneCommand() return ProcessCommands800To899(command); if (command < 1000) return ProcessCommands900To999(command); -#ifdef GTA_PS2 - if (command < 1200) - return ProcessCommands1000To1099(command); -#else if (command < 1100) return ProcessCommands1000To1099(command); if (command < 1200) return ProcessCommands1100To1199(command); -#endif + if (command < 1300) + return ProcessCommands1200To1299(command); + if (command < 1400) + return ProcessCommands1300To1399(command); + if (command < 1500) + return ProcessCommands1400To1499(command); return -1; } @@ -1173,13 +1278,11 @@ int8 CRunningScript::ProcessCommands0To99(int32 command) UpdateCompareFlag(*ptr1 == *ptr2); return 0; } - /* Following commands are not implemented, and go to default case - case COMMAND_IS_INT_VAR_NOT_EQUAL_TO_NUMBER: - case COMMAND_IS_INT_LVAR_NOT_EQUAL_TO_NUMBER: - case COMMAND_IS_INT_VAR_NOT_EQUAL_TO_INT_VAR: - case COMMAND_IS_INT_LVAR_NOT_EQUAL_TO_INT_LVAR: - case COMMAND_IS_INT_VAR_NOT_EQUAL_TO_INT_LVAR: - */ + //case COMMAND_IS_INT_VAR_NOT_EQUAL_TO_NUMBER: + //case COMMAND_IS_INT_LVAR_NOT_EQUAL_TO_NUMBER: + //case COMMAND_IS_INT_VAR_NOT_EQUAL_TO_INT_VAR: + //case COMMAND_IS_INT_LVAR_NOT_EQUAL_TO_INT_LVAR: + //case COMMAND_IS_INT_VAR_NOT_EQUAL_TO_INT_LVAR: case COMMAND_IS_FLOAT_VAR_EQUAL_TO_NUMBER: { int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); @@ -1215,19 +1318,18 @@ int8 CRunningScript::ProcessCommands0To99(int32 command) UpdateCompareFlag(*(float*)ptr1 == *(float*)ptr2); return 0; } - /* Following commands are not implemented, and go to default case - case COMMAND_IS_FLOAT_VAR_NOT_EQUAL_TO_NUMBER: - case COMMAND_IS_FLOAT_LVAR_NOT_EQUAL_TO_NUMBER: - case COMMAND_IS_FLOAT_VAR_NOT_EQUAL_TO_FLOAT_VAR: - case COMMAND_IS_FLOAT_LVAR_NOT_EQUAL_TO_FLOAT_LVAR: - case COMMAND_IS_FLOAT_VAR_NOT_EQUAL_TO_FLOAT_LVAR: - */ + //case COMMAND_IS_FLOAT_VAR_NOT_EQUAL_TO_NUMBER: + //case COMMAND_IS_FLOAT_LVAR_NOT_EQUAL_TO_NUMBER: + //case COMMAND_IS_FLOAT_VAR_NOT_EQUAL_TO_FLOAT_VAR: + //case COMMAND_IS_FLOAT_LVAR_NOT_EQUAL_TO_FLOAT_LVAR: + //case COMMAND_IS_FLOAT_VAR_NOT_EQUAL_TO_FLOAT_LVAR: + /* case COMMAND_GOTO_IF_TRUE: CollectParameters(&m_nIp, 1); if (m_bCondResult) SetIP(ScriptParams[0] >= 0 ? ScriptParams[0] : SIZE_MAIN_SCRIPT - ScriptParams[0]); - /* Check COMMAND_GOTO note. */ return 0; + */ case COMMAND_GOTO_IF_FALSE: CollectParameters(&m_nIp, 1); if (!m_bCondResult) @@ -1239,12 +1341,14 @@ int8 CRunningScript::ProcessCommands0To99(int32 command) CTheScripts::bAlreadyRunningAMissionScript = false; RemoveScriptFromList(&CTheScripts::pActiveScripts); AddScriptToList(&CTheScripts::pIdleScripts); + m_bIsActive = false; return 1; case COMMAND_START_NEW_SCRIPT: { CollectParameters(&m_nIp, 1); assert(ScriptParams[0] >= 0); CRunningScript* pNew = CTheScripts::StartNewScript(ScriptParams[0]); + m_bIsActive = true; int8 type = CTheScripts::Read1ByteFromScript(&m_nIp); float tmp; for (int i = 0; type != ARGUMENT_END; type = CTheScripts::Read1ByteFromScript(&m_nIp), i++) { @@ -1292,7 +1396,7 @@ int8 CRunningScript::ProcessCommands0To99(int32 command) { CollectParameters(&m_nIp, 4); int32 index = ScriptParams[0]; - assert(index < 1); /* Constant? Also no more double player glitch */ + assert(index < NUMPLAYERS); printf("&&&&&&&&&&&&&Creating player: %d\n", index); if (!CStreaming::HasModelLoaded(MI_PLAYER)) { CStreaming::RequestSpecialModel(MI_PLAYER, "player", STREAMFLAGS_DONT_REMOVE | STREAMFLAGS_DEPENDENCY); @@ -1332,20 +1436,49 @@ int8 CRunningScript::ProcessCommands0To99(int32 command) if (pos.z <= MAP_Z_LOW_LIMIT) pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); CPlayerPed* ped = CWorld::Players[index].m_pPed; - if (!ped->bInVehicle) { - pos.z += ped->GetDistanceFromCentreOfMassToBaseOfModel(); - ped->Teleport(pos); - CTheScripts::ClearSpaceForMissionEntity(pos, ped); + if (ped->bInVehicle) { + pos.z += ped->m_pMyVehicle->GetDistanceFromCentreOfMassToBaseOfModel(); + ped->m_pMyVehicle->Teleport(pos); // removed dumb stuff that was present here + CTheScripts::ClearSpaceForMissionEntity(pos, ped->m_pMyVehicle); return 0; } - pos.z += ped->m_pMyVehicle->GetDistanceFromCentreOfMassToBaseOfModel(); - if (ped->m_pMyVehicle->IsBoat()) - ped->m_pMyVehicle->Teleport(pos); - else - ped->m_pMyVehicle->Teleport(pos); - /* I'll keep this condition here but obviously it is absolutely pointless */ - /* It's clearly present in disassembly so it had to be in original code */ - CTheScripts::ClearSpaceForMissionEntity(pos, ped->m_pMyVehicle); + pos.z += ped->GetDistanceFromCentreOfMassToBaseOfModel(); + CVector vOldPos = ped->GetPosition(); + ped->Teleport(pos); + CTheScripts::ClearSpaceForMissionEntity(pos, ped); + if (ped) { // great time to check + for (int i = 0; i < ped->m_numNearPeds; i++) { + CPed* pTestedPed = ped->m_nearPeds[i]; + if (!pTestedPed || !IsPedPointerValid(pTestedPed)) + continue; + if (pTestedPed->m_pedInObjective == ped && pTestedPed->m_objective == OBJ_15) { + CVector vFollowerPos = pTestedPed->GetFormationPosition(); + CTheScripts::ClearSpaceForMissionEntity(vFollowerPos, ped); + bool bFound = false; + vFollowerPos.z = CWorld::FindGroundZFor3DCoord(vFollowerPos.x, vFollowerPos.y, vFollowerPos.z + 1.0f, &bFound) + 1.0f; + if (bFound) { + if (CWorld::GetIsLineOfSightClear(vFollowerPos, ped->GetPosition(), true, false, false, true, false, false)) { + pTestedPed->Teleport(vFollowerPos); + } + } + } + else if (pTestedPed->m_leader == ped) { + CVector vFollowerPos; + if (pTestedPed->m_pedFormation) + vFollowerPos = pTestedPed->GetFormationPosition(); + else + vFollowerPos = ped->GetPosition() + pTestedPed->GetPosition() - vOldPos; + CTheScripts::ClearSpaceForMissionEntity(vFollowerPos, ped); + bool bFound = false; + vFollowerPos.z = CWorld::FindGroundZFor3DCoord(vFollowerPos.x, vFollowerPos.y, vFollowerPos.z + 1.0f, &bFound) + 1.0f; + if (bFound) { + if (CWorld::GetIsLineOfSightClear(vFollowerPos, ped->GetPosition(), true, false, false, true, false, false)) { + pTestedPed->Teleport(vFollowerPos); + } + } + } + } + } return 0; } case COMMAND_IS_PLAYER_IN_AREA_2D: @@ -1767,6 +1900,7 @@ int8 CRunningScript::ProcessCommands100To199(int32 command) ped->CharCreatedBy = MISSION_CHAR; ped->bRespondsToThreats = false; ped->bAllowMedicsToReviveMe = false; + ped->bIsPlayerFriend = false; CVector pos = *(CVector*)&ScriptParams[2]; if (pos.z <= MAP_Z_LOW_LIMIT) pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); @@ -1774,6 +1908,8 @@ int8 CRunningScript::ProcessCommands100To199(int32 command) ped->SetPosition(pos); ped->SetOrientation(0.0f, 0.0f, 0.0f); CTheScripts::ClearSpaceForMissionEntity(pos, ped); + if (m_bIsMissionScript) + ped->bIsStaticWaitingForCollision = true; CWorld::Add(ped); ped->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pos); CPopulation::ms_nTotalMissionPeds++; @@ -1787,24 +1923,7 @@ int8 CRunningScript::ProcessCommands100To199(int32 command) { CollectParameters(&m_nIp, 1); CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); - if (ped) { - if (ped->InVehicle()) { - if (ped->m_pMyVehicle->pDriver == ped) { - ped->m_pMyVehicle->RemoveDriver(); - ped->m_pMyVehicle->SetStatus(STATUS_ABANDONED); - if (ped->m_pMyVehicle->m_nDoorLock == CARLOCK_LOCKED_INITIALLY) - ped->m_pMyVehicle->m_nDoorLock = CARLOCK_UNLOCKED; - if (ped->m_nPedType == PEDTYPE_COP && ped->m_pMyVehicle->IsLawEnforcementVehicle()) - ped->m_pMyVehicle->ChangeLawEnforcerState(0); - } - else { - ped->m_pMyVehicle->RemovePassenger(ped); - } - } - CWorld::RemoveReferencesToDeletedObject(ped); - delete ped; - --CPopulation::ms_nTotalMissionPeds; - } + CTheScripts::RemoveThisPed(ped); if (m_bIsMissionScript) CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CHAR); return 0; @@ -1821,19 +1940,26 @@ int8 CRunningScript::ProcessCommands100To199(int32 command) ped->SetWanderPath(path); return 0; } - /* Not implemented. - case COMMAND_CHAR_WANDER_RANGE: - */ + //case COMMAND_CHAR_WANDER_RANGE: case COMMAND_CHAR_FOLLOW_PATH: { - CollectParameters(&m_nIp, 4); + CollectParameters(&m_nIp, 6); CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(ped); + if (ped->GetPedState() == PED_ATTACK || ped->GetPedState() == PED_FIGHT || !ped->IsPedInControl()) + return 0; CVector pos = *(CVector*)&ScriptParams[1]; if (pos.z <= MAP_Z_LOW_LIMIT) pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + float radius = *(float*)&ScriptParams[4]; + eMoveState state; + switch (ScriptParams[5]) { + case 0: state = PEDMOVE_WALK; + case 1: state = PEDMOVE_SPRINT; + default: assert(0); + } ped->ClearAll(); - ped->SetFollowPath(pos); + ped->SetFollowPath(pos, radius, state, nil, nil, 999999); return 0; } case COMMAND_CHAR_SET_IDLE: @@ -1878,44 +2004,27 @@ int8 CRunningScript::ProcessCommands100To199(int32 command) CVector pos = *(CVector*)&ScriptParams[1]; if (pos.z <= MAP_Z_LOW_LIMIT) pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - /* The following block was once again written - * by someone not familiar with virtual functions. - * It doesn't require any ifs at all. - * To keep as close to original as possible, I'll keep it. - * Maybe there was more commented out/debug - * stuff, but I doubt it. - */ + // removed dumb stuff again if (!vehicle) { pos.z += ped->GetDistanceFromCentreOfMassToBaseOfModel(); ped->Teleport(pos); CTheScripts::ClearSpaceForMissionEntity(pos, ped); - } - else if (vehicle->IsBoat()) { - pos.z += vehicle->GetDistanceFromCentreOfMassToBaseOfModel(); - vehicle->Teleport(pos); - CTheScripts::ClearSpaceForMissionEntity(pos, vehicle); + for (int i = 0; i < ped->m_numNearPeds; i++) { + CPed* pNearPed = ped->m_nearPeds[i]; + if (pNearPed->m_leader == ped) { + pNearPed->Teleport(pos); + pNearPed->PositionPedOutOfCollision(); // TODO(MIAMI): this is PositionAnyPedOutOfCollision!!! + } + } } else { pos.z += vehicle->GetDistanceFromCentreOfMassToBaseOfModel(); vehicle->Teleport(pos); CTheScripts::ClearSpaceForMissionEntity(pos, vehicle); } - /* Short version of this command. - * - * CollectParameters(&m_nIp, 4); - * CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); - * assert(ped); - * CEntity* entityToMove = ped->bInVehicle ? ped->m_pMyVehicle : ped; - * CVector pos = *(CVector*)&ScriptParams[1]; - * if (pos.z <= MAP_Z_LOW_LIMIT) - * pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - * pos.z += entityToMove->GetDistanceFromCentreOfMassToBaseOfModel(); - * entityToMove->Teleport(pos); - * CTheScripts::ClearSpaceForMissionEntity(pos, entityToMove); - * - */ return 0; } + /* case COMMAND_IS_CHAR_STILL_ALIVE: { CollectParameters(&m_nIp, 1); @@ -1923,6 +2032,7 @@ int8 CRunningScript::ProcessCommands100To199(int32 command) UpdateCompareFlag(ped && ped->GetPedState() != PED_DEAD && ped->GetPedState() != PED_DIE); return 0; } + */ case COMMAND_IS_CHAR_IN_AREA_2D: { CollectParameters(&m_nIp, 6); @@ -1990,15 +2100,19 @@ int8 CRunningScript::ProcessCommands100To199(int32 command) boat->SetStatus(STATUS_ABANDONED); boat->bIsLocked = true; boat->AutoPilot.m_nCarMission = MISSION_NONE; - boat->AutoPilot.m_nTempAction = TEMPACT_NONE; /* Animation ID? */ + boat->AutoPilot.m_nTempAction = TEMPACT_NONE; boat->AutoPilot.m_nCruiseSpeed = boat->AutoPilot.m_fMaxTrafficSpeed = 20.0f; + if (m_bIsMissionScript) + boat->bIsStaticWaitingForCollision = true; CWorld::Add(boat); handle = CPools::GetVehiclePool()->GetIndex(boat); } else { CVehicle* car; - if (!CModelInfo::IsBikeModel(ScriptParams[0])) - car = new CAutomobile(ScriptParams[0], MISSION_VEHICLE); + + // TODO(MIAMI) + //if (!CModelInfo::IsBikeModel(ScriptParams[0])) + car = new CAutomobile(ScriptParams[0], MISSION_VEHICLE); CVector pos = *(CVector*)&ScriptParams[1]; if (pos.z <= MAP_Z_LOW_LIMIT) pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); @@ -2009,13 +2123,15 @@ int8 CRunningScript::ProcessCommands100To199(int32 command) car->bIsLocked = true; CCarCtrl::JoinCarWithRoadSystem(car); car->AutoPilot.m_nCarMission = MISSION_NONE; - car->AutoPilot.m_nTempAction = TEMPACT_NONE; /* Animation ID? */ + car->AutoPilot.m_nTempAction = TEMPACT_NONE; car->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS; car->AutoPilot.m_nCruiseSpeed = car->AutoPilot.m_fMaxTrafficSpeed = 9.0f; car->AutoPilot.m_nCurrentLane = car->AutoPilot.m_nNextLane = 0; car->bEngineOn = false; car->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pos); car->bHasBeenOwnedByPlayer = true; + if (m_bIsMissionScript) + car->bIsStaticWaitingForCollision = true; CWorld::Add(car); handle = CPools::GetVehiclePool()->GetIndex(car); } @@ -2137,6 +2253,7 @@ int8 CRunningScript::ProcessCommands100To199(int32 command) } return 0; } + /* case COMMAND_IS_CAR_STILL_ALIVE: { CollectParameters(&m_nIp, 1); @@ -2144,6 +2261,7 @@ int8 CRunningScript::ProcessCommands100To199(int32 command) UpdateCompareFlag(car && car->GetStatus() != STATUS_WRECKED && (car->IsBoat() || !car->bIsInWater)); return 0; } + */ case COMMAND_SET_CAR_CRUISE_SPEED: { CollectParameters(&m_nIp, 2); @@ -2218,32 +2336,28 @@ int8 CRunningScript::ProcessCommands100To199(int32 command) return 0; case COMMAND_PRINT_BIG: { - wchar* key = TheText.Get((char*)&CTheScripts::ScriptSpace[m_nIp]); - m_nIp += KEY_LENGTH_IN_SCRIPT; + wchar* key = CTheScripts::GetTextByKeyFromScript(&m_nIp); CollectParameters(&m_nIp, 2); CMessages::AddBigMessage(key, ScriptParams[0], ScriptParams[1] - 1); return 0; } case COMMAND_PRINT: { - wchar* key = TheText.Get((char*)&CTheScripts::ScriptSpace[m_nIp]); - m_nIp += KEY_LENGTH_IN_SCRIPT; + wchar* key = CTheScripts::GetTextByKeyFromScript(&m_nIp); CollectParameters(&m_nIp, 2); CMessages::AddMessage(key, ScriptParams[0], ScriptParams[1]); return 0; } case COMMAND_PRINT_NOW: { - wchar* key = TheText.Get((char*)&CTheScripts::ScriptSpace[m_nIp]); - m_nIp += KEY_LENGTH_IN_SCRIPT; + wchar* key = CTheScripts::GetTextByKeyFromScript(&m_nIp); CollectParameters(&m_nIp, 2); CMessages::AddMessageJumpQ(key, ScriptParams[0], ScriptParams[1]); return 0; } case COMMAND_PRINT_SOON: { - wchar* key = TheText.Get((char*)&CTheScripts::ScriptSpace[m_nIp]); - m_nIp += KEY_LENGTH_IN_SCRIPT; + wchar* key = CTheScripts::GetTextByKeyFromScript(&m_nIp); CollectParameters(&m_nIp, 2); CMessages::AddMessageSoon(key, ScriptParams[0], ScriptParams[1]); return 0; @@ -2280,15 +2394,15 @@ int8 CRunningScript::ProcessCommands100To199(int32 command) case COMMAND_DEBUG_OFF: CTheScripts::DbgFlag = false; return 0; + /* case COMMAND_RETURN_TRUE: UpdateCompareFlag(true); return 0; case COMMAND_RETURN_FALSE: UpdateCompareFlag(false); return 0; - /* Special command only used by compiler. - case COMMAND_VAR_INT: */ + //case COMMAND_VAR_INT: default: assert(0); break; @@ -2341,8 +2455,6 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) { if (!m_bIsMissionScript) return 0; - if (strcmp(m_abScriptName, "love3") == 0) /* A Drop in the Ocean */ - CPickups::RemoveAllFloatingPickups(); CTheScripts::MissionCleanup.Process(); return 0; } @@ -2485,29 +2597,23 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) { CollectParameters(&m_nIp, 1); CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - UpdateCompareFlag(pPed->bInVehicle); + UpdateCompareFlag(pPed->bInVehicle && pPed->m_pMyVehicle); return 0; } case COMMAND_IS_PLAYER_IN_ANY_CAR: { CollectParameters(&m_nIp, 1); CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - UpdateCompareFlag(pPed->bInVehicle); + UpdateCompareFlag(pPed->bInVehicle && pPed->m_pMyVehicle); return 0; } case COMMAND_IS_BUTTON_PRESSED: { CollectParameters(&m_nIp, 2); - bool value = GetPadState(ScriptParams[0], ScriptParams[1]) != 0; - if (CGame::playingIntro && ScriptParams[0] == 0 && ScriptParams[1] == 12) { - if (CPad::GetPad(0)->GetLeftMouseJustDown() || - CPad::GetPad(0)->GetEnterJustDown() || - CPad::GetPad(0)->GetCharJustDown(' ')) - value = true; - } - UpdateCompareFlag(value); + UpdateCompareFlag(GetPadState(ScriptParams[0], ScriptParams[1]) != 0); return 0; } + /* case COMMAND_GET_PAD_STATE: { CollectParameters(&m_nIp, 1); @@ -2515,6 +2621,7 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) StoreParameters(&m_nIp, 1); return 0; } + */ case COMMAND_LOCATE_PLAYER_ANY_MEANS_2D: case COMMAND_LOCATE_PLAYER_ON_FOOT_2D: case COMMAND_LOCATE_PLAYER_IN_CAR_2D: @@ -2581,6 +2688,9 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) pObj->SetOrientation(0.0f, 0.0f, 0.0f); pObj->GetMatrix().UpdateRW(); pObj->UpdateRwFrame(); + CBaseModelInfo* pModelInfo = CModelInfo::GetModelInfo(mi); + if (pModelInfo->IsBuilding() && ((CSimpleModelInfo*)pModelInfo)->m_isBigBuilding) + pObj->SetupBigBuilding(); CTheScripts::ClearSpaceForMissionEntity(pos, pObj); CWorld::Add(pObj); ScriptParams[0] = CPools::GetObjectPool()->GetIndex(pObj); @@ -2605,6 +2715,8 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) case COMMAND_ADD_SCORE: CollectParameters(&m_nIp, 2); CWorld::Players[ScriptParams[0]].m_nMoney += ScriptParams[1]; + if (CWorld::Players[ScriptParams[0]].m_nMoney < 0) + CWorld::Players[ScriptParams[0]].m_nMoney = 0; return 0; case COMMAND_IS_SCORE_GREATER: CollectParameters(&m_nIp, 2); @@ -2647,12 +2759,14 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) case COMMAND_HAS_DEATHARREST_BEEN_EXECUTED: UpdateCompareFlag(m_bDeatharrestExecuted); return 0; + /* case COMMAND_ADD_AMMO_TO_PLAYER: { CollectParameters(&m_nIp, 3); CWorld::Players[ScriptParams[0]].m_pPed->GrantAmmo((eWeaponType)ScriptParams[1], ScriptParams[2]); return 0; } + */ case COMMAND_ADD_AMMO_TO_CHAR: { CollectParameters(&m_nIp, 3); @@ -2661,10 +2775,8 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) pPed->GrantAmmo((eWeaponType)ScriptParams[1], ScriptParams[2]); return 0; } - /* Not implemented - case COMMAND_ADD_AMMO_TO_CAR: - case COMMAND_IS_PLAYER_STILL_ALIVE: - */ + //case COMMAND_ADD_AMMO_TO_CAR: + //case COMMAND_IS_PLAYER_STILL_ALIVE: case COMMAND_IS_PLAYER_DEAD: CollectParameters(&m_nIp, 1); UpdateCompareFlag(CWorld::Players[ScriptParams[0]].m_WBState == WBSTATE_WASTED); @@ -2673,14 +2785,14 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) { CollectParameters(&m_nIp, 1); CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - UpdateCompareFlag(!pPed || pPed->GetPedState() == PED_DIE || pPed->GetPedState() == PED_DEAD); + UpdateCompareFlag(!pPed || pPed->DyingOrDead()); return 0; } case COMMAND_IS_CAR_DEAD: { CollectParameters(&m_nIp, 1); CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - UpdateCompareFlag(!pVehicle || pVehicle->GetStatus() == STATUS_WRECKED || !pVehicle->IsBoat() && pVehicle->bIsInWater); + UpdateCompareFlag(!pVehicle || pVehicle->GetStatus() == STATUS_WRECKED || pVehicle->bIsDrowning); return 0; } case COMMAND_SET_CHAR_THREAT_SEARCH: @@ -2691,9 +2803,7 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) pPed->m_fearFlags |= ScriptParams[1]; return 0; } - /* Not implemented. - case COMMAND_SET_CHAR_THREAT_REACTION: - */ + //case COMMAND_SET_CHAR_THREAT_REACTION: case COMMAND_SET_CHAR_OBJ_NO_OBJ: { CollectParameters(&m_nIp, 1); @@ -2703,23 +2813,21 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) pPed->ClearObjective(); return 0; } - /* Not implemented. - case COMMAND_ORDER_DRIVER_OUT_OF_CAR: - case COMMAND_ORDER_CHAR_TO_DRIVE_CAR: - case COMMAND_ADD_PATROL_POINT: - case COMMAND_IS_PLAYER_IN_GANGZONE: - */ + //case COMMAND_ORDER_DRIVER_OUT_OF_CAR: + //case COMMAND_ORDER_CHAR_TO_DRIVE_CAR: + //case COMMAND_ADD_PATROL_POINT: + //case COMMAND_IS_PLAYER_IN_GANGZONE: case COMMAND_IS_PLAYER_IN_ZONE: { CollectParameters(&m_nIp, 1); CPlayerInfo* pPlayer = &CWorld::Players[ScriptParams[0]]; char label[12]; CTheScripts::ReadTextLabelFromScript(&m_nIp, label); - int zoneToCheck = CTheZones::FindZoneByLabelAndReturnIndex(label); + int zoneToCheck = CTheZones::FindZoneByLabelAndReturnIndex(label, ZONE_DEFAULT); if (zoneToCheck != -1) m_nIp += KEY_LENGTH_IN_SCRIPT; /* why only if zone != 1? */ CVector pos = pPlayer->GetPos(); - CZone* pZone = CTheZones::GetZone(zoneToCheck); + CZone* pZone = CTheZones::GetNavigationZone(zoneToCheck); UpdateCompareFlag(CTheZones::PointLiesWithinZone(&pos, pZone)); return 0; } @@ -2727,8 +2835,6 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) CollectParameters(&m_nIp, 1); UpdateCompareFlag(CWorld::Players[ScriptParams[0]].m_pPed->GetPedState() == PED_DRIVING && CPad::GetPad(ScriptParams[0])->GetHorn()); - /* Is it correct that same parameter is used both as index of Players */ - /* and as ID of pad? Pratically this parameter is always 0 anyway of course. */ return 0; case COMMAND_HAS_CHAR_SPOTTED_PLAYER: { @@ -2738,10 +2844,8 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) UpdateCompareFlag(pPed->OurPedCanSeeThisOne(CWorld::Players[ScriptParams[1]].m_pPed)); return 0; } - /* Not implemented. - case COMMAND_ORDER_CHAR_TO_BACKDOOR: - case COMMAND_ADD_CHAR_TO_GANG: - */ + //case COMMAND_ORDER_CHAR_TO_BACKDOOR: + //case COMMAND_ADD_CHAR_TO_GANG: case COMMAND_IS_CHAR_OBJECTIVE_PASSED: { CollectParameters(&m_nIp, 1); @@ -2797,6 +2901,9 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) pPed->CharCreatedBy = MISSION_CHAR; pPed->bRespondsToThreats = false; pPed->bAllowMedicsToReviveMe = false; + pPed->bIsPlayerFriend = false; + if (pVehicle->bIsBus) + pPed->bRenderPedInCar = false; pPed->SetPosition(pVehicle->GetPosition()); pPed->SetOrientation(0.0f, 0.0f, 0.0f); pPed->SetPedState(PED_DRIVING); @@ -2812,13 +2919,7 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) pVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE; pVehicle->bEngineOn = true; pPed->bUsesCollision = false; -#ifdef FIX_BUGS - AnimationId anim = pVehicle->GetDriverAnim(); -#else - AnimationId anim = pVehicle->bLowVehicle ? ANIM_CAR_LSIT : ANIM_CAR_SIT; -#endif - pPed->m_pVehicleAnim = CAnimManager::BlendAnimation(pPed->GetClump(), ASSOCGRP_STD, anim, 100.0f); - pPed->StopNonPartialAnims(); + pPed->AddInCarAnims(pVehicle, true); pPed->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pPed->GetPosition()); CWorld::Add(pPed); ScriptParams[0] = CPools::GetPedPool()->GetIndex(pPed); @@ -2852,7 +2953,7 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) pPlayer->m_pPed->SetPedState(PED_IDLE); pPlayer->m_pPed->bUsesCollision = true; pPlayer->m_pPed->SetMoveSpeed(0.0f, 0.0f, 0.0f); - pPlayer->m_pPed->AddWeaponModel(CWeaponInfo::GetWeaponInfo(pPlayer->m_pPed->GetWeapon()->m_eWeaponType)->m_nModelId); + pPlayer->m_pPed->ReplaceWeaponWhenExitingVehicle(); pPlayer->m_pPed->RemoveInCarAnims(); if (pPlayer->m_pPed->m_pVehicleAnim) pPlayer->m_pPed->m_pVehicleAnim->blendDelta = -1000.0f; @@ -2866,9 +2967,7 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) CTheScripts::ClearSpaceForMissionEntity(pos, pPlayer->m_pPed); return 0; } - /* Not implemented. - case COMMAND_MAKE_CHAR_DO_NOTHING: - */ + //case COMMAND_MAKE_CHAR_DO_NOTHING: default: assert(0); break; @@ -3044,18 +3143,27 @@ int8 CRunningScript::ProcessCommands300To399(int32 command) case COMMAND_SET_ZONE_CAR_INFO: { char label[12]; + int16 gangDensities[NUM_GANGS] = { 0 }; + int i; + CTheScripts::ReadTextLabelFromScript(&m_nIp, label); m_nIp += KEY_LENGTH_IN_SCRIPT; - CollectParameters(&m_nIp, 16); - int zone = CTheZones::FindZoneByLabelAndReturnIndex(label); + CollectParameters(&m_nIp, 12); + for (i = 0; i < NUM_GANGS; i++) + gangDensities[i] = ScriptParams[i + 2]; + int zone = CTheZones::FindZoneByLabelAndReturnIndex(label, ZONE_INFO); + for (int i = 0; i < NUM_GANGS; i++) { + if (gangDensities[i] != 0 && CGangs::GetGangInfo(i)->m_nVehicleMI == -1) + debug("SET_ZONE_CAR_INFO - Gang %d car ratio should be 0 in %s zone\n", i + 1, label); + } if (zone < 0) { debug("Couldn't find zone - %s\n", label); return 0; } - CTheZones::SetZoneCarInfo(zone, ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], - ScriptParams[4], ScriptParams[5], ScriptParams[6], ScriptParams[7], ScriptParams[8], 0, 0, - ScriptParams[9], ScriptParams[10], ScriptParams[11], ScriptParams[12], - ScriptParams[13], ScriptParams[14], ScriptParams[15]); + while (zone >= 0) { + CTheZones::SetZoneCarInfo(zone, ScriptParams[0], ScriptParams[1], ScriptParams[11], gangDensities); + zone = CTheZones::FindNextZoneByLabelAndReturnIndex(label, ZONE_INFO); + } return 0; } /* Not implemented. @@ -3068,41 +3176,17 @@ int8 CRunningScript::ProcessCommands300To399(int32 command) assert(pPed); char label[12]; CTheScripts::ReadTextLabelFromScript(&m_nIp, label); - int zone = CTheZones::FindZoneByLabelAndReturnIndex(label); + int zone = CTheZones::FindZoneByLabelAndReturnIndex(label, ZONE_DEFAULT); if (zone != -1) m_nIp += KEY_LENGTH_IN_SCRIPT; CVector pos = pPed->bInVehicle ? pPed->m_pMyVehicle->GetPosition() : pPed->GetPosition(); - UpdateCompareFlag(CTheZones::PointLiesWithinZone(&pos, CTheZones::GetZone(zone))); + UpdateCompareFlag(CTheZones::PointLiesWithinZone(&pos, CTheZones::GetNavigationZone(zone))); return 0; } + /* Not implemented. case COMMAND_SET_CAR_DENSITY: - { - char label[12]; - CTheScripts::ReadTextLabelFromScript(&m_nIp, label); - int16 zone = CTheZones::FindZoneByLabelAndReturnIndex(label); - m_nIp += 8; - CollectParameters(&m_nIp, 2); - if (zone < 0) { - debug("Couldn't find zone - %s\n", label); - return 0; - } - CTheZones::SetCarDensity(zone, ScriptParams[0], ScriptParams[1]); - return 0; - } case COMMAND_SET_PED_DENSITY: - { - char label[12]; - CTheScripts::ReadTextLabelFromScript(&m_nIp, label); - int16 zone = CTheZones::FindZoneByLabelAndReturnIndex(label); - m_nIp += KEY_LENGTH_IN_SCRIPT; - CollectParameters(&m_nIp, 2); - if (zone < 0) { - debug("Couldn't find zone - %s\n", label); - return 0; - } - CTheZones::SetPedDensity(zone, ScriptParams[0], ScriptParams[1]); - return 0; - } + */ case COMMAND_POINT_CAMERA_AT_PLAYER: { CollectParameters(&m_nIp, 3); @@ -3137,14 +3221,17 @@ int8 CRunningScript::ProcessCommands300To399(int32 command) char label[12]; CTheScripts::ReadTextLabelFromScript(&m_nIp, label); m_nIp += KEY_LENGTH_IN_SCRIPT; - CollectParameters(&m_nIp, 10); - int16 zone = CTheZones::FindZoneByLabelAndReturnIndex(label); + CollectParameters(&m_nIp, 12); + int16 zone = CTheZones::FindZoneByLabelAndReturnIndex(label, ZONE_INFO); if (zone < 0) { debug("Couldn't find zone - %s\n", label); return 0; } - CTheZones::SetZonePedInfo(zone, ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], - ScriptParams[4], ScriptParams[5], ScriptParams[6], ScriptParams[7], ScriptParams[8], 0, 0, ScriptParams[9]); + while (zone >= 0) { + CTheZones::SetZonePedInfo(zone, ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], + ScriptParams[4], ScriptParams[5], ScriptParams[6], ScriptParams[7], ScriptParams[8], ScriptParams[9], ScriptParams[10], ScriptParams[11]); + zone = CTheZones::FindNextZoneByLabelAndReturnIndex(label, ZONE_INFO); + } return 0; } case COMMAND_SET_TIME_SCALE: @@ -3429,14 +3516,8 @@ int8 CRunningScript::ProcessCommands300To399(int32 command) case COMMAND_DECLARE_MISSION_FLAG: CTheScripts::OnAMissionFlag = CTheScripts::Read2BytesFromScript(&++m_nIp); return 0; - case COMMAND_DECLARE_MISSION_FLAG_FOR_CONTACT: - CollectParameters(&m_nIp, 1); - CTheScripts::OnAMissionForContactFlag[ScriptParams[0]] = CTheScripts::Read2BytesFromScript(&++m_nIp); - return 0; - case COMMAND_DECLARE_BASE_BRIEF_ID_FOR_CONTACT: - CollectParameters(&m_nIp, 2); - CTheScripts::BaseBriefIdForContact[ScriptParams[0]] = ScriptParams[1]; - return 0; + //case COMMAND_DECLARE_MISSION_FLAG_FOR_CONTACT: + //case COMMAND_DECLARE_BASE_BRIEF_ID_FOR_CONTACT: case COMMAND_IS_PLAYER_HEALTH_GREATER: { CollectParameters(&m_nIp, 2); @@ -3751,13 +3832,8 @@ int8 CRunningScript::ProcessCommands400To499(int32 command) CollectParameters(&m_nIp, 2); CPlayerInfo* pPlayer = &CWorld::Players[ScriptParams[0]]; if (ScriptParams[1]){ - if (CGame::playingIntro || CTheScripts::DelayMakingPlayerUnsafeThisTime){ - CTheScripts::CountdownToMakePlayerUnsafe = 50; - if (CTheScripts::DelayMakingPlayerUnsafeThisTime) - CTheScripts::DelayMakingPlayerUnsafeThisTime--; - }else{ - pPlayer->MakePlayerSafe(false); - } + pPlayer->MakePlayerSafe(false); + // TODO(MIAMI): Four Iron hack }else{ pPlayer->MakePlayerSafe(true); if (strcmp(m_abScriptName, "camera") == 0){ @@ -3783,7 +3859,7 @@ int8 CRunningScript::ProcessCommands400To499(int32 command) { CollectParameters(&m_nIp, 2); CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - for (int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++){ + for (int i = 0; i < TOTAL_WEAPON_SLOTS; i++){ if (pPed->m_weapons[i].m_eWeaponType == ScriptParams[1]) pPed->m_nSelectedWepSlot = i; } @@ -3793,7 +3869,7 @@ int8 CRunningScript::ProcessCommands400To499(int32 command) { CollectParameters(&m_nIp, 2); CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - for (int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++) { + for (int i = 0; i < TOTAL_WEAPON_SLOTS; i++) { if (pPed->m_weapons[i].m_eWeaponType == ScriptParams[1]) pPed->SetCurrentWeapon(i); } @@ -4003,13 +4079,7 @@ int8 CRunningScript::ProcessCommands400To499(int32 command) pPed->SetPedState(PED_DRIVING); pVehicle->SetStatus(STATUS_PHYSICS); pPed->bUsesCollision = false; -#ifdef FIX_BUGS - AnimationId anim = pVehicle->GetDriverAnim(); -#else - AnimationId anim = pVehicle->bLowVehicle ? ANIM_CAR_LSIT : ANIM_CAR_SIT; -#endif - pPed->m_pVehicleAnim = CAnimManager::BlendAnimation(pPed->GetClump(), ASSOCGRP_STD, anim, 100.0f); - pPed->StopNonPartialAnims(); + pPed->AddInCarAnims(pVehicle, false); pPed->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pPed->GetPosition()); CWorld::Add(pPed); ScriptParams[0] = CPools::GetPedPool()->GetIndex(pPed); @@ -4637,51 +4707,31 @@ int8 CRunningScript::ProcessCommands500To599(int32 command) } case COMMAND_SET_GARAGE: { - CollectParameters(&m_nIp, 7); + CollectParameters(&m_nIp, 9); float infX = *(float*)&ScriptParams[0]; float infY = *(float*)&ScriptParams[1]; float infZ = *(float*)&ScriptParams[2]; - float supX = *(float*)&ScriptParams[3]; - float supY = *(float*)&ScriptParams[4]; - float supZ = *(float*)&ScriptParams[5]; - if (infX > supX) { - infX = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[0]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[1]; - } - if (infZ > supZ) { - infZ = *(float*)&ScriptParams[5]; - supZ = *(float*)&ScriptParams[2]; - } - ScriptParams[0] = CGarages::AddOne(infX, infY, infZ, supX, supY, supZ, (eGarageType)ScriptParams[6], 0); + float X2 = *(float*)&ScriptParams[3]; + float Y2 = *(float*)&ScriptParams[4]; + float supX = *(float*)&ScriptParams[5]; + float supY = *(float*)&ScriptParams[6]; + float supZ = *(float*)&ScriptParams[7]; + ScriptParams[0] = CGarages::AddOne(infX, infY, infZ, X2, Y2, supX, supY, supZ, (eGarageType)ScriptParams[8], 0); StoreParameters(&m_nIp, 1); return 0; } case COMMAND_SET_GARAGE_WITH_CAR_MODEL: { - CollectParameters(&m_nIp, 8); + CollectParameters(&m_nIp, 10); float infX = *(float*)&ScriptParams[0]; float infY = *(float*)&ScriptParams[1]; float infZ = *(float*)&ScriptParams[2]; - float supX = *(float*)&ScriptParams[3]; - float supY = *(float*)&ScriptParams[4]; - float supZ = *(float*)&ScriptParams[5]; - if (infX > supX) { - infX = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[0]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[1]; - } - if (infZ > supZ) { - infZ = *(float*)&ScriptParams[5]; - supZ = *(float*)&ScriptParams[2]; - } - ScriptParams[0] = CGarages::AddOne(infX, infY, infZ, supX, supY, supZ, (eGarageType)ScriptParams[6], ScriptParams[7]); + float X2 = *(float*)&ScriptParams[3]; + float Y2 = *(float*)&ScriptParams[4]; + float supX = *(float*)&ScriptParams[5]; + float supY = *(float*)&ScriptParams[6]; + float supZ = *(float*)&ScriptParams[7]; + ScriptParams[0] = CGarages::AddOne(infX, infY, infZ, X2, Y2, supX, supY, supZ, (eGarageType)ScriptParams[8], ScriptParams[9]); StoreParameters(&m_nIp, 1); return 0; } @@ -4764,7 +4814,7 @@ int8 CRunningScript::ProcessCommands500To599(int32 command) CollectParameters(&m_nIp, 2); CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; assert(pPed); - pPed->m_fHealth = ScriptParams[1]; + pPed->m_fHealth = Min(ScriptParams[1], CWorld::Players[ScriptParams[0]].m_nMaxHealth); return 0; } case COMMAND_SET_CHAR_HEALTH: @@ -4950,7 +5000,10 @@ int8 CRunningScript::ProcessCommands500To599(int32 command) //case COMMAND_SET_GANG_ATTITUDE: //case COMMAND_SET_GANG_GANG_ATTITUDE: //case COMMAND_SET_GANG_PLAYER_ATTITUDE: - //case COMMAND_SET_GANG_PED_MODELS: + case COMMAND_SET_GANG_PED_MODELS: + CollectParameters(&m_nIp, 3); + CGangs::SetGangPedModels(ScriptParams[0], ScriptParams[1], ScriptParams[2]); + return 0; case COMMAND_SET_GANG_CAR_MODEL: CollectParameters(&m_nIp, 2); CGangs::SetGangVehicleModel(ScriptParams[0], ScriptParams[1]); @@ -5188,12 +5241,8 @@ int8 CRunningScript::ProcessCommands500To599(int32 command) ScriptParams[3] / 255.0f, ScriptParams[4] / 255.0f, ScriptParams[5] / 255.0f, 0, true); return 0; } - case COMMAND_STORE_WEATHER: - CWeather::StoreWeatherState(); - return 0; - case COMMAND_RESTORE_WEATHER: - CWeather::RestoreWeatherState(); - return 0; + //case COMMAND_STORE_WEATHER: + //case COMMAND_RESTORE_WEATHER: case COMMAND_STORE_CLOCK: CClock::StoreClock(); return 0; @@ -5325,8 +5374,7 @@ int8 CRunningScript::ProcessCommands600To699(int32 command) CollectParameters(&m_nIp, 1); CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); assert(pVehicle); - int mi = pVehicle->GetModelIndex(); - UpdateCompareFlag(mi == MI_TAXI || mi == MI_CABBIE || mi == MI_BORGNINE); + UpdateCompareFlag(pVehicle->IsTaxi()); return 0; } case COMMAND_UNLOAD_SPECIAL_CHARACTER: @@ -5870,8 +5918,8 @@ int8 CRunningScript::ProcessCommands700To799(int32 command) continue; if (pPed->bFadeOut) continue; - if (pPed->GetModelIndex() == MI_SCUM_WOM || pPed->GetModelIndex() == MI_SCUM_MAN) - continue; +// if (pPed->GetModelIndex() == MI_SCUM_WOM || pPed->GetModelIndex() == MI_SCUM_MAN) +// continue; if (!ThisIsAValidRandomPed(pPed->m_nPedType)) continue; if (pPed->bIsLeader || pPed->m_leader) @@ -5898,10 +5946,10 @@ int8 CRunningScript::ProcessCommands700To799(int32 command) { char zone[KEY_LENGTH_IN_SCRIPT]; strncpy(zone, (const char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); - int nZone = CTheZones::FindZoneByLabelAndReturnIndex(zone); + int nZone = CTheZones::FindZoneByLabelAndReturnIndex(zone, ZONE_DEFAULT); if (nZone != -1) m_nIp += KEY_LENGTH_IN_SCRIPT; - CZone* pZone = CTheZones::GetZone(nZone); + CZone* pZone = CTheZones::GetNavigationZone(nZone); int ped_handle = -1; CVector pos = FindPlayerCoors(); int i = CPools::GetPedPool()->GetSize(); @@ -5919,8 +5967,8 @@ int8 CRunningScript::ProcessCommands700To799(int32 command) continue; if (pPed->bFadeOut) continue; - if (pPed->GetModelIndex() == MI_SCUM_WOM || pPed->GetModelIndex() == MI_SCUM_MAN) - continue; +// if (pPed->GetModelIndex() == MI_SCUM_WOM || pPed->GetModelIndex() == MI_SCUM_MAN) +// continue; if (!ThisIsAValidRandomPed(pPed->m_nPedType)) continue; if (pPed->bIsLeader || pPed->m_leader) @@ -6142,25 +6190,12 @@ int8 CRunningScript::ProcessCommands700To799(int32 command) } case COMMAND_CREATE_CUTSCENE_HEAD: { - CollectParameters(&m_nIp, 2); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - assert(pObject); - CCutsceneHead* pCutHead = CCutsceneMgr::AddCutsceneHead(pObject, ScriptParams[1]); - ScriptParams[0] = CPools::GetObjectPool()->GetIndex(pCutHead); - StoreParameters(&m_nIp, 1); + assert(0); return 0; } case COMMAND_SET_CUTSCENE_HEAD_ANIM: { - CollectParameters(&m_nIp, 1); - CObject* pCutHead = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - assert(pCutHead); - char name[KEY_LENGTH_IN_SCRIPT]; - strncpy(name, (const char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); - m_nIp += KEY_LENGTH_IN_SCRIPT; - CTimer::Stop(); - CCutsceneMgr::SetHeadAnim(name, pCutHead); - CTimer::Update(); + assert(0); return 0; } case COMMAND_SIN: @@ -6506,7 +6541,7 @@ int8 CRunningScript::ProcessCommands800To899(int32 command) CTheScripts::ReadTextLabelFromScript(&m_nIp, zone); m_nIp += KEY_LENGTH_IN_SCRIPT; CollectParameters(&m_nIp, 2); - int zone_id = CTheZones::FindZoneByLabelAndReturnIndex(zone); + int zone_id = CTheZones::FindZoneByLabelAndReturnIndex(zone, ZONE_INFO); if (zone_id < 0) { printf("Couldn't find zone - %s\n", zone); return 0; @@ -6566,10 +6601,11 @@ int8 CRunningScript::ProcessCommands800To899(int32 command) { char zone[KEY_LENGTH_IN_SCRIPT]; CTheScripts::ReadTextLabelFromScript(&m_nIp, zone); - int zone_id = CTheZones::FindZoneByLabelAndReturnIndex(zone); +// TODO(MIAMI): just getting this to compile with new argument + int zone_id = CTheZones::FindZoneByLabelAndReturnIndex(zone, ZONE_DEFAULT); if (zone_id != -1) m_nIp += KEY_LENGTH_IN_SCRIPT; - CZone* pZone = CTheZones::GetZone(zone_id); + CZone* pZone = CTheZones::GetNavigationZone(zone_id); CollectParameters(&m_nIp, 1); int handle = -1; uint32 i = CPools::GetVehiclePool()->GetSize(); @@ -6972,28 +7008,16 @@ int8 CRunningScript::ProcessCommands800To899(int32 command) CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); if (pPed && pPed->CharCreatedBy == MISSION_CHAR){ CWorld::RemoveReferencesToDeletedObject(pPed); - if (pPed->bInVehicle){ - if (pPed->m_pMyVehicle){ - if (pPed == pPed->m_pMyVehicle->pDriver){ - pPed->m_pMyVehicle->RemoveDriver(); - pPed->m_pMyVehicle->SetStatus(STATUS_ABANDONED); - if (pPed->m_pMyVehicle->m_nDoorLock == CARLOCK_LOCKED_INITIALLY) - pPed->m_pMyVehicle->m_nDoorLock = CARLOCK_UNLOCKED; - if (pPed->m_nPedType == PEDTYPE_COP && pPed->m_pMyVehicle->IsLawEnforcementVehicle()) - pPed->m_pMyVehicle->ChangeLawEnforcerState(0); - }else{ - pPed->m_pMyVehicle->RemovePassenger(pPed); - } - } - delete pPed; - --CPopulation::ms_nTotalMissionPeds; - }else{ + if (pPed->bInVehicle && pPed->m_pMyVehicle) + CTheScripts::RemoveThisPed(pPed); + else{ pPed->CharCreatedBy = RANDOM_CHAR; pPed->bRespondsToThreats = true; pPed->bScriptObjectiveCompleted = false; pPed->ClearLeader(); --CPopulation::ms_nTotalMissionPeds; pPed->bFadeOut = true; + CWorld::RemoveReferencesToDeletedObject(pPed); } } if (m_bIsMissionScript) @@ -7080,10 +7104,11 @@ int8 CRunningScript::ProcessCommands800To899(int32 command) CollectParameters(&m_nIp, 1); char zone[KEY_LENGTH_IN_SCRIPT]; CTheScripts::ReadTextLabelFromScript(&m_nIp, zone); - int zone_id = CTheZones::FindZoneByLabelAndReturnIndex(zone); +// TODO(MIAMI): just getting this to compile with new argument + int zone_id = CTheZones::FindZoneByLabelAndReturnIndex(zone, ZONE_DEFAULT); if (zone_id != -1) m_nIp += KEY_LENGTH_IN_SCRIPT; - CZone* pZone = CTheZones::GetZone(zone_id); + CZone* pZone = CTheZones::GetNavigationZone(zone_id); UpdateCompareFlag(CExplosion::TestForExplosionInArea((eExplosionType)ScriptParams[0], pZone->minx, pZone->maxx, pZone->miny, pZone->maxy, pZone->minz, pZone->maxz)); return 0; @@ -7103,12 +7128,13 @@ int8 CRunningScript::ProcessCommands800To899(int32 command) } case COMMAND_CREATE_FLOATING_PACKAGE: { - CollectParameters(&m_nIp, 3); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y) + PICKUP_PLACEMENT_OFFSET; - ScriptParams[0] = CPickups::GenerateNewOne(pos, MI_FLOATPACKAGE1, PICKUP_FLOATINGPACKAGE, 0); - StoreParameters(&m_nIp, 1); +// removed in MIAMI +// CollectParameters(&m_nIp, 3); +// CVector pos = *(CVector*)&ScriptParams[0]; +// if (pos.z <= MAP_Z_LOW_LIMIT) +// pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y) + PICKUP_PLACEMENT_OFFSET; +// ScriptParams[0] = CPickups::GenerateNewOne(pos, MI_FLOATPACKAGE1, PICKUP_FLOATINGPACKAGE, 0); +// StoreParameters(&m_nIp, 1); return 0; } case COMMAND_PLACE_OBJECT_RELATIVE_TO_CAR: @@ -7137,7 +7163,7 @@ int8 CRunningScript::ProcessCommands800To899(int32 command) CollectParameters(&m_nIp, 2); CPlayerPed* pPlayerPed = CWorld::Players[ScriptParams[0]].m_pPed; assert(pPlayerPed); - pPlayerPed->m_fArmour = clamp(pPlayerPed->m_fArmour + ScriptParams[1], 0.0f, 100.0f); + pPlayerPed->m_fArmour = clamp(pPlayerPed->m_fArmour + ScriptParams[1], 0.0f, CWorld::Players[ScriptParams[0]].m_nMaxArmour); return 0; } case COMMAND_ADD_ARMOUR_TO_CHAR: @@ -7188,7 +7214,7 @@ int8 CRunningScript::ProcessCommands800To899(int32 command) pPed->m_nLastPedState = PED_NONE; pPed->bUsesCollision = true; pPed->SetMoveSpeed(0.0f, 0.0f, 0.0f); - pPed->AddWeaponModel(CWeaponInfo::GetWeaponInfo(pPed->m_weapons[pPed->m_currentWeapon].m_eWeaponType)->m_nModelId); + pPed->ReplaceWeaponWhenExitingVehicle(); pPed->RemoveInCarAnims(); if (pPed->m_pVehicleAnim) pPed->m_pVehicleAnim->blendDelta = -1000.0f; @@ -7215,7 +7241,7 @@ int8 CRunningScript::ProcessCommands800To899(int32 command) if (total == 0) CWorld::FindObjectsOfTypeInRangeSectorList(mi, CWorld::GetBigBuildingList(LEVEL_NONE), pos, range, true, &total, 16, apEntities); if (total == 0) - CWorld::FindObjectsOfTypeInRangeSectorList(mi, CWorld::GetBigBuildingList(CTheZones::FindZoneForPoint(pos)), pos, range, true, &total, 16, apEntities); + CWorld::FindObjectsOfTypeInRangeSectorList(mi, CWorld::GetBigBuildingList(CTheZones::GetLevelFromPosition(&pos)), pos, range, true, &total, 16, apEntities); CEntity* pClosestEntity = nil; float min_dist = 2.0f * range; for (int i = 0; i < total; i++) { @@ -7399,6 +7425,8 @@ int8 CRunningScript::ProcessCommands800To899(int32 command) ped->SetPosition(pos); ped->SetOrientation(0.0f, 0.0f, 0.0f); CTheScripts::ClearSpaceForMissionEntity(pos, ped); + if (m_bIsMissionScript) + ped->bIsStaticWaitingForCollision = true; CWorld::Add(ped); ped->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pos); CPopulation::ms_nTotalMissionPeds++; @@ -7686,9 +7714,7 @@ int8 CRunningScript::ProcessCommands900To999(int32 command) } case COMMAND_REMOVE_TEXTURE_DICTIONARY: { - for (int i = 0; i < ARRAY_SIZE(CTheScripts::ScriptSprites); i++) - CTheScripts::ScriptSprites[i].Delete(); - CTxdStore::RemoveTxd(CTxdStore::FindTxdSlot("script")); + CTheScripts::RemoveScriptTextureDictionary(); return 0; } case COMMAND_SET_OBJECT_DYNAMIC: @@ -7967,7 +7993,7 @@ int8 CRunningScript::ProcessCommands900To999(int32 command) if (total == 0) CWorld::FindObjectsOfTypeInRangeSectorList(mi1, CWorld::GetBigBuildingList(LEVEL_NONE), pos, radius, true, &total, 16, apEntities); if (total == 0) - CWorld::FindObjectsOfTypeInRangeSectorList(mi1, CWorld::GetBigBuildingList(CTheZones::FindZoneForPoint(pos)), pos, radius, true, &total, 16, apEntities); + CWorld::FindObjectsOfTypeInRangeSectorList(mi1, CWorld::GetBigBuildingList(CTheZones::GetLevelFromPosition(&pos)), pos, radius, true, &total, 16, apEntities); CEntity* pClosestEntity = nil; float min_dist = 2.0f * radius; for (int i = 0; i < total; i++) { @@ -8141,7 +8167,7 @@ int8 CRunningScript::ProcessCommands900To999(int32 command) case MI_FBICAR: case MI_MRWHOOP: case MI_BFINJECT: - case MI_CORPSE: + // case MI_CORPSE: case MI_POLICE: case MI_ENFORCER: case MI_SECURICA: @@ -8154,27 +8180,27 @@ int8 CRunningScript::ProcessCommands900To999(int32 command) case MI_DODO: case MI_COACH: case MI_RCBANDIT: - case MI_BELLYUP: - case MI_MRWONGS: - case MI_MAFIA: - case MI_YARDIE: - case MI_YAKUZA: - case MI_DIABLOS: - case MI_COLUMB: - case MI_HOODS: + // case MI_BELLYUP: + // case MI_MRWONGS: + // case MI_MAFIA: + case MI_VOODOO: + // case MI_YAKUZA: + // case MI_DIABLOS: + // case MI_COLUMB: + // case MI_HOODS: case MI_AIRTRAIN: case MI_DEADDODO: case MI_SPEEDER: case MI_REEFER: - case MI_PANLANT: + // case MI_PANLANT: case MI_FLATBED: case MI_YANKEE: - case MI_ESCAPE: - case MI_BORGNINE: - case MI_TOYZ: - case MI_GHOST: - case MI_MIAMI_RCBARON: - case MI_MIAMI_RCRAIDER: + // case MI_ESCAPE: + case MI_ZEBRA: + case MI_TOPFUN: + // case MI_GHOST: + case MI_RCBARON: + case MI_RCRAIDER: model = -1; break; case MI_IDAHO: @@ -8184,21 +8210,21 @@ int8 CRunningScript::ProcessCommands900To999(int32 command) case MI_PATRIOT: case MI_MANANA: case MI_INFERNUS: - case MI_BLISTA: + // case MI_BLISTA: case MI_PONY: case MI_CHEETAH: case MI_MOONBEAM: case MI_ESPERANT: case MI_TAXI: - case MI_KURUMA: + case MI_WASHING: case MI_BOBCAT: case MI_BANSHEE: case MI_CABBIE: case MI_STALLION: case MI_RUMPO: - case 151: - case 152: - case 153: +// case 151: +// case 152: +// case 153: break; default: printf("CREATE_RANDOM_CAR_FOR_CAR_PARK - Unknown car model %d\n", CStreaming::ms_vehiclesLoaded[index]); @@ -8293,14 +8319,34 @@ int8 CRunningScript::ProcessCommands900To999(int32 command) DMAudio.PreloadMissionAudio(str); return 0; case COMMAND_HAS_MISSION_AUDIO_LOADED: - UpdateCompareFlag(DMAudio.GetMissionAudioLoadingStatus() == 1); + { + CollectParameters(&m_nIp, 1); + static bool bShowed = false; + if (!bShowed) { + debug("HAS_MISSION_AUDIO_LOADED not implemented, default to TRUE\n"); + bShowed = true; + } + UpdateCompareFlag(true); + //UpdateCompareFlag(DMAudio.GetMissionAudioLoadingStatus() == 1); return 0; + } case COMMAND_PLAY_MISSION_AUDIO: - DMAudio.PlayLoadedMissionAudio(); + CollectParameters(&m_nIp, 1); + debug("PLAY_MISSION_AUDIO doesn't support parameter yet, skipping\n"); + //DMAudio.PlayLoadedMissionAudio(); return 0; case COMMAND_HAS_MISSION_AUDIO_FINISHED: - UpdateCompareFlag(DMAudio.IsMissionAudioSampleFinished()); + { + CollectParameters(&m_nIp, 1); + static bool bShowed = false; + if (!bShowed) { + debug("HAS_MISSION_AUDIO_FINISHED not implemented, default to TRUE\n"); + bShowed = true; + } + UpdateCompareFlag(true); + //UpdateCompareFlag(DMAudio.IsMissionAudioSampleFinished()); return 0; + } case COMMAND_GET_CLOSEST_CAR_NODE_WITH_HEADING: { CollectParameters(&m_nIp, 3); @@ -8395,10 +8441,15 @@ int8 CRunningScript::ProcessCommands900To999(int32 command) ScriptParams[0] = CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages; StoreParameters(&m_nIp, 1); return 0; - case COMMAND_REGISTER_EL_BURRO_TIME: + case COMMAND_SET_CHAR_OBJ_LEAVE_ANY_CAR: + { CollectParameters(&m_nIp, 1); - CStats::RegisterElBurroTime(ScriptParams[0]); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(pPed); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_LEAVE_VEHICLE, pPed->m_pMyVehicle); return 0; + } case COMMAND_SET_SPRITES_DRAW_BEFORE_FADE: CollectParameters(&m_nIp, 1); CTheScripts::IntroRectangles[CTheScripts::NumberOfIntroRectanglesThisFrame].m_bBeforeFade = ScriptParams[0] != 0; @@ -8537,8 +8588,8 @@ int8 CRunningScript::ProcessCommands1000To1099(int32 command) return 0; } case COMMAND_GET_BODY_CAST_HEALTH: - ScriptParams[0] = CObject::nBodyCastHealth; - StoreParameters(&m_nIp, 1); + // ScriptParams[0] = CObject::nBodyCastHealth; + // StoreParameters(&m_nIp, 1); return 0; case COMMAND_SET_CHARS_CHATTING: { @@ -8573,21 +8624,17 @@ int8 CRunningScript::ProcessCommands1000To1099(int32 command) pPed->m_nZoneLevel = LEVEL_NONE; return 0; } - case COMMAND_REGISTER_4X4_ONE_TIME: - CollectParameters(&m_nIp, 1); - CStats::Register4x4OneTime(ScriptParams[0]); + case COMMAND_SET_DRUNK_INPUT_DELAY: + assert(0 && "SET_DRUNK_INPUT_DELAY not yet implemented"); return 0; - case COMMAND_REGISTER_4X4_TWO_TIME: - CollectParameters(&m_nIp, 1); - CStats::Register4x4TwoTime(ScriptParams[0]); + case COMMAND_SET_CHAR_MONEY: + assert(0 && "SET_CHAR_MONEY not yet implemented"); return 0; - case COMMAND_REGISTER_4X4_THREE_TIME: - CollectParameters(&m_nIp, 1); - CStats::Register4x4ThreeTime(ScriptParams[0]); + case COMMAND_INCREASE_CHAR_MONEY: + assert(0 && "INCREASE_CHAR_MONEY not yet implemented"); return 0; - case COMMAND_REGISTER_4X4_MAYHEM_TIME: - CollectParameters(&m_nIp, 1); - CStats::Register4x4MayhemTime(ScriptParams[0]); + case COMMAND_GET_OFFSET_FROM_OBJECT_IN_WORLD_COORDS: + assert(0 && "GET_OFFSET_FROM_OBJECT_IN_WORLD_COORDS not yet implemented"); return 0; case COMMAND_REGISTER_LIFE_SAVED: CStats::AnotherLifeSavedWithAmbulance(); @@ -8610,10 +8657,16 @@ int8 CRunningScript::ProcessCommands1000To1099(int32 command) CollectParameters(&m_nIp, 1); CStats::RegisterLongestFlightInDodo(ScriptParams[0]); return 0; - case COMMAND_REGISTER_DEFUSE_BOMB_TIME: - CollectParameters(&m_nIp, 1); - CStats::RegisterTimeTakenDefuseMission(ScriptParams[0]); + case COMMAND_GET_OFFSET_FROM_CAR_IN_WORLD_COORDS: + { + CollectParameters(&m_nIp, 4); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(pVehicle); + CVector result = pVehicle->GetMatrix() * *(CVector*)&ScriptParams[1] + pVehicle->GetPosition(); + *(CVector*)&ScriptParams[0] = result; + StoreParameters(&m_nIp, 3); return 0; + } case COMMAND_SET_TOTAL_NUMBER_OF_KILL_FRENZIES: CollectParameters(&m_nIp, 1); CStats::SetTotalNumberKillFrenzies(ScriptParams[0]); @@ -8687,8 +8740,14 @@ int8 CRunningScript::ProcessCommands1000To1099(int32 command) CollectParameters(&m_nIp, 1); CTimer::Suspend(); int offset = CTheScripts::MultiScriptArray[ScriptParams[0]]; +#ifdef USE_DEBUG_SCRIPT_LOADER + CFileMgr::ChangeDir("\\data\\"); + int handle = CFileMgr::OpenFile(scriptfile, "rb"); + CFileMgr::ChangeDir("\\"); +#else CFileMgr::ChangeDir("\\"); int handle = CFileMgr::OpenFile("data\\main.scm", "rb"); +#endif CFileMgr::Seek(handle, offset, 0); CFileMgr::Read(handle, (const char*)&CTheScripts::ScriptSpace[SIZE_MAIN_SCRIPT], SIZE_MISSION_SCRIPT); CFileMgr::CloseFile(handle); @@ -9125,7 +9184,6 @@ int8 CRunningScript::ProcessCommands1000To1099(int32 command) pPed->m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER); return 0; } -#ifndef GTA_PS2 default: assert(0); } @@ -9136,8 +9194,7 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) { char tmp[48]; switch (command) { -#endif - case COMMAND_LOAD_COLLISION_WITH_SCREEN: + case COMMAND_LOAD_COLLISION_WITH_SCREEN: // NB: not actually implemented CollectParameters(&m_nIp, 1); CTimer::Stop(); CGame::currLevel = (eLevelName)ScriptParams[0]; @@ -9164,7 +9221,7 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) m_nIp += 8; LoadSplash(tmp); return 0; - case COMMAND_SET_CAR_IGNORE_LEVEL_TRANSITIONS: + case COMMAND_SET_CAR_IGNORE_LEVEL_TRANSITIONS: // NB: not actually implemented { CollectParameters(&m_nIp, 2); CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); @@ -9175,7 +9232,7 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) pVehicle->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pVehicle->GetPosition()); return 0; } - case COMMAND_MAKE_CRAIGS_CAR_A_BIT_STRONGER: + case COMMAND_MAKE_CRAIGS_CAR_A_BIT_STRONGER: // NB: not actually implemented { CollectParameters(&m_nIp, 2); CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); @@ -9199,12 +9256,9 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) DMAudio.PreloadCutSceneMusic(STREAMED_SOUND_GAME_COMPLETED); printf("End preload end of game audio\n"); return 0; - case COMMAND_ENABLE_PLAYER_CONTROL_CAMERA: + case COMMAND_ENABLE_PLAYER_CONTROL_CAMERA: // NB: not actually implemented CPad::GetPad(0)->DisablePlayerControls &= PLAYERCONTROL_DISABLED_1; return 0; -#ifndef GTA_PS2 - // To be precise, on PS2 previous handlers were in 1000-1099 function - // These are "beta" VC commands (with bugs) case COMMAND_SET_OBJECT_ROTATION: { CollectParameters(&m_nIp, 4); @@ -9224,11 +9278,11 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) *(CVector*)&ScriptParams[0] = TheCamera.Cams[2].Source; StoreParameters(&m_nIp, 3); return 0; - case COMMAND_GET_DEBUG_CAMERA_FRONT_VECTOR: + case COMMAND_GET_DEBUG_CAMERA_FRONT_VECTOR: // NB: not actually implemented *(CVector*)&ScriptParams[0] = TheCamera.Cams[2].Front; StoreParameters(&m_nIp, 3); return 0; - case COMMAND_IS_PLAYER_TARGETTING_ANY_CHAR: + case COMMAND_IS_PLAYER_TARGETTING_ANY_CHAR: // NB: not actually implemented { CollectParameters(&m_nIp, 1); CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; @@ -9245,10 +9299,38 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) CPed* pTestedPed = CPools::GetPedPool()->GetAt(ScriptParams[1]); assert(pTestedPed); CEntity* pTarget = pPed->m_pPointGunAt; - UpdateCompareFlag(pTarget && pTarget->IsPed() && pTarget == pTestedPed); + bool bTargetting = pTarget && pTarget->IsPed() && pTarget == pTestedPed; + // PC shit + static int nCounter = 0; + nCounter = Max(0, nCounter - 1); + if (!pPed->GetWeapon()->IsTypeMelee() && !bTargetting) { + if ((pTarget->GetPosition() - TheCamera.GetPosition()).Magnitude() < 10.0f) { + CVector vTestedPos(pTarget->GetPosition().x, pTarget->GetPosition().y, pTarget->GetPosition().z + 0.4); + CVector vScreenPos; + float w, h; + if (CSprite::CalcScreenCoors(vTestedPos, vScreenPos, &w, &h, false)) { + CVector2D vCrosshairPosition(CCamera::m_f3rdPersonCHairMultX * RsGlobal.maximumWidth, CCamera::m_f3rdPersonCHairMultY * RsGlobal.maximumHeight); + float fScreenDistance = ((CVector2D)vScreenPos - vCrosshairPosition).Magnitude(); + if (SCREEN_STRETCH_X(0.45f) > fScreenDistance / w) { + CColPoint point; + CEntity* entity; + if (!CWorld::ProcessLineOfSight(TheCamera.GetPosition() + 2.0f * TheCamera.GetForward(), + vTestedPos, point, entity, true, true, true, true, true, false) || + entity == pTarget) { + nCounter += 2; + if (nCounter > 20) { + bTargetting = true; + nCounter = 20; + } + } + } + } + } + } + UpdateCompareFlag(bTargetting); return 0; } - case COMMAND_IS_PLAYER_TARGETTING_OBJECT: + case COMMAND_IS_PLAYER_TARGETTING_OBJECT: // NB: not actually implemented { CollectParameters(&m_nIp, 2); CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; @@ -9301,7 +9383,7 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) case COMMAND_FAIL_CURRENT_MISSION: CTheScripts::FailCurrentMission = 2; return 0; - case COMMAND_GET_CLOSEST_OBJECT_OF_TYPE: + case COMMAND_GET_CLOSEST_OBJECT_OF_TYPE: // NB: actually does nothing { CollectParameters(&m_nIp, 5); CVector pos = *(CVector*)&ScriptParams[0]; @@ -9347,7 +9429,7 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) StoreParameters(&m_nIp, 1); return 0; } - case COMMAND_PLACE_OBJECT_RELATIVE_TO_OBJECT: + case COMMAND_PLACE_OBJECT_RELATIVE_TO_OBJECT: // NB: not actually implemented { CollectParameters(&m_nIp, 5); CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); @@ -9363,24 +9445,14 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) CollectParameters(&m_nIp, 1); CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); assert(pVehicle); - if (pVehicle->pDriver) { - pVehicle->pDriver->bScriptObjectiveCompleted = false; - pVehicle->pDriver->SetObjective(OBJECTIVE_LEAVE_VEHICLE, pVehicle); - } - for (int i = 0; i < ARRAY_SIZE(pVehicle->pPassengers); i++) - { - if (pVehicle->pPassengers[i]) { - pVehicle->pPassengers[i]->bScriptObjectiveCompleted = false; - pVehicle->pPassengers[i]->SetObjective(OBJECTIVE_LEAVE_VEHICLE, pVehicle); - } - } + CCarAI::TellOccupantsToLeaveCar(pVehicle); return 0; } case COMMAND_SET_INTERPOLATION_PARAMETERS: CollectParameters(&m_nIp, 2); - TheCamera.SetParametersForScriptInterpolation(*(float*)&ScriptParams[0], 50.0f - *(float*)&ScriptParams[0], ScriptParams[1]); + TheCamera.SetParametersForScriptInterpolation(*(float*)&ScriptParams[0], 100.0f - *(float*)&ScriptParams[0], ScriptParams[1]); return 0; - case COMMAND_GET_CLOSEST_CAR_NODE_WITH_HEADING_TOWARDS_POINT: + case COMMAND_GET_CLOSEST_CAR_NODE_WITH_HEADING_TOWARDS_POINT: // NB: not actually implemented { CollectParameters(&m_nIp, 5); CVector pos = *(CVector*)&ScriptParams[0]; @@ -9395,7 +9467,7 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) StoreParameters(&m_nIp, 4); return 0; } - case COMMAND_GET_CLOSEST_CAR_NODE_WITH_HEADING_AWAY_POINT: + case COMMAND_GET_CLOSEST_CAR_NODE_WITH_HEADING_AWAY_POINT: // NB: not actually implemented { CollectParameters(&m_nIp, 5); CVector pos = *(CVector*)&ScriptParams[0]; @@ -9415,10 +9487,12 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) StoreParameters(&m_nIp, 3); return 0; case COMMAND_ATTACH_CHAR_TO_CAR: - // empty implementation + // TODO(MIAMI) + assert(0); return 0; case COMMAND_DETACH_CHAR_FROM_CAR: - // empty implementation + // TODO(MIAMI) + assert(0); return 0; case COMMAND_SET_CAR_CHANGE_LANE: // for some reason changed in SA { @@ -9432,15 +9506,20 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) { CollectParameters(&m_nIp, 1); CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - assert(pPed); - pPed->m_lastWepDam = -1; + if (pPed) + pPed->m_lastWepDam = -1; + else + debug("CLEAR_CHAR_LAST_WEAPON_DAMAGE - Character doesn't exist\n"); return 0; } case COMMAND_CLEAR_CAR_LAST_WEAPON_DAMAGE: { CollectParameters(&m_nIp, 1); CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - pVehicle->m_nLastWeaponDamage = -1; + if (pVehicle) + pVehicle->m_nLastWeaponDamage = -1; + else + debug("CLEAR_CAR_LAST_WEAPON_DAMAGE - Vehicle doesn't exist\n"); return 0; } case COMMAND_GET_RANDOM_COP_IN_AREA: @@ -9461,9 +9540,11 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) continue; if (pPed->m_nPedType != PEDTYPE_COP) continue; + if (!ThisIsAValidRandomCop(pPed->GetModelIndex(), ScriptParams[4], ScriptParams[5], ScriptParams[6], ScriptParams[7], ScriptParams[8])) + continue; if (pPed->CharCreatedBy != RANDOM_CHAR) continue; - if (!pPed->IsPedInControl() && pPed->GetPedState() != PED_DRIVING) + if (!pPed->IsPedInControl() && pPed->GetPedState() != PED_DRIVING /* && pPed->GetPedState() != PED_ONROPE */) // TODO(MIAMI)! continue; if (pPed->bRemoveFromWorld) continue; @@ -9489,14 +9570,15 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) StoreParameters(&m_nIp, 1); return 0; } - case COMMAND_GET_RANDOM_COP_IN_ZONE: + case COMMAND_GET_RANDOM_COP_IN_ZONE: // NB: not actually implemented { char zone[KEY_LENGTH_IN_SCRIPT]; strncpy(zone, (const char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); - int nZone = CTheZones::FindZoneByLabelAndReturnIndex(zone); +// TODO(MIAMI): just getting this to compile with new argument + int nZone = CTheZones::FindZoneByLabelAndReturnIndex(zone, ZONE_DEFAULT); if (nZone != -1) m_nIp += KEY_LENGTH_IN_SCRIPT; - CZone* pZone = CTheZones::GetZone(nZone); + CZone* pZone = CTheZones::GetNavigationZone(nZone); int ped_handle = -1; CVector pos = FindPlayerCoors(); int i = CPools::GetPedPool()->GetSize(); @@ -9592,7 +9674,7 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) CollectParameters(&m_nIp, 1); CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; assert(pPed); - ScriptParams[0] = pPed->m_weapons[pPed->m_currentWeapon].m_eWeaponType; + ScriptParams[0] = pPed->GetWeapon()->m_eWeaponType; StoreParameters(&m_nIp, 1); return 0; } @@ -9601,7 +9683,7 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) CollectParameters(&m_nIp, 1); CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(pPed); - ScriptParams[0] = pPed->m_weapons[pPed->m_currentWeapon].m_eWeaponType; + ScriptParams[0] = pPed->GetWeapon()->m_eWeaponType; StoreParameters(&m_nIp, 1); return 0; } @@ -9613,16 +9695,16 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) case COMMAND_LOCATE_CHAR_IN_CAR_OBJECT_3D: LocateCharObjectCommand(command, &m_nIp); return 0; - case COMMAND_SET_CAR_HANDBRAKE_TURN_LEFT: // this will be changed in final VC version to a more general SET_TEMP_ACTION + case COMMAND_SET_CAR_TEMP_ACTION: { - CollectParameters(&m_nIp, 2); + CollectParameters(&m_nIp, 3); CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); assert(pVehicle); - pVehicle->AutoPilot.m_nTempAction = TEMPACT_HANDBRAKETURNLEFT; - pVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + ScriptParams[1]; + pVehicle->AutoPilot.m_nTempAction = (eCarTempAction)ScriptParams[1]; + pVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + ScriptParams[2]; return 0; } - case COMMAND_SET_CAR_HANDBRAKE_TURN_RIGHT: + case COMMAND_SET_CAR_HANDBRAKE_TURN_RIGHT: // NB: not actually implemented { CollectParameters(&m_nIp, 2); CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); @@ -9631,7 +9713,7 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) pVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + ScriptParams[1]; return 0; } - case COMMAND_SET_CAR_HANDBRAKE_STOP: + case COMMAND_SET_CAR_HANDBRAKE_STOP: // NB: not actually implemented { CollectParameters(&m_nIp, 2); CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); @@ -9645,11 +9727,11 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) CollectParameters(&m_nIp, 1); CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(pPed); - UpdateCompareFlag(pPed->bInVehicle&& pPed->m_pMyVehicle->m_vehType == VEHICLE_TYPE_BIKE); + UpdateCompareFlag(pPed->bInVehicle&& pPed->m_pMyVehicle->GetVehicleAppearance() == VEHICLE_APPEARANCE_BIKE); return 0; } - case COMMAND_LOCATE_SNIPER_BULLET_2D: - case COMMAND_LOCATE_SNIPER_BULLET_3D: + case COMMAND_LOCATE_SNIPER_BULLET_2D: // NB: not actually implemented + case COMMAND_LOCATE_SNIPER_BULLET_3D: // NB: not actually implemented LocateSniperBulletCommand(command, &m_nIp); return 0; case COMMAND_GET_NUMBER_OF_SEATS_IN_MODEL: @@ -9662,10 +9744,10 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) CollectParameters(&m_nIp, 1); CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; assert(pPed); - UpdateCompareFlag(pPed->bInVehicle && pPed->m_pMyVehicle->m_vehType == VEHICLE_TYPE_BIKE); + UpdateCompareFlag(pPed->bInVehicle && pPed->m_pMyVehicle->GetVehicleAppearance() == VEHICLE_APPEARANCE_BIKE); return 0; } - case COMMAND_IS_CHAR_LYING_DOWN: + case COMMAND_IS_CHAR_LYING_DOWN: // NB: not actually implemented { CollectParameters(&m_nIp, 1); CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); @@ -9690,29 +9772,1033 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) } case COMMAND_SET_ENTER_CAR_RANGE_MULTIPLIER: CollectParameters(&m_nIp, 1); -#ifdef FIX_BUGS CPed::nEnterCarRangeMultiplier = *(float*)&ScriptParams[0]; -#else - CPed::nEnterCarRangeMultiplier = (float)ScriptParams[0]; -#endif return 0; -#endif -#ifndef GTA3_1_1_PATCH case COMMAND_SET_THREAT_REACTION_RANGE_MULTIPLIER: CollectParameters(&m_nIp, 1); -#ifdef FIX_BUGS CPed::nThreatReactionRangeMultiplier = *(float*)&ScriptParams[0]; -#else - CPed::nThreatReactionRangeMultiplier = (float)ScriptParams[0]; -#endif return 0; -#endif + case COMMAND_SET_CHAR_CEASE_ATTACK_TIMER: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(pPed); + pPed->m_ceaseAttackTimer = ScriptParams[1]; + return 0; + } + case COMMAND_GET_REMOTE_CONTROLLED_CAR: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CWorld::Players[ScriptParams[0]].m_pRemoteVehicle; + if (pVehicle) + ScriptParams[0] = CPools::GetVehiclePool()->GetIndex(pVehicle); + else + ScriptParams[0] = -1; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_IS_PC_VERSION: + UpdateCompareFlag(true); + return 0; + //case COMMAND_REPLAY: + //case COMMAND_IS_REPLAY_PLAYING: + case COMMAND_IS_MODEL_AVAILABLE: + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(CModelInfo::GetModelInfo(ScriptParams[0]) != nil); + return 0; + case COMMAND_SHUT_CHAR_UP: + assert("SHUT_CHAR_UP not implemented"); // TODO(MIAMI) + case COMMAND_SET_ENABLE_RC_DETONATE: + CollectParameters(&m_nIp, 1); + CVehicle::bDisableRemoteDetonation = ScriptParams[0]; + return 0; + case COMMAND_SET_CAR_RANDOM_ROUTE_SEED: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(pVehicle); + pVehicle->m_nRouteSeed = ScriptParams[1]; + return 0; + } + case COMMAND_IS_ANY_PICKUP_AT_COORDS: + { + CollectParameters(&m_nIp, 3); + CVector pos = *(CVector*)&ScriptParams[0]; + CRunningScript::UpdateCompareFlag(CPickups::TestForPickupsInBubble(pos, 0.5f)); + return 0; + } + case COMMAND_GET_FIRST_PICKUP_COORDS: + case COMMAND_GET_NEXT_PICKUP_COORDS: + case COMMAND_REMOVE_ALL_CHAR_WEAPONS: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(pPed); + pPed->ClearWeapons(); + return 0; + } + case COMMAND_HAS_PLAYER_GOT_WEAPON: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + assert(pPed); + bool bFound = false; + for (int i = 0; i < TOTAL_WEAPON_SLOTS; i++) { + if (pPed->GetWeapon(i).m_eWeaponType == ScriptParams[1]) { + bFound = true; + break; + } + } + UpdateCompareFlag(bFound); + return 0; + } + //case COMMAND_HAS_CHAR_GOT_WEAPON: + //case COMMAND_IS_PLAYER_FACING_CHAR: + case COMMAND_SET_TANK_DETONATE_CARS: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(pVehicle && pVehicle->m_vehType == VEHICLE_TYPE_CAR); + ((CAutomobile*)pVehicle)->bTankDetonateCars = ScriptParams[1]; + return 0; + } + case COMMAND_GET_POSITION_OF_ANALOGUE_STICKS: + { + CollectParameters(&m_nIp, 1); + CPad* pPad = CPad::GetPad(ScriptParams[0]); + ScriptParams[0] = pPad->NewState.LeftStickX; + ScriptParams[1] = pPad->NewState.LeftStickY; + ScriptParams[2] = pPad->NewState.RightStickX; + ScriptParams[3] = pPad->NewState.RightStickY; + StoreParameters(&m_nIp, 4); + return 0; + } + case COMMAND_IS_CAR_ON_FIRE: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(pVehicle); + bool bOnFire = false; + if (pVehicle->m_pCarFire) + bOnFire = true; + if (pVehicle->m_vehType == VEHICLE_TYPE_CAR && ((CAutomobile*)pVehicle)->Damage.GetEngineStatus() >= ENGINE_STATUS_ON_FIRE) + bOnFire = true; + if (pVehicle->m_fHealth < 250.0f) + bOnFire = true; + UpdateCompareFlag(bOnFire); + return 0; + } + case COMMAND_IS_CAR_TYRE_BURST: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(pVehicle); + bool bIsBurst = false; + if (pVehicle->m_vehType == VEHICLE_APPEARANCE_BIKE) { + assert("IS_CAR_TYPE_BURST not yet implemented for bikes"); + } + else { + CAutomobile* pCar = (CAutomobile*)pVehicle; + if (ScriptParams[1] == 4) { + for (int i = 0; i < 4; i++) { + if (pCar->Damage.GetWheelStatus(i) == WHEEL_STATUS_BURST) + bIsBurst = true; + } + } + else + bIsBurst = pCar->Damage.GetWheelStatus(ScriptParams[1] == WHEEL_STATUS_BURST); + } + UpdateCompareFlag(bIsBurst); + } + //case COMMAND_SET_CAR_DRIVE_STRAIGHT_AHEAD: + //case COMMAND_SET_CAR_WAIT: + //case COMMAND_IS_PLAYER_STANDING_ON_A_VEHICLE: + //case COMMAND_IS_PLAYER_FOOT_DOWN: + //case COMMAND_IS_CHAR_FOOT_DOWN: + case COMMAND_INITIALISE_OBJECT_PATH: + // TODO(MIAMI): script path + CollectParameters(&m_nIp, 2); + debug("INITALISE_OBJECT_PATH not yet implemented, skipping\n"); + ScriptParams[0] = 0; + StoreParameters(&m_nIp, 1); + return 0; + case COMMAND_START_OBJECT_ON_PATH: + { + CollectParameters(&m_nIp, 2); + debug("START_OBJECT_ON_PATH not yet implemented, skipping\n"); + return 0; + } + case COMMAND_SET_OBJECT_PATH_SPEED: + { + CollectParameters(&m_nIp, 2); + debug("SET_OBJECT_PATH_SPEED not yet implemented, skipping\n"); + return 0; + } + case COMMAND_SET_OBJECT_PATH_POSITION: + { + CollectParameters(&m_nIp, 2); + debug("SET_OBJECT_PATH_POSITION not yet implemented, skipping\n"); + return 0; + } + //case COMMAND_GET_OBJECT_DISTANCE_ALONG_PATH: + case COMMAND_CLEAR_OBJECT_PATH: + { + CollectParameters(&m_nIp, 1); + debug("CLEAR_OBJECT_PATH not yet implemented, skipping\n"); + return 0; + } + case COMMAND_HELI_GOTO_COORDS: + { + CollectParameters(&m_nIp, 5); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(pVehicle && pVehicle->GetVehicleAppearance() == VEHICLE_APPEARANCE_HELI); + ((CAutomobile*)pVehicle)->TellHeliToGoToCoors(*(float*)&ScriptParams[1], *(float*)&ScriptParams[2], *(float*)&ScriptParams[3], ScriptParams[4]); + return 0; + } + case COMMAND_IS_INT_VAR_EQUAL_TO_CONSTANT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(*ptr = ScriptParams[0]); + return 0; + } + case COMMAND_IS_INT_LVAR_EQUAL_TO_CONSTANT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(*ptr = ScriptParams[0]); + return 0; + } + case COMMAND_GET_DEAD_CHAR_PICKUP_COORDS: + { + CollectParameters(&m_nIp, 1); + CPed *pTarget = CPools::GetPedPool()->GetAt(ScriptParams[0]); + CVector pos; + pTarget->CreateDeadPedPickupCoors(&pos.x, &pos.y, &pos.z); + *(CVector*)&ScriptParams[0] = pos; + StoreParameters(&m_nIp, 3); + return 0; + } + case COMMAND_CREATE_PROTECTION_PICKUP: + { + CollectParameters(&m_nIp, 5); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y) + PICKUP_PLACEMENT_OFFSET; + ScriptParams[0] = CPickups::GenerateNewOne(pos, MI_PICKUP_REVENUE, PICKUP_ASSET_REVENUE, ScriptParams[3], ScriptParams[4]); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_IS_CHAR_IN_ANY_BOAT: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(pPed); + UpdateCompareFlag(pPed->bInVehicle && pPed->m_pMyVehicle->GetVehicleAppearance() == VEHICLE_APPEARANCE_BOAT); + return 0; + } + case COMMAND_IS_PLAYER_IN_ANY_BOAT: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + assert(pPed); + UpdateCompareFlag(pPed->bInVehicle && pPed->m_pMyVehicle->GetVehicleAppearance() == VEHICLE_APPEARANCE_BIKE); + return 0; + } + case COMMAND_IS_CHAR_IN_ANY_HELI: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(pPed); + UpdateCompareFlag(pPed->bInVehicle && pPed->m_pMyVehicle->GetVehicleAppearance() == VEHICLE_APPEARANCE_HELI); + return 0; + } + case COMMAND_IS_PLAYER_IN_ANY_HELI: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + assert(pPed); + UpdateCompareFlag(pPed->bInVehicle && pPed->m_pMyVehicle->GetVehicleAppearance() == VEHICLE_APPEARANCE_HELI); + return 0; + } + case COMMAND_IS_CHAR_IN_ANY_PLANE: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(pPed); + UpdateCompareFlag(pPed->bInVehicle && pPed->m_pMyVehicle->GetVehicleAppearance() == VEHICLE_APPEARANCE_PLANE); + return 0; + } + case COMMAND_IS_PLAYER_IN_ANY_PLANE: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + assert(pPed); + UpdateCompareFlag(pPed->bInVehicle && pPed->m_pMyVehicle->GetVehicleAppearance() == VEHICLE_APPEARANCE_HELI); + return 0; + } + case COMMAND_IS_CHAR_IN_WATER: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + UpdateCompareFlag(pPed && pPed->bIsInWater); + return 0; + } + case COMMAND_SET_VAR_INT_TO_CONSTANT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + *ptr = ScriptParams[0]; + return 0; + } + case COMMAND_SET_LVAR_INT_TO_CONSTANT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + *ptr = ScriptParams[0]; + return 0; + } default: assert(0); } return -1; } + +int8 CRunningScript::ProcessCommands1200To1299(int32 command) +{ + switch (command) { + case COMMAND_IS_INT_VAR_GREATER_THAN_CONSTANT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(*ptr > ScriptParams[0]); + return 0; + } + case COMMAND_IS_INT_LVAR_GREATER_THAN_CONSTANT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(*ptr > ScriptParams[0]); + return 0; + } + case COMMAND_IS_CONSTANT_GREATER_THAN_INT_VAR: + { + CollectParameters(&m_nIp, 1); + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + UpdateCompareFlag(ScriptParams[0] > *ptr); + return 0; + } + case COMMAND_IS_CONSTANT_GREATER_THAN_INT_LVAR: + { + CollectParameters(&m_nIp, 1); + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + UpdateCompareFlag(ScriptParams[0] > *ptr); + return 0; + } + case COMMAND_IS_INT_VAR_GREATER_OR_EQUAL_TO_CONSTANT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(*ptr >= ScriptParams[0]); + return 0; + } + case COMMAND_IS_INT_LVAR_GREATER_OR_EQUAL_TO_CONSTANT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(*ptr >= ScriptParams[0]); + return 0; + } + case COMMAND_IS_CONSTANT_GREATER_OR_EQUAL_TO_INT_VAR: + { + CollectParameters(&m_nIp, 1); + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + UpdateCompareFlag(ScriptParams[0] >= *ptr); + return 0; + } + case COMMAND_IS_CONSTANT_GREATER_OR_EQUAL_TO_INT_LVAR: + { + CollectParameters(&m_nIp, 1); + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + UpdateCompareFlag(ScriptParams[0] >= *ptr); + return 0; + } + case COMMAND_GET_CHAR_WEAPON_IN_SLOT: + case COMMAND_GET_CLOSEST_STRAIGHT_ROAD: + assert(0); + case COMMAND_SET_CAR_FORWARD_SPEED: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(pVehicle); + float speed = *(float*)&ScriptParams[1] / GAME_SPEED_TO_CARAI_SPEED; + pVehicle->SetMoveSpeed(pVehicle->GetForward() * speed); + // TODO(MIAMI): heli hack! + return 0; + } + case COMMAND_SET_AREA_VISIBLE: + CollectParameters(&m_nIp, 1); + CGame::currArea = ScriptParams[0]; + // TODO(MIAMI) !! + //CStreaming::RemoveBuildingsNotInArea(ScriptParams[0]); + return 0; + case COMMAND_SET_CUTSCENE_ANIM_TO_LOOP: + { + char key[KEY_LENGTH_IN_SCRIPT]; + CTheScripts::ReadTextLabelFromScript(&m_nIp, key); + m_nIp += KEY_LENGTH_IN_SCRIPT; + debug("SET_CUTSCENE_ANIM_TO_LOOP not implemented yet, skipping\n"); + return 0; + } + case COMMAND_MARK_CAR_AS_CONVOY_CAR: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(pVehicle); + pVehicle->bPartOfConvoy = ScriptParams[1]; + return 0; + } + case COMMAND_RESET_HAVOC_CAUSED_BY_PLAYER: + case COMMAND_GET_HAVOC_CAUSED_BY_PLAYER: + case COMMAND_CREATE_SCRIPT_ROADBLOCK: + case COMMAND_CLEAR_ALL_SCRIPT_ROADBLOCKS: + case COMMAND_SET_CHAR_OBJ_WALK_TO_CHAR: + case COMMAND_IS_PICKUP_IN_ZONE: + case COMMAND_GET_OFFSET_FROM_CHAR_IN_WORLD_COORDS: + case COMMAND_HAS_CHAR_BEEN_PHOTOGRAPHED: + case COMMAND_SET_CHAR_OBJ_AIM_GUN_AT_CHAR: + case COMMAND_SWITCH_SECURITY_CAMERA: + case COMMAND_IS_CHAR_IN_FLYING_VEHICLE: + assert(0); + case COMMAND_IS_PLAYER_IN_FLYING_VEHICLE: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + assert(pPed); + UpdateCompareFlag(pPed->bInVehicle && (pPed->m_pMyVehicle->GetVehicleAppearance() == VEHICLE_APPEARANCE_HELI || pPed->m_pMyVehicle->GetVehicleAppearance() == VEHICLE_APPEARANCE_PLANE)); + return 0; + } + case COMMAND_HAS_SONY_CD_BEEN_READ: + case COMMAND_GET_NUMBER_OF_SONY_CDS_READ: + case COMMAND_ADD_SHORT_RANGE_BLIP_FOR_COORD_OLD: + case COMMAND_ADD_SHORT_RANGE_BLIP_FOR_COORD: + assert(0); + case COMMAND_ADD_SHORT_RANGE_SPRITE_BLIP_FOR_COORD: + { + CollectParameters(&m_nIp, 4); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + int id = CRadar::SetShortRangeCoordBlip(BLIP_COORD, pos, 5, BLIP_DISPLAY_BOTH); + CRadar::SetBlipSprite(id, ScriptParams[3]); + ScriptParams[0] = id; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_ADD_MONEY_SPENT_ON_CLOTHES: + CollectParameters(&m_nIp, 1); + CStats::MoneySpentOnFashion(ScriptParams[0]); + return 0; + + case COMMAND_SET_HELI_ORIENTATION: + case COMMAND_CLEAR_HELI_ORIENTATION: + case COMMAND_PLANE_GOTO_COORDS: + case COMMAND_GET_NTH_CLOSEST_CAR_NODE: + case COMMAND_GET_NTH_CLOSEST_CHAR_NODE: + case COMMAND_DRAW_WEAPONSHOP_CORONA: + case COMMAND_SET_ENABLE_RC_DETONATE_ON_CONTACT: + case COMMAND_FREEZE_CHAR_POSITION: + case COMMAND_SET_CHAR_DROWNS_IN_WATER: + case COMMAND_SET_OBJECT_RECORDS_COLLISIONS: + case COMMAND_HAS_OBJECT_COLLIDED_WITH_ANYTHING: + case COMMAND_REMOVE_RC_BUGGY: + case COMMAND_HAS_PHOTOGRAPH_BEEN_TAKEN: + case COMMAND_GET_CHAR_ARMOUR: + case COMMAND_SET_CHAR_ARMOUR: + case COMMAND_SET_HELI_STABILISER: + case COMMAND_SET_CAR_STRAIGHT_LINE_DISTANCE: + case COMMAND_POP_CAR_BOOT: + case COMMAND_SHUT_PLAYER_UP: + case COMMAND_SET_PLAYER_MOOD: + assert(0); + case COMMAND_REQUEST_COLLISION: + { + CollectParameters(&m_nIp, 2); + CVector2D pos; + pos.x = *(float*)&ScriptParams[0]; + pos.y = *(float*)&ScriptParams[1]; + CColStore::RequestCollision(pos); + return 0; + } + case COMMAND_LOCATE_OBJECT_2D: + case COMMAND_LOCATE_OBJECT_3D: + case COMMAND_IS_OBJECT_IN_WATER: + case COMMAND_SET_CHAR_OBJ_STEAL_ANY_CAR_EVEN_MISSION_CAR: + case COMMAND_IS_OBJECT_IN_AREA_2D: + case COMMAND_IS_OBJECT_IN_AREA_3D: + case COMMAND_TASK_TOGGLE_DUCK: + assert(0); + case COMMAND_SET_ZONE_CIVILIAN_CAR_INFO: + { + char label[12]; + int16 carDensities[CCarCtrl::NUM_CAR_CLASSES] = { 0 }; + int16 boatDensities[CCarCtrl::NUM_BOAT_CLASSES] = { 0 }; + int i; + + CTheScripts::ReadTextLabelFromScript(&m_nIp, label); + m_nIp += KEY_LENGTH_IN_SCRIPT; + CollectParameters(&m_nIp, 12); + for (i = 0; i < CCarCtrl::NUM_CAR_CLASSES; i++) + carDensities[i] = ScriptParams[i + 1]; + for (i = 0; i < CCarCtrl::NUM_BOAT_CLASSES; i++) + boatDensities[i] = ScriptParams[i + 1 + CCarCtrl::NUM_CAR_CLASSES]; + int zone = CTheZones::FindZoneByLabelAndReturnIndex(label, ZONE_INFO); + if (zone < 0) { + debug("Couldn't find zone - %s\n", label); + return 0; + } + while (zone >= 0) { + CTheZones::SetZoneCivilianCarInfo(zone, ScriptParams[0], carDensities, boatDensities); + zone = CTheZones::FindNextZoneByLabelAndReturnIndex(label, ZONE_INFO); + } + return 0; + } + case COMMAND_REQUEST_ANIMATION: + case COMMAND_HAS_ANIMATION_LOADED: + case COMMAND_REMOVE_ANIMATION: + case COMMAND_IS_CHAR_WAITING_FOR_WORLD_COLLISION: + case COMMAND_IS_CAR_WAITING_FOR_WORLD_COLLISION: + case COMMAND_IS_OBJECT_WAITING_FOR_WORLD_COLLISION: + case COMMAND_SET_CHAR_SHUFFLE_INTO_DRIVERS_SEAT: + case COMMAND_ATTACH_CHAR_TO_OBJECT: + case COMMAND_SET_CHAR_AS_PLAYER_FRIEND: + case COMMAND_DISPLAY_NTH_ONSCREEN_COUNTER: + case COMMAND_DISPLAY_NTH_ONSCREEN_COUNTER_WITH_STRING: + assert(0); + case COMMAND_ADD_SET_PIECE: + { + CollectParameters(&m_nIp, 13); + debug("ADD_SET_PIECE not implemented, skipping\n"); + return 0; + } + case COMMAND_SET_EXTRA_COLOURS: + { + CollectParameters(&m_nIp, 2); + debug("SET_EXTRA_COLOURS not implemented, skipping\n"); + return 0; + } + case COMMAND_CLEAR_EXTRA_COLOURS: + { + CollectParameters(&m_nIp, 1); + debug("CLEAR_EXTRA_COLOURS not implemented, skipping\n"); + return 0; + } + case COMMAND_CLOSE_CAR_BOOT: + assert(0); + case COMMAND_GET_WHEELIE_STATS: + { + CollectParameters(&m_nIp, 1); + static bool bShowed = false; + if (!bShowed) { + debug("GET_WHEELIE_STATS not implemented\n"); + bShowed = true; + } + for (int i = 0; i < 6; i++) + ScriptParams[i] = 0; + StoreParameters(&m_nIp, 6); + return 0; + } + case COMMAND_DISARM_CHAR: + case COMMAND_BURST_CAR_TYRE: + case COMMAND_IS_CHAR_OBJ_NO_OBJ: + case COMMAND_IS_PLAYER_WEARING: + case COMMAND_SET_PLAYER_CAN_DO_DRIVE_BY: + case COMMAND_SET_CHAR_OBJ_SPRINT_TO_COORD: + case COMMAND_CREATE_SWAT_ROPE: + case COMMAND_SET_FIRST_PERSON_CONTROL_CAMERA: + case COMMAND_GET_NEAREST_TYRE_TO_POINT: + case COMMAND_SET_CAR_MODEL_COMPONENTS: + case COMMAND_SWITCH_LIFT_CAMERA: + case COMMAND_CLOSE_ALL_CAR_DOORS: + case COMMAND_GET_DISTANCE_BETWEEN_COORDS_2D: + case COMMAND_GET_DISTANCE_BETWEEN_COORDS_3D: + case COMMAND_POP_CAR_BOOT_USING_PHYSICS: + case COMMAND_SET_FIRST_PERSON_WEAPON_CAMERA: + case COMMAND_IS_CHAR_LEAVING_VEHICLE_TO_DIE: + case COMMAND_SORT_OUT_OBJECT_COLLISION_WITH_CAR: + case COMMAND_GET_MAX_WANTED_LEVEL: + case COMMAND_IS_CHAR_WANDER_PATH_CLEAR: + case COMMAND_PRINT_HELP_WITH_NUMBER: + case COMMAND_PRINT_HELP_FOREVER: + case COMMAND_PRINT_HELP_FOREVER_WITH_NUMBER: + default: + assert(0); + } + return -1; +} + +int8 CRunningScript::ProcessCommands1300To1399(int32 command) +{ + switch (command) { + case COMMAND_SET_CHAR_CAN_BE_DAMAGED_BY_MEMBERS_OF_GANG: + { + CollectParameters(&m_nIp, 3); + CPed *pTarget = CPools::GetPedPool()->GetAt(ScriptParams[0]); + uint8 flag = 1 << (uint8)ScriptParams[1]; + if (ScriptParams[2]) + pTarget->m_gangFlags |= flag; + else + pTarget->m_gangFlags &= ~flag; + + return 0; + } + case COMMAND_LOAD_AND_LAUNCH_MISSION_EXCLUSIVE: + case COMMAND_IS_MISSION_AUDIO_PLAYING: + assert(0); + case COMMAND_CREATE_LOCKED_PROPERTY_PICKUP: + { + CollectParameters(&m_nIp, 3); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y) + PICKUP_PLACEMENT_OFFSET; + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + // TODO(MIAMI) - add text + CPickups::GetActualPickupIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + ScriptParams[0] = CPickups::GenerateNewOne(pos, MI_PICKUP_PROPERTY, PICKUP_PROPERTY_LOCKED, 0, 0, false, text); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_CREATE_FORSALE_PROPERTY_PICKUP: + { + CollectParameters(&m_nIp, 4); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y) + PICKUP_PLACEMENT_OFFSET; + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + // TODO(MIAMI) - add text + CPickups::GetActualPickupIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + ScriptParams[0] = CPickups::GenerateNewOne(pos, MI_PICKUP_PROPERTY_FORSALE, PICKUP_PROPERTY_FORSALE, ScriptParams[3], 0, false, text); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_FREEZE_CAR_POSITION: + case COMMAND_HAS_CHAR_BEEN_DAMAGED_BY_CHAR: + case COMMAND_HAS_CHAR_BEEN_DAMAGED_BY_CAR: + case COMMAND_HAS_CAR_BEEN_DAMAGED_BY_CHAR: + case COMMAND_HAS_CAR_BEEN_DAMAGED_BY_CAR: + case COMMAND_GET_RADIO_CHANNEL: + case COMMAND_DISPLAY_TEXT_WITH_3_NUMBERS: + case COMMAND_IS_CAR_DROWNING_IN_WATER: + case COMMAND_IS_CHAR_DROWNING_IN_WATER: + assert(0); + case COMMAND_DISABLE_CUTSCENE_SHADOWS: + { + debug("DISABLE_CUTSCENE_SHADOWS not implemented, skipping\n"); + return 0; + } + case COMMAND_HAS_GLASS_BEEN_SHATTERED_NEARBY: + case COMMAND_ATTACH_CUTSCENE_OBJECT_TO_BONE: + case COMMAND_ATTACH_CUTSCENE_OBJECT_TO_COMPONENT: + case COMMAND_SET_CHAR_STAY_IN_CAR_WHEN_JACKED: + case COMMAND_IS_MISSION_AUDIO_LOADING: + case COMMAND_ADD_MONEY_SPENT_ON_WEAPONS: + case COMMAND_ADD_MONEY_SPENT_ON_PROPERTY: + case COMMAND_ADD_MONEY_SPENT_ON_AUTO_PAINTING: + case COMMAND_SET_CHAR_ANSWERING_MOBILE: + case COMMAND_SET_PLAYER_DRUNKENNESS: + case COMMAND_GET_PLAYER_DRUNKENNESS: + case COMMAND_SET_PLAYER_DRUG_LEVEL: + case COMMAND_GET_PLAYER_DRUG_LEVEL: + case COMMAND_ADD_LOAN_SHARK_VISITS: + case COMMAND_ADD_STORES_KNOCKED_OFF: + case COMMAND_ADD_MOVIE_STUNTS: + case COMMAND_ADD_NUMBER_OF_ASSASSINATIONS: + case COMMAND_ADD_PIZZAS_DELIVERED: + case COMMAND_ADD_GARBAGE_PICKUPS: + case COMMAND_ADD_ICE_CREAMS_SOLD: + case COMMAND_SET_TOP_SHOOTING_RANGE_SCORE: + case COMMAND_ADD_SHOOTING_RANGE_RANK: + case COMMAND_ADD_MONEY_SPENT_ON_GAMBLING: + case COMMAND_ADD_MONEY_WON_ON_GAMBLING: + case COMMAND_SET_LARGEST_GAMBLING_WIN: + case COMMAND_SET_CHAR_IN_PLAYERS_GROUP_CAN_FIGHT: + case COMMAND_CLEAR_CHAR_WAIT_STATE: + case COMMAND_GET_RANDOM_CAR_OF_TYPE_IN_AREA_NO_SAVE: + case COMMAND_SET_CAN_BURST_CAR_TYRES: + case COMMAND_SET_PLAYER_AUTO_AIM: + case COMMAND_FIRE_HUNTER_GUN: + case COMMAND_SET_PROPERTY_AS_OWNED: + case COMMAND_ADD_BLOOD_RING_KILLS: + case COMMAND_SET_LONGEST_TIME_IN_BLOOD_RING: + assert(0); + case COMMAND_REMOVE_EVERYTHING_FOR_HUGE_CUTSCENE: + { + debug("REMOVE_EVERYTHING_FOR_HUGE_CUTSCENE not implemented, skipping\n"); + return 0; + } + case COMMAND_IS_PLAYER_TOUCHING_VEHICLE: + case COMMAND_IS_CHAR_TOUCHING_VEHICLE: + case COMMAND_CHECK_FOR_PED_MODEL_AROUND_PLAYER: + case COMMAND_CLEAR_CHAR_FOLLOW_PATH: + case COMMAND_SET_CHAR_CAN_BE_SHOT_IN_VEHICLE: + case COMMAND_ATTACH_CUTSCENE_OBJECT_TO_VEHICLE: + assert(0); + case COMMAND_LOAD_MISSION_TEXT: + { + char key[8]; + CTheScripts::ReadTextLabelFromScript(&m_nIp, key); + m_nIp += KEY_LENGTH_IN_SCRIPT; + TheText.LoadMissionText(key); + return 0; + } + case COMMAND_SET_TONIGHTS_EVENT: + { + CollectParameters(&m_nIp, 1); + debug("skipping SET_TONIGHTS_EVENT\n"); + return 0; + } + case COMMAND_CLEAR_CHAR_LAST_DAMAGE_ENTITY: + case COMMAND_CLEAR_CAR_LAST_DAMAGE_ENTITY: + case COMMAND_FREEZE_OBJECT_POSITION: + case COMMAND_SET_PLAYER_HAS_MET_DEBBIE_HARRY: + case COMMAND_SET_RIOT_INTENSITY: + case COMMAND_IS_CAR_IN_ANGLED_AREA_2D: + case COMMAND_IS_CAR_IN_ANGLED_AREA_3D: + case COMMAND_REMOVE_WEAPON_FROM_CHAR: + case COMMAND_SET_UP_TAXI_SHORTCUT: + case COMMAND_CLEAR_TAXI_SHORTCUT: + case COMMAND_SET_CHAR_OBJ_GOTO_CAR_ON_FOOT: + case COMMAND_GET_CLOSEST_WATER_NODE: + case COMMAND_ADD_PORN_LEAFLET_TO_RUBBISH: + assert(0); + case COMMAND_CREATE_CLOTHES_PICKUP: + { + CollectParameters(&m_nIp, 4); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y) + PICKUP_PLACEMENT_OFFSET; + CPickups::GetActualPickupIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + ScriptParams[0] = CPickups::GenerateNewOne(pos, MI_PICKUP_CLOTHES, PICKUP_ON_STREET, ScriptParams[3]); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_CHANGE_BLIP_THRESHOLD: + assert(0); + case COMMAND_MAKE_PLAYER_FIRE_PROOF: + { + CollectParameters(&m_nIp, 2); + CPlayerInfo* pPlayerInfo = &CWorld::Players[ScriptParams[0]]; + pPlayerInfo->m_bFireproof = ScriptParams[1]; + return 0; + } + case COMMAND_INCREASE_PLAYER_MAX_HEALTH: + { + CollectParameters(&m_nIp, 2); + CPlayerInfo* pPlayerInfo = &CWorld::Players[ScriptParams[0]]; + pPlayerInfo->m_nMaxHealth += ScriptParams[1]; + pPlayerInfo->m_pPed->m_fHealth = pPlayerInfo->m_nMaxHealth; + return 0; + } + case COMMAND_INCREASE_PLAYER_MAX_ARMOUR: + { + CollectParameters(&m_nIp, 2); + CPlayerInfo* pPlayerInfo = &CWorld::Players[ScriptParams[0]]; + pPlayerInfo->m_nMaxArmour += ScriptParams[1]; + pPlayerInfo->m_pPed->m_fArmour = pPlayerInfo->m_nMaxArmour; + return 0; + } + case COMMAND_CREATE_RANDOM_CHAR_AS_DRIVER: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + CPed* pPed = CPopulation::AddPedInCar(pVehicle, true); + pPed->CharCreatedBy = MISSION_CHAR; + pPed->bRespondsToThreats = false; + pPed->bAllowMedicsToReviveMe = false; + pPed->bIsPlayerFriend = false; + if (pVehicle->bIsBus) + pPed->bRenderPedInCar = false; + pPed->SetPosition(pVehicle->GetPosition()); + pPed->SetOrientation(0.0f, 0.0f, 0.0f); + pPed->SetPedState(PED_DRIVING); + pPed->m_pMyVehicle = pVehicle; + pPed->m_pMyVehicle->RegisterReference((CEntity**)&pPed->m_pMyVehicle); + pVehicle->pDriver = pPed; + pVehicle->pDriver->RegisterReference((CEntity**)&pVehicle->pDriver); + pPed->bInVehicle = true; + pVehicle->SetStatus(STATUS_PHYSICS); + if (pVehicle->m_vehType == VEHICLE_TYPE_BOAT) + pVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE; + pVehicle->bEngineOn = true; + pVehicle->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pVehicle->GetPosition()); + CPopulation::ms_nTotalMissionPeds++; + ScriptParams[0] = CPools::GetPedPool()->GetIndex(pPed); + StoreParameters(&m_nIp, 1); + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_CHAR); + return 0; + } + case COMMAND_CREATE_RANDOM_CHAR_AS_PASSENGER: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + CPed* pPed = CPopulation::AddPedInCar(pVehicle, false); + pPed->CharCreatedBy = MISSION_CHAR; + pPed->bRespondsToThreats = false; + pPed->bAllowMedicsToReviveMe = false; + pPed->bIsPlayerFriend = false; + if (pVehicle->bIsBus) + pPed->bRenderPedInCar = false; + pPed->SetPosition(pVehicle->GetPosition()); + pPed->SetOrientation(0.0f, 0.0f, 0.0f); + CPopulation::ms_nTotalMissionPeds++; + pVehicle->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pVehicle->GetPosition()); + if (ScriptParams[1] >= 0) + pVehicle->AddPassenger(pPed, ScriptParams[1]); + else + pVehicle->AddPassenger(pPed); + + pPed->m_pMyVehicle = pVehicle; + pPed->m_pMyVehicle->RegisterReference((CEntity**)&pPed->m_pMyVehicle); + pPed->bInVehicle = true; + pPed->SetPedState(PED_DRIVING); + ScriptParams[0] = CPools::GetPedPool()->GetIndex(pPed); + StoreParameters(&m_nIp, 1); + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_CHAR); + return 0; + } + case COMMAND_SET_CHAR_IGNORE_THREATS_BEHIND_OBJECTS: + case COMMAND_ENSURE_PLAYER_HAS_DRIVE_BY_WEAPON: + case COMMAND_MAKE_HELI_COME_CRASHING_DOWN: + case COMMAND_ADD_EXPLOSION_NO_SOUND: + assert(0); + case COMMAND_SET_OBJECT_AREA_VISIBLE: + { + CollectParameters(&m_nIp, 2); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + assert(pObject); + pObject->m_area = ScriptParams[1]; + return 0; + } + case COMMAND_WAS_VEHICLE_EVER_POLICE: + case COMMAND_SET_CHAR_NEVER_TARGETTED: + case COMMAND_LOAD_UNCOMPRESSED_ANIM: + assert(0); + case COMMAND_WAS_CUTSCENE_SKIPPED: + { + static bool bShowed = false; + if (!bShowed) { + debug("COMMAND_WAS_CUTSCENE_SKIPPED not implemented, default to TRUE\n"); + bShowed = true; + } + UpdateCompareFlag(true); + return 0; + } + case COMMAND_SET_CHAR_CROUCH_WHEN_THREATENED: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + debug("SET_CHAR_CROUCH_WHEN_THREATENED not implemented, skipping\n"); + return 0; + } + case COMMAND_IS_CHAR_IN_ANY_POLICE_VEHICLE: + { + CollectParameters(&m_nIp, 1); + static bool bShowed = false; + if (!bShowed) { + debug("IS_CHAR_IN_ANY_POLICE_VEHICLE not implemented, default to FALSE\n"); + bShowed = true; + } + UpdateCompareFlag(false); + return 0; + } + case COMMAND_DOES_CHAR_EXIST: + case COMMAND_DOES_VEHICLE_EXIST: + case COMMAND_ADD_SHORT_RANGE_BLIP_FOR_CONTACT_POINT: + assert(0); + case COMMAND_ADD_SHORT_RANGE_SPRITE_BLIP_FOR_CONTACT_POINT: + { + CollectParameters(&m_nIp, 4); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + int id = CRadar::SetShortRangeCoordBlip(BLIP_COORD, pos, 2, BLIP_DISPLAY_BOTH); + CRadar::SetBlipSprite(id, ScriptParams[3]); + ScriptParams[0] = id; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_IS_CHAR_STUCK: + case COMMAND_SET_ALL_TAXIS_HAVE_NITRO: + case COMMAND_SET_CHAR_STOP_SHOOT_DONT_SEEK_ENTITY: + case COMMAND_FREEZE_CAR_POSITION_AND_DONT_LOAD_COLLISION: + case COMMAND_FREEZE_CHAR_POSITION_AND_DONT_LOAD_COLLISION: + case COMMAND_FREEZE_OBJECT_POSITION_AND_DONT_LOAD_COLLISION: + case COMMAND_SET_FADE_AND_JUMPCUT_AFTER_RC_EXPLOSION: + default: + assert(0); + } + return -1; +} + +int8 CRunningScript::ProcessCommands1400To1499(int32 command) +{ + switch (command) { + case COMMAND_REGISTER_VIGILANTE_LEVEL: + case COMMAND_CLEAR_ALL_CHAR_ANIMS: + assert(0); + case COMMAND_SET_MAXIMUM_NUMBER_OF_CARS_IN_GARAGE: + CollectParameters(&m_nIp, 2); + CGarages::SetMaxNumStoredCarsForGarage(ScriptParams[0], ScriptParams[1]); + break; + case COMMAND_WANTED_STARS_ARE_FLASHING: + { + static bool bShowed = false; + if (!bShowed) { + debug("WANTED_STARS_ARE_FLASHING not implemented, default to FALSE\n"); + bShowed = true; + } + UpdateCompareFlag(false); + return 0; + } + case COMMAND_SET_ALLOW_HURRICANES: + CollectParameters(&m_nIp, 1); + CStats::NoMoreHurricanes = ScriptParams[0]; + return 0; + case COMMAND_PLAY_ANNOUNCEMENT: + { + CollectParameters(&m_nIp, 1); + debug("PLAY_ANNOUNCEMENT not implemented, skipping\n"); + return 0; + } + case COMMAND_SET_PLAYER_IS_IN_STADIUM: + case COMMAND_GET_BUS_FARES_COLLECTED_BY_PLAYER: + case COMMAND_SET_CHAR_OBJ_BUY_ICE_CREAM: + case COMMAND_DISPLAY_RADAR: + case COMMAND_REGISTER_BEST_POSITION: + assert(0); + case COMMAND_IS_PLAYER_IN_INFO_ZONE: + { + CollectParameters(&m_nIp, 1); + char key[KEY_LENGTH_IN_SCRIPT]; + CTheScripts::ReadTextLabelFromScript(&m_nIp, key); + m_nIp += KEY_LENGTH_IN_SCRIPT; + static bool bShowed = false; + if (!bShowed) { + debug("IS_PLAYER_IN_INFO_ZONE not implemented, default to FALSE\n"); + bShowed = true; + } + UpdateCompareFlag(false); + return 0; + } + case COMMAND_CLEAR_CHAR_ICE_CREAM_PURCHASE: + case COMMAND_IS_IN_CAR_FIRE_BUTTON_PRESSED: + case COMMAND_HAS_CHAR_ATTEMPTED_ATTRACTOR: + case COMMAND_SET_LOAD_COLLISION_FOR_CAR_FLAG: + case COMMAND_SET_LOAD_COLLISION_FOR_CHAR_FLAG: + case COMMAND_SET_LOAD_COLLISION_FOR_OBJECT_FLAG: + case COMMAND_ADD_BIG_GUN_FLASH: + case COMMAND_HAS_CHAR_BOUGHT_ICE_CREAM: + assert(0); + case COMMAND_GET_PROGRESS_PERCENTAGE: + *(float*)&ScriptParams[0] = CStats::GetPercentageProgress(); + StoreParameters(&m_nIp, 1); + return 0; + case COMMAND_SET_SHORTCUT_PICKUP_POINT: + { + CollectParameters(&m_nIp, 4); + debug("SET_SHORTCUT_PICKUP_POINT not implemented, skipping\n"); + return 0; + } + case COMMAND_SET_SHORTCUT_DROPOFF_POINT_FOR_MISSION: + { + CollectParameters(&m_nIp, 4); + debug("SET_SHORTCUT_DROPOFF_POINT_FOR_MISSION not implemented, skipping"); + return 0; + } + case COMMAND_GET_RANDOM_ICE_CREAM_CUSTOMER_IN_AREA: + case COMMAND_GET_RANDOM_ICE_CREAM_CUSTOMER_IN_ZONE: + case COMMAND_UNLOCK_ALL_CAR_DOORS_IN_AREA: + assert(0); + case COMMAND_SET_GANG_ATTACK_PLAYER_WITH_COPS: + CollectParameters(&m_nIp, 2); + CGangs::SetWillAttackPlayerWithCops((ePedType)((int)PEDTYPE_GANG1 + ScriptParams[0]), !!ScriptParams[1]); + return 0; + case COMMAND_SET_CHAR_FRIGHTENED_IN_JACKED_CAR: + assert(0); + case COMMAND_SET_VEHICLE_TO_FADE_IN: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(pVehicle); + CVisibilityPlugins::SetClumpAlpha(pVehicle->GetClump(), ScriptParams[1]); + return 0; + } + case COMMAND_REGISTER_ODDJOB_MISSION_PASSED: + assert(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); + return 0; + } + case COMMAND_IS_CHAR_DUCKING: + case COMMAND_CREATE_DUST_EFFECT_FOR_CUTSCENE_HELI: + case COMMAND_REGISTER_FIRE_LEVEL: + case COMMAND_IS_AUSTRALIAN_GAME: + case COMMAND_DISARM_CAR_BOMB: + default: + assert(0); + } + return -1; +} + +bool CRunningScript::ThisIsAValidRandomCop(int32 mi, bool cop, bool swat, bool fbi, bool army, bool miami) +{ + switch (mi) + { + case MI_COP: if (cop) return true; + case MI_SWAT: if (swat) return true; + case MI_FBI: if (fbi) return true; + case MI_ARMY: if (army) return true; + default: + return miami && (mi >= MI_VICE1 && mi <= MI_VICE8); + } +} + +void CTheScripts::RemoveThisPed(CPed* pPed) +{ + if (pPed) { + bool bWasMissionPed = pPed->CharCreatedBy == MISSION_CHAR; + if (pPed->InVehicle() && pPed->m_pMyVehicle) { + if (pPed->m_pMyVehicle->pDriver == pPed) { + pPed->m_pMyVehicle->RemoveDriver(); + pPed->m_pMyVehicle->SetStatus(STATUS_ABANDONED); + if (pPed->m_pMyVehicle->m_nDoorLock == CARLOCK_LOCKED_INITIALLY) + pPed->m_pMyVehicle->m_nDoorLock = CARLOCK_UNLOCKED; + if (pPed->m_nPedType == PEDTYPE_COP && pPed->m_pMyVehicle->IsLawEnforcementVehicle()) + pPed->m_pMyVehicle->ChangeLawEnforcerState(0); + } + else { + pPed->m_pMyVehicle->RemovePassenger(pPed); + } + } + CWorld::RemoveReferencesToDeletedObject(pPed); + delete pPed; + if (bWasMissionPed) + --CPopulation::ms_nTotalMissionPeds; + } +} + int32 CTheScripts::GetNewUniqueScriptSphereIndex(int32 index) { if (ScriptSphereArray[index].m_Index >= UINT16_MAX - 1) @@ -11077,29 +12163,6 @@ void CRunningScript::DoDeatharrestCheck() while (m_nStackPointer > 1) --m_nStackPointer; m_nIp = m_anStack[--m_nStackPointer]; - int16 messageId; - if (pPlayer->IsRestartingAfterDeath()) - messageId = 0; - else if (pPlayer->IsRestartingAfterArrest()) - messageId = 5; - else - messageId = 10; - messageId += CGeneral::GetRandomNumberInRange(0, 5); - bool found = false; - for (int16 contact = 0; !found && contact < MAX_NUM_CONTACTS; contact++) { - int contactFlagOffset = CTheScripts::OnAMissionForContactFlag[contact]; - if (contactFlagOffset && CTheScripts::ScriptSpace[contactFlagOffset] == 1) { - messageId += CTheScripts::BaseBriefIdForContact[contact]; - found = true; - } - } - if (!found) - messageId = 8001; - char tmp[16]; - sprintf(tmp, "%d", messageId); - CMessages::ClearSmallMessagesOnly(); - wchar* text = TheText.Get(tmp); - // ...and do nothing about it *(int32*)&CTheScripts::ScriptSpace[CTheScripts::OnAMissionFlag] = 0; m_bDeatharrestExecuted = true; m_nWakeTime = 0; @@ -11243,8 +12306,8 @@ void CTheScripts::RenderTheScriptDebugLines() RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)0); } -#define SCRIPT_DATA_SIZE sizeof(CTheScripts::OnAMissionFlag) + sizeof(CTheScripts::BaseBriefIdForContact) + sizeof(CTheScripts::OnAMissionForContactFlag) +\ - sizeof(CTheScripts::CollectiveArray) + 4 * sizeof(uint32) * MAX_NUM_BUILDING_SWAPS + 2 * sizeof(uint32) * MAX_NUM_INVISIBILITY_SETTINGS + 5 * sizeof(uint32) +#define SCRIPT_DATA_SIZE sizeof(CTheScripts::OnAMissionFlag) +\ + 4 * sizeof(uint32) * MAX_NUM_BUILDING_SWAPS + 2 * sizeof(uint32) * MAX_NUM_INVISIBILITY_SETTINGS + 5 * sizeof(uint32) void CTheScripts::SaveAllScripts(uint8* buf, uint32* size) { @@ -11264,12 +12327,6 @@ INITSAVEBUF uint32 script_data_size = SCRIPT_DATA_SIZE; WriteSaveBuf(buf, script_data_size); WriteSaveBuf(buf, OnAMissionFlag); - for (uint32 i = 0; i < MAX_NUM_CONTACTS; i++) { - WriteSaveBuf(buf, OnAMissionForContactFlag[i]); - WriteSaveBuf(buf, BaseBriefIdForContact[i]); - } - for (uint32 i = 0; i < MAX_NUM_COLLECTIVES; i++) - WriteSaveBuf(buf, CollectiveArray[i]); WriteSaveBuf(buf, NextFreeCollectiveIndex); for (uint32 i = 0; i < MAX_NUM_BUILDING_SWAPS; i++) { CBuilding* pBuilding = BuildingSwapArray[i].m_pBuilding; @@ -11342,12 +12399,6 @@ INITSAVEBUF ScriptSpace[i] = ReadSaveBuf<uint8>(buf); assert(ReadSaveBuf<uint32>(buf) == SCRIPT_DATA_SIZE); OnAMissionFlag = ReadSaveBuf<uint32>(buf); - for (uint32 i = 0; i < MAX_NUM_CONTACTS; i++) { - OnAMissionForContactFlag[i] = ReadSaveBuf<uint32>(buf); - BaseBriefIdForContact[i] = ReadSaveBuf<uint32>(buf); - } - for (uint32 i = 0; i < MAX_NUM_COLLECTIVES; i++) - CollectiveArray[i] = ReadSaveBuf<tCollectiveData>(buf); NextFreeCollectiveIndex = ReadSaveBuf<uint32>(buf); for (uint32 i = 0; i < MAX_NUM_BUILDING_SWAPS; i++) { uint32 type = ReadSaveBuf<uint32>(buf); diff --git a/src/control/Script.h b/src/control/Script.h index acab66cc..3393467e 100644 --- a/src/control/Script.h +++ b/src/control/Script.h @@ -6,6 +6,7 @@ class CEntity; class CBuilding; +class CPhysical; class CVehicle; class CPed; class CObject; @@ -131,6 +132,8 @@ public: void AddEntityToList(int32, uint8); void RemoveEntityFromList(int32, uint8); void Process(); + void CheckIfCollisionHasLoadedForMissionObject(); + CPhysical* DoesThisEntityWaitForCollision(int i); }; struct CUpsideDownCarCheckEntry @@ -218,19 +221,17 @@ enum { }; enum { - SIZE_MAIN_SCRIPT = 128 * 1024, - SIZE_MISSION_SCRIPT = 32 * 1024, + SIZE_MAIN_SCRIPT = 225512, + SIZE_MISSION_SCRIPT = 35000, SIZE_SCRIPT_SPACE = SIZE_MAIN_SCRIPT + SIZE_MISSION_SCRIPT }; enum { MAX_NUM_SCRIPTS = 128, - MAX_NUM_CONTACTS = 16, MAX_NUM_INTRO_TEXT_LINES = 2, MAX_NUM_INTRO_RECTANGLES = 16, MAX_NUM_SCRIPT_SRPITES = 16, MAX_NUM_SCRIPT_SPHERES = 16, - MAX_NUM_COLLECTIVES = 32, MAX_NUM_USED_OBJECTS = 200, MAX_NUM_MISSION_SCRIPTS = 120, MAX_NUM_BUILDING_SWAPS = 25, @@ -242,13 +243,10 @@ class CTheScripts { static uint8 ScriptSpace[SIZE_SCRIPT_SPACE]; static CRunningScript ScriptsArray[MAX_NUM_SCRIPTS]; - static int32 BaseBriefIdForContact[MAX_NUM_CONTACTS]; - static int32 OnAMissionForContactFlag[MAX_NUM_CONTACTS]; static intro_text_line IntroTextLines[MAX_NUM_INTRO_TEXT_LINES]; static intro_script_rectangle IntroRectangles[MAX_NUM_INTRO_RECTANGLES]; static CSprite2d ScriptSprites[MAX_NUM_SCRIPT_SRPITES]; static script_sphere_struct ScriptSphereArray[MAX_NUM_SCRIPT_SPHERES]; - static tCollectiveData CollectiveArray[MAX_NUM_COLLECTIVES]; static tUsedObject UsedObjectArray[MAX_NUM_USED_OBJECTS]; static int32 MultiScriptArray[MAX_NUM_MISSION_SCRIPTS]; static tBuildingSwap BuildingSwapArray[MAX_NUM_BUILDING_SWAPS]; @@ -272,14 +270,17 @@ class CTheScripts static uint32 LargestMissionScriptSize; static uint32 MainScriptSize; static uint8 FailCurrentMission; - static uint8 CountdownToMakePlayerUnsafe; - static uint8 DelayMakingPlayerUnsafeThisTime; static uint16 NumScriptDebugLines; static uint16 NumberOfIntroRectanglesThisFrame; static uint16 NumberOfIntroTextLinesThisFrame; static uint8 UseTextCommands; static uint16 CommandsExecuted; static uint16 ScriptsUpdated; + static uint8 RiotIntensity; + static uint32 LastMissionPassedTime; + static uint16 NumberOfExclusiveMissionScripts; + static bool bPlayerIsInTheStatium; + static bool bPlayerHasMetDebbieHarry; public: static void Init(); @@ -303,9 +304,6 @@ public: static int32* GetPointerToScriptVariable(int32 offset) { assert(offset >= 8 && offset < CTheScripts::GetSizeOfVariableSpace()); return (int32*)&ScriptSpace[offset]; } - static void ResetCountdownToMakePlayerUnsafe() { CountdownToMakePlayerUnsafe = 0; } - static bool IsCountdownToMakePlayerUnsafeOn() { return CountdownToMakePlayerUnsafe != 0; } - static int32 Read4BytesFromScript(uint32* pIp) { int32 retval = ScriptSpace[*pIp + 3] << 24 | ScriptSpace[*pIp + 2] << 16 | ScriptSpace[*pIp + 1] << 8 | ScriptSpace[*pIp]; *pIp += 4; @@ -368,10 +366,13 @@ private: static int32 AddScriptSphere(int32 id, CVector pos, float radius); static int32 GetNewUniqueScriptSphereIndex(int32 index); static void RemoveScriptSphere(int32 index); + static void RemoveScriptTextureDictionary(); + static void RemoveThisPed(CPed* pPed); friend class CRunningScript; friend class CHud; friend void CMissionCleanup::Process(); + friend class CColStore; }; @@ -410,6 +411,7 @@ class CRunningScript uint32 m_anStack[MAX_STACK_DEPTH]; uint16 m_nStackPointer; int32 m_anLocalVariables[NUM_LOCAL_VARS + NUM_TIMERS]; + bool m_bIsActive; bool m_bCondResult; bool m_bIsMissionScript; bool m_bSkipWakeTime; @@ -462,9 +464,11 @@ private: int8 ProcessCommands800To899(int32); int8 ProcessCommands900To999(int32); int8 ProcessCommands1000To1099(int32); -#ifndef GTA_PS2 int8 ProcessCommands1100To1199(int32); -#endif + int8 ProcessCommands1200To1299(int32); + int8 ProcessCommands1300To1399(int32); + int8 ProcessCommands1400To1499(int32); + void LocatePlayerCommand(int32, uint32*); void LocatePlayerCharCommand(int32, uint32*); void LocatePlayerCarCommand(int32, uint32*); @@ -501,4 +505,6 @@ private: return false; } } + + static bool ThisIsAValidRandomCop(int32 mi, bool cop, bool swat, bool fbi, bool army, bool miami); }; diff --git a/src/control/ScriptCommands.h b/src/control/ScriptCommands.h index 77cf3f0f..67b1b9bc 100644 --- a/src/control/ScriptCommands.h +++ b/src/control/ScriptCommands.h @@ -995,7 +995,7 @@ enum { COMMAND_FORCE_RANDOM_PED_TYPE, COMMAND_SET_TEXT_DRAW_BEFORE_FADE, COMMAND_GET_COLLECTABLE1S_COLLECTED, - COMMAND_REGISTER_EL_BURRO_TIME, + COMMAND_SET_CHAR_OBJ_LEAVE_ANY_CAR, COMMAND_SET_SPRITES_DRAW_BEFORE_FADE, COMMAND_SET_TEXT_RIGHT_JUSTIFY, COMMAND_PRINT_HELP, @@ -1022,17 +1022,17 @@ enum { COMMAND_MAKE_PLAYER_SAFE, COMMAND_SET_CAR_STAYS_IN_CURRENT_LEVEL, COMMAND_SET_CHAR_STAYS_IN_CURRENT_LEVEL, - COMMAND_REGISTER_4X4_ONE_TIME, - COMMAND_REGISTER_4X4_TWO_TIME, - COMMAND_REGISTER_4X4_THREE_TIME, - COMMAND_REGISTER_4X4_MAYHEM_TIME, + COMMAND_SET_DRUNK_INPUT_DELAY, + COMMAND_SET_CHAR_MONEY, + COMMAND_INCREASE_CHAR_MONEY, + COMMAND_GET_OFFSET_FROM_OBJECT_IN_WORLD_COORDS, COMMAND_REGISTER_LIFE_SAVED, COMMAND_REGISTER_CRIMINAL_CAUGHT, COMMAND_REGISTER_AMBULANCE_LEVEL, COMMAND_REGISTER_FIRE_EXTINGUISHED, COMMAND_TURN_PHONE_ON, COMMAND_REGISTER_LONGEST_DODO_FLIGHT, - COMMAND_REGISTER_DEFUSE_BOMB_TIME, + COMMAND_GET_OFFSET_FROM_CAR_IN_WORLD_COORDS, COMMAND_SET_TOTAL_NUMBER_OF_KILL_FRENZIES, COMMAND_BLOW_UP_RC_BUGGY, COMMAND_REMOVE_CAR_FROM_CHASE, @@ -1108,7 +1108,6 @@ enum { COMMAND_SET_JAMES_CAR_ON_PATH_TO_PLAYER, COMMAND_LOAD_END_OF_GAME_TUNE, COMMAND_ENABLE_PLAYER_CONTROL_CAMERA, -#ifndef GTA_PS2 COMMAND_SET_OBJECT_ROTATION, COMMAND_GET_DEBUG_CAMERA_COORDINATES, COMMAND_GET_DEBUG_CAMERA_FRONT_VECTOR, @@ -1145,7 +1144,7 @@ enum { COMMAND_LOCATE_CHAR_ANY_MEANS_OBJECT_3D, COMMAND_LOCATE_CHAR_ON_FOOT_OBJECT_3D, COMMAND_LOCATE_CHAR_IN_CAR_OBJECT_3D, - COMMAND_SET_CAR_HANDBRAKE_TURN_LEFT, + COMMAND_SET_CAR_TEMP_ACTION, COMMAND_SET_CAR_HANDBRAKE_TURN_RIGHT, COMMAND_SET_CAR_HANDBRAKE_STOP, COMMAND_IS_CHAR_ON_ANY_BIKE, @@ -1156,8 +1155,286 @@ enum { COMMAND_IS_CHAR_LYING_DOWN, COMMAND_CAN_CHAR_SEE_DEAD_CHAR, COMMAND_SET_ENTER_CAR_RANGE_MULTIPLIER, -#ifndef GTA3_1_1_PATCH - COMMAND_SET_THREAT_REACTION_RANGE_MULTIPLIER -#endif -#endif + COMMAND_SET_THREAT_REACTION_RANGE_MULTIPLIER, + COMMAND_SET_CHAR_CEASE_ATTACK_TIMER, + COMMAND_GET_REMOTE_CONTROLLED_CAR, + COMMAND_IS_PC_VERSION, + COMMAND_REPLAY, + COMMAND_IS_REPLAY_PLAYING, + COMMAND_IS_MODEL_AVAILABLE, + COMMAND_SHUT_CHAR_UP, + COMMAND_SET_ENABLE_RC_DETONATE, + COMMAND_SET_CAR_RANDOM_ROUTE_SEED, + COMMAND_IS_ANY_PICKUP_AT_COORDS, + COMMAND_GET_FIRST_PICKUP_COORDS, + COMMAND_GET_NEXT_PICKUP_COORDS, + COMMAND_REMOVE_ALL_CHAR_WEAPONS, + COMMAND_HAS_PLAYER_GOT_WEAPON, + COMMAND_HAS_CHAR_GOT_WEAPON, + COMMAND_IS_PLAYER_FACING_CHAR, + COMMAND_SET_TANK_DETONATE_CARS, + COMMAND_GET_POSITION_OF_ANALOGUE_STICKS, + COMMAND_IS_CAR_ON_FIRE, + COMMAND_IS_CAR_TYRE_BURST, + COMMAND_SET_CAR_DRIVE_STRAIGHT_AHEAD, + COMMAND_SET_CAR_WAIT, + COMMAND_IS_PLAYER_STANDING_ON_A_VEHICLE, + COMMAND_IS_PLAYER_FOOT_DOWN, + COMMAND_IS_CHAR_FOOT_DOWN, + COMMAND_INITIALISE_OBJECT_PATH, + COMMAND_START_OBJECT_ON_PATH, + COMMAND_SET_OBJECT_PATH_SPEED, + COMMAND_SET_OBJECT_PATH_POSITION, + COMMAND_GET_OBJECT_DISTANCE_ALONG_PATH, + COMMAND_CLEAR_OBJECT_PATH, + COMMAND_HELI_GOTO_COORDS, + COMMAND_IS_INT_VAR_EQUAL_TO_CONSTANT, + COMMAND_IS_INT_LVAR_EQUAL_TO_CONSTANT, + COMMAND_GET_DEAD_CHAR_PICKUP_COORDS, + COMMAND_CREATE_PROTECTION_PICKUP, + COMMAND_IS_CHAR_IN_ANY_BOAT, + COMMAND_IS_PLAYER_IN_ANY_BOAT, + COMMAND_IS_CHAR_IN_ANY_HELI, + COMMAND_IS_PLAYER_IN_ANY_HELI, + COMMAND_IS_CHAR_IN_ANY_PLANE, + COMMAND_IS_PLAYER_IN_ANY_PLANE, + COMMAND_IS_CHAR_IN_WATER, + COMMAND_SET_VAR_INT_TO_CONSTANT, + COMMAND_SET_LVAR_INT_TO_CONSTANT, + COMMAND_IS_INT_VAR_GREATER_THAN_CONSTANT, + COMMAND_IS_INT_LVAR_GREATER_THAN_CONSTANT, + COMMAND_IS_CONSTANT_GREATER_THAN_INT_VAR, + COMMAND_IS_CONSTANT_GREATER_THAN_INT_LVAR, + COMMAND_IS_INT_VAR_GREATER_OR_EQUAL_TO_CONSTANT, + COMMAND_IS_INT_LVAR_GREATER_OR_EQUAL_TO_CONSTANT, + COMMAND_IS_CONSTANT_GREATER_OR_EQUAL_TO_INT_VAR, + COMMAND_IS_CONSTANT_GREATER_OR_EQUAL_TO_INT_LVAR, + COMMAND_GET_CHAR_WEAPON_IN_SLOT, + COMMAND_GET_CLOSEST_STRAIGHT_ROAD, + COMMAND_SET_CAR_FORWARD_SPEED, + COMMAND_SET_AREA_VISIBLE, + COMMAND_SET_CUTSCENE_ANIM_TO_LOOP, + COMMAND_MARK_CAR_AS_CONVOY_CAR, + COMMAND_RESET_HAVOC_CAUSED_BY_PLAYER, + COMMAND_GET_HAVOC_CAUSED_BY_PLAYER, + COMMAND_CREATE_SCRIPT_ROADBLOCK, + COMMAND_CLEAR_ALL_SCRIPT_ROADBLOCKS, + COMMAND_SET_CHAR_OBJ_WALK_TO_CHAR, + COMMAND_IS_PICKUP_IN_ZONE, + COMMAND_GET_OFFSET_FROM_CHAR_IN_WORLD_COORDS, + COMMAND_HAS_CHAR_BEEN_PHOTOGRAPHED, + COMMAND_SET_CHAR_OBJ_AIM_GUN_AT_CHAR, + COMMAND_SWITCH_SECURITY_CAMERA, + COMMAND_IS_CHAR_IN_FLYING_VEHICLE, + COMMAND_IS_PLAYER_IN_FLYING_VEHICLE, + COMMAND_HAS_SONY_CD_BEEN_READ, + COMMAND_GET_NUMBER_OF_SONY_CDS_READ, + COMMAND_ADD_SHORT_RANGE_BLIP_FOR_COORD_OLD, + COMMAND_ADD_SHORT_RANGE_BLIP_FOR_COORD, + COMMAND_ADD_SHORT_RANGE_SPRITE_BLIP_FOR_COORD, + COMMAND_ADD_MONEY_SPENT_ON_CLOTHES, + COMMAND_SET_HELI_ORIENTATION, + COMMAND_CLEAR_HELI_ORIENTATION, + COMMAND_PLANE_GOTO_COORDS, + COMMAND_GET_NTH_CLOSEST_CAR_NODE, + COMMAND_GET_NTH_CLOSEST_CHAR_NODE, + COMMAND_DRAW_WEAPONSHOP_CORONA, + COMMAND_SET_ENABLE_RC_DETONATE_ON_CONTACT, + COMMAND_FREEZE_CHAR_POSITION, + COMMAND_SET_CHAR_DROWNS_IN_WATER, + COMMAND_SET_OBJECT_RECORDS_COLLISIONS, + COMMAND_HAS_OBJECT_COLLIDED_WITH_ANYTHING, + COMMAND_REMOVE_RC_BUGGY, + COMMAND_HAS_PHOTOGRAPH_BEEN_TAKEN, + COMMAND_GET_CHAR_ARMOUR, + COMMAND_SET_CHAR_ARMOUR, + COMMAND_SET_HELI_STABILISER, + COMMAND_SET_CAR_STRAIGHT_LINE_DISTANCE, + COMMAND_POP_CAR_BOOT, + COMMAND_SHUT_PLAYER_UP, + COMMAND_SET_PLAYER_MOOD, + COMMAND_REQUEST_COLLISION, + COMMAND_LOCATE_OBJECT_2D, + COMMAND_LOCATE_OBJECT_3D, + COMMAND_IS_OBJECT_IN_WATER, + COMMAND_SET_CHAR_OBJ_STEAL_ANY_CAR_EVEN_MISSION_CAR, + COMMAND_IS_OBJECT_IN_AREA_2D, + COMMAND_IS_OBJECT_IN_AREA_3D, + COMMAND_TASK_TOGGLE_DUCK, + COMMAND_SET_ZONE_CIVILIAN_CAR_INFO, + COMMAND_REQUEST_ANIMATION, + COMMAND_HAS_ANIMATION_LOADED, + COMMAND_REMOVE_ANIMATION, + COMMAND_IS_CHAR_WAITING_FOR_WORLD_COLLISION, + COMMAND_IS_CAR_WAITING_FOR_WORLD_COLLISION, + COMMAND_IS_OBJECT_WAITING_FOR_WORLD_COLLISION, + COMMAND_SET_CHAR_SHUFFLE_INTO_DRIVERS_SEAT, + COMMAND_ATTACH_CHAR_TO_OBJECT, + COMMAND_SET_CHAR_AS_PLAYER_FRIEND, + COMMAND_DISPLAY_NTH_ONSCREEN_COUNTER, + COMMAND_DISPLAY_NTH_ONSCREEN_COUNTER_WITH_STRING, + COMMAND_ADD_SET_PIECE, + COMMAND_SET_EXTRA_COLOURS, + COMMAND_CLEAR_EXTRA_COLOURS, + COMMAND_CLOSE_CAR_BOOT, + COMMAND_GET_WHEELIE_STATS, + COMMAND_DISARM_CHAR, + COMMAND_BURST_CAR_TYRE, + COMMAND_IS_CHAR_OBJ_NO_OBJ, + COMMAND_IS_PLAYER_WEARING, + COMMAND_SET_PLAYER_CAN_DO_DRIVE_BY, + COMMAND_SET_CHAR_OBJ_SPRINT_TO_COORD, + COMMAND_CREATE_SWAT_ROPE, + COMMAND_SET_FIRST_PERSON_CONTROL_CAMERA, + COMMAND_GET_NEAREST_TYRE_TO_POINT, + COMMAND_SET_CAR_MODEL_COMPONENTS, + COMMAND_SWITCH_LIFT_CAMERA, + COMMAND_CLOSE_ALL_CAR_DOORS, + COMMAND_GET_DISTANCE_BETWEEN_COORDS_2D, + COMMAND_GET_DISTANCE_BETWEEN_COORDS_3D, + COMMAND_POP_CAR_BOOT_USING_PHYSICS, + COMMAND_SET_FIRST_PERSON_WEAPON_CAMERA, + COMMAND_IS_CHAR_LEAVING_VEHICLE_TO_DIE, + COMMAND_SORT_OUT_OBJECT_COLLISION_WITH_CAR, + COMMAND_GET_MAX_WANTED_LEVEL, + COMMAND_IS_CHAR_WANDER_PATH_CLEAR, + COMMAND_PRINT_HELP_WITH_NUMBER, + COMMAND_PRINT_HELP_FOREVER, + COMMAND_PRINT_HELP_FOREVER_WITH_NUMBER, + COMMAND_SET_CHAR_CAN_BE_DAMAGED_BY_MEMBERS_OF_GANG, + COMMAND_LOAD_AND_LAUNCH_MISSION_EXCLUSIVE, + COMMAND_IS_MISSION_AUDIO_PLAYING, + COMMAND_CREATE_LOCKED_PROPERTY_PICKUP, + COMMAND_CREATE_FORSALE_PROPERTY_PICKUP, + COMMAND_FREEZE_CAR_POSITION, + COMMAND_HAS_CHAR_BEEN_DAMAGED_BY_CHAR, + COMMAND_HAS_CHAR_BEEN_DAMAGED_BY_CAR, + COMMAND_HAS_CAR_BEEN_DAMAGED_BY_CHAR, + COMMAND_HAS_CAR_BEEN_DAMAGED_BY_CAR, + COMMAND_GET_RADIO_CHANNEL, + COMMAND_DISPLAY_TEXT_WITH_3_NUMBERS, + COMMAND_IS_CAR_DROWNING_IN_WATER, + COMMAND_IS_CHAR_DROWNING_IN_WATER, + COMMAND_DISABLE_CUTSCENE_SHADOWS, + COMMAND_HAS_GLASS_BEEN_SHATTERED_NEARBY, + COMMAND_ATTACH_CUTSCENE_OBJECT_TO_BONE, + COMMAND_ATTACH_CUTSCENE_OBJECT_TO_COMPONENT, + COMMAND_SET_CHAR_STAY_IN_CAR_WHEN_JACKED, + COMMAND_IS_MISSION_AUDIO_LOADING, + COMMAND_ADD_MONEY_SPENT_ON_WEAPONS, + COMMAND_ADD_MONEY_SPENT_ON_PROPERTY, + COMMAND_ADD_MONEY_SPENT_ON_AUTO_PAINTING, + COMMAND_SET_CHAR_ANSWERING_MOBILE, + COMMAND_SET_PLAYER_DRUNKENNESS, + COMMAND_GET_PLAYER_DRUNKENNESS, + COMMAND_SET_PLAYER_DRUG_LEVEL, + COMMAND_GET_PLAYER_DRUG_LEVEL, + COMMAND_ADD_LOAN_SHARK_VISITS, + COMMAND_ADD_STORES_KNOCKED_OFF, + COMMAND_ADD_MOVIE_STUNTS, + COMMAND_ADD_NUMBER_OF_ASSASSINATIONS, + COMMAND_ADD_PIZZAS_DELIVERED, + COMMAND_ADD_GARBAGE_PICKUPS, + COMMAND_ADD_ICE_CREAMS_SOLD, + COMMAND_SET_TOP_SHOOTING_RANGE_SCORE, + COMMAND_ADD_SHOOTING_RANGE_RANK, + COMMAND_ADD_MONEY_SPENT_ON_GAMBLING, + COMMAND_ADD_MONEY_WON_ON_GAMBLING, + COMMAND_SET_LARGEST_GAMBLING_WIN, + COMMAND_SET_CHAR_IN_PLAYERS_GROUP_CAN_FIGHT, + COMMAND_CLEAR_CHAR_WAIT_STATE, + COMMAND_GET_RANDOM_CAR_OF_TYPE_IN_AREA_NO_SAVE, + COMMAND_SET_CAN_BURST_CAR_TYRES, + COMMAND_SET_PLAYER_AUTO_AIM, + COMMAND_FIRE_HUNTER_GUN, + COMMAND_SET_PROPERTY_AS_OWNED, + COMMAND_ADD_BLOOD_RING_KILLS, + COMMAND_SET_LONGEST_TIME_IN_BLOOD_RING, + COMMAND_REMOVE_EVERYTHING_FOR_HUGE_CUTSCENE, + COMMAND_IS_PLAYER_TOUCHING_VEHICLE, + COMMAND_IS_CHAR_TOUCHING_VEHICLE, + COMMAND_CHECK_FOR_PED_MODEL_AROUND_PLAYER, + COMMAND_CLEAR_CHAR_FOLLOW_PATH, + COMMAND_SET_CHAR_CAN_BE_SHOT_IN_VEHICLE, + COMMAND_ATTACH_CUTSCENE_OBJECT_TO_VEHICLE, + COMMAND_LOAD_MISSION_TEXT, + COMMAND_SET_TONIGHTS_EVENT, + COMMAND_CLEAR_CHAR_LAST_DAMAGE_ENTITY, + COMMAND_CLEAR_CAR_LAST_DAMAGE_ENTITY, + COMMAND_FREEZE_OBJECT_POSITION, + COMMAND_SET_PLAYER_HAS_MET_DEBBIE_HARRY, + COMMAND_SET_RIOT_INTENSITY, + COMMAND_IS_CAR_IN_ANGLED_AREA_2D, + COMMAND_IS_CAR_IN_ANGLED_AREA_3D, + COMMAND_REMOVE_WEAPON_FROM_CHAR, + COMMAND_SET_UP_TAXI_SHORTCUT, + COMMAND_CLEAR_TAXI_SHORTCUT, + COMMAND_SET_CHAR_OBJ_GOTO_CAR_ON_FOOT, + COMMAND_GET_CLOSEST_WATER_NODE, + COMMAND_ADD_PORN_LEAFLET_TO_RUBBISH, + COMMAND_CREATE_CLOTHES_PICKUP, + COMMAND_CHANGE_BLIP_THRESHOLD, + COMMAND_MAKE_PLAYER_FIRE_PROOF, + COMMAND_INCREASE_PLAYER_MAX_HEALTH, + COMMAND_INCREASE_PLAYER_MAX_ARMOUR, + COMMAND_CREATE_RANDOM_CHAR_AS_DRIVER, + COMMAND_CREATE_RANDOM_CHAR_AS_PASSENGER, + COMMAND_SET_CHAR_IGNORE_THREATS_BEHIND_OBJECTS, + COMMAND_ENSURE_PLAYER_HAS_DRIVE_BY_WEAPON, + COMMAND_MAKE_HELI_COME_CRASHING_DOWN, + COMMAND_ADD_EXPLOSION_NO_SOUND, + COMMAND_SET_OBJECT_AREA_VISIBLE, + COMMAND_WAS_VEHICLE_EVER_POLICE, + COMMAND_SET_CHAR_NEVER_TARGETTED, + COMMAND_LOAD_UNCOMPRESSED_ANIM, + COMMAND_WAS_CUTSCENE_SKIPPED, + COMMAND_SET_CHAR_CROUCH_WHEN_THREATENED, + COMMAND_IS_CHAR_IN_ANY_POLICE_VEHICLE, + COMMAND_DOES_CHAR_EXIST, + COMMAND_DOES_VEHICLE_EXIST, + COMMAND_ADD_SHORT_RANGE_BLIP_FOR_CONTACT_POINT, + COMMAND_ADD_SHORT_RANGE_SPRITE_BLIP_FOR_CONTACT_POINT, + COMMAND_IS_CHAR_STUCK, + COMMAND_SET_ALL_TAXIS_HAVE_NITRO, + COMMAND_SET_CHAR_STOP_SHOOT_DONT_SEEK_ENTITY, + COMMAND_FREEZE_CAR_POSITION_AND_DONT_LOAD_COLLISION, + COMMAND_FREEZE_CHAR_POSITION_AND_DONT_LOAD_COLLISION, + COMMAND_FREEZE_OBJECT_POSITION_AND_DONT_LOAD_COLLISION, + COMMAND_SET_FADE_AND_JUMPCUT_AFTER_RC_EXPLOSION, + COMMAND_REGISTER_VIGILANTE_LEVEL, + COMMAND_CLEAR_ALL_CHAR_ANIMS, + COMMAND_SET_MAXIMUM_NUMBER_OF_CARS_IN_GARAGE, + COMMAND_WANTED_STARS_ARE_FLASHING, + COMMAND_SET_ALLOW_HURRICANES, + COMMAND_PLAY_ANNOUNCEMENT, + COMMAND_SET_PLAYER_IS_IN_STADIUM, + COMMAND_GET_BUS_FARES_COLLECTED_BY_PLAYER, + COMMAND_SET_CHAR_OBJ_BUY_ICE_CREAM, + COMMAND_DISPLAY_RADAR, + COMMAND_REGISTER_BEST_POSITION, + COMMAND_IS_PLAYER_IN_INFO_ZONE, + COMMAND_CLEAR_CHAR_ICE_CREAM_PURCHASE, + COMMAND_IS_IN_CAR_FIRE_BUTTON_PRESSED, + COMMAND_HAS_CHAR_ATTEMPTED_ATTRACTOR, + COMMAND_SET_LOAD_COLLISION_FOR_CAR_FLAG, + COMMAND_SET_LOAD_COLLISION_FOR_CHAR_FLAG, + COMMAND_SET_LOAD_COLLISION_FOR_OBJECT_FLAG, + COMMAND_ADD_BIG_GUN_FLASH, + COMMAND_HAS_CHAR_BOUGHT_ICE_CREAM, + COMMAND_GET_PROGRESS_PERCENTAGE, + COMMAND_SET_SHORTCUT_PICKUP_POINT, + COMMAND_SET_SHORTCUT_DROPOFF_POINT_FOR_MISSION, + COMMAND_GET_RANDOM_ICE_CREAM_CUSTOMER_IN_AREA, + COMMAND_GET_RANDOM_ICE_CREAM_CUSTOMER_IN_ZONE, + COMMAND_UNLOCK_ALL_CAR_DOORS_IN_AREA, + COMMAND_SET_GANG_ATTACK_PLAYER_WITH_COPS, + COMMAND_SET_CHAR_FRIGHTENED_IN_JACKED_CAR, + COMMAND_SET_VEHICLE_TO_FADE_IN, + COMMAND_REGISTER_ODDJOB_MISSION_PASSED, + COMMAND_IS_PLAYER_IN_SHORTCUT_TAXI, + COMMAND_IS_CHAR_DUCKING, + COMMAND_CREATE_DUST_EFFECT_FOR_CUTSCENE_HELI, + COMMAND_REGISTER_FIRE_LEVEL, + COMMAND_IS_AUSTRALIAN_GAME, + COMMAND_DISARM_CAR_BOMB, };
\ No newline at end of file diff --git a/src/control/TrafficLights.cpp b/src/control/TrafficLights.cpp index 278366a3..b1816936 100644 --- a/src/control/TrafficLights.cpp +++ b/src/control/TrafficLights.cpp @@ -145,7 +145,10 @@ CTrafficLights::ScanForLightsOnMap(void) CPtrList &list = CWorld::GetSector(x, y)->m_lists[ENTITYLIST_DUMMIES]; for(node = list.first; node; node = node->next){ CEntity *light = (CEntity*)node->item; - if(light->GetModelIndex() != MI_TRAFFICLIGHTS) + if(light->GetModelIndex() != MI_TRAFFICLIGHTS && + light->GetModelIndex() != MI_TRAFFICLIGHTS_VERTICAL && + light->GetModelIndex() != MI_TRAFFICLIGHTS_MIAMI && + light->GetModelIndex() != MI_TRAFFICLIGHTS_TWOVERTICAL) continue; // Check cars @@ -274,8 +277,12 @@ CTrafficLights::ShouldCarStopForLight(CVehicle *vehicle, bool alwaysStop) bool CTrafficLights::ShouldCarStopForBridge(CVehicle *vehicle) { +#ifdef GTA_BRIDGE return ThePaths.m_carPathLinks[vehicle->AutoPilot.m_nNextPathNodeInfo].bBridgeLights && !ThePaths.m_carPathLinks[vehicle->AutoPilot.m_nCurrentPathNodeInfo].bBridgeLights; +#else + return false; +#endif } int |