diff options
52 files changed, 2211 insertions, 62 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 345f4cb4..24e7cc53 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); @@ -119,4 +131,3 @@ public: #endif }; -static_assert(sizeof(CAutoPilot) == 0x70, "CAutoPilot: error");
\ No newline at end of file diff --git a/src/control/CarAI.cpp b/src/control/CarAI.cpp index 3e22ee77..465b0b33 100644 --- a/src/control/CarAI.cpp +++ b/src/control/CarAI.cpp @@ -21,16 +21,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 +41,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,6 +85,7 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) if (pVehicle->UsesSiren(pVehicle->GetModelIndex())) pVehicle->m_bSirenOrAlarm = true; } +#ifndef MIAMI if (FindPlayerPed()->m_pWanted->m_bIgnoredByEveryone || pVehicle->bIsLawEnforcer && (FindPlayerPed()->m_pWanted->m_nWantedLevel == 0 || FindPlayerPed()->m_pWanted->m_bIgnoredByCops || CCullZones::NoPolice())) { CCarCtrl::JoinCarWithRoadSystem(pVehicle); @@ -76,6 +95,9 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle) if (CCullZones::NoPolice()) pVehicle->AutoPilot.m_nCarMission = MISSION_NONE; } +#else + BackToCruisingIfNoWantedLevel(pVehicle); +#endif break; case MISSION_RAMPLAYER_CLOSE: if (FindSwitchDistanceFar(pVehicle) >= (FindPlayerCoors() - pVehicle->GetPosition()).Magnitude2D() || @@ -120,18 +142,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,15 +153,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_BLOCKPLAYER_CLOSE: if (FindSwitchDistanceFar(pVehicle) >= (FindPlayerCoors() - pVehicle->GetPosition()).Magnitude2D() || @@ -178,20 +183,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 +200,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 +260,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 +283,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 && +#ifdef FIX_BUGS // btw fixed in SA + if (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 - ) -#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 +328,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 +369,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 +390,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 +403,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 +440,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 +486,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 +540,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 +569,41 @@ void CCarAI::AddPoliceCarOccupants(CVehicle* pVehicle) if (FindPlayerPed()->m_pWanted->m_nWantedLevel > 1) pVehicle->SetupPassenger(0); return; + case MI_PREDATOR: + pVehicle->SetUpDriver(); + return; +//TODO(MIAMI) uncomment this when we have MI_VICECHEE +/* + case MI_VICECHEE: + { + pVehicle->SetUpDriver()->bIsMiamiViceCop = true; + pVehicle->SetUpPassenger(0)->bIsMiamiViceCop = 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 +614,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 +649,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 +659,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 +674,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 +704,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 +743,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 +786,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 9b2bd4f0..d5b86478 100644 --- a/src/control/CarCtrl.cpp +++ b/src/control/CarCtrl.cpp @@ -1641,6 +1641,7 @@ void CCarCtrl::PickNextNodeToChaseCar(CVehicle* pVehicle, float targetX, float t CPathNode* pTargetNode; int16 numNodes; float distanceToTargetNode; +#ifndef MIAMI if (pTarget && pTarget->m_pCurGroundEntity && pTarget->m_pCurGroundEntity->IsBuilding() && ((CBuilding*)pTarget->m_pCurGroundEntity)->GetIsATreadable() && @@ -1666,6 +1667,7 @@ void CCarCtrl::PickNextNodeToChaseCar(CVehicle* pVehicle, float targetX, float t #endif &pTargetNode, &numNodes, 1, pVehicle, &distanceToTargetNode, 999999.9f, closestNode); }else +#endif { ThePaths.DoPathSearch(0, pCurNode->GetPosition(), curNode, @@ -2745,3 +2747,13 @@ bool CCarCtrl::MapCouldMoveInThisArea(float x, float y) return x > -342.0f && x < -219.0f && y > -677.0f && y < -580.0f; } + +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 44ef9ab6..4f92bdcf 100644 --- a/src/control/CarCtrl.h +++ b/src/control/CarCtrl.h @@ -104,6 +104,7 @@ public: static void ClearInterestingVehicleList(); static void FindLinksToGoWithTheseNodes(CVehicle*); static bool GenerateOneEmergencyServicesCar(uint32, CVector); + static float FindSpeedMultiplierWithSpeedFromNodes(int8); static float GetPositionAlongCurrentCurve(CVehicle* pVehicle) { diff --git a/src/control/PathFind.cpp b/src/control/PathFind.cpp index ee15b82f..fd1b4950 100644 --- a/src/control/PathFind.cpp +++ b/src/control/PathFind.cpp @@ -18,9 +18,16 @@ CPathFind ThePaths; #define MIN_PED_ROUTE_DISTANCE 23.8f +#ifdef MIAMI +#define NUMTEMPNODES 5000 +#define NUMDETACHED_CARS 1024 +#define NUMDETACHED_PEDS 1214 +#define NUMTEMPEXTERNALNODES 4600 +#else #define NUMTEMPNODES 4000 #define NUMDETACHED_CARS 100 #define NUMDETACHED_PEDS 50 +#endif // object flags: @@ -30,9 +37,18 @@ CPathFind ThePaths; CPathInfoForObject *InfoForTileCars; CPathInfoForObject *InfoForTilePeds; +#ifndef MIAMI // unused CTempDetachedNode *DetachedNodesCars; CTempDetachedNode *DetachedNodesPeds; +#else +CPathInfoForObject *DetachedInfoForTileCars; +CPathInfoForObject *DetachedInfoForTilePeds; +CTempNodeExternal *TempExternalNodes; +int32 NumTempExternalNodes; +int32 NumDetachedPedNodeGroups; +int32 NumDetachedCarNodeGroups; +#endif bool CPedPath::CalcPedRoute(int8 pathType, CVector position, CVector destination, CVector *pointPoses, int16 *pointsFound, int16 maxPoints) @@ -227,6 +243,28 @@ CPedPath::AddBlockade(CEntity *pEntity, CPedPathNode(*pathNodes)[40], CVector *p } } +#ifdef MIAMI +// 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; + } +} +#endif + +//--MIAMI: done void CPathFind::Init(void) { @@ -237,11 +275,15 @@ CPathFind::Init(void) m_numConnections = 0; m_numCarPathLinks = 0; unk = 0; +#ifdef MIAMI + NumTempExternalNodes = 0; +#endif for(i = 0; i < NUM_PATHNODES; i++) m_pathNodes[i].distance = MAX_DIST; } +//--MIAMI: done void CPathFind::AllocatePathFindInfoMem(int16 numPathGroups) { @@ -256,6 +298,7 @@ CPathFind::AllocatePathFindInfoMem(int16 numPathGroups) InfoForTilePeds = new CPathInfoForObject[12*numPathGroups]; memset(InfoForTilePeds, 0, 12*numPathGroups*sizeof(CPathInfoForObject)); +#ifndef MIAMI // unused delete[] DetachedNodesCars; DetachedNodesCars = nil; @@ -265,14 +308,32 @@ CPathFind::AllocatePathFindInfoMem(int16 numPathGroups) memset(DetachedNodesCars, 0, NUMDETACHED_CARS*sizeof(CTempDetachedNode)); DetachedNodesPeds = new CTempDetachedNode[NUMDETACHED_PEDS]; memset(DetachedNodesPeds, 0, NUMDETACHED_PEDS*sizeof(CTempDetachedNode)); +#else + 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; +#endif } +//--MIAMI: done void CPathFind::RegisterMapObject(CTreadable *mapObject) { m_mapObjects[m_numMapObjects++] = mapObject; } +//--MIAMI: TODO: implement all the arguments once we can load the VC map void CPathFind::StoreNodeInfoPed(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, int16 width, bool crossing) { @@ -281,13 +342,27 @@ CPathFind::StoreNodeInfoPed(int16 id, int16 node, int8 type, int8 next, int16 x, i = id*12 + node; InfoForTilePeds[i].type = type; InfoForTilePeds[i].next = next; +#ifndef MIAMI InfoForTilePeds[i].x = x; InfoForTilePeds[i].y = y; InfoForTilePeds[i].z = z; +#else + InfoForTilePeds[i].x = x/16.0f; + InfoForTilePeds[i].y = y/16.0f; + InfoForTilePeds[i].z = z/16.0f; +#endif InfoForTilePeds[i].numLeftLanes = 0; InfoForTilePeds[i].numRightLanes = 0; InfoForTilePeds[i].crossing = crossing; +#ifdef MIAMI + InfoForTilePeds[i].flag02 = false; + InfoForTilePeds[i].roadBlock = false; + InfoForTilePeds[i].disabled = false; + InfoForTilePeds[i].waterPath = false; + InfoForTilePeds[i].betweenLevels = false; +#endif +#ifndef MIAMI if(type) for(i = 0; i < node; i++){ j = id*12 + i; @@ -298,8 +373,13 @@ CPathFind::StoreNodeInfoPed(int16 id, int16 node, int8 type, int8 next, int16 x, printf("Modelindex of cullprit: %d\n\n", id); } } +#else + if(node == 11) + InfoForTilePeds[id*12].SwapConnectionsToBeRightWayRound(); +#endif } +//--MIAMI: TODO: implement all the arguments once we can load the VC map void CPathFind::StoreNodeInfoCar(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, int16 width, int8 numLeft, int8 numRight) { @@ -308,13 +388,28 @@ CPathFind::StoreNodeInfoCar(int16 id, int16 node, int8 type, int8 next, int16 x, i = id*12 + node; InfoForTileCars[i].type = type; InfoForTileCars[i].next = next; +#ifndef MIAMI InfoForTileCars[i].x = x; InfoForTileCars[i].y = y; InfoForTileCars[i].z = z; +#else + InfoForTileCars[i].x = x/16.0f; + InfoForTileCars[i].y = y/16.0f; + InfoForTileCars[i].z = z/16.0f; +#endif InfoForTileCars[i].numLeftLanes = numLeft; InfoForTileCars[i].numRightLanes = numRight; +#ifdef MIAMI + InfoForTileCars[i].crossing = false; + InfoForTileCars[i].flag02 = false; + InfoForTileCars[i].roadBlock = false; + InfoForTileCars[i].disabled = false; + InfoForTileCars[i].waterPath = false; + InfoForTileCars[i].betweenLevels = false; +#endif +#ifndef MIAMI if(type) for(i = 0; i < node; i++){ j = id*12 + i; @@ -325,8 +420,13 @@ CPathFind::StoreNodeInfoCar(int16 id, int16 node, int8 type, int8 next, int16 x, printf("Modelindex of cullprit: %d\n\n", id); } } +#else + if(node == 11) + InfoForTileCars[id*12].SwapConnectionsToBeRightWayRound(); +#endif } +#ifndef MIAMI void CPathFind::CalcNodeCoors(int16 x, int16 y, int16 z, int id, CVector *out) { @@ -336,7 +436,19 @@ CPathFind::CalcNodeCoors(int16 x, int16 y, int16 z, int id, CVector *out) pos.z = z / 16.0f; *out = m_mapObjects[id]->GetMatrix() * pos; } +#else +void +CPathFind::CalcNodeCoors(float x, float y, float z, int id, CVector *out) +{ + CVector pos; + pos.x = x; + pos.y = y; + pos.z = z; + *out = m_mapObjects[id]->GetMatrix() * pos; +} +#endif +//--MIAMI: done bool CPathFind::LoadPathFindData(void) { @@ -344,6 +456,7 @@ CPathFind::LoadPathFindData(void) return false; } +//--MIAMI: done void CPathFind::PreparePathData(void) { @@ -355,14 +468,20 @@ CPathFind::PreparePathData(void) printf("PreparePathData\n"); if(!CPathFind::LoadPathFindData() && // empty InfoForTileCars && InfoForTilePeds && +#ifndef MIAMI DetachedNodesCars && DetachedNodesPeds +#else + DetachedInfoForTileCars && DetachedInfoForTilePeds && TempExternalNodes +#endif ){ tempNodes = new CTempNode[NUMTEMPNODES]; m_numConnections = 0; +#ifndef MIAMI for(i = 0; i < PATHNODESIZE; i++) m_pathNodes[i].unkBits = 0; +#endif for(i = 0; i < PATHNODESIZE; i++){ numExtern = 0; @@ -377,6 +496,21 @@ CPathFind::PreparePathData(void) printf("ILLEGAL BLOCK. MORE THAN 1 INTERNALS AND NOT 2 EXTERNALS (Modelindex:%d)\n", i); } +#ifdef MIAMI + 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 + } +#endif + for(i = 0; i < PATHNODESIZE; i++) for(j = 0; j < 12; j++) if(InfoForTileCars[i*12 + j].type == NodeTypeExtern){ @@ -388,13 +522,33 @@ 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); } +#ifdef MIAMI + for(i = 0; i < NUMDETACHED_CARS; i++) + for(j = 0; j < 12; j++) + if(DetachedInfoForTilePeds[i*12 + j].type == NodeTypeExtern){ + // MI:%d here but no argument for it + if(DetachedInfoForTilePeds[i*12 + j].numLeftLanes < 0) + printf("ILLEGAL BLOCK. NEGATIVE NUMBER OF LANES (Obj:%d)\n", i); + if(DetachedInfoForTilePeds[i*12 + j].numRightLanes < 0) + printf("ILLEGAL BLOCK. NEGATIVE NUMBER OF LANES (Obj:%d)\n", i); + if(DetachedInfoForTilePeds[i*12 + j].numLeftLanes + DetachedInfoForTilePeds[i*12 + j].numRightLanes <= 0) + printf("ILLEGAL BLOCK. NO LANES IN NODE (Obj:%d)\n", i); + } +#endif m_numPathNodes = 0; +#ifndef MIAMI PreparePathDataForType(PATH_CAR, tempNodes, InfoForTileCars, 1.0f, DetachedNodesCars, NUMDETACHED_CARS); m_numCarPathNodes = m_numPathNodes; PreparePathDataForType(PATH_PED, tempNodes, InfoForTilePeds, 1.0f, DetachedNodesPeds, NUMDETACHED_PEDS); +#else + PreparePathDataForType(PATH_CAR, tempNodes, InfoForTileCars, 1.0f, DetachedInfoForTileCars, NumDetachedCarNodeGroups); + m_numCarPathNodes = m_numPathNodes; + PreparePathDataForType(PATH_PED, tempNodes, InfoForTilePeds, 1.0f, DetachedInfoForTilePeds, NumDetachedPedNodeGroups); +#endif m_numPedPathNodes = m_numPathNodes - m_numCarPathNodes; +#ifndef MIAMI // 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++){ @@ -433,6 +587,7 @@ CPathFind::PreparePathData(void) } } } +#endif delete[] tempNodes; @@ -444,14 +599,24 @@ CPathFind::PreparePathData(void) delete[] InfoForTilePeds; InfoForTilePeds = nil; +#ifndef MIAMI delete[] DetachedNodesCars; DetachedNodesCars = nil; delete[] DetachedNodesPeds; DetachedNodesPeds = nil; +#else + delete[] DetachedInfoForTileCars; + DetachedInfoForTileCars = nil; + delete[] DetachedInfoForTilePeds; + DetachedInfoForTilePeds = nil; + delete[] TempExternalNodes; + TempExternalNodes = nil; +#endif } 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 +659,13 @@ CPathFind::CountFloodFillGroups(uint8 type) if(node->numLinks == 0){ if(type == PATH_CAR) +#ifndef MIAMI printf("Single car node: %f %f %f (%d)\n", node->GetX(), node->GetY(), node->GetZ(), m_mapObjects[node->objectIndex]->GetModelIndex()); +#else + printf("Single car node: %f %f %f\n", + node->GetX(), node->GetY(), node->GetZ()); +#endif else printf("Single ped node: %f %f %f\n", node->GetX(), node->GetY(), node->GetZ()); @@ -523,9 +693,14 @@ CPathFind::CountFloodFillGroups(uint8 type) int32 TempListLength; +//--MIAMI: done void CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoForObject *objectpathinfo, +#ifndef MIAMI float maxdist, CTempDetachedNode *detachednodes, int numDetached) +#else + float maxdist, CPathInfoForObject *detachednodes, int numDetached) +#endif { static CVector CoorsXFormed; int i, j, k, l; @@ -546,11 +721,17 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor oldNumPathNodes = m_numPathNodes; oldNumLinks = m_numConnections; +#ifndef MIAMI #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; +#else +#define OBJECTINDEX(n) (mapObjIndices[(n)]) + int16 *mapObjIndices = new int16[NUM_PATHNODES]; + NumTempExternalNodes = 0; +#endif // Calculate internal nodes, store them and connect them to defining object for(i = 0; i < m_numMapObjects; i++){ @@ -566,16 +747,83 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor &CoorsXFormed); m_pathNodes[m_numPathNodes].SetPosition(CoorsXFormed); OBJECTINDEX(m_numPathNodes) = i; +#ifndef MIAMI m_pathNodes[m_numPathNodes].unkBits = 1; m_mapObjects[i]->m_nodeIndices[type][j] = m_numPathNodes; +#else + 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].flagB2 = objectpathinfo[start + j].flag02; + m_pathNodes[m_numPathNodes].bBetweenLevels = objectpathinfo[start + j].betweenLevels; +#endif m_numPathNodes++; } +#ifdef MIAMI + 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++; + } +#endif } } +#ifdef MIAMI + // 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].flagB2 = detachednodes[start + j].flag02; + 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++; + } + } + } +#endif // Insert external nodes into TempList TempListLength = 0; +#ifndef MIAMI for(i = 0; i < m_numMapObjects; i++){ start = 12 * m_mapObjects[i]->GetModelIndex(); for(j = 0; j < 12; j++){ @@ -651,6 +899,62 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor } } } +#else + 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; + 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 = 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; + } + } + } +#endif // Loop through previously added internal nodes and link them for(i = oldNumPathNodes; i < m_numPathNodes; i++){ @@ -673,27 +977,49 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor continue; dist = (m_pathNodes[i].GetPosition() - m_pathNodes[ConnectedNode(m_numConnections)].GetPosition()).Magnitude(); +#ifndef MIAMI m_distances[m_numConnections] = dist; m_connectionFlags[m_numConnections].flags = 0; +#else + m_distances[m_numConnections] = Min(dist, 255); + if(tempnodes[j].isCross) + m_connections[j] |= 0x8000; // crosses road flag +#endif if(type == PATH_CAR){ // IMPROVE: use a goto here // Find existing car path link for(k = 0; k < m_numCarPathLinks; k++){ +#ifndef MIAMI 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){ +#else + 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)){ +#endif m_carPathConnections[m_numConnections] = k; k = m_numCarPathLinks; } } // k is m_numCarPathLinks+1 if we found one if(k == m_numCarPathLinks){ +#ifndef MIAMI 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; +#else + 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; +#endif m_carPathLinks[m_numCarPathLinks].pathNodeIndex = i; m_carPathLinks[m_numCarPathLinks].numLeftLanes = tempnodes[j].numLeftLanes; m_carPathLinks[m_numCarPathLinks].numRightLanes = tempnodes[j].numRightLanes; @@ -707,6 +1033,20 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor m_numConnections++; } +#ifdef MIAMI + 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()]; + } +#endif // Find i inside path segment iseg = 0; @@ -714,7 +1054,9 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor if(OBJECTINDEX(j) == OBJECTINDEX(i)) iseg++; +#ifndef MIAMI istart = 12 * m_mapObjects[m_pathNodes[i].objectIndex]->GetModelIndex(); +#endif // 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 +1064,23 @@ 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; +#ifndef MIAMI jstart = 12 * m_mapObjects[m_pathNodes[j].objectIndex]->GetModelIndex(); if(objectpathinfo[istart + iseg].next == jseg || objectpathinfo[jstart + jseg].next == iseg){ +#else + if(tile[iseg].next == jseg || + tile[jseg].next == iseg){ +#endif // 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(); +#ifndef MIAMI m_distances[m_numConnections] = dist; +#else + m_distances[m_numConnections] = Min(dist, 255); +#endif if(type == PATH_CAR){ posx = (m_pathNodes[i].GetX() + m_pathNodes[j].GetX())*0.5f; @@ -739,6 +1090,9 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor mag = Sqrt(dx*dx + dy*dy); dx /= mag; dy /= mag; +#ifdef MIAMI + int width = Max(m_pathNodes[i].width, m_pathNodes[j].width); +#endif if(i < j){ dx = -dx; dy = -dy; @@ -746,20 +1100,36 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor // IMPROVE: use a goto here // Find existing car path link for(k = 0; k < m_numCarPathLinks; k++){ +#ifndef MIAMI 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){ +#else + 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)){ +#endif m_carPathConnections[m_numConnections] = k; k = m_numCarPathLinks; } } // k is m_numCarPathLinks+1 if we found one if(k == m_numCarPathLinks){ +#ifndef MIAMI 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; +#else + 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; +#endif m_carPathLinks[m_numCarPathLinks].pathNodeIndex = i; m_carPathLinks[m_numCarPathLinks].numLeftLanes = -1; m_carPathLinks[m_numCarPathLinks].numRightLanes = -1; @@ -769,11 +1139,17 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor } }else{ // Crosses road +#ifndef MIAMI 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; +#else + if(tile[iseg].next == jseg && tile[iseg].crossing || + tile[jseg].next == iseg && tile[jseg].crossing) + m_connections[m_numConnections] |= 0x8000; // crosses road flag +#endif } m_pathNodes[i].numLinks++; @@ -786,7 +1162,11 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor done = 0; // Set number of lanes for all nodes somehow // very strange code +#ifndef MIAMI for(k = 0; !done && k < 10; k++){ +#else + for(k = 0; !done && k < 12; k++){ +#endif done = 1; for(i = 0; i < m_numPathNodes; i++){ if(m_pathNodes[i].numLinks != 2) @@ -794,6 +1174,7 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor l1 = m_carPathConnections[m_pathNodes[i].firstLink]; l2 = m_carPathConnections[m_pathNodes[i].firstLink+1]; +#ifndef MIAMI if(m_carPathLinks[l1].numLeftLanes == -1 && m_carPathLinks[l2].numLeftLanes != -1){ done = 0; @@ -821,6 +1202,52 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor }else if(m_carPathLinks[l1].numLeftLanes == -1 && m_carPathLinks[l2].numLeftLanes == -1) done = 0; +#else + 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(*l1Rightp == -1 && *l2Leftp != -1){ + *l1Rightp = *l2Leftp; + done = 0; + } + 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; +#endif } } @@ -828,10 +1255,17 @@ 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]; +#ifndef MIAMI if(m_carPathLinks[k].numLeftLanes < 0) m_carPathLinks[k].numLeftLanes = 1; if(m_carPathLinks[k].numRightLanes < 0) m_carPathLinks[k].numRightLanes = 1; +#else + if(m_carPathLinks[k].numLeftLanes == -1) + m_carPathLinks[k].numLeftLanes = 0; + if(m_carPathLinks[k].numRightLanes == -1) + m_carPathLinks[k].numRightLanes = 0; +#endif } } @@ -840,8 +1274,10 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor do{ cont = 0; for(i = 0; i < m_numPathNodes; i++){ +#ifndef MIAMI m_pathNodes[i].bDisabled = false; m_pathNodes[i].bBetweenLevels = false; +#endif // See if node is a dead end, if so, we're not done yet if(!m_pathNodes[i].bDeadEnd){ k = 0; @@ -874,6 +1310,7 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor m_connections[j] = node-1; } +#ifndef MIAMI // Also in treadables for(j = 0; j < m_numMapObjects; j++) for(k = 0; k < 12; k++){ @@ -885,12 +1322,17 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor }else if(m_mapObjects[j]->m_nodeIndices[PATH_PED][k] > i) m_mapObjects[j]->m_nodeIndices[PATH_PED][k]--; } +#endif i--; m_numPathNodes--; } +#ifdef MIAMI + delete[] mapObjIndices; +#endif } +//--MIAMI: done float CPathFind::CalcRoadDensity(float x, float y) { @@ -908,6 +1350,7 @@ CPathFind::CalcRoadDensity(float x, float y) density += m_carPathLinks[next].numLeftLanes * dist; density += m_carPathLinks[next].numRightLanes * dist; +#ifndef MIAMI if(m_carPathLinks[next].numLeftLanes < 0) printf("Link from object %d to %d (MIs)\n", m_mapObjects[m_pathNodes[i].objectIndex]->GetModelIndex(), @@ -916,12 +1359,14 @@ CPathFind::CalcRoadDensity(float x, float y) 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()); +#endif } } } return density/2500.0f; } +//--MIAMI: done bool CPathFind::TestForPedTrafficLight(CPathNode *n1, CPathNode *n2) { @@ -932,6 +1377,7 @@ CPathFind::TestForPedTrafficLight(CPathNode *n1, CPathNode *n2) return false; } +//--MIAMI: done bool CPathFind::TestCrossesRoad(CPathNode *n1, CPathNode *n2) { @@ -942,6 +1388,7 @@ CPathFind::TestCrossesRoad(CPathNode *n1, CPathNode *n2) return false; } +//--MIAMI: done void CPathFind::AddNodeToList(CPathNode *node, int32 listId) { @@ -954,6 +1401,7 @@ CPathFind::AddNodeToList(CPathNode *node, int32 listId) node->distance = listId; } +//--MIAMI: done void CPathFind::RemoveNodeFromList(CPathNode *node) { @@ -962,6 +1410,7 @@ CPathFind::RemoveNodeFromList(CPathNode *node) node->GetNext()->SetPrev(node->GetPrev()); } +//--MIAMI: done void CPathFind::RemoveBadStartNode(CVector pos, CPathNode **nodes, int16 *n) { @@ -987,6 +1436,7 @@ CPathFind::SetLinksBridgeLights(float x1, float x2, float y1, float y2, bool ena } } +//--MIAMI: done void CPathFind::SwitchOffNodeAndNeighbours(int32 nodeId, bool disable) { @@ -1002,6 +1452,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 +1468,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 +1484,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 +1536,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 +1552,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 +1567,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 +1582,14 @@ CPathFind::PedMarkRoadsBetweenLevelsInArea(float x1, float x2, float y1, float y } } +//--MIAMI: done +#ifndef MIAMI int32 CPathFind::FindNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bool ignoreDisabled, bool ignoreBetweenLevels) +#else +int32 +CPathFind::FindNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bool ignoreDisabled, bool ignoreBetweenLevels, bool ignoreFlagB4, bool bWaterPath) +#endif { int i; int firstNode, lastNode; @@ -1149,9 +1611,14 @@ 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; +#ifndef MIAMI switch(m_pathNodes[i].unkBits){ case 1: case 2: +#else + if(ignoreFlagB4 && m_pathNodes[i].flagB4) continue; + if(bWaterPath != m_pathNodes[i].bWaterPath) continue; +#endif dist = Abs(m_pathNodes[i].GetX() - coors.x) + Abs(m_pathNodes[i].GetY() - coors.y) + 3.0f*Abs(m_pathNodes[i].GetZ() - coors.z); @@ -1159,12 +1626,15 @@ CPathFind::FindNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bo closestDist = dist; closestNode = i; } +#ifndef MIAMI break; } +#endif } return closestDist < distLimit ? closestNode : -1; } +//--MIAMI: done int32 CPathFind::FindNodeClosestToCoorsFavourDirection(CVector coors, uint8 type, float dirX, float dirY) { @@ -1187,9 +1657,11 @@ CPathFind::FindNodeClosestToCoorsFavourDirection(CVector coors, uint8 type, floa } for(i = firstNode; i < lastNode; i++){ +#ifndef MIAMI switch(m_pathNodes[i].unkBits){ case 1: case 2: +#endif dX = m_pathNodes[i].GetX() - coors.x; dY = m_pathNodes[i].GetY() - coors.y; dist = Abs(dX) + Abs(dY) + @@ -1202,12 +1674,15 @@ CPathFind::FindNodeClosestToCoorsFavourDirection(CVector coors, uint8 type, floa closestNode = i; } } +#ifndef MIAMI break; } +#endif } return closestNode; } +//--MIAMI: done float CPathFind::FindNodeOrientationForCarPlacement(int32 nodeId) { @@ -1219,6 +1694,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 +1738,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) { @@ -1316,6 +1794,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,6 +1854,7 @@ CPathFind::GeneratePedCreationCoors(float x, float y, float minDist, float maxDi return false; } +#ifndef MIAMI CTreadable* CPathFind::FindRoadObjectClosestToCoors(CVector coors, uint8 type) { @@ -1410,7 +1890,9 @@ CPathFind::FindRoadObjectClosestToCoors(CVector coors, uint8 type) } return closestMapObj; } +#endif +//--MIAMI: done void CPathFind::FindNextNodeWandering(uint8 type, CVector coors, CPathNode **lastNode, CPathNode **nextNode, uint8 curDir, uint8 *nextDir) { @@ -1418,6 +1900,7 @@ CPathFind::FindNextNodeWandering(uint8 type, CVector coors, CPathNode **lastNode CPathNode *node; if(lastNode == nil || (node = *lastNode) == nil || (coors - (*lastNode)->GetPosition()).MagnitudeSqr() > 7.0f){ +#ifndef MIAMI // need to find the node we're coming from node = nil; CTreadable *obj = FindRoadObjectClosestToCoors(coors, type); @@ -1431,6 +1914,10 @@ CPathFind::FindNextNodeWandering(uint8 type, CVector coors, CPathNode **lastNode node = &m_pathNodes[obj->m_nodeIndices[type][i]]; } } +#else + int32 nodeIdx = FindNodeClosestToCoors(coors, type, 999999.88f); + node = &m_pathNodes[nodeIdx]; +#endif } CVector2D vCurDir(Sin(curDir*PI/4.0f), Cos(curDir * PI / 4.0f)); @@ -1486,8 +1973,13 @@ CPathFind::FindNextNodeWandering(uint8 type, CVector coors, CPathNode **lastNode } } +#ifndef MIAMI static CPathNode *apNodesToBeCleared[4995]; +#else +static CPathNode *apNodesToBeCleared[6525]; +#endif +//--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,6 +1995,7 @@ CPathFind::DoPathSearch(uint8 type, CVector start, int32 startNodeId, CVector ta } // Find start +#ifndef MIAMI int numPathsToTry; CTreadable *startObj; if(startNodeId < 0){ @@ -1540,6 +2033,25 @@ CPathFind::DoPathSearch(uint8 type, CVector start, int32 startNodeId, CVector ta return; } } +#else + if(startNodeId < 0) + startNodeId = FindNodeClosestToCoors(start, type, 999999.88f); + if(startNodeId < 0) { + *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; + } +#endif for(i = 0; i < ARRAY_SIZE(m_searchNodes); i++) m_searchNodes[i].SetNext(nil); @@ -1550,14 +2062,23 @@ CPathFind::DoPathSearch(uint8 type, CVector start, int32 startNodeId, CVector ta // Dijkstra's algorithm // Find distances int numPathsFound = 0; +#ifndef MIAMI if(startNodeId < 0 && m_mapObjects[m_pathNodes[targetNodeId].objectIndex] == startObj) numPathsFound++; for(i = 0; numPathsFound < numPathsToTry; i = (i+1) & 0x1FF){ +#else + for(i = 0; numPathsFound == 0; i = (i+1) & 0x1FF){ +#endif CPathNode *node; for(node = m_searchNodes[i].GetNext(); node; node = node->GetNext()){ +#ifndef MIAMI if(m_mapObjects[node->objectIndex] == startObj && (startNodeId < 0 || node == &m_pathNodes[startNodeId])) numPathsFound++; +#else + if(node == &m_pathNodes[startNodeId]) + numPathsFound = 1; +#endif for(j = 0; j < node->numLinks; j++){ int next = ConnectedNode(node->firstLink + j); @@ -1577,6 +2098,7 @@ CPathFind::DoPathSearch(uint8 type, CVector start, int32 startNodeId, CVector ta // Find out whence to start tracing back CPathNode *curNode; +#ifndef MIAMI if(startNodeId < 0){ int minDist = MAX_DIST; *pNumNodes = 1; @@ -1598,6 +2120,7 @@ CPathFind::DoPathSearch(uint8 type, CVector start, int32 startNodeId, CVector ta if(pDist) *pDist = minDist; }else +#endif { curNode = &m_pathNodes[startNodeId]; *pNumNodes = 0; @@ -1605,6 +2128,9 @@ CPathFind::DoPathSearch(uint8 type, CVector start, int32 startNodeId, CVector ta *pDist = m_pathNodes[startNodeId].distance; } +#ifdef MIAMI + nodes[(*pNumNodes)++] = curNode; +#endif // Trace back to target and update list of nodes while(*pNumNodes < maxNumNodes && curNode != &m_pathNodes[targetNodeId]) for(i = 0; i < curNode->numLinks; i++){ @@ -1625,6 +2151,7 @@ static CPathNode *pNodeList[32]; static int16 DummyResult; static int16 DummyResult2; +//--MIAMI: done bool CPathFind::TestCoorsCloseness(CVector target, uint8 type, CVector start) { @@ -1635,11 +2162,16 @@ 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) +#ifndef MIAMI return dist < 160.0f; +#else + return dist < 150.0f; +#endif else return dist < 100.0f; } +//--MIAMI: done void CPathFind::Save(uint8 *buf, uint32 *size) { @@ -1661,6 +2193,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 +2338,25 @@ CPathFind::DisplayPathData(void) } } } + +#ifdef MIAMI +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); +} +#endif diff --git a/src/control/PathFind.h b/src/control/PathFind.h index 8049ea52..d2799f87 100644 --- a/src/control/PathFind.h +++ b/src/control/PathFind.h @@ -55,6 +55,7 @@ public: struct CPathNode { +#ifndef MIAMI CVector pos; CPathNode *prev; CPathNode *next; @@ -80,6 +81,44 @@ struct CPathNode CPathNode *GetNext(void) { return next; } void SetPrev(CPathNode *node) { prev = node; } void SetNext(CPathNode *node) { next = node; } +#else + int16 prevIndex; + int16 nextIndex; + int16 x; + int16 y; + int16 z; + int16 distance; // in path search + int16 firstLink; + int8 width; + int8 group; + + uint8 numLinks : 4; + uint8 bDeadEnd : 1; + uint8 bDisabled : 1; + uint8 bBetweenLevels : 1; + uint8 bUseInRoadBlock : 1; + + uint8 bWaterPath : 1; + uint8 flagB2 : 1; // flag 2 in node info, always zero + 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); +#endif }; union CConnectionFlags @@ -93,6 +132,7 @@ union CConnectionFlags struct CCarPathLink { +#ifndef MIAMI CVector2D pos; CVector2D dir; int16 pathNodeIndex; @@ -109,6 +149,26 @@ struct CCarPathLink float GetY(void) { return pos.y; } float GetDirX(void) { return dir.x; } float GetDirY(void) { return dir.y; } +#else + int16 x; + int16 y; + int16 pathNodeIndex; + 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; } +#endif float OneWayLaneOffset() { @@ -123,6 +183,7 @@ struct CCarPathLink // This is what we're reading from the files, only temporary struct CPathInfoForObject { +#ifndef MIAMI int16 x; int16 y; int16 z; @@ -131,6 +192,28 @@ struct CPathInfoForObject int8 numLeftLanes; int8 numRightLanes; uint8 crossing : 1; +#else + float x; + float y; + float z; + int8 type; + int8 next; + int8 numLeftLanes; + int8 numRightLanes; + int8 speedLimit; + int8 width; + + uint8 crossing : 1; + uint8 flag02 : 1; // always zero + uint8 roadBlock : 1; + uint8 disabled : 1; + uint8 waterPath : 1; + uint8 betweenLevels : 1; + + uint8 spawnRate : 4; + + void SwapConnectionsToBeRightWayRound(void); +#endif }; extern CPathInfoForObject *InfoForTileCars; extern CPathInfoForObject *InfoForTilePeds; @@ -138,6 +221,7 @@ extern CPathInfoForObject *InfoForTilePeds; struct CTempNode { CVector pos; +#ifndef MIAMI float dirX; float dirY; int16 link1; @@ -145,12 +229,37 @@ struct CTempNode int8 numLeftLanes; int8 numRightLanes; int8 linkState; +#else + int8 dirX; // *100 + int8 dirY; + int16 link1; + int16 link2; + int8 numLeftLanes; + int8 numRightLanes; + int8 width; + bool isCross; + int8 linkState; +#endif }; +#ifdef MIAMI +struct CTempNodeExternal // made up name +{ + CVector pos; + int16 next; + int8 numLeftLanes; + int8 numRightLanes; + int8 width; + bool isCross; +}; +#endif + +#ifndef MIAMI struct CTempDetachedNode // unused { uint8 foo[20]; }; +#endif class CPathFind { @@ -158,10 +267,15 @@ public: CPathNode m_pathNodes[NUM_PATHNODES]; CCarPathLink m_carPathLinks[NUM_CARPATHLINKS]; CTreadable *m_mapObjects[NUM_MAPOBJECTS]; +#ifndef MIAMI uint8 m_objectFlags[NUM_MAPOBJECTS]; int16 m_connections[NUM_PATHCONNECTIONS]; int16 m_distances[NUM_PATHCONNECTIONS]; CConnectionFlags m_connectionFlags[NUM_PATHCONNECTIONS]; +#else + uint16 m_connections[NUM_PATHCONNECTIONS]; // and flags + uint8 m_distances[NUM_PATHCONNECTIONS]; +#endif int16 m_carPathConnections[NUM_PATHCONNECTIONS]; int32 m_numPathNodes; @@ -179,12 +293,20 @@ public: 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); +#ifndef MIAMI void CalcNodeCoors(int16 x, int16 y, int16 z, int32 id, CVector *out); +#else + void CalcNodeCoors(float x, float y, float z, int32 id, CVector *out); +#endif bool LoadPathFindData(void); void PreparePathData(void); void CountFloodFillGroups(uint8 type); void PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoForObject *objectpathinfo, +#ifndef MIAMI float maxdist, CTempDetachedNode *detachednodes, int32 numDetached); +#else + float maxdist, CPathInfoForObject *detachednodes, int32 numDetached); +#endif bool IsPathObject(int id) { return id < PATHNODESIZE && (InfoForTileCars[id*12].type != 0 || InfoForTilePeds[id*12].type != 0); } @@ -202,29 +324,56 @@ 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); +#ifndef MIAMI int32 FindNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bool ignoreDisabled = false, bool ignoreBetweenLevels = false); +#else +//--MIAMI: TODO: 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); +#endif 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); +#ifndef MIAMI CTreadable *FindRoadObjectClosestToCoors(CVector coors, uint8 type); +#endif 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); + +#ifdef MIAMI + 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; } +#else 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; } +#endif void DisplayPathData(void); }; +#ifndef MIAMI static_assert(sizeof(CPathFind) == 0x49bf4, "CPathFind: error"); +#endif extern CPathFind ThePaths; +#ifdef MIAMI +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); } +#endif + extern bool gbShowPedPaths; extern bool gbShowCarPaths; extern bool gbShowCarPathsLinks; diff --git a/src/control/Record.cpp b/src/control/Record.cpp index d086543f..6ae99e2c 100644 --- a/src/control/Record.cpp +++ b/src/control/Record.cpp @@ -417,8 +417,10 @@ void CRecordDataForChase::GiveUsACar(int32 mi, CVector pos, float angle, CAutomo *ppCar = pCar; } +//--MIAMI: unused void RemoveUnusedCollision(void) { +#ifndef MIAMI static const char* dontDeleteArray[] = { "rd_SrRoad2A50", "rd_SrRoad2A20", "rd_CrossRda1w22", "rd_CrossRda1rw22", "road_broadway02", "road_broadway01", "com_21way5", "com_21way50", @@ -430,6 +432,7 @@ void RemoveUnusedCollision(void) CModelInfo::RemoveColModelsFromOtherLevels(LEVEL_NONE); for (int i = 0; i < ARRAY_SIZE(dontDeleteArray); i++) CModelInfo::GetModelInfo(dontDeleteArray[i], nil)->GetColModel()->level = LEVEL_COMMERCIAL; +#endif } void CRecordDataForChase::StartChaseScene(float startTime) diff --git a/src/control/RoadBlocks.cpp b/src/control/RoadBlocks.cpp index 1c0d9f96..322cc1df 100644 --- a/src/control/RoadBlocks.cpp +++ b/src/control/RoadBlocks.cpp @@ -15,22 +15,40 @@ #include "CarCtrl.h" #include "General.h" +#ifndef MIAMI #define ROADBLOCKDIST (80.0f) +#else +#define ROADBLOCKDIST (90.0f) +#endif int16 CRoadBlocks::NumRoadBlocks; +#ifndef MIAMI int16 CRoadBlocks::RoadBlockObjects[NUMROADBLOCKS]; +#else +int16 CRoadBlocks::RoadBlockNodes[NUMROADBLOCKS]; +#endif bool CRoadBlocks::InOrOut[NUMROADBLOCKS]; +//--MIAMI: TODO: script roadblocks void CRoadBlocks::Init(void) { int i; NumRoadBlocks = 0; +#ifndef MIAMI for (i = 0; i < ThePaths.m_numMapObjects; i++) { if (ThePaths.m_objectFlags[i] & UseInRoadBlock) { +#else + for(i = 0; i < ThePaths.m_numCarPathNodes; i++){ + if(ThePaths.m_pathNodes[i].bUseInRoadBlock && ThePaths.m_pathNodes[i].numLinks == 2){ +#endif if (NumRoadBlocks < NUMROADBLOCKS) { InOrOut[NumRoadBlocks] = true; +#ifndef MIAMI RoadBlockObjects[NumRoadBlocks] = i; +#else + RoadBlockNodes[NumRoadBlocks] = i; +#endif NumRoadBlocks++; } else { #ifndef MASTER @@ -110,14 +128,19 @@ CRoadBlocks::GenerateRoadBlocks(void) int16 nRoadblockNode = (int16)(NUMROADBLOCKS * frame) / 16; const int16 maxRoadBlocks = (int16)(NUMROADBLOCKS * (frame + 1)) / 16; for (; nRoadblockNode < Min(NumRoadBlocks, maxRoadBlocks); nRoadblockNode++) { +#ifndef MIAMI CTreadable *mapObject = ThePaths.m_mapObjects[RoadBlockObjects[nRoadblockNode]]; CVector2D vecDistance = FindPlayerCoors() - mapObject->GetPosition(); +#else + CVector2D vecDistance = FindPlayerCoors() - ThePaths.m_pathNodes[nRoadblockNode].GetPosition(); +#endif 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 +210,13 @@ CRoadBlocks::GenerateRoadBlocks(void) } } } +#endif } } } else { InOrOut[nRoadblockNode] = false; } } + +//--MIAMI: TODO 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/Script.h b/src/control/Script.h index 01cad269..12a507c1 100644 --- a/src/control/Script.h +++ b/src/control/Script.h @@ -372,6 +372,9 @@ private: friend class CRunningScript; friend class CHud; friend void CMissionCleanup::Process(); +#ifdef MIAMI + friend class CColStore; +#endif }; diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp index 9b178f35..30f4287b 100644 --- a/src/core/Camera.cpp +++ b/src/core/Camera.cpp @@ -930,11 +930,13 @@ CCamera::CamControl(void) if(CCullZones::CamStairsForPlayer() && CCullZones::FindZoneWithStairsAttributeForPlayer()) stairs = true; // Some hack for Mr Whoopee in a bomb shop +#ifndef MIAMI // uhh, check this if(Cams[ActiveCam].Using3rdPersonMouseCam() && CCollision::ms_collisionInMemory == LEVEL_COMMERCIAL){ if(pTargetEntity->GetPosition().x < 83.0f && pTargetEntity->GetPosition().x > 18.0f && pTargetEntity->GetPosition().y < -305.0f && pTargetEntity->GetPosition().y > -390.0f) disableGarageCam = true; } +#endif if(!disableGarageCam && (CGarages::IsPointInAGarageCameraZone(pTargetEntity->GetPosition()) || stairs)){ if(!m_bGarageFixedCamPositionSet && m_bLookingAtPlayer){ if(pToGarageWeAreIn || stairs){ diff --git a/src/core/ColStore.cpp b/src/core/ColStore.cpp new file mode 100644 index 00000000..0c3356c5 --- /dev/null +++ b/src/core/ColStore.cpp @@ -0,0 +1,231 @@ +#include "common.h" +#ifdef MIAMI + +#include "templates.h" +#include "General.h" +#include "ModelInfo.h" +#include "Streaming.h" +#include "FileLoader.h" +#include "Script.h" +#include "Timer.h" +#include "Camera.h" +#include "Frontend.h" +#include "ColStore.h" + +CPool<ColDef,ColDef> *CColStore::ms_pColPool; + +void +CColStore::Initialise(void) +{ + if(ms_pColPool == nil) + ms_pColPool = new CPool<ColDef,ColDef>(COLSTORESIZE, "CollisionFiles"); + AddColSlot("generic"); // slot 0. not streamed +} + +void +CColStore::Shutdown(void) +{ + int i; + for(i = 0; i < COLSTORESIZE; i++) + RemoveColSlot(i); + if(ms_pColPool) + delete ms_pColPool; + ms_pColPool = nil; +} + +int +CColStore::AddColSlot(const char *name) +{ + ColDef *def = ms_pColPool->New(); + assert(def); + def->isLoaded = false; + def->a = 0; + def->bounds.left = 1000000.0f; + def->bounds.top = 1000000.0f; + def->bounds.right = -1000000.0f; + def->bounds.bottom = -1000000.0f; + def->minIndex = INT16_MAX; + def->maxIndex = INT16_MIN; + strcpy(def->name, name); + return ms_pColPool->GetJustIndex(def); +} + +void +CColStore::RemoveColSlot(int slot) +{ + if(GetSlot(slot)){ + if(GetSlot(slot)->isLoaded) + RemoveCol(slot); + ms_pColPool->Delete(GetSlot(slot)); + } +} + +int +CColStore::FindColSlot(const char *name) +{ + ColDef *def; + int size = ms_pColPool->GetSize(); + for(int i = 0; i < size; i++){ + def = GetSlot(i); + if(def && !CGeneral::faststricmp(def->name, name)) + return i; + } + return -1; +} + +char* +CColStore::GetColName(int32 slot) +{ + return GetSlot(slot)->name; +} + +CRect& +CColStore::GetBoundingBox(int32 slot) +{ + return GetSlot(slot)->bounds; +} + +void +CColStore::IncludeModelIndex(int32 slot, int32 modelIndex) +{ + ColDef *def = GetSlot(slot); + if(modelIndex < def->minIndex) + def->minIndex = modelIndex; + if(modelIndex > def->maxIndex) + def->maxIndex = modelIndex; +} + +bool +CColStore::LoadCol(int32 slot, uint8 *buffer, int32 bufsize) +{ + bool success; + ColDef *def = GetSlot(slot); + if(def->minIndex > def->maxIndex) + success = CFileLoader::LoadCollisionFileFirstTime(buffer, bufsize, slot); + else + success = CFileLoader::LoadCollisionFile(buffer, bufsize, slot); + if(success) + def->isLoaded = true; + else + debug("Failed to load Collision\n"); + return success; +} + +void +CColStore::RemoveCol(int32 slot) +{ + int id; + GetSlot(slot)->isLoaded = false; + for(id = 0; id < MODELINFOSIZE; id++){ + CBaseModelInfo *mi = CModelInfo::GetModelInfo(id); + if(mi){ + CColModel *col = mi->GetColModel(); + if(col && col->level == slot) + col->RemoveCollisionVolumes(); + } + } +} + +void +CColStore::LoadAllCollision(void) +{ + int i; + for(i = 1; i < COLSTORESIZE; i++) + if(GetSlot(i)) + CStreaming::RequestCol(i, 0); + CStreaming::LoadAllRequestedModels(false); +} + +void +CColStore::RemoveAllCollision(void) +{ + int i; + for(i = 1; i < COLSTORESIZE; i++) + if(GetSlot(i)) + if(CStreaming::CanRemoveCol(i)) + CStreaming::RemoveCol(i); +} + +static bool bLoadAtSecondPosition; +static CVector2D secondPosition; + +void +CColStore::AddCollisionNeededAtPosn(const CVector2D &pos) +{ + bLoadAtSecondPosition = true; + secondPosition = pos; +} + +void +CColStore::LoadCollision(const CVector2D &pos) +{ + int i; + + if(CStreaming::ms_disableStreaming) + return; + + for(i = 1; i < COLSTORESIZE; i++){ + if(GetSlot(i) == nil) + continue; + + bool wantThisOne = false; + + if(GetBoundingBox(i).IsPointInside(pos) || + bLoadAtSecondPosition && GetBoundingBox(i).IsPointInside(secondPosition, -119.0f) || + CGeneral::faststrcmp(GetColName(i), "yacht") == 0){ + wantThisOne = true; + }else{ + // TODO: check mission cleanup list + } + + if(wantThisOne) + CStreaming::RequestCol(i, STREAMFLAGS_PRIORITY); + else + CStreaming::RemoveCol(i); + } + bLoadAtSecondPosition = false; +} + +void +CColStore::RequestCollision(const CVector2D &pos) +{ + int i; + + for(i = 1; i < COLSTORESIZE; i++) + if(GetSlot(i) && GetBoundingBox(i).IsPointInside(pos, -115.0f)) + CStreaming::RequestCol(i, STREAMFLAGS_PRIORITY); +} + +void +CColStore::EnsureCollisionIsInMemory(const CVector2D &pos) +{ + int i; + + if(CStreaming::ms_disableStreaming) + return; + + for(i = 1; i < COLSTORESIZE; i++) + if(GetSlot(i) && GetBoundingBox(i).IsPointInside(pos, -110.0f) && + !CStreaming::HasColLoaded(i)){ + CStreaming::RequestCol(i, 0); + if(TheCamera.GetScreenFadeStatus() == FADE_0) + FrontEndMenuManager.MessageScreen("LOADCOL", false); + CTimer::Suspend(); + CStreaming::LoadAllRequestedModels(false); + CTimer::Resume(); + } +} + +bool +CColStore::HasCollisionLoaded(const CVector2D &pos) +{ + int i; + + for(i = 1; i < COLSTORESIZE; i++) + if(GetSlot(i) && GetBoundingBox(i).IsPointInside(pos, -110.0f) && + !GetSlot(i)->isLoaded) + return false; + return true; +} + +#endif diff --git a/src/core/ColStore.h b/src/core/ColStore.h new file mode 100644 index 00000000..0d686ffd --- /dev/null +++ b/src/core/ColStore.h @@ -0,0 +1,43 @@ +#pragma once + +#include "templates.h" + +struct ColDef { // made up name + int32 a; + bool isLoaded; + CRect bounds; + char name[20]; + int16 minIndex; + int16 maxIndex; +}; + +class CColStore +{ + static CPool<ColDef,ColDef> *ms_pColPool; + +public: + static void Initialise(void); + static void Shutdown(void); + static int AddColSlot(const char *name); + static void RemoveColSlot(int32 slot); + static int FindColSlot(const char *name); + static char *GetColName(int32 slot); + static CRect &GetBoundingBox(int32 slot); + static void IncludeModelIndex(int32 slot, int32 modelIndex); + static bool LoadCol(int32 storeID, uint8 *buffer, int32 bufsize); + static void RemoveCol(int32 slot); + static void AddCollisionNeededAtPosn(const CVector2D &pos); + static void LoadAllCollision(void); + static void RemoveAllCollision(void); + static void LoadCollision(const CVector2D &pos); + static void RequestCollision(const CVector2D &pos); + static void EnsureCollisionIsInMemory(const CVector2D &pos); + static bool HasCollisionLoaded(const CVector2D &pos); + + static ColDef *GetSlot(int slot) { + assert(slot >= 0); + assert(ms_pColPool); + assert(slot < ms_pColPool->GetSize()); + return ms_pColPool->GetSlot(slot); + } +}; diff --git a/src/core/Collision.cpp b/src/core/Collision.cpp index 0cdacfdb..f20fee6d 100644 --- a/src/core/Collision.cpp +++ b/src/core/Collision.cpp @@ -20,6 +20,10 @@ #include "SurfaceTable.h" #include "Lines.h" #include "Collision.h" +#ifdef MIAMI +#include "Camera.h" +#include "ColStore.h" +#endif enum Direction { @@ -34,22 +38,32 @@ enum Direction eLevelName CCollision::ms_collisionInMemory; CLinkList<CColModel*> CCollision::ms_colModelCache; +//--MIAMI: done void CCollision::Init(void) { ms_colModelCache.Init(NUMCOLCACHELINKS); ms_collisionInMemory = LEVEL_NONE; +#ifdef MIAMI + CColStore::Initialise(); +#endif } +//--MIAMI: done void CCollision::Shutdown(void) { ms_colModelCache.Shutdown(); +#ifdef MIAMI + CColStore::Shutdown(); +#endif } +//--MIAMI: done void CCollision::Update(void) { +#ifndef MIAMI CVector playerCoors; playerCoors = FindPlayerCoors(); eLevelName level = CTheZones::m_CurrLevel; @@ -83,8 +97,10 @@ CCollision::Update(void) if(ms_collisionInMemory != CGame::currLevel) LoadCollisionWhenINeedIt(forceLevelChange); CStreaming::HaveAllBigBuildingsLoaded(CGame::currLevel); +#endif } +//--MIAMI: unused eLevelName GetCollisionInSectorList(CPtrList &list) { @@ -101,6 +117,7 @@ GetCollisionInSectorList(CPtrList &list) return LEVEL_NONE; } +//--MIAMI: unused // Get a level this sector is in based on collision models eLevelName GetCollisionInSector(CSector §) @@ -121,9 +138,11 @@ GetCollisionInSector(CSector §) return (eLevelName)level; } +//--MIAMI: done void CCollision::LoadCollisionWhenINeedIt(bool forceChange) { +#ifndef MIAMI eLevelName level, l; bool multipleLevels; CVector playerCoors; @@ -210,11 +229,14 @@ CCollision::LoadCollisionWhenINeedIt(bool forceChange) CTimer::Update(); DMAudio.SetEffectsFadeVol(127); } +#endif } +//--MIAMI: done void CCollision::SortOutCollisionAfterLoad(void) { +#ifndef MIAMI if(ms_collisionInMemory == CGame::currLevel) return; @@ -226,6 +248,10 @@ CCollision::SortOutCollisionAfterLoad(void) } ms_collisionInMemory = CGame::currLevel; CGame::TidyUpMemory(true, false); +#else + CColStore::LoadCollision(TheCamera.GetPosition()); + CStreaming::LoadAllRequestedModels(false); +#endif } void @@ -1974,7 +2000,11 @@ CColModel::CColModel(void) vertices = nil; triangles = nil; trianglePlanes = nil; +#ifndef MIAMI level = CGame::currLevel; +#else + level = 0; // generic col slot +#endif ownsCollisionVolumes = true; } diff --git a/src/core/Collision.h b/src/core/Collision.h index 895f012a..fc3c1647 100644 --- a/src/core/Collision.h +++ b/src/core/Collision.h @@ -93,7 +93,11 @@ struct CColModel int16 numLines; int16 numBoxes; int16 numTriangles; +#ifndef MIAMI int32 level; +#else + uint8 level; // colstore slot but probably same name +#endif bool ownsCollisionVolumes; CColSphere *spheres; CColLine *lines; diff --git a/src/core/FileLoader.cpp b/src/core/FileLoader.cpp index a2654369..ab09d72f 100644 --- a/src/core/FileLoader.cpp +++ b/src/core/FileLoader.cpp @@ -24,6 +24,10 @@ #include "ZoneCull.h" #include "CdStream.h" #include "FileLoader.h" +#ifdef MIAMI +#include "Streaming.h" +#include "ColStore.h" +#endif char CFileLoader::ms_line[256]; @@ -53,7 +57,9 @@ CFileLoader::LoadLevel(const char *filename) savedTxd = RwTexDictionaryGetCurrent(); objectsLoaded = false; +#ifndef MIAMI savedLevel = CGame::currLevel; +#endif if(savedTxd == nil){ savedTxd = RwTexDictionaryCreate(); RwTexDictionarySetCurrent(savedTxd); @@ -77,12 +83,17 @@ CFileLoader::LoadLevel(const char *filename) AddTexDictionaries(savedTxd, txd); RwTexDictionaryDestroy(txd); }else if(strncmp(line, "COLFILE", 7) == 0){ +#ifndef MIAMI int level; sscanf(line+8, "%d", &level); CGame::currLevel = (eLevelName)level; LoadingScreenLoadingFile(line+10); LoadCollisionFile(line+10); CGame::currLevel = savedLevel; +#else + LoadingScreenLoadingFile(line+10); + LoadCollisionFile(line+10, 0); +#endif }else if(strncmp(line, "MODELFILE", 9) == 0){ LoadingScreenLoadingFile(line + 10); LoadModelFile(line + 10); @@ -94,8 +105,16 @@ CFileLoader::LoadLevel(const char *filename) LoadObjectTypes(line + 4); }else if(strncmp(line, "IPL", 3) == 0){ if(!objectsLoaded){ +#ifndef MIAMI CModelInfo::ConstructMloClumps(); CObjectData::Initialise("DATA\\OBJECT.DAT"); +#else + LoadingScreenLoadingFile("Collision"); + CObjectData::Initialise("DATA\\OBJECT.DAT"); + CStreaming::Init(); + CColStore::LoadAllCollision(); + // TODO: anim indices +#endif objectsLoaded = true; } LoadingScreenLoadingFile(line + 4); @@ -112,8 +131,18 @@ CFileLoader::LoadLevel(const char *filename) CFileMgr::CloseFile(fd); RwTexDictionarySetCurrent(savedTxd); + +#ifdef MIAMI + int i; + for(i = 1; i < COLSTORESIZE; i++) + if(CColStore::GetSlot(i)) + CColStore::GetBoundingBox(i).Grow(120.0f); + CWorld::RepositionCertainDynamicObjects(); + CColStore::RemoveAllCollision(); +#endif } +#ifndef MIAMI void CFileLoader::LoadCollisionFromDatFile(int currlevel) { @@ -137,6 +166,7 @@ CFileLoader::LoadCollisionFromDatFile(int currlevel) CFileMgr::CloseFile(fd); } +#endif char* CFileLoader::LoadLine(int fd) @@ -178,8 +208,14 @@ struct ColHeader uint32 size; }; +//--MIAMI: done +#ifndef MIAMI void CFileLoader::LoadCollisionFile(const char *filename) +#else +void +CFileLoader::LoadCollisionFile(const char *filename, uint8 colSlot) +#endif { int fd; char modelname[24]; @@ -196,10 +232,17 @@ CFileLoader::LoadCollisionFile(const char *filename) mi = CModelInfo::GetModelInfo(modelname, nil); if(mi){ +#ifndef MIAMI if(mi->GetColModel()){ +#else + if(mi->GetColModel() && mi->DoesOwnColModel()){ +#endif LoadCollisionModel(work_buff+24, *mi->GetColModel(), modelname); }else{ CColModel *model = new CColModel; +#ifdef MIAMI + model->level = colSlot; +#endif LoadCollisionModel(work_buff+24, *model, modelname); mi->SetColModel(model, true); } @@ -211,6 +254,82 @@ CFileLoader::LoadCollisionFile(const char *filename) CFileMgr::CloseFile(fd); } +#ifdef MIAMI +bool +CFileLoader::LoadCollisionFileFirstTime(uint8 *buffer, uint32 size, uint8 colSlot) +{ + uint32 modelsize; + char modelname[24]; + CBaseModelInfo *mi; + ColHeader *header; + int modelIndex; + + while(size > 8){ + header = (ColHeader*)buffer; + modelsize = header->size; + if(strncmp(header->ident, "COLL", 4) != 0) + return size-8 < CDSTREAM_SECTOR_SIZE; + memcpy(modelname, buffer+8, 24); + memcpy(work_buff, buffer+32, modelsize-24); + size -= 32 + (modelsize-24); + buffer += 32 + (modelsize-24); + if(modelsize > 15*1024) + debug("colmodel %s is huge, size %d\n", modelname, modelsize); + + mi = CModelInfo::GetModelInfo(modelname, &modelIndex); + if(mi){ +if(modelIndex == 855) +modelIndex = modelIndex; + CColStore::IncludeModelIndex(colSlot, modelIndex); + CColModel *model = new CColModel; + model->level = colSlot; + LoadCollisionModel(work_buff, *model, modelname); + mi->SetColModel(model, true); + }else{ + debug("colmodel %s can't find a modelinfo\n", modelname); + } + } + return true; +} + +bool +CFileLoader::LoadCollisionFile(uint8 *buffer, uint32 size, uint8 colSlot) +{ + uint32 modelsize; + char modelname[24]; + CBaseModelInfo *mi; + ColHeader *header; + + while(size > 8){ + header = (ColHeader*)buffer; + modelsize = header->size; + if(strncmp(header->ident, "COLL", 4) != 0) + return size-8 < CDSTREAM_SECTOR_SIZE; + memcpy(modelname, buffer+8, 24); + memcpy(work_buff, buffer+32, modelsize-24); + size -= 32 + (modelsize-24); + buffer += 32 + (modelsize-24); + if(modelsize > 15*1024) + debug("colmodel %s is huge, size %d\n", modelname, modelsize); + + mi = CModelInfo::GetModelInfo(modelname, CColStore::GetSlot(colSlot)->minIndex, CColStore::GetSlot(colSlot)->maxIndex); + if(mi){ + if(mi->GetColModel()){ + LoadCollisionModel(work_buff, *mi->GetColModel(), modelname); + }else{ + CColModel *model = new CColModel; + model->level = colSlot; + LoadCollisionModel(work_buff, *model, modelname); + mi->SetColModel(model, true); + } + }else{ + debug("colmodel %s can't find a modelinfo\n", modelname); + } + } + return true; +} +#endif + void CFileLoader::LoadCollisionModel(uint8 *buf, CColModel &model, char *modelname) { @@ -1063,18 +1182,36 @@ CFileLoader::LoadObjectInstance(const char *line) CSimpleModelInfo *mi; RwMatrix *xform; CEntity *entity; +#ifdef MIAMI + float area; + + if(sscanf(line, "%d %s %f %f %f %f %f %f %f %f %f %f %f", + &id, name, &area, + &trans.x, &trans.y, &trans.z, + &scale.x, &scale.y, &scale.z, + &axis.x, &axis.y, &axis.z, &angle) != 13){ +#endif if(sscanf(line, "%d %s %f %f %f %f %f %f %f %f %f %f", &id, name, &trans.x, &trans.y, &trans.z, &scale.x, &scale.y, &scale.z, &axis.x, &axis.y, &axis.z, &angle) != 12) return; +#ifdef MIAMI + area = 0; + } +#endif mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(id); if(mi == nil) return; assert(mi->IsSimple()); +#ifdef MIAMI + if(!CStreaming::IsObjectInCdImage(id)) + debug("Not in cdimage %s\n", mi->GetName()); +#endif + angle = -RADTODEG(2.0f * acosf(angle)); xform = RwMatrixCreate(); RwMatrixRotate(xform, &axis, angle, rwCOMBINEREPLACE); @@ -1089,6 +1226,9 @@ CFileLoader::LoadObjectInstance(const char *line) entity->SetModelIndexNoCreate(id); entity->GetMatrix() = CMatrix(xform); entity->m_level = CTheZones::GetLevelFromPosition(entity->GetPosition()); +#ifdef MIAMI + entity->m_area = area; +#endif if(mi->IsSimple()){ if(mi->m_isBigBuilding) entity->SetupBigBuilding(); @@ -1098,14 +1238,28 @@ CFileLoader::LoadObjectInstance(const char *line) if(mi->GetLargestLodDistance() < 2.0f) entity->bIsVisible = false; CWorld::Add(entity); + +#ifdef MIAMI + CColModel *col = entity->GetColModel(); + if(col->numSpheres || col->numBoxes || col->numTriangles){ + if(col->level != 0) + CColStore::GetBoundingBox(col->level).ContainRect(entity->GetBoundRect()); + }else + entity->bUsesCollision = false; + // TODO: set some flag here if col min is below 6 +#endif }else{ entity = new CDummyObject; entity->SetModelIndexNoCreate(id); entity->GetMatrix() = CMatrix(xform); CWorld::Add(entity); +//--MIAMI: TODO if(IsGlass(entity->GetModelIndex())) entity->bIsVisible = false; entity->m_level = CTheZones::GetLevelFromPosition(entity->GetPosition()); +#ifdef MIAMI + entity->m_area = area; +#endif } RwMatrixDestroy(xform); diff --git a/src/core/FileLoader.h b/src/core/FileLoader.h index 87b8fe61..aa8dcdb8 100644 --- a/src/core/FileLoader.h +++ b/src/core/FileLoader.h @@ -8,7 +8,13 @@ public: static void LoadCollisionFromDatFile(int currlevel); static char *LoadLine(int fd); static RwTexDictionary *LoadTexDictionary(const char *filename); +#ifndef MIAMI static void LoadCollisionFile(const char *filename); +#else + static void LoadCollisionFile(const char *filename, uint8 colSlot = 0); + static bool LoadCollisionFileFirstTime(uint8 *buffer, uint32 size, uint8 colSlot); + static bool LoadCollisionFile(uint8 *buffer, uint32 size, uint8 colSlot); +#endif static void LoadCollisionModel(uint8 *buf, struct CColModel &model, char *name); static void LoadModelFile(const char *filename); static RpAtomic *FindRelatedModelInfoCB(RpAtomic *atomic, void *data); diff --git a/src/core/Frontend.h b/src/core/Frontend.h index 3286f275..c27e5239 100644 --- a/src/core/Frontend.h +++ b/src/core/Frontend.h @@ -624,6 +624,10 @@ public: void LoadAllTextures(); void LoadSettings(); void MessageScreen(const char *); +#ifdef MIAMI + //--MIAMI: TODO: implement the second argument + void MessageScreen(const char *str, bool) { MessageScreen(str); } +#endif void PickNewPlayerColour(); void PrintBriefs(); static void PrintErrorMessage(); diff --git a/src/core/Game.cpp b/src/core/Game.cpp index d0f412d8..96109e56 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -89,6 +89,9 @@ eLevelName CGame::currLevel; +#ifdef MIAMI +int32 CGame::currArea; +#endif bool CGame::bDemoMode = true; bool CGame::nastyGame = true; bool CGame::frenchGame; @@ -319,7 +322,9 @@ bool CGame::Initialise(const char* datFile) CDraw::SetFOV(120.0f); CDraw::ms_fLODDistance = 500.0f; LoadingScreen("Loading the Game", "Setup streaming", nil); +#ifndef MIAMI CStreaming::Init(); +#endif CStreaming::LoadInitialVehicles(); CStreaming::LoadInitialPeds(); CStreaming::RequestBigBuildings(LEVEL_NONE); @@ -367,8 +372,10 @@ bool CGame::Initialise(const char* datFile) CWaterCannons::Init(); CBridge::Init(); CGarages::Init(); +#ifndef MIAMI LoadingScreen("Loading the Game", "Position dynamic objects", nil); CWorld::RepositionCertainDynamicObjects(); +#endif LoadingScreen("Loading the Game", "Initialise vehicle paths", nil); CCullZones::ResolveVisibilities(); CTrain::InitTrains(); @@ -381,7 +388,9 @@ bool CGame::Initialise(const char* datFile) CTheScripts::Process(); TheCamera.Process(); LoadingScreen("Loading the Game", "Load scene", nil); +#ifndef MIAMI CModelInfo::RemoveColModelsFromOtherLevels(currLevel); +#endif CCollision::ms_collisionInMemory = currLevel; for (int i = 0; i < MAX_PADS; i++) CPad::GetPad(i)->Clear(true); @@ -519,7 +528,9 @@ void CGame::ReloadIPLs(void) CRoadBlocks::Init(); CCranes::InitCranes(); CGarages::Init(); +#ifndef MIAMI CWorld::RepositionCertainDynamicObjects(); +#endif CCullZones::ResolveVisibilities(); CRenderer::SortBIGBuildings(); CTimer::Update(); diff --git a/src/core/Game.h b/src/core/Game.h index 48f31abc..8db5adf5 100644 --- a/src/core/Game.h +++ b/src/core/Game.h @@ -12,6 +12,9 @@ class CGame { public: static eLevelName currLevel; +#ifdef MIAMI + static int32 currArea; +#endif static bool bDemoMode; static bool nastyGame; static bool frenchGame; diff --git a/src/core/PlayerInfo.h b/src/core/PlayerInfo.h index e970e42d..13266331 100644 --- a/src/core/PlayerInfo.h +++ b/src/core/PlayerInfo.h @@ -80,4 +80,6 @@ public: ~CPlayerInfo() { }; }; +#ifndef MIAMI static_assert(sizeof(CPlayerInfo) == 0x13C, "CPlayerInfo: error"); +#endif diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp index da9e7d33..daeda35d 100644 --- a/src/core/Streaming.cpp +++ b/src/core/Streaming.cpp @@ -32,6 +32,10 @@ #include "Replay.h" #endif #include "main.h" +#ifdef MIAMI +#include "ColStore.h" +#include "DMAudio.h" +#endif bool CStreaming::ms_disableStreaming; bool CStreaming::ms_bLoadingBigModel; @@ -53,7 +57,9 @@ int32 CStreaming::ms_vehiclesLoaded[MAXVEHICLESLOADED]; int32 CStreaming::ms_lastVehicleDeleted; CDirectory *CStreaming::ms_pExtraObjectsDir; int32 CStreaming::ms_numPriorityRequests; +#ifndef MIAMI bool CStreaming::ms_hasLoadedLODs; +#endif int32 CStreaming::ms_currentPedGrp; int32 CStreaming::ms_currentPedLoading; int32 CStreaming::ms_lastCullZone; @@ -184,7 +190,9 @@ CStreaming::Init2(void) ms_pExtraObjectsDir = new CDirectory(EXTRADIRSIZE); ms_numPriorityRequests = 0; +#ifndef MIAMI ms_hasLoadedLODs = true; +#endif ms_currentPedGrp = -1; ms_lastCullZone = -1; // unused because RemoveModelsNotVisibleFromCullzone is gone ms_loadedGangs = 0; @@ -231,6 +239,7 @@ CStreaming::Init2(void) CModelInfo::GetModelInfo("IslandLODsubIND", &islandLODsubInd); CModelInfo::GetModelInfo("IslandLODsubCOM", &islandLODsubCom); +#ifndef MIAMI for(i = CPools::GetBuildingPool()->GetSize()-1; i >= 0; i--){ CBuilding *building = CPools::GetBuildingPool()->GetSlot(i); if(building == nil) @@ -241,6 +250,7 @@ CStreaming::Init2(void) if(building->GetModelIndex() == islandLODsubInd) pIslandLODsubIndEntity = building; if(building->GetModelIndex() == islandLODsubCom) pIslandLODsubComEntity = building; } +#endif } void @@ -292,21 +302,35 @@ CStreaming::Update(void) if(CTimer::GetIsPaused()) return; +#ifndef MIAMI train = FindPlayerTrain(); if(train && train->GetPosition().z < 0.0f){ RequestSubway(); requestedSubway = true; }else if(!ms_disableStreaming) AddModelsToRequestList(TheCamera.GetPosition()); +#else + LoadBigBuildingsWhenNeeded(); + if(!ms_disableStreaming && TheCamera.GetPosition().z < 55.0f) + AddModelsToRequestList(TheCamera.GetPosition()); +#endif DeleteFarAwayRwObjects(TheCamera.GetPosition()); if(!ms_disableStreaming && +#ifndef MIAMI !CCutsceneMgr::IsRunning() && !requestedSubway && !CGame::playingIntro && +#else + !CCutsceneMgr::IsCutsceneProcessing() && +#endif ms_numModelsRequested < 5 && !CRenderer::m_loadingPriority +#ifdef MIAMI + && CGame::currArea == 0 + // replay is also MIAMI +#endif #ifdef FIX_BUGS && !CReplay::IsPlayingBack() #endif @@ -317,6 +341,16 @@ CStreaming::Update(void) LoadRequestedModels(); +#ifdef MIAMI + if(CWorld::Players[0].m_pRemoteVehicle){ + CColStore::AddCollisionNeededAtPosn(FindPlayerCoors()); + CColStore::LoadCollision(CWorld::Players[0].m_pRemoteVehicle->GetPosition()); + CColStore::EnsureCollisionIsInMemory(CWorld::Players[0].m_pRemoteVehicle->GetPosition()); + }else{ + CColStore::LoadCollision(FindPlayerCoors()); + CColStore::EnsureCollisionIsInMemory(FindPlayerCoors()); + } +#endif for(si = ms_endRequestedList.m_prev; si != &ms_startRequestedList; si = prev){ prev = si->m_prev; @@ -375,6 +409,7 @@ CStreaming::LoadCdDirectory(const char *dirname, int n) imgSelector = n<<24; assert(sizeof(direntry) == 32); while(CFileMgr::Read(fd, (char*)&direntry, sizeof(direntry))){ +#ifndef MIAMI dot = strchr(direntry.name, '.'); if(dot) *dot = '\0'; if(direntry.size > (uint32)ms_streamingBufferSize) @@ -417,6 +452,64 @@ CStreaming::LoadCdDirectory(const char *dirname, int n) } }else lastID = -1; +#else + bool bAddToStreaming = false; + + if(direntry.size > (uint32)ms_streamingBufferSize) + ms_streamingBufferSize = direntry.size; + direntry.name[23] = '\0'; + dot = strchr(direntry.name, '.'); + if(dot == nil || dot-direntry.name > 20){ + debug("%s is too long\n", direntry.name); + lastID = -1; + continue; + } + + *dot = '\0'; + + if(!CGeneral::faststricmp(dot+1, "DFF")){ + if(CModelInfo::GetModelInfo(direntry.name, &modelId)){ + bAddToStreaming = true; + }else{ +#ifdef FIX_BUGS + // remember which cdimage this came from + ms_pExtraObjectsDir->AddItem(direntry, n); +#else + ms_pExtraObjectsDir->AddItem(direntry); +#endif + lastID = -1; + } + }else if(!CGeneral::faststricmp(dot+1, "TXD")){ + modelId = CTxdStore::FindTxdSlot(direntry.name); + if(modelId == -1) + modelId = CTxdStore::AddTxdSlot(direntry.name); + modelId += STREAM_OFFSET_TXD; + bAddToStreaming = true; + }else if(!CGeneral::faststricmp(dot+1, "COL")){ + modelId = CColStore::FindColSlot(direntry.name); + if(modelId == -1) + modelId = CColStore::AddColSlot(direntry.name); + modelId += STREAM_OFFSET_COL; + bAddToStreaming = true; + // TODO: IFP + }else{ + *dot = '.'; + lastID = -1; + } + + if(bAddToStreaming){ + if(ms_aInfoForModel[modelId].GetCdSize()){ + debug("%s.%s appears more than once in %s\n", direntry.name, dot+1, dirname); + lastID = -1; + }else{ + direntry.offset |= imgSelector; + ms_aInfoForModel[modelId].SetCdPosnAndSize(direntry.offset, direntry.size); + if(lastID != -1) + ms_aInfoForModel[lastID].m_nextID = modelId; + lastID = modelId; + } + } +#endif } CFileMgr::CloseFile(fd); @@ -440,6 +533,7 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId) stream = RwStreamOpen(rwSTREAMMEMORY, rwSTREAMREAD, &mem); if(streamId < STREAM_OFFSET_TXD){ +//--MIAMI: also check animation // Model mi = CModelInfo::GetModelInfo(streamId); @@ -481,7 +575,11 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId) RwStreamClose(stream, &mem); return false; } +#ifndef MIAMI }else{ +#else + }else if(streamId >= STREAM_OFFSET_TXD && streamId < STREAM_OFFSET_COL){ +#endif // Txd assert(streamId < NUMSTREAMINFO); if((ms_aInfoForModel[streamId].m_flags & STREAMFLAGS_KEEP_IN_MEMORY) == 0 && @@ -506,10 +604,22 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId) RwStreamClose(stream, &mem); return false; } +#ifdef MIAMI + }else if(streamId >= STREAM_OFFSET_COL && streamId < NUMSTREAMINFO){ + if(!CColStore::LoadCol(streamId-STREAM_OFFSET_COL, mem.start, mem.length)){ + debug("Failed to load %s.col\n", CColStore::GetColName(streamId - STREAM_OFFSET_COL)); + RemoveModel(streamId); + ReRequestModel(streamId); + RwStreamClose(stream, &mem); + return false; + } + // TODO: IFPs +#endif } RwStreamClose(stream, &mem); +#ifndef MIAMI // We shouldn't even end up here unless load was successful if(!success){ ReRequestModel(streamId); @@ -519,6 +629,7 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId) debug("Failed to load %s.txd\n", CTxdStore::GetTxdName(streamId - STREAM_OFFSET_TXD)); return false; } +#endif if(streamId < STREAM_OFFSET_TXD){ // Model @@ -537,7 +648,11 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId) if((ms_aInfoForModel[streamId].m_flags & STREAMFLAGS_CANT_REMOVE) == 0) ms_aInfoForModel[streamId].AddToList(&ms_startLoadedList); } +#ifndef MIAMI }else{ +#else + }else if(streamId >= STREAM_OFFSET_TXD && streamId < STREAM_OFFSET_COL){ // TODO: animations +#endif // Txd if((ms_aInfoForModel[streamId].m_flags & STREAMFLAGS_CANT_REMOVE) == 0) ms_aInfoForModel[streamId].AddToList(&ms_startLoadedList); @@ -552,10 +667,23 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId) endTime = CTimer::GetCurrentTimeInCycles() / CTimer::GetCyclesPerMillisecond(); timeDiff = endTime - startTime; if(timeDiff > 5){ +#ifndef MIAMI if(streamId < STREAM_OFFSET_TXD) debug("model %s took %d ms\n", CModelInfo::GetModelInfo(streamId)->GetName(), timeDiff); else debug("txd %s took %d ms\n", CTxdStore::GetTxdName(streamId - STREAM_OFFSET_TXD), timeDiff); +#else + // TODO: is this inlined? + static char objname[32]; + if(streamId < STREAM_OFFSET_TXD) + sprintf(objname, "%s.dff", CModelInfo::GetModelInfo(streamId)->GetName()); + else if(streamId >= STREAM_OFFSET_TXD && streamId < STREAM_OFFSET_COL) + sprintf(objname, "%s.txd", CTxdStore::GetTxdName(streamId-STREAM_OFFSET_TXD)); + else if(streamId >= STREAM_OFFSET_COL && streamId < NUMSTREAMINFO) + sprintf(objname, "%s.col", CColStore::GetColName(streamId-STREAM_OFFSET_COL)); + // TODO: IFP + debug("%s took %d ms\n", objname, timeDiff); +#endif } return true; @@ -713,7 +841,11 @@ CStreaming::RequestSubway(void) } } +#ifndef MIAMI #define BIGBUILDINGFLAGS STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_PRIORITY +#else +#define BIGBUILDINGFLAGS STREAMFLAGS_DONT_REMOVE +#endif void CStreaming::RequestBigBuildings(eLevelName level) @@ -725,12 +857,54 @@ CStreaming::RequestBigBuildings(eLevelName level) for(i = n; i >= 0; i--){ b = CPools::GetBuildingPool()->GetSlot(i); if(b && b->bIsBIGBuilding && b->m_level == level) +#ifdef MIAMI + if(!b->bStreamBIGBuilding) +#endif RequestModel(b->GetModelIndex(), BIGBUILDINGFLAGS); } RequestIslands(level); +#ifndef MIAMI ms_hasLoadedLODs = false; +#endif } +#ifdef MIAMI +void +CStreaming::RequestBigBuildings(eLevelName level, const CVector &pos) +{ + int i, n; + CBuilding *b; + + n = CPools::GetBuildingPool()->GetSize()-1; + for(i = n; i >= 0; i--){ + b = CPools::GetBuildingPool()->GetSlot(i); + if(b && b->bIsBIGBuilding && b->m_level == level) + if(b->bStreamBIGBuilding){ + if(CRenderer::ShouldModelBeStreamed(b)) + RequestModel(b->GetModelIndex(), 0); + }else + RequestModel(b->GetModelIndex(), BIGBUILDINGFLAGS); + } + RequestIslands(level); +} + +void +CStreaming::InstanceBigBuildings(eLevelName level, const CVector &pos) +{ + int i, n; + CBuilding *b; + + n = CPools::GetBuildingPool()->GetSize()-1; + for(i = n; i >= 0; i--){ + b = CPools::GetBuildingPool()->GetSlot(i); + if(b && b->bIsBIGBuilding && b->m_level == level && + b->bStreamBIGBuilding && b->m_rwObject == nil) + if(CRenderer::ShouldModelBeStreamed(b)) + b->CreateRwObject(); + } +} +#endif + void CStreaming::RequestIslands(eLevelName level) { @@ -828,10 +1002,20 @@ CStreaming::RemoveModel(int32 id) return; if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_LOADED){ +#ifndef MIAMI if(id < STREAM_OFFSET_TXD) CModelInfo::GetModelInfo(id)->DeleteRwObject(); else CTxdStore::RemoveTxd(id - STREAM_OFFSET_TXD); +#else + if(id < STREAM_OFFSET_TXD) + CModelInfo::GetModelInfo(id)->DeleteRwObject(); + else if(id >= STREAM_OFFSET_TXD && id < STREAM_OFFSET_COL) + CTxdStore::RemoveTxd(id - STREAM_OFFSET_TXD); + else if(id >= STREAM_OFFSET_COL && id < NUMSTREAMINFO) + CColStore::RemoveCol(id - STREAM_OFFSET_COL); + // TODO: IFP +#endif ms_memoryUsed -= ms_aInfoForModel[id].GetCdSize()*CDSTREAM_SECTOR_SIZE; } @@ -850,15 +1034,26 @@ CStreaming::RemoveModel(int32 id) } if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_STARTED){ +#ifndef MIAMI if(id < STREAM_OFFSET_TXD) RpClumpGtaCancelStream(); else CTxdStore::RemoveTxd(id - STREAM_OFFSET_TXD); +#else + if(id < STREAM_OFFSET_TXD) + RpClumpGtaCancelStream(); + else if(id >= STREAM_OFFSET_TXD && id < STREAM_OFFSET_COL) + CTxdStore::RemoveTxd(id - STREAM_OFFSET_TXD); + else if(id >= STREAM_OFFSET_COL && id < NUMSTREAMINFO) + CColStore::RemoveCol(id - STREAM_OFFSET_COL); + // TODO: IFP +#endif } ms_aInfoForModel[id].m_loadState = STREAMSTATE_NOTLOADED; } +//--MIAMI: change islands void CStreaming::RemoveUnusedBuildings(eLevelName level) { @@ -870,6 +1065,7 @@ CStreaming::RemoveUnusedBuildings(eLevelName level) RemoveBuildings(LEVEL_SUBURBAN); } +//--MIAMI: done void CStreaming::RemoveBuildings(eLevelName level) { @@ -930,6 +1126,7 @@ CStreaming::RemoveBuildings(eLevelName level) } } +//--MIAMI: change islands void CStreaming::RemoveUnusedBigBuildings(eLevelName level) { @@ -958,6 +1155,21 @@ DeleteIsland(CEntity *island) void CStreaming::RemoveIslandsNotUsed(eLevelName level) { +#ifdef MIAMI + int i; + if(pIslandLODindustEntity == nil) + for(i = CPools::GetBuildingPool()->GetSize()-1; i >= 0; i--){ + CBuilding *building = CPools::GetBuildingPool()->GetSlot(i); + if(building == nil) + continue; + if(building->GetModelIndex() == islandLODindust) pIslandLODindustEntity = building; + if(building->GetModelIndex() == islandLODcomInd) pIslandLODcomIndEntity = building; + if(building->GetModelIndex() == islandLODcomSub) pIslandLODcomSubEntity = building; + if(building->GetModelIndex() == islandLODsubInd) pIslandLODsubIndEntity = building; + if(building->GetModelIndex() == islandLODsubCom) pIslandLODsubComEntity = building; + } +#endif + switch(level){ case LEVEL_INDUSTRIAL: DeleteIsland(pIslandLODindustEntity); @@ -984,6 +1196,7 @@ CStreaming::RemoveIslandsNotUsed(eLevelName level) } } +//--MIAMI: done void CStreaming::RemoveBigBuildings(eLevelName level) { @@ -1187,6 +1400,7 @@ CStreaming::IsObjectInCdImage(int32 id) return ms_aInfoForModel[id].GetCdPosnAndSize(posn, size); } +#ifndef MIAMI void CStreaming::HaveAllBigBuildingsLoaded(eLevelName level) { @@ -1221,6 +1435,7 @@ CStreaming::HaveAllBigBuildingsLoaded(eLevelName level) RemoveUnusedBigBuildings(level); ms_hasLoadedLODs = true; } +#endif void CStreaming::SetModelIsDeletable(int32 id) @@ -1454,6 +1669,44 @@ CStreaming::RemoveCurrentZonesModels(void) ms_loadedGangCars = 0; } +#ifdef MIAMI +void +CStreaming::LoadBigBuildingsWhenNeeded(void) +{ + // Very much like CCollision::Update and CCollision::LoadCollisionWhenINeedIt + if(CCutsceneMgr::IsCutsceneProcessing()) + return; + + if(CTheZones::m_CurrLevel == LEVEL_NONE || + CTheZones::m_CurrLevel == CGame::currLevel) + return; + + CTimer::Suspend(); + CGame::currLevel = CTheZones::m_CurrLevel; + DMAudio.SetEffectsFadeVol(0); + CPad::StopPadsShaking(); + CCollision::LoadCollisionScreen(CGame::currLevel); + DMAudio.Service(); + + // CPopulation::DealWithZoneChange is unused in VC + RemoveUnusedBigBuildings(CGame::currLevel); + RemoveUnusedBuildings(CGame::currLevel); + RemoveUnusedModelsInLoadedList(); + CGame::TidyUpMemory(true, true); + + CReplay::EmptyReplayBuffer(); + if(CGame::currLevel != LEVEL_NONE) + LoadSplash(GetLevelSplashScreen(CGame::currLevel)); + + CStreaming::RequestBigBuildings(CGame::currLevel, TheCamera.GetPosition()); + CStreaming::LoadAllRequestedModels(true); + + CGame::TidyUpMemory(true, true); + CTimer::Resume(); + DMAudio.SetEffectsFadeVol(127); +} +#endif + // Find starting offset of the cdimage we next want to read // Not useful at all on PC... @@ -2432,11 +2685,33 @@ CStreaming::LoadScene(const CVector &pos) CRenderer::m_loadingPriority = false; CCullZones::ForceCullZoneCoors(pos); DeleteAllRwObjects(); +#ifndef MIAMI AddModelsToRequestList(pos); CRadar::StreamRadarSections(pos); RemoveUnusedBigBuildings(level); RequestBigBuildings(level); LoadAllRequestedModels(false); +#else + if(level == LEVEL_NONE) + level = CGame::currLevel; + CGame::currLevel = level; + RemoveUnusedBigBuildings(level); + RequestBigBuildings(level, pos); + RequestBigBuildings(LEVEL_NONE, pos); + RemoveIslandsNotUsed(level); + LoadAllRequestedModels(false); + InstanceBigBuildings(level, pos); + InstanceBigBuildings(LEVEL_NONE, pos); + AddModelsToRequestList(pos); + CRadar::StreamRadarSections(pos); + + // TODO: stream zone vehicles + LoadAllRequestedModels(false); + // TODO: InstanceLoadedModels + + for(int i = 0; i < NUMSTREAMINFO; i++) + ms_aInfoForModel[i].m_flags &= ~STREAMFLAGS_20; +#endif debug("End load scene\n"); } diff --git a/src/core/Streaming.h b/src/core/Streaming.h index 84434769..d2920824 100644 --- a/src/core/Streaming.h +++ b/src/core/Streaming.h @@ -4,7 +4,12 @@ enum { STREAM_OFFSET_TXD = MODELINFOSIZE, +#ifndef MIAMI NUMSTREAMINFO = STREAM_OFFSET_TXD+TXDSTORESIZE +#else + STREAM_OFFSET_COL = STREAM_OFFSET_TXD+TXDSTORESIZE, + NUMSTREAMINFO = STREAM_OFFSET_COL+COLSTORESIZE +#endif }; enum StreamFlags @@ -14,6 +19,9 @@ enum StreamFlags STREAMFLAGS_DEPENDENCY = 0x04, // Is this right? STREAMFLAGS_PRIORITY = 0x08, STREAMFLAGS_NOFADE = 0x10, +#ifdef MIAMI + STREAMFLAGS_20 = 0x20, +#endif STREAMFLAGS_CANT_REMOVE = STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_SCRIPTOWNED, STREAMFLAGS_KEEP_IN_MEMORY = STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_SCRIPTOWNED|STREAMFLAGS_DEPENDENCY, @@ -94,7 +102,9 @@ public: static int32 ms_lastVehicleDeleted; static CDirectory *ms_pExtraObjectsDir; static int32 ms_numPriorityRequests; +#ifndef MIAMI static bool ms_hasLoadedLODs; +#endif static int32 ms_currentPedGrp; static int32 ms_lastCullZone; static uint16 ms_loadedGangs; @@ -115,14 +125,28 @@ public: static bool FinishLoadingLargeFile(int8 *buf, int32 streamId); static bool HasModelLoaded(int32 id) { return ms_aInfoForModel[id].m_loadState == STREAMSTATE_LOADED; } static bool HasTxdLoaded(int32 id) { return HasModelLoaded(id+STREAM_OFFSET_TXD); } +#ifdef MIAMI + static bool HasColLoaded(int32 id) { return HasModelLoaded(id+STREAM_OFFSET_COL); } +#endif static bool CanRemoveModel(int32 id) { return (ms_aInfoForModel[id].m_flags & STREAMFLAGS_CANT_REMOVE) == 0; } static bool CanRemoveTxd(int32 id) { return CanRemoveModel(id+STREAM_OFFSET_TXD); } +#ifdef MIAMI + static bool CanRemoveCol(int32 id) { return CanRemoveModel(id+STREAM_OFFSET_COL); } +#endif static void RequestModel(int32 model, int32 flags); static void ReRequestModel(int32 model) { RequestModel(model, ms_aInfoForModel[model].m_flags); } static void RequestTxd(int32 txd, int32 flags) { RequestModel(txd + STREAM_OFFSET_TXD, flags); } static void ReRequestTxd(int32 txd) { ReRequestModel(txd + STREAM_OFFSET_TXD); } +#ifdef MIAMI + static void RequestCol(int32 col, int32 flags) { RequestModel(col + STREAM_OFFSET_COL, flags); } + static void ReRequestCol(int32 col) { ReRequestModel(col + STREAM_OFFSET_COL); } +#endif static void RequestSubway(void); static void RequestBigBuildings(eLevelName level); +#ifdef MIAMI + static void RequestBigBuildings(eLevelName level, const CVector &pos); + static void InstanceBigBuildings(eLevelName level, const CVector &pos); +#endif static void RequestIslands(eLevelName level); static void RequestSpecialModel(int32 modelId, const char *modelName, int32 flags); static void RequestSpecialChar(int32 charId, const char *modelName, int32 flags); @@ -131,6 +155,9 @@ public: static void DecrementRef(int32 id); static void RemoveModel(int32 id); static void RemoveTxd(int32 id) { RemoveModel(id + STREAM_OFFSET_TXD); } +#ifdef MIAMI + static void RemoveCol(int32 id) { RemoveModel(id + STREAM_OFFSET_COL); } +#endif static void RemoveUnusedBuildings(eLevelName level); static void RemoveBuildings(eLevelName level); static void RemoveUnusedBigBuildings(eLevelName level); @@ -145,7 +172,9 @@ public: static bool IsTxdUsedByRequestedModels(int32 txdId); static bool AddToLoadedVehiclesList(int32 modelId); static bool IsObjectInCdImage(int32 id); +#ifndef MIAMI static void HaveAllBigBuildingsLoaded(eLevelName level); +#endif static void SetModelIsDeletable(int32 id); static void SetModelTxdIsDeletable(int32 id); static void SetMissionDoesntRequireModel(int32 id); @@ -154,6 +183,9 @@ public: static void StreamVehiclesAndPeds(void); static void StreamZoneModels(const CVector &pos); static void RemoveCurrentZonesModels(void); +#ifdef MIAMI + static void LoadBigBuildingsWhenNeeded(void); +#endif static int32 GetCdImageOffset(int32 lastPosn); static int32 GetNextFileOnCd(int32 position, bool priority); diff --git a/src/core/ZoneCull.h b/src/core/ZoneCull.h index 9bc07b8c..e0a905e4 100644 --- a/src/core/ZoneCull.h +++ b/src/core/ZoneCull.h @@ -122,4 +122,7 @@ public: static bool DoWeHaveMoreThanXOccurencesOfSet(int32 count, uint16 *set); static void CompressIndicesArray() {};// todo + + //--MIAMI: TODO + static bool PoliceAbandonCars(void) { return false; } }; diff --git a/src/core/config.h b/src/core/config.h index 7c1fab5b..c0597db2 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -7,8 +7,14 @@ enum Config { MAX_CDIMAGES = 8, // additional cdimages MAX_CDCHANNELS = 5, +#ifndef MIAMI MODELINFOSIZE = 5500, TXDSTORESIZE = 850, +#else + MODELINFOSIZE = 6500, + TXDSTORESIZE = 1385, + COLSTORESIZE = 31, +#endif EXTRADIRSIZE = 128, CUTSCENEDIRSIZE = 512, @@ -41,10 +47,17 @@ enum Config { NUMTEMPOBJECTS = 30, // Path data +#ifndef MIAMI NUM_PATHNODES = 4930, NUM_CARPATHLINKS = 2076, NUM_MAPOBJECTS = 1250, NUM_PATHCONNECTIONS = 10260, +#else + NUM_PATHNODES = 9650, + NUM_CARPATHLINKS = 3500, + NUM_MAPOBJECTS = 1250, + NUM_PATHCONNECTIONS = 20400, +#endif // Link list lengths NUMALPHALIST = 20, @@ -110,7 +123,11 @@ enum Config { NUMMODELSPERPEDGROUP = 8, NUMSHOTINFOS = 100, +#ifndef MIAMI NUMROADBLOCKS = 600, +#else + NUMROADBLOCKS = 300, +#endif NUMVISIBLEENTITIES = 2000, NUMINVISIBLEENTITIES = 150, diff --git a/src/core/templates.h b/src/core/templates.h index 921b109a..74bc4713 100644 --- a/src/core/templates.h +++ b/src/core/templates.h @@ -39,13 +39,20 @@ public: m_entries = (U*)malloc(sizeof(U)*size); m_flags = (Flags*)malloc(sizeof(Flags)*size); m_size = size; +#ifndef MIAMI m_allocPtr = 0; +#else + m_allocPtr = -1; +#endif for(int i = 0; i < size; i++){ m_flags[i].id = 0; m_flags[i].free = 1; } } - +#ifdef MIAMI + CPool(int size, const char *name) + : CPool(size) {} +#endif ~CPool() { Flush(); } diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp index e2b91552..1f85015e 100644 --- a/src/entities/Entity.cpp +++ b/src/entities/Entity.cpp @@ -52,6 +52,9 @@ CEntity::CEntity(void) bRenderScorched = false; bHasBlip = false; bIsBIGBuilding = false; +#ifdef MIAMI + bStreamBIGBuilding = false; +#endif bRenderDamaged = false; bBulletProof = false; @@ -332,6 +335,11 @@ CEntity::SetupBigBuilding(void) bStreamingDontDelete = true; bUsesCollision = false; m_level = CTheZones::GetLevelFromPosition(GetPosition()); +#ifdef MIAMI + if(mi->m_lodDistances[0] <= 2000.0f) + bStreamBIGBuilding = true; + // TODO: the stuff down there isn't right yet +#endif if(m_level == LEVEL_NONE){ if(mi->GetTxdSlot() != CTxdStore::FindTxdSlot("generic")){ mi->SetTexDictionary("generic"); diff --git a/src/entities/Entity.h b/src/entities/Entity.h index 7b1d4c07..ffafa705 100644 --- a/src/entities/Entity.h +++ b/src/entities/Entity.h @@ -59,6 +59,9 @@ public: uint32 bRenderScorched : 1; uint32 bHasBlip : 1; uint32 bIsBIGBuilding : 1; // Set if this entity is a big building +#ifdef MIAMI + uint32 bStreamBIGBuilding : 1; // set when draw dist <= 2000 +#endif uint32 bRenderDamaged : 1; // use damaged LOD models for objects with applicable damage // flagsC @@ -88,7 +91,12 @@ public: uint16 m_scanCode; uint16 m_randomSeed; int16 m_modelIndex; +#ifndef MIAMI uint16 m_level; // int16 +#else + int8 m_level; + int8 m_area; +#endif CReference *m_pFirstReference; public: diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp index dd49ea3e..a61aaa78 100644 --- a/src/entities/Physical.cpp +++ b/src/entities/Physical.cpp @@ -267,6 +267,7 @@ void CPhysical::AddCollisionRecord_Treadable(CEntity *ent) { if(ent->IsBuilding() && ((CBuilding*)ent)->GetIsATreadable()){ +#ifndef MIAMI CTreadable *t = (CTreadable*)ent; if(t->m_nodeIndices[PATH_PED][0] >= 0 || t->m_nodeIndices[PATH_PED][1] >= 0 || @@ -278,6 +279,7 @@ CPhysical::AddCollisionRecord_Treadable(CEntity *ent) t->m_nodeIndices[PATH_CAR][2] >= 0 || t->m_nodeIndices[PATH_CAR][3] >= 0) m_treadable[PATH_CAR] = t; +#endif } } diff --git a/src/entities/Treadable.h b/src/entities/Treadable.h index 9e4de59a..78f69c8a 100644 --- a/src/entities/Treadable.h +++ b/src/entities/Treadable.h @@ -8,8 +8,12 @@ public: static void *operator new(size_t); static void operator delete(void*, size_t); +#ifndef MIAMI int16 m_nodeIndices[2][12]; // first car, then ped +#endif bool GetIsATreadable(void) { return true; } }; +#ifndef MIAMI static_assert(sizeof(CTreadable) == 0x94, "CTreadable: error"); +#endif diff --git a/src/modelinfo/ModelInfo.cpp b/src/modelinfo/ModelInfo.cpp index da09bdfa..62deae2b 100644 --- a/src/modelinfo/ModelInfo.cpp +++ b/src/modelinfo/ModelInfo.cpp @@ -200,6 +200,20 @@ CModelInfo::GetModelInfo(const char *name, int *id) return nil; } +#ifdef MIAMI +CBaseModelInfo* +CModelInfo::GetModelInfo(const char *name, int minIndex, int maxIndex) +{ + CBaseModelInfo *modelinfo; + for(int i = minIndex; i <= maxIndex; i++){ + modelinfo = CModelInfo::ms_modelInfoPtrs[i]; + if(modelinfo && !CGeneral::faststricmp(modelinfo->GetName(), name)) + return modelinfo; + } + return nil; +} +#endif + bool CModelInfo::IsBoatModel(int32 id) { @@ -214,6 +228,7 @@ CModelInfo::IsBikeModel(int32 id) ((CVehicleModelInfo*)GetModelInfo(id))->m_vehicleType == VEHICLE_TYPE_BIKE; } +#ifndef MIAMI void CModelInfo::RemoveColModelsFromOtherLevels(eLevelName level) { @@ -230,6 +245,7 @@ CModelInfo::RemoveColModelsFromOtherLevels(eLevelName level) } } } +#endif void CModelInfo::ConstructMloClumps() diff --git a/src/modelinfo/ModelInfo.h b/src/modelinfo/ModelInfo.h index 65cfa4e7..dadc8f8b 100644 --- a/src/modelinfo/ModelInfo.h +++ b/src/modelinfo/ModelInfo.h @@ -42,6 +42,9 @@ public: static CBaseModelInfo *GetModelInfo(int id){ return ms_modelInfoPtrs[id]; } +#ifdef MIAMI + static CBaseModelInfo *GetModelInfo(const char *name, int minIndex, int maxIndex); +#endif static bool IsBoatModel(int32 id); static bool IsBikeModel(int32 id); diff --git a/src/modelinfo/SimpleModelInfo.cpp b/src/modelinfo/SimpleModelInfo.cpp index 36e98e18..63b057da 100644 --- a/src/modelinfo/SimpleModelInfo.cpp +++ b/src/modelinfo/SimpleModelInfo.cpp @@ -130,6 +130,16 @@ CSimpleModelInfo::GetAtomicFromDistance(float dist) return nil; } +#ifdef MIAMI +RpAtomic* +CSimpleModelInfo::GetFirstAtomicFromDistance(float dist) +{ + if(dist < m_lodDistances[0] * TheCamera.LODDistMultiplier) + return m_atomics[0]; + return nil; +} +#endif + void CSimpleModelInfo::FindRelatedModel(void) { diff --git a/src/modelinfo/SimpleModelInfo.h b/src/modelinfo/SimpleModelInfo.h index 8c4173e9..451a9c00 100644 --- a/src/modelinfo/SimpleModelInfo.h +++ b/src/modelinfo/SimpleModelInfo.h @@ -40,6 +40,9 @@ public: float GetNearDistance(void); float GetLargestLodDistance(void); RpAtomic *GetAtomicFromDistance(float dist); +#ifdef MIAMI + RpAtomic *GetFirstAtomicFromDistance(float dist); // inline +#endif void FindRelatedModel(void); void SetupBigBuilding(void); diff --git a/src/peds/CivilianPed.cpp b/src/peds/CivilianPed.cpp index 2dee0397..3c25d827 100644 --- a/src/peds/CivilianPed.cpp +++ b/src/peds/CivilianPed.cpp @@ -187,8 +187,10 @@ CCivilianPed::CivilianAI(void) void CCivilianPed::ProcessControl(void) { +#ifndef MIAMI if (m_nZoneLevel > LEVEL_NONE && m_nZoneLevel != CCollision::ms_collisionInMemory) return; +#endif CPed::ProcessControl(); diff --git a/src/peds/CopPed.cpp b/src/peds/CopPed.cpp index 99e8c1ae..0fb0b9e0 100644 --- a/src/peds/CopPed.cpp +++ b/src/peds/CopPed.cpp @@ -425,8 +425,14 @@ CCopPed::CopAI(void) #ifdef VC_PED_PORTS float dotProd; if (m_nRoadblockNode != -1) { +#ifndef MIAMI CTreadable *roadBlockRoad = ThePaths.m_mapObjects[CRoadBlocks::RoadBlockObjects[m_nRoadblockNode]]; dotProd = DotProduct2D(playerOrHisVeh->GetPosition() - roadBlockRoad->GetPosition(), GetPosition() - roadBlockRoad->GetPosition()); +#else + // TODO: check this, i'm only getting this compile here.... + CPathNode *roadBlockNode = &ThePaths.m_pathNodes[CRoadBlocks::RoadBlockNodes[m_nRoadblockNode]]; + dotProd = DotProduct2D(playerOrHisVeh->GetPosition() - roadBlockNode->GetPosition(), GetPosition() - roadBlockNode->GetPosition()); +#endif } else dotProd = -1.0f; @@ -559,8 +565,10 @@ CCopPed::CopAI(void) void CCopPed::ProcessControl(void) { +#ifndef MIAMI if (m_nZoneLevel > LEVEL_NONE && m_nZoneLevel != CCollision::ms_collisionInMemory) return; +#endif CPed::ProcessControl(); if (bWasPostponed) diff --git a/src/peds/EmergencyPed.cpp b/src/peds/EmergencyPed.cpp index 7229ed3f..e85cfc8b 100644 --- a/src/peds/EmergencyPed.cpp +++ b/src/peds/EmergencyPed.cpp @@ -44,8 +44,10 @@ CEmergencyPed::InRange(CPed *victim) void CEmergencyPed::ProcessControl(void) { +#ifndef MIAMI if (m_nZoneLevel > LEVEL_NONE && m_nZoneLevel != CCollision::ms_collisionInMemory) return; +#endif CPed::ProcessControl(); if (bWasPostponed) diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index 56a18dab..04b62e46 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -9397,8 +9397,10 @@ CPed::ProcessControl(void) CColPoint foundCol; CEntity *foundEnt = nil; +#ifndef MIAMI if (m_nZoneLevel > LEVEL_NONE && m_nZoneLevel != CCollision::ms_collisionInMemory) return; +#endif int alpha = CVisibilityPlugins::GetClumpAlpha(GetClump()); if (!bFadeOut) { diff --git a/src/peds/Population.cpp b/src/peds/Population.cpp index ce781983..fed607ed 100644 --- a/src/peds/Population.cpp +++ b/src/peds/Population.cpp @@ -858,6 +858,7 @@ CPopulation::AddPedInCar(CVehicle* car) void CPopulation::MoveCarsAndPedsOutOfAbandonedZones() { +#ifndef MIAMI eLevelName level; int zone; int frame = CTimer::GetFrameCounter() & 7; @@ -940,6 +941,7 @@ CPopulation::MoveCarsAndPedsOutOfAbandonedZones() } } } +#endif } void diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 0c5e8fae..982c61cd 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -194,6 +194,7 @@ CRenderer::RenderRoads(void) t = (CTreadable*)ms_aVisibleEntityPtrs[i]; if(t->IsBuilding() && t->GetIsATreadable()){ #ifndef MASTER +#ifndef MIAMI if(gbShowCarRoadGroups || gbShowPedRoadGroups){ int ind = 0; if(gbShowCarRoadGroups) @@ -203,6 +204,7 @@ CRenderer::RenderRoads(void) SetAmbientColoursToIndicateRoadGroup(ind); } #endif +#endif RenderOneRoad(t); #ifndef MASTER if(gbShowCarRoadGroups || gbShowPedRoadGroups) @@ -326,6 +328,7 @@ enum Visbility int32 CRenderer::SetupEntityVisibility(CEntity *ent) { +#ifndef MIAMI CSimpleModelInfo *mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(ent->m_modelIndex); CTimeModelInfo *ti; int32 other; @@ -471,11 +474,164 @@ CRenderer::SetupEntityVisibility(CEntity *ent) ent->bDistanceFade = true; return VIS_OFFSCREEN; // Why this? } +#else + CSimpleModelInfo *mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(ent->m_modelIndex); + CTimeModelInfo *ti; + int32 other; + float dist; + + bool request = true; + if(mi->GetModelType() == MITYPE_TIME){ + ti = (CTimeModelInfo*)mi; + other = ti->GetOtherTimeModel(); + if(CClock::GetIsTimeInRange(ti->GetTimeOn(), ti->GetTimeOff())){ + // don't fade in, or between time objects + if(CANTIMECULL) + ti->m_alpha = 255; + }else{ + // Hide if possible + if(CANTIMECULL) + return VIS_INVISIBLE; + // can't cull, so we'll try to draw this one, but don't request + // it since what we really want is the other one. + request = false; + } + }else{ +// TODO(MIAMI): weapon + if(mi->GetModelType() != MITYPE_SIMPLE){ + if(FindPlayerVehicle() == ent && + TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_1STPERSON){ + // Player's vehicle in first person mode + if(TheCamera.Cams[TheCamera.ActiveCam].DirectionWasLooking == LOOKING_FORWARD || + ent->GetModelIndex() == MI_RHINO || + ent->GetModelIndex() == MI_COACH || + TheCamera.m_bInATunnelAndABigVehicle){ + ent->bNoBrightHeadLights = true; + }else{ + m_pFirstPersonVehicle = (CVehicle*)ent; + ent->bNoBrightHeadLights = false; + } + return VIS_OFFSCREEN; + }else{ + // All sorts of Clumps + if(ent->m_rwObject == nil || !ent->bIsVisible) + return VIS_INVISIBLE; +// TODO(MIAMI): occlusion + if(!ent->GetIsOnScreen()) + return VIS_OFFSCREEN; + if(ent->bDrawLast){ + dist = (ent->GetPosition() - ms_vecCameraPosition).Magnitude(); + CVisibilityPlugins::InsertEntityIntoSortedList(ent, dist); + ent->bDistanceFade = false; + return VIS_INVISIBLE; + }else + return VIS_VISIBLE; + } + return VIS_INVISIBLE; + } +// TODO(MIAMI): this is different + if(ent->IsObject() && + ((CObject*)ent)->ObjectCreatedBy == TEMP_OBJECT){ + if(ent->m_rwObject == nil || !ent->bIsVisible) + return VIS_INVISIBLE; + return ent->GetIsOnScreen() ? VIS_VISIBLE : VIS_OFFSCREEN; + } + } + + // Simple ModelInfo + +// TODO(MIAMI): area + + dist = (ent->GetPosition() - ms_vecCameraPosition).Magnitude(); + + if(LOD_DISTANCE < dist && dist < mi->GetLargestLodDistance() + FADE_DISTANCE) + dist += mi->GetLargestLodDistance() - 300.0f; + + if(ent->IsObject() && ent->bRenderDamaged) + mi->m_isDamaged = true; + + RpAtomic *a = mi->GetAtomicFromDistance(dist); + if(a){ + mi->m_isDamaged = false; + if(ent->m_rwObject == nil) + ent->CreateRwObject(); + assert(ent->m_rwObject); + RpAtomic *rwobj = (RpAtomic*)ent->m_rwObject; + // Make sure our atomic uses the right geometry and not + // that of an atomic for another draw distance. + if(RpAtomicGetGeometry(a) != RpAtomicGetGeometry(rwobj)) + RpAtomicSetGeometry(rwobj, RpAtomicGetGeometry(a), rpATOMICSAMEBOUNDINGSPHERE); // originally 5 (mistake?) + mi->IncreaseAlpha(); + if(ent->m_rwObject == nil || !ent->bIsVisible) + return VIS_INVISIBLE; + + if(!ent->GetIsOnScreen()){ + mi->m_alpha = 255; + return VIS_OFFSCREEN; + } + + if(mi->m_alpha != 255){ + CVisibilityPlugins::InsertEntityIntoSortedList(ent, dist); + ent->bDistanceFade = true; + return VIS_INVISIBLE; + } + + if(mi->m_drawLast || ent->bDrawLast){ + if(CVisibilityPlugins::InsertEntityIntoSortedList(ent, dist)){ + ent->bDistanceFade = false; + return VIS_INVISIBLE; + } + } + return VIS_VISIBLE; + } + + // Object is not loaded, figure out what to do + + if(mi->m_noFade){ + mi->m_isDamaged = false; + // request model + if(dist - STREAM_DISTANCE < mi->GetLargestLodDistance() && request) + return VIS_STREAMME; + return VIS_INVISIBLE; + } + + // We might be fading + + a = mi->GetAtomicFromDistance(dist - FADE_DISTANCE); + mi->m_isDamaged = false; + if(a == nil){ + // request model + if(dist - FADE_DISTANCE - STREAM_DISTANCE < mi->GetLargestLodDistance() && request) + return VIS_STREAMME; + return VIS_INVISIBLE; + } + + if(ent->m_rwObject == nil) + ent->CreateRwObject(); + assert(ent->m_rwObject); + RpAtomic *rwobj = (RpAtomic*)ent->m_rwObject; + if(RpAtomicGetGeometry(a) != RpAtomicGetGeometry(rwobj)) + RpAtomicSetGeometry(rwobj, RpAtomicGetGeometry(a), rpATOMICSAMEBOUNDINGSPHERE); // originally 5 (mistake?) + mi->IncreaseAlpha(); + if(ent->m_rwObject == nil || !ent->bIsVisible) + return VIS_INVISIBLE; + +// TODO(MIAMI): occlusion + if(!ent->GetIsOnScreen()){ + mi->m_alpha = 255; + return VIS_OFFSCREEN; + }else{ + CVisibilityPlugins::InsertEntityIntoSortedList(ent, dist); + ent->bDistanceFade = true; + return VIS_OFFSCREEN; // Why this? + } +#endif } int32 CRenderer::SetupBigBuildingVisibility(CEntity *ent) { +#ifndef MIAMI CSimpleModelInfo *mi = (CSimpleModelInfo *)CModelInfo::GetModelInfo(ent->GetModelIndex()); CTimeModelInfo *ti; int32 other; @@ -557,6 +713,121 @@ CRenderer::SetupBigBuildingVisibility(CEntity *ent) if(ent->IsVisibleComplex()) CVisibilityPlugins::InsertEntityIntoSortedList(ent, dist); return VIS_INVISIBLE; +#else + CSimpleModelInfo *mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(ent->m_modelIndex); + CTimeModelInfo *ti; + int32 other; + +// TODO(MIAMI): area + + bool request = true; + if(mi->GetModelType() == MITYPE_TIME){ + ti = (CTimeModelInfo*)mi; + other = ti->GetOtherTimeModel(); + if(CClock::GetIsTimeInRange(ti->GetTimeOn(), ti->GetTimeOff())){ + // don't fade in, or between time objects + if(CANTIMECULL) + ti->m_alpha = 255; + }else{ + // Hide if possible + if(CANTIMECULL){ + ent->DeleteRwObject(); + return VIS_INVISIBLE; + } + // can't cull, so we'll try to draw this one, but don't request + // it since what we really want is the other one. + request = false; + } + }else if(mi->GetModelType() == MITYPE_VEHICLE) + return ent->IsVisible() ? VIS_VISIBLE : VIS_INVISIBLE; + + float dist = (ms_vecCameraPosition-ent->GetPosition()).Magnitude(); + CSimpleModelInfo *nonLOD = mi->GetRelatedModel(); + + // Find out whether to draw below near distance. + // This is only the case if there is a non-LOD which is either not + // loaded or not completely faded in yet. + if(dist < mi->GetNearDistance() && dist < LOD_DISTANCE){ + // No non-LOD or non-LOD is completely visible. + if(nonLOD == nil || + nonLOD->GetRwObject() && nonLOD->m_alpha == 255) + return VIS_INVISIBLE; + + // But if it is a time object, we'd rather draw the wrong + // non-LOD than the right LOD. + if(nonLOD->GetModelType() == MITYPE_TIME){ + ti = (CTimeModelInfo*)nonLOD; + other = ti->GetOtherTimeModel(); + if(other != -1 && CModelInfo::GetModelInfo(other)->GetRwObject()) + return VIS_INVISIBLE; + } + } + + RpAtomic *a = mi->GetFirstAtomicFromDistance(dist); + if(a){ + if(ent->m_rwObject == nil) + ent->CreateRwObject(); + assert(ent->m_rwObject); + RpAtomic *rwobj = (RpAtomic*)ent->m_rwObject; + + // Make sure our atomic uses the right geometry and not + // that of an atomic for another draw distance. + if(RpAtomicGetGeometry(a) != RpAtomicGetGeometry(rwobj)) + RpAtomicSetGeometry(rwobj, RpAtomicGetGeometry(a), rpATOMICSAMEBOUNDINGSPHERE); // originally 5 (mistake?) + mi->IncreaseAlpha(); +// TODO(MIAMI): occlusion + if(!ent->IsVisibleComplex()){ + mi->m_alpha = 255; + return VIS_INVISIBLE; + } + + if(mi->m_alpha != 255){ + CVisibilityPlugins::InsertEntityIntoSortedList(ent, dist); + ent->bDistanceFade = true; + return VIS_INVISIBLE; + } + + if(mi->m_drawLast){ + CVisibilityPlugins::InsertEntityIntoSortedList(ent, dist); + ent->bDistanceFade = false; + return VIS_INVISIBLE; + } + return VIS_VISIBLE; + } + + if(mi->m_noFade){ + ent->DeleteRwObject(); + return VIS_INVISIBLE; + } + + + // get faded atomic + a = mi->GetFirstAtomicFromDistance(dist - FADE_DISTANCE); + if(a == nil){ + if(ent->bStreamBIGBuilding && dist-STREAM_DISTANCE < mi->GetLodDistance(0) && request){ + return ent->GetIsOnScreen() ? VIS_STREAMME : VIS_INVISIBLE; + }else{ + ent->DeleteRwObject(); + return VIS_INVISIBLE; + } + } + + // Fade... + if(ent->m_rwObject == nil) + ent->CreateRwObject(); + assert(ent->m_rwObject); + RpAtomic *rwobj = (RpAtomic*)ent->m_rwObject; + if(RpAtomicGetGeometry(a) != RpAtomicGetGeometry(rwobj)) + RpAtomicSetGeometry(rwobj, RpAtomicGetGeometry(a), rpATOMICSAMEBOUNDINGSPHERE); // originally 5 (mistake?) + mi->IncreaseAlpha(); +// TODO(MIAMI): occlusion + if(ent->IsVisibleComplex()){ + CVisibilityPlugins::InsertEntityIntoSortedList(ent, dist); + ent->bDistanceFade = true; + }else + mi->m_alpha = 255; + return VIS_INVISIBLE; +#endif } void @@ -703,7 +974,11 @@ CRenderer::ScanWorld(void) } ScanSectorPoly(poly, 3, ScanSectorList); +#ifndef MIAMI ScanBigBuildingList(CWorld::GetBigBuildingList(CCollision::ms_collisionInMemory)); +#else + ScanBigBuildingList(CWorld::GetBigBuildingList(CGame::currLevel)); +#endif ScanBigBuildingList(CWorld::GetBigBuildingList(LEVEL_NONE)); } } @@ -948,11 +1223,27 @@ CRenderer::ScanBigBuildingList(CPtrList &list) CPtrNode *node; CEntity *ent; +#ifndef MIAMI for(node = list.first; node; node = node->next){ ent = (CEntity*)node->item; if(!ent->bZoneCulled && SetupBigBuildingVisibility(ent) == VIS_VISIBLE) ms_aVisibleEntityPtrs[ms_nNoOfVisibleEntities++] = ent; } +#else + // TODO(MIAMI): some flags and such + for(node = list.first; node; node = node->next){ + ent = (CEntity*)node->item; + switch(SetupBigBuildingVisibility(ent)){ + case VIS_VISIBLE: + ms_aVisibleEntityPtrs[ms_nNoOfVisibleEntities++] = ent; + break; + case VIS_STREAMME: + if(!CStreaming::ms_disableStreaming) + CStreaming::RequestModel(ent->GetModelIndex(), 0); + break; + } + } +#endif } void diff --git a/src/save/GenericGameStorage.cpp b/src/save/GenericGameStorage.cpp index bb074042..c22a060c 100644 --- a/src/save/GenericGameStorage.cpp +++ b/src/save/GenericGameStorage.cpp @@ -543,11 +543,13 @@ RestoreForStartLoad() ReadDataFromBufferPointer(_buf, TheCamera.GetMatrix().GetPosition().z); CStreaming::RemoveUnusedBigBuildings(CGame::currLevel); CStreaming::RemoveUnusedBuildings(CGame::currLevel); +#ifndef MIAMI CCollision::SortOutCollisionAfterLoad(); CStreaming::RequestBigBuildings(CGame::currLevel); CStreaming::LoadAllRequestedModels(false); CStreaming::HaveAllBigBuildingsLoaded(CGame::currLevel); CGame::TidyUpMemory(true, false); +#endif if (CloseFile(file)) { return true; diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 9db60da0..602eb589 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -229,9 +229,11 @@ CAutomobile::ProcessControl(void) colModel = GetColModel(); bWarnedPeds = false; +#ifndef MIAMI // skip if the collision isn't for the current level if(colModel->level > LEVEL_NONE && colModel->level != CCollision::ms_collisionInMemory) return; +#endif // Improve grip of vehicles in certain cases bool strongGrip1 = false; diff --git a/src/vehicles/Automobile.h b/src/vehicles/Automobile.h index 041302bf..0356a9f2 100644 --- a/src/vehicles/Automobile.h +++ b/src/vehicles/Automobile.h @@ -197,8 +197,6 @@ public: static void SetAllTaxiLights(bool set); }; -static_assert(sizeof(CAutomobile) == 0x5A8, "CAutomobile: error"); - inline uint8 GetCarDoorFlag(int32 carnode) { switch (carnode) { case CAR_DOOR_LF: diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp index 348f2732..ecf760e4 100644 --- a/src/vehicles/Boat.cpp +++ b/src/vehicles/Boat.cpp @@ -109,8 +109,10 @@ CBoat::GetComponentWorldPosition(int32 component, CVector &pos) void CBoat::ProcessControl(void) { +#ifndef MIAMI if(m_nZoneLevel > LEVEL_NONE && m_nZoneLevel != CCollision::ms_collisionInMemory) return; +#endif bool onLand = m_fDamageImpulse > 0.0f && m_vecDamageNormal.z > 0.1f; diff --git a/src/vehicles/Boat.h b/src/vehicles/Boat.h index 70407ab9..cde5de84 100644 --- a/src/vehicles/Boat.h +++ b/src/vehicles/Boat.h @@ -72,8 +72,6 @@ public: }; -static_assert(sizeof(CBoat) == 0x484, "CBoat: error"); - extern float MAX_WAKE_LENGTH; extern float MIN_WAKE_INTERVAL; extern float WAKE_LIFETIME;
\ No newline at end of file diff --git a/src/vehicles/Heli.h b/src/vehicles/Heli.h index 39e4cbcf..a8f604aa 100644 --- a/src/vehicles/Heli.h +++ b/src/vehicles/Heli.h @@ -95,4 +95,3 @@ public: static void ActivateHeli(bool activate); }; -static_assert(sizeof(CHeli) == 0x33C, "CHeli: error"); diff --git a/src/vehicles/Plane.h b/src/vehicles/Plane.h index 79738858..6fa6776b 100644 --- a/src/vehicles/Plane.h +++ b/src/vehicles/Plane.h @@ -63,7 +63,6 @@ public: static bool HasCesnaBeenDestroyed(void); static bool HasDropOffCesnaBeenShotDown(void); }; -static_assert(sizeof(CPlane) == 0x29C, "CPlane: error"); extern float LandingPoint; extern float TakeOffPoint; diff --git a/src/vehicles/Train.h b/src/vehicles/Train.h index bf541250..e20a08fd 100644 --- a/src/vehicles/Train.h +++ b/src/vehicles/Train.h @@ -91,4 +91,3 @@ public: float *totalLength, float *totalDuration, CTrainInterpolationLine *interpLines, bool rightRail); static void UpdateTrains(void); }; -static_assert(sizeof(CTrain) == 0x2E4, "CTrain: error"); diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index 5dc7bc72..efbc56c0 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -99,6 +99,9 @@ CVehicle::CVehicle(uint8 CreatedBy) m_bSirenOrAlarm = 0; m_nCarHornTimer = 0; m_nCarHornPattern = 0; +#ifdef MIAMI + bParking = false; +#endif m_nAlarmState = 0; m_nDoorLock = CARLOCK_UNLOCKED; m_nLastWeaponDamage = -1; @@ -118,6 +121,9 @@ CVehicle::CVehicle(uint8 CreatedBy) AutoPilot.m_nTimeToStartMission = CTimer::GetTimeInMilliseconds(); AutoPilot.m_bStayInCurrentLevel = false; AutoPilot.m_bIgnorePathfinding = false; +#ifdef MIAMI + AutoPilot.m_nSwitchDistance = 20; +#endif } CVehicle::~CVehicle() @@ -1347,3 +1353,21 @@ CVehicle::Load(uint8*& buf) SkipSaveBuf(buf, 99); } #endif + +eVehicleAppearance +//--MIAMI: TODO, implement VC version, appearance != type +// This would work for cars, boats and bikes but not for planes and helis +CVehicle::GetVehicleAppearance(void) +{ + if (IsCar()) + return VEHICLE_CAR; + if (IsBoat()) + return VEHICLE_BOAT; + if (IsBike()) + return VEHICLE_BIKE; + if (IsPlane()) + return VEHICLE_PLANE; + if (IsHeli()) + return VEHICLE_HELI; + return VEHICLE_NONE; +} diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h index 110ff97c..a818456d 100644 --- a/src/vehicles/Vehicle.h +++ b/src/vehicles/Vehicle.h @@ -109,6 +109,16 @@ enum eFlightModel FLIGHT_MODEL_SEAPLANE }; +enum eVehicleAppearance +{ + VEHICLE_NONE, + VEHICLE_CAR, + VEHICLE_BIKE, + VEHICLE_HELI, + VEHICLE_BOAT, + VEHICLE_PLANE, +}; + // Or Weapon.h? void FireOneInstantHitRound(CVector *shotSource, CVector *shotTarget, int32 damage); @@ -172,6 +182,8 @@ public: uint8 bIsCarParkVehicle : 1; // Car has been created using the special CAR_PARK script command uint8 bHasAlreadyBeenRecorded : 1; // Used for replays + uint8 bParking : 1; + int8 m_numPedsUseItAsCover; uint8 m_nAmmoInClip; // Used to make the guns on boat do a reload (20 by default) int8 m_nPacManPickupsCarried; @@ -236,6 +248,7 @@ public: virtual void Load(uint8*& buf); #endif + eVehicleAppearance GetVehicleAppearance(void); bool IsCar(void) { return m_vehType == VEHICLE_TYPE_CAR; } bool IsBoat(void) { return m_vehType == VEHICLE_TYPE_BOAT; } bool IsTrain(void) { return m_vehType == VEHICLE_TYPE_TRAIN; } @@ -291,9 +304,4 @@ public: static bool m_bDisableMouseSteering; }; -static_assert(sizeof(CVehicle) == 0x288, "CVehicle: error"); -static_assert(offsetof(CVehicle, m_pCurGroundEntity) == 0x1E0, "CVehicle: error"); -static_assert(offsetof(CVehicle, m_nAlarmState) == 0x1A0, "CVehicle: error"); -static_assert(offsetof(CVehicle, m_nLastWeaponDamage) == 0x228, "CVehicle: error"); - void DestroyVehicleAndDriverAndPassengers(CVehicle* pVehicle); |