From 903adceab529d112acc6c2010678c9326d309bc6 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 12 Feb 2024 00:48:13 +0000 Subject: [PATCH] Maintain map of targeted road vehicles to small UFO disaster vehicle --- src/disaster_vehicle.cpp | 52 ++++++++++++++++++++++++++++++---------- src/misc.cpp | 1 + src/openttd.cpp | 1 + src/sl/vehicle_sl.cpp | 18 ++++++++++++++ src/vehicle.cpp | 5 ++-- src/vehicle_func.h | 4 +++- 6 files changed, 66 insertions(+), 15 deletions(-) diff --git a/src/disaster_vehicle.cpp b/src/disaster_vehicle.cpp index 0eca295acd..e4ca9cf424 100644 --- a/src/disaster_vehicle.cpp +++ b/src/disaster_vehicle.cpp @@ -48,6 +48,7 @@ #include "core/backup_type.hpp" #include "core/checksum_func.hpp" #include "event_logs.h" +#include "3rdparty/cpp-btree/btree_map.h" #include "table/strings.h" @@ -57,6 +58,7 @@ uint16_t _disaster_delay; static uint32_t _disaster_vehicle_count = 0; +static btree::btree_map _disaster_ufo_target_map; static void DisasterClearSquare(TileIndex tile) { @@ -369,6 +371,11 @@ static bool DisasterTick_Ufo(DisasterVehicle *v) for (const RoadVehicle *u : RoadVehicle::Iterate()) { /* Find (n+1)-th road vehicle. */ if (u->IsFrontEngine() && (n-- == 0)) { + if (u->crashed_ctr != 0 || !SetDisasterVehicleTargetingVehicle(u->index, v->index)) { + /* Targetted vehicle is crashed or already a target, destroy the UFO. */ + delete v; + return false; + } /* Target it. */ v->dest_tile = u->index; v->age = 0; @@ -1010,22 +1017,43 @@ void ReleaseDisastersTargetingIndustry(IndustryID i) * Notify disasters that we are about to delete a vehicle. So make them head elsewhere. * @param vehicle deleted vehicle */ -void ReleaseDisastersTargetingVehicle(VehicleID vehicle) +void ReleaseDisasterVehicleTargetingVehicle(VehicleID vehicle) { if (!_disaster_vehicle_count) return; - for (DisasterVehicle *v : DisasterVehicle::Iterate()) { - /* primary disaster vehicles that have chosen target */ - if (v->subtype == ST_SMALL_UFO) { - if (v->state != 0 && v->dest_tile == vehicle) { - /* Revert to target-searching */ - v->state = 0; - v->dest_tile = RandomTile(); - GetAircraftFlightLevelBounds(v, &v->z_pos, nullptr); - v->age = 0; - } - } + auto iter = _disaster_ufo_target_map.find(vehicle); + if (iter == _disaster_ufo_target_map.end()) return; + + DisasterVehicle *v = DisasterVehicle::GetIfValid(iter->second); + _disaster_ufo_target_map.erase(iter); + + if (v == nullptr) return; + + /* primary disaster vehicles that have chosen target */ + assert(v->subtype == ST_SMALL_UFO); + assert(v->state != 0); + + /* Revert to target-searching */ + v->state = 0; + v->dest_tile = RandomTile(); + GetAircraftFlightLevelBounds(v, &v->z_pos, nullptr); + v->age = 0; +} + +void ResetDisasterVehicleTargeting() +{ + _disaster_ufo_target_map.clear(); +} + +bool SetDisasterVehicleTargetingVehicle(VehicleID vehicle, VehicleID disaster_vehicle) +{ + auto insert_result = _disaster_ufo_target_map.insert(std::make_pair(vehicle, disaster_vehicle)); + if (!insert_result.second) { + /* Vehicle already has an associated disaster vehicle, return failure if that isn't this disaster vehicle */ + if (insert_result.first->second != disaster_vehicle) return false; } + + return true; } void DisasterVehicle::UpdateDeltaXY() diff --git a/src/misc.cpp b/src/misc.cpp index 590afd65c5..6fd68eb227 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -120,6 +120,7 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin AllocateMap(size_x, size_y); ViewportMapClearTunnelCache(); + ResetDisasterVehicleTargeting(); ClearCommandLog(); ClearCommandQueue(); ClearSpecialEventsLog(); diff --git a/src/openttd.cpp b/src/openttd.cpp index d7e0cf39d6..e427d67935 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -520,6 +520,7 @@ static void ShutdownGame() InvalidateVehicleTickCaches(); ClearVehicleTickCaches(); InvalidateTemplateReplacementImages(); + ResetDisasterVehicleTargeting(); ClearCommandLog(); ClearCommandQueue(); ClearSpecialEventsLog(); diff --git a/src/sl/vehicle_sl.cpp b/src/sl/vehicle_sl.cpp index 019253e8dc..fe9933057d 100644 --- a/src/sl/vehicle_sl.cpp +++ b/src/sl/vehicle_sl.cpp @@ -507,6 +507,8 @@ void AfterLoadVehicles(bool part_of_load) } } + ResetDisasterVehicleTargeting(); + for (Vehicle *v : Vehicle::Iterate()) { si_v = v; switch (v->type) { @@ -539,6 +541,22 @@ void AfterLoadVehicles(bool part_of_load) UpdateAircraftCache(Aircraft::From(v), true); } break; + + case VEH_DISASTER: { + auto *dv = DisasterVehicle::From(v); + if (dv->subtype == ST_SMALL_UFO && dv->state != 0) { + RoadVehicle *u = RoadVehicle::GetIfValid(v->dest_tile); + if (u != nullptr && u->IsFrontEngine()) { + /* Delete UFO targeting a vehicle which is already a target. */ + if (!SetDisasterVehicleTargetingVehicle(u->index, dv->index)) { + delete v; + continue; + } + } + } + break; + } + default: break; } diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 83244aeef8..6bacf9918e 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -1030,6 +1030,7 @@ void InitializeVehicles() { _vehicles_to_autoreplace.clear(); ResetVehicleHash(); + ResetDisasterVehicleTargeting(); } uint CountVehiclesInChain(const Vehicle *v) @@ -1202,6 +1203,8 @@ void Vehicle::PreDestructor() /* Leave the drive through roadstop, when you have not already left it. */ RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v); } + + ReleaseDisasterVehicleTargetingVehicle(this->index); } if (HasBit(this->vehicle_flags, VF_HAVE_SLOT)) { @@ -1238,8 +1241,6 @@ void Vehicle::PreDestructor() StopGlobalFollowVehicle(this); - ReleaseDisastersTargetingVehicle(this->index); - /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles, * it may happen that vehicle chain is deleted when visible */ if (this->IsDrawn()) this->MarkAllViewportsDirty(); diff --git a/src/vehicle_func.h b/src/vehicle_func.h index 269829990b..ec53ec4954 100644 --- a/src/vehicle_func.h +++ b/src/vehicle_func.h @@ -258,7 +258,9 @@ bool CanVehicleUseStation(EngineID engine_type, const struct Station *st); bool CanVehicleUseStation(const Vehicle *v, const struct Station *st); StringID GetVehicleCannotUseStationReason(const Vehicle *v, const Station *st); -void ReleaseDisastersTargetingVehicle(VehicleID vehicle); +void ResetDisasterVehicleTargeting(); +void ReleaseDisasterVehicleTargetingVehicle(VehicleID vehicle); +bool SetDisasterVehicleTargetingVehicle(VehicleID vehicle, VehicleID disaster_vehicle); typedef std::vector VehicleSet; void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8_t num_vehicles);