diff --git a/src/disaster_vehicle.cpp b/src/disaster_vehicle.cpp --- a/src/disaster_vehicle.cpp +++ b/src/disaster_vehicle.cpp @@ -345,12 +345,18 @@ static bool DisasterTick_Ufo(DisasterVeh } n = RandomRange(n); // Choose one of them. - for (const RoadVehicle *u : RoadVehicle::Iterate()) { + for (RoadVehicle *u : RoadVehicle::Iterate()) { /* Find (n+1)-th road vehicle. */ if (u->IsFrontEngine() && (n-- == 0)) { + if (u->crashed_ctr != 0 || u->disaster_vehicle != INVALID_VEHICLE) { + /* 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; + u->disaster_vehicle = v->index; break; } } @@ -379,6 +385,7 @@ static bool DisasterTick_Ufo(DisasterVeh v->age++; if (u->crashed_ctr == 0) { u->Crash(); + u->disaster_vehicle = INVALID_VEHICLE; AddTileNewsItem(STR_NEWS_DISASTER_SMALL_UFO, NT_ACCIDENT, u->tile); @@ -970,20 +977,20 @@ void ReleaseDisastersTargetingIndustry(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 ReleaseDisasterVehicle(VehicleID vehicle) { - 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; - } - } - } + DisasterVehicle *v = DisasterVehicle::GetIfValid(vehicle); + 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 DisasterVehicle::UpdateDeltaXY() diff --git a/src/roadveh.h b/src/roadveh.h --- a/src/roadveh.h +++ b/src/roadveh.h @@ -116,6 +116,8 @@ struct RoadVehicle final : public Ground RoadType roadtype; //!< Roadtype of this vehicle. RoadTypes compatible_roadtypes; //!< Roadtypes this consist is powered on. + VehicleID disaster_vehicle = INVALID_VEHICLE; ///< NOSAVE: Disaster vehicle targetting this vehicle. + /** We don't want GCC to zero our struct! It already is zeroed and has an index! */ RoadVehicle() : GroundVehicleBase() {} /** We want to 'destruct' the right class. */ diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -496,6 +496,24 @@ 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.base()); + if (u != nullptr && u->IsFrontEngine()) { + /* Delete UFO targetting a vehicle which is already a target. */ + if (u->disaster_vehicle != INVALID_VEHICLE) { + delete v; + continue; + } else { + u->disaster_vehicle = dv->index; + } + } + } + break; + } + default: break; } diff --git a/src/vehicle.cpp b/src/vehicle.cpp --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -862,6 +862,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); } + + if (v->disaster_vehicle != INVALID_VEHICLE) ReleaseDisasterVehicle(v->disaster_vehicle); } if (this->Previous() == nullptr) { @@ -884,8 +886,6 @@ void Vehicle::PreDestructor() DeleteDepotHighlightOfVehicle(this); StopGlobalFollowVehicle(this); - - ReleaseDisastersTargetingVehicle(this->index); } Vehicle::~Vehicle() diff --git a/src/vehicle_func.h b/src/vehicle_func.h --- a/src/vehicle_func.h +++ b/src/vehicle_func.h @@ -168,7 +168,7 @@ bool CanVehicleUseStation(EngineID engin bool CanVehicleUseStation(const Vehicle *v, const struct Station *st); StringID GetVehicleCannotUseStationReason(const Vehicle *v, const Station *st); -void ReleaseDisastersTargetingVehicle(VehicleID vehicle); +void ReleaseDisasterVehicle(VehicleID vehicle); typedef std::vector VehicleSet; void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8_t num_vehicles);