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 | 1064 | ||||
-rw-r--r-- | src/control/CarCtrl.h | 47 | ||||
-rw-r--r-- | src/control/Curves.cpp | 18 | ||||
-rw-r--r-- | src/control/Garages.cpp | 874 | ||||
-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 | 2 | ||||
-rw-r--r-- | src/control/Pickups.h | 6 | ||||
-rw-r--r-- | src/control/Record.cpp | 426 | ||||
-rw-r--r-- | src/control/Replay.cpp | 5 | ||||
-rw-r--r-- | src/control/Replay.h | 2 | ||||
-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 | 830 | ||||
-rw-r--r-- | src/control/Script.h | 10 | ||||
-rw-r--r-- | src/control/ScriptCommands.h | 301 | ||||
-rw-r--r-- | src/control/TrafficLights.cpp | 4 |
25 files changed, 3053 insertions, 2041 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 3e22ee77..c233178f 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_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_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; @@ -445,13 +475,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_CAR || + FindPlayerVehicle()->GetVehicleAppearance() == VEHICLE_BIKE) { + if (pVehicle->GetVehicleAppearance() == VEHICLE_BOAT) { + pVehicle->AutoPilot.m_nTempAction = TEMPACT_WAIT; + pVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 1000; + } + } + else if (FindPlayerVehicle()->GetVehicleAppearance() == VEHICLE_BOAT) { + if (pVehicle->GetVehicleAppearance() == VEHICLE_CAR || + pVehicle->GetVehicleAppearance() == VEHICLE_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){ @@ -469,6 +529,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) @@ -488,23 +558,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){ @@ -515,11 +600,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; @@ -529,6 +635,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; @@ -538,6 +645,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){ @@ -552,6 +660,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) { @@ -566,6 +690,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){ @@ -604,8 +729,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(); @@ -628,6 +772,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 fcd1e83f..833bd192 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; @@ -494,6 +531,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; @@ -515,62 +553,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; @@ -593,58 +638,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_BIKE: + nMadDrivers = 30; + break; + case VEHICLE_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; } @@ -653,34 +792,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)) @@ -701,7 +892,7 @@ int32 CCarCtrl::ChooseGangCarModel(int32 gang) { if (CStreaming::HasModelLoaded(MI_GANG01 + 2 * gang) && - CStreaming::HasModelLoaded(MI_GANG02 + 2 * gang)) + CStreaming::HasModelLoaded(MI_GANG01+1 + 2 * gang)) return CGangs::GetGangVehicleModel(gang); return -1; } @@ -709,6 +900,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; } @@ -730,6 +922,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); @@ -742,7 +964,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 || @@ -754,12 +976,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); @@ -768,7 +992,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 && @@ -785,7 +1010,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); @@ -809,6 +1034,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) { @@ -841,8 +1076,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( @@ -865,7 +1104,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; @@ -877,23 +1116,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 @@ -1095,8 +1334,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); } @@ -1322,19 +1561,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(); @@ -1508,23 +1749,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) @@ -1546,6 +1794,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){ @@ -1555,7 +1804,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; } } @@ -1565,9 +1814,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) { @@ -1648,6 +1898,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, @@ -1656,6 +1907,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; @@ -1706,74 +1967,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++) ; } @@ -1793,11 +2037,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(); @@ -1852,6 +2096,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){ @@ -1944,6 +2190,7 @@ void CCarCtrl::Init(void) LastTimeAmbulanceCreated = 0; #ifdef FIX_BUGS LastTimeLawEnforcerCreated = 0; + LastTimeMiamiViceGenerated = 0; #endif bCarsGeneratedAroundCamera = false; CountDownToCarsAtStart = 2; @@ -1951,9 +2198,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; } } @@ -1971,13 +2220,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) @@ -2087,7 +2337,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; @@ -2095,7 +2345,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; @@ -2206,6 +2456,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, @@ -2219,6 +2472,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, @@ -2240,26 +2499,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) @@ -2267,6 +2593,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(); @@ -2294,18 +2664,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; } } @@ -2341,6 +2705,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: @@ -2446,6 +2811,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; @@ -2487,26 +2853,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) { @@ -2628,6 +2974,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++) @@ -2641,11 +2989,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; @@ -2655,6 +3013,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; @@ -2710,9 +3070,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; } @@ -2771,18 +3133,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; } } @@ -2800,7 +3168,7 @@ void CCarCtrl::UpdateCarCount(CVehicle* pVehicle, bool remove) ++NumParkedCars; return; case PERMANENT_VEHICLE: - ++NumPermanentCars;; + ++NumPermanentCars; return; } } @@ -2808,12 +3176,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..8138266f 100644 --- a/src/control/CarCtrl.h +++ b/src/control/CarCtrl.h @@ -12,7 +12,7 @@ class CZoneInfo; enum{ MAX_CARS_TO_KEEP = 2, - MAX_CAR_MODELS_IN_ARRAY = 256, + MAX_CAR_MODELS_IN_ARRAY = 25, }; #define LANE_WIDTH 5.0f @@ -25,14 +25,20 @@ class CCarCtrl { public: enum eCarClass { - POOR = 0, + NORMAL = 0, + POOR, RICH, EXEC, WORKER, - SPECIAL, BIG, TAXI, - TOTAL_CUSTOM_CLASSES, + MOPED, + MOTORBIKE, + + LEISUREBOAT, + WORKERBOAT, + + COPS, MAFIA, TRIAD, DIABLO, @@ -42,7 +48,14 @@ public: NINES, GANG8, GANG9, - COPS + COPS_BOAT, + FIRST_CAR_RATING = NORMAL, + FIRST_BOAT_RATING = LEISUREBOAT, + FIRST_GANG_CAR_RATING = MAFIA, + 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 +107,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 +161,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 d8fd3ec0..b72931c6 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,60 +523,67 @@ 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; - } - 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; - } + 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; + } + 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; + 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: @@ -602,6 +622,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); @@ -646,92 +668,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())) { @@ -764,6 +704,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; @@ -851,75 +793,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: @@ -938,6 +811,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); @@ -1033,6 +908,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: { @@ -1045,7 +929,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)) { @@ -1061,11 +945,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; - } + StoreAndRemoveCarsForThisHideout(CGarages::aCarsInSafeHouses[CGarages::FindSafeHouseIndexForGarageType(m_eGarageType)], NUM_GARAGE_STORED_CARS); } UpdateDoorsHeight(); break; @@ -1074,29 +954,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_HELI && FindPlayerVehicle()->GetVehicleAppearance() != VEHICLE_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; - } - if (bCreatedAllCars) - m_eGarageState = GS_OPENING; - } + else if (RestoreCarsForThisHideout(CGarages::aCarsInSafeHouses[CGarages::FindSafeHouseIndexForGarageType(m_eGarageType)])) + m_eGarageState = GS_OPENING; } break; } @@ -1126,6 +996,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; @@ -1158,11 +1030,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()) @@ -1174,8 +1099,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 || @@ -1186,35 +1111,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; @@ -1222,15 +1170,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; @@ -1239,8 +1186,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() @@ -1253,20 +1207,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) @@ -1275,9 +1227,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; @@ -1296,9 +1246,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; } } @@ -1318,9 +1266,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; } } @@ -1340,9 +1286,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; } } @@ -1357,9 +1301,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; @@ -1374,9 +1316,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; @@ -1395,7 +1335,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) @@ -1408,7 +1348,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 { @@ -1416,7 +1356,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); } } @@ -1424,7 +1364,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); } } @@ -1454,15 +1394,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(); } @@ -1564,6 +1516,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; } @@ -1615,11 +1568,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; @@ -1627,11 +1578,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; @@ -1639,12 +1588,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) @@ -1677,16 +1624,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); @@ -1707,10 +1654,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); @@ -1725,20 +1672,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) @@ -1751,29 +1700,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) + if (!IsPointInsideGarage(pEntity->GetPosition(), 2.0f)) 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; - continue; - } if (!m_pDoor1) { m_pDoor1 = pEntity; m_bDoor1IsDummy = dummy; @@ -1808,6 +1736,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) @@ -1850,15 +1780,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; @@ -1892,9 +1819,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); @@ -1936,17 +1861,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; } @@ -1977,9 +1897,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; @@ -2003,11 +1921,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 @@ -2050,6 +1965,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: @@ -2101,36 +2027,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(); @@ -2141,34 +2050,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; - } + 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; - } - return 0; -} - bool CGarages::IsPointWithinHideOutGarage(Const CVector& point) { for (int i = 0; i < NUM_GARAGES; i++) { @@ -2176,9 +2062,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; } } @@ -2192,9 +2076,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; } } @@ -2231,6 +2113,7 @@ void CGarages::SetAllDoorsBackToOriginalHeight() } } +// TODO(MIAMI) void CGarages::Save(uint8 * buf, uint32 * size) { #ifdef FIX_GARAGE_SIZE @@ -2250,9 +2133,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]); @@ -2280,6 +2163,7 @@ const CStoredCar &CStoredCar::operator=(const CStoredCar & other) return *this; } +//TODO(MIAMI) void CGarages::Load(uint8* buf, uint32 size) { #ifdef FIX_GARAGE_SIZE @@ -2299,9 +2183,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); @@ -2328,8 +2212,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 || @@ -2343,7 +2226,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 || @@ -2352,13 +2234,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 569af776..59b8b5c2 100644 --- a/src/control/Pickups.cpp +++ b/src/control/Pickups.cpp @@ -485,7 +485,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; diff --git a/src/control/Pickups.h b/src/control/Pickups.h index b05f5db7..2842edfa 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 }; @@ -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(); 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..ab187c10 100644 --- a/src/control/Replay.cpp +++ b/src/control/Replay.cpp @@ -47,7 +47,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; @@ -835,13 +835,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)){ diff --git a/src/control/Replay.h b/src/control/Replay.h index 66bee3bf..09cf601e 100644 --- a/src/control/Replay.h +++ b/src/control/Replay.h @@ -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 6aa64a3c..1b6292b8 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 30793f55..ccfc010e 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" @@ -170,10 +171,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,6 +218,52 @@ 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; @@ -391,11 +474,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 +497,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; @@ -504,9 +583,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 +599,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 @@ -647,6 +729,7 @@ void CTheScripts::Process() float timeStep = CTimer::GetTimeStepInMilliseconds(); UpsideDownCars.UpdateTimers(); StuckCars.Process(); + MissionCleanup.CheckIfCollisionHasLoadedForMissionObject(); DrawScriptSpheres(); if (FailCurrentMission) --FailCurrentMission; @@ -737,15 +820,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; } @@ -1773,6 +1857,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++; @@ -1991,6 +2077,8 @@ int8 CRunningScript::ProcessCommands100To199(int32 command) boat->AutoPilot.m_nCarMission = MISSION_NONE; boat->AutoPilot.m_nTempAction = TEMPACT_NONE; /* Animation ID? */ boat->AutoPilot.m_nCruiseSpeed = boat->AutoPilot.m_fMaxTrafficSpeed = 20.0f; + if (m_bIsMissionScript) + boat->bIsStaticWaitingForCollision = true; CWorld::Add(boat); handle = CPools::GetVehiclePool()->GetIndex(boat); } @@ -2015,6 +2103,8 @@ int8 CRunningScript::ProcessCommands100To199(int32 command) 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); } @@ -2714,11 +2804,11 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) 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; } @@ -3043,18 +3133,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. @@ -3067,41 +3166,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); @@ -3136,14 +3211,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: @@ -4636,51 +4714,34 @@ 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]; + + // TODO(MIAMI): new 2 parameters, requires CGarage change + 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]; + // TODO(MIAMI): new 2 parameters, requires CGarage change + ScriptParams[0] = CGarages::AddOne(infX, infY, infZ, X2, Y2, supX, supY, supZ, (eGarageType)ScriptParams[8], ScriptParams[9]); StoreParameters(&m_nIp, 1); return 0; } @@ -5324,8 +5385,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 +5930,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 +5958,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 +5979,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 +6202,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 +6553,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 +6613,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(); @@ -7072,10 +7120,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; @@ -7207,7 +7256,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++) { @@ -7391,6 +7440,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++; @@ -7959,7 +8010,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++) { @@ -8133,7 +8184,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: @@ -8146,27 +8197,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: @@ -8176,21 +8227,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]); @@ -8387,10 +8438,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; @@ -8565,21 +8621,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(); @@ -8602,9 +8654,8 @@ 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: + assert(0 && "GET_OFFSET_FROM_CAR_IN_WORLD_COORDS not yet implemented"); return 0; case COMMAND_SET_TOTAL_NUMBER_OF_KILL_FRENZIES: CollectParameters(&m_nIp, 1); @@ -8679,8 +8730,13 @@ 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"); +#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); @@ -9117,7 +9173,6 @@ int8 CRunningScript::ProcessCommands1000To1099(int32 command) pPed->m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER); return 0; } -#ifndef GTA_PS2 default: assert(0); } @@ -9128,7 +9183,6 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) { char tmp[48]; switch (command) { -#endif case COMMAND_LOAD_COLLISION_WITH_SCREEN: CollectParameters(&m_nIp, 1); CTimer::Stop(); @@ -9194,9 +9248,6 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) case COMMAND_ENABLE_PLAYER_CONTROL_CAMERA: 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); @@ -9485,10 +9536,11 @@ int8 CRunningScript::ProcessCommands1100To1199(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); +// 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(); @@ -9605,13 +9657,13 @@ 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: @@ -9682,23 +9734,443 @@ 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: + case COMMAND_GET_REMOTE_CONTROLLED_CAR: + case COMMAND_IS_PC_VERSION: + case COMMAND_REPLAY: + case COMMAND_IS_REPLAY_PLAYING: + case COMMAND_IS_MODEL_AVAILABLE: + case COMMAND_SHUT_CHAR_UP: + case COMMAND_SET_ENABLE_RC_DETONATE: + assert(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: + case COMMAND_GET_FIRST_PICKUP_COORDS: + case COMMAND_GET_NEXT_PICKUP_COORDS: + case COMMAND_REMOVE_ALL_CHAR_WEAPONS: + case COMMAND_HAS_PLAYER_GOT_WEAPON: + case COMMAND_HAS_CHAR_GOT_WEAPON: + case COMMAND_IS_PLAYER_FACING_CHAR: + case COMMAND_SET_TANK_DETONATE_CARS: + case COMMAND_GET_POSITION_OF_ANALOGUE_STICKS: + case COMMAND_IS_CAR_ON_FIRE: + case COMMAND_IS_CAR_TYRE_BURST: + 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: + case COMMAND_START_OBJECT_ON_PATH: + case COMMAND_SET_OBJECT_PATH_SPEED: + case COMMAND_SET_OBJECT_PATH_POSITION: + case COMMAND_GET_OBJECT_DISTANCE_ALONG_PATH: + case COMMAND_CLEAR_OBJECT_PATH: + case COMMAND_HELI_GOTO_COORDS: + case COMMAND_IS_INT_VAR_EQUAL_TO_CONSTANT: + case COMMAND_IS_INT_LVAR_EQUAL_TO_CONSTANT: + case COMMAND_GET_DEAD_CHAR_PICKUP_COORDS: + case COMMAND_CREATE_PROTECTION_PICKUP: + case COMMAND_IS_CHAR_IN_ANY_BOAT: + case COMMAND_IS_PLAYER_IN_ANY_BOAT: + case COMMAND_IS_CHAR_IN_ANY_HELI: + case COMMAND_IS_PLAYER_IN_ANY_HELI: + case COMMAND_IS_CHAR_IN_ANY_PLANE: + case COMMAND_IS_PLAYER_IN_ANY_PLANE: + case COMMAND_IS_CHAR_IN_WATER: + assert(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: + case COMMAND_IS_INT_LVAR_GREATER_THAN_CONSTANT: + case COMMAND_IS_CONSTANT_GREATER_THAN_INT_VAR: + case COMMAND_IS_CONSTANT_GREATER_THAN_INT_LVAR: + case COMMAND_IS_INT_VAR_GREATER_OR_EQUAL_TO_CONSTANT: + case COMMAND_IS_INT_LVAR_GREATER_OR_EQUAL_TO_CONSTANT: + case COMMAND_IS_CONSTANT_GREATER_OR_EQUAL_TO_INT_VAR: + case COMMAND_IS_CONSTANT_GREATER_OR_EQUAL_TO_INT_LVAR: + case COMMAND_GET_CHAR_WEAPON_IN_SLOT: + case COMMAND_GET_CLOSEST_STRAIGHT_ROAD: + case COMMAND_SET_CAR_FORWARD_SPEED: + assert(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: + assert(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: + case COMMAND_IS_PLAYER_IN_FLYING_VEHICLE: + 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: + 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: + case COMMAND_ADD_SET_PIECE: + case COMMAND_SET_EXTRA_COLOURS: + case COMMAND_CLEAR_EXTRA_COLOURS: + case COMMAND_CLOSE_CAR_BOOT: + case COMMAND_GET_WHEELIE_STATS: + 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: + case COMMAND_LOAD_AND_LAUNCH_MISSION_EXCLUSIVE: + case COMMAND_IS_MISSION_AUDIO_PLAYING: + 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: + case COMMAND_DISABLE_CUTSCENE_SHADOWS: + 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: + case COMMAND_REMOVE_EVERYTHING_FOR_HUGE_CUTSCENE: + 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: + case COMMAND_LOAD_MISSION_TEXT: + case COMMAND_SET_TONIGHTS_EVENT: + 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: + case COMMAND_CREATE_CLOTHES_PICKUP: + case COMMAND_CHANGE_BLIP_THRESHOLD: + case COMMAND_MAKE_PLAYER_FIRE_PROOF: + case COMMAND_INCREASE_PLAYER_MAX_HEALTH: + case COMMAND_INCREASE_PLAYER_MAX_ARMOUR: + case COMMAND_CREATE_RANDOM_CHAR_AS_DRIVER: + case COMMAND_CREATE_RANDOM_CHAR_AS_PASSENGER: + 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: + case COMMAND_SET_OBJECT_AREA_VISIBLE: + case COMMAND_WAS_VEHICLE_EVER_POLICE: + case COMMAND_SET_CHAR_NEVER_TARGETTED: + case COMMAND_LOAD_UNCOMPRESSED_ANIM: + case COMMAND_WAS_CUTSCENE_SKIPPED: + case COMMAND_SET_CHAR_CROUCH_WHEN_THREATENED: + case COMMAND_IS_CHAR_IN_ANY_POLICE_VEHICLE: + case COMMAND_DOES_CHAR_EXIST: + case COMMAND_DOES_VEHICLE_EXIST: + case COMMAND_ADD_SHORT_RANGE_BLIP_FOR_CONTACT_POINT: + 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: + case COMMAND_SET_ALLOW_HURRICANES: + case COMMAND_PLAY_ANNOUNCEMENT: + 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: + case COMMAND_IS_PLAYER_IN_INFO_ZONE: + 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: + case COMMAND_GET_PROGRESS_PERCENTAGE: + case COMMAND_SET_SHORTCUT_PICKUP_POINT: + case COMMAND_SET_SHORTCUT_DROPOFF_POINT_FOR_MISSION: + 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: + case COMMAND_SET_GANG_ATTACK_PLAYER_WITH_COPS: + case COMMAND_SET_CHAR_FRIGHTENED_IN_JACKED_CAR: + case COMMAND_SET_VEHICLE_TO_FADE_IN: + case COMMAND_REGISTER_ODDJOB_MISSION_PASSED: + case COMMAND_IS_PLAYER_IN_SHORTCUT_TAXI: + 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); } diff --git a/src/control/Script.h b/src/control/Script.h index acab66cc..9931f13e 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 @@ -372,6 +375,7 @@ private: friend class CRunningScript; friend class CHud; friend void CMissionCleanup::Process(); + friend class CColStore; }; @@ -462,9 +466,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*); 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 b2f0900e..f2dd6814 100644 --- a/src/control/TrafficLights.cpp +++ b/src/control/TrafficLights.cpp @@ -273,8 +273,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 |