diff --git a/src/articulated_vehicles.cpp b/src/articulated_vehicles.cpp index af3263e877..f7592b94dc 100644 --- a/src/articulated_vehicles.cpp +++ b/src/articulated_vehicles.cpp @@ -432,7 +432,10 @@ void AddArticulatedParts(Vehicle *first) if (flip_image) v->spritenum++; - if (v->type == VEH_TRAIN && TestVehicleBuildProbability(v, v->engine_type, BuildProbabilityType::Reversed)) Train::From(v)->flags.Set(VehicleRailFlag::Flipped); + if (v->type == VEH_TRAIN) { + auto prob = TestVehicleBuildProbability(v, v->engine_type, BuildProbabilityType::Reversed); + if (prob.has_value()) Train::From(v)->flags.Set(VehicleRailFlag::Flipped, prob.value()); + } v->UpdatePosition(); } } diff --git a/src/autoreplace_cmd.cpp b/src/autoreplace_cmd.cpp index c253612333..888306b260 100644 --- a/src/autoreplace_cmd.cpp +++ b/src/autoreplace_cmd.cpp @@ -374,7 +374,11 @@ static CommandCost BuildReplacementVehicle(Vehicle *old_veh, Vehicle **new_vehic /* Try to reverse the vehicle, but do not care if it fails as the new type might not be reversible */ if (new_veh->type == VEH_TRAIN && Train::From(old_veh)->flags.Test(VehicleRailFlag::Flipped)) { - Command::Do(DoCommandFlag::Execute, new_veh->index, true); + /* Only copy the reverse state if neither old or new vehicle implements reverse-on-build probability callback. */ + if (!TestVehicleBuildProbability(old_veh, old_veh->engine_type, BuildProbabilityType::Reversed).has_value() && + !TestVehicleBuildProbability(new_veh, new_veh->engine_type, BuildProbabilityType::Reversed).has_value()) { + Command::Do(DoCommandFlag::Execute, new_veh->index, true); + } } return cost; diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index 909424c1f9..e37ed01cf4 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -1235,12 +1235,12 @@ int GetEngineProperty(EngineID engine, PropertyID property, int orig_value, cons * Test for vehicle build probablity type. * @param v Vehicle whose build probability to test. * @param type Build probability type to test for. - * @returns True iff the probability result says so. + * @returns True or false depending on the probability result, or std::nullopt if the callback failed. */ -bool TestVehicleBuildProbability(Vehicle *v, EngineID engine, BuildProbabilityType type) +std::optional TestVehicleBuildProbability(Vehicle *v, EngineID engine, BuildProbabilityType type) { uint16_t p = GetVehicleCallback(CBID_VEHICLE_BUILD_PROBABILITY, to_underlying(type), 0, engine, v); - if (p == CALLBACK_FAILED) return false; + if (p == CALLBACK_FAILED) return std::nullopt; const uint16_t PROBABILITY_RANGE = 100; return p + RandomRange(PROBABILITY_RANGE) >= PROBABILITY_RANGE; diff --git a/src/newgrf_engine.h b/src/newgrf_engine.h index 5906d71ed6..912fba67b6 100644 --- a/src/newgrf_engine.h +++ b/src/newgrf_engine.h @@ -105,7 +105,7 @@ enum class BuildProbabilityType : uint8_t { Reversed = 0, }; -bool TestVehicleBuildProbability(Vehicle *v, EngineID engine, BuildProbabilityType type); +std::optional TestVehicleBuildProbability(Vehicle *v, EngineID engine, BuildProbabilityType type); void TriggerVehicleRandomisation(Vehicle *veh, VehicleRandomTrigger trigger); diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 6fa02d8666..ab2472af15 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -662,7 +662,8 @@ static CommandCost CmdBuildRailWagon(DoCommandFlags flags, TileIndex tile, const v->group_id = DEFAULT_GROUP; - if (TestVehicleBuildProbability(v, v->engine_type, BuildProbabilityType::Reversed)) v->flags.Set(VehicleRailFlag::Flipped); + auto prob = TestVehicleBuildProbability(v, v->engine_type, BuildProbabilityType::Reversed); + if (prob.has_value()) v->flags.Set(VehicleRailFlag::Flipped, prob.value()); AddArticulatedParts(v); v->UpdatePosition(); @@ -731,7 +732,8 @@ static void AddRearEngineToMultiheadedTrain(Train *v) v->SetMultiheaded(); u->SetMultiheaded(); v->SetNext(u); - if (TestVehicleBuildProbability(u, u->engine_type, BuildProbabilityType::Reversed)) u->flags.Set(VehicleRailFlag::Flipped); + auto prob = TestVehicleBuildProbability(u, u->engine_type, BuildProbabilityType::Reversed); + if (prob.has_value()) u->flags.Set(VehicleRailFlag::Flipped, prob.value()); u->UpdatePosition(); /* Now we need to link the front and rear engines together */ @@ -804,7 +806,8 @@ CommandCost CmdBuildRailVehicle(DoCommandFlags flags, TileIndex tile, const Engi v->SetFrontEngine(); v->SetEngine(); - if (TestVehicleBuildProbability(v, v->engine_type, BuildProbabilityType::Reversed)) v->flags.Set(VehicleRailFlag::Flipped); + auto prob = TestVehicleBuildProbability(v, v->engine_type, BuildProbabilityType::Reversed); + if (prob.has_value()) v->flags.Set(VehicleRailFlag::Flipped, prob.value()); v->UpdatePosition(); if (rvi->railveh_type == RAILVEH_MULTIHEAD) { diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index 0411ccdd0e..2352e8ec62 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -906,7 +906,11 @@ std::tuple CmdCloneVehicle(DoCommandFlags flags, TileInd w = Vehicle::Get(new_veh_id); if (v->type == VEH_TRAIN && Train::From(v)->flags.Test(VehicleRailFlag::Flipped)) { - Train::From(w)->flags.Set(VehicleRailFlag::Flipped); + /* Only copy the reverse state if neither old or new vehicle implements reverse-on-build probability callback. */ + if (!TestVehicleBuildProbability(v, v->engine_type, BuildProbabilityType::Reversed).has_value() && + !TestVehicleBuildProbability(w, w->engine_type, BuildProbabilityType::Reversed).has_value()) { + Train::From(w)->flags.Set(VehicleRailFlag::Flipped); + } } if (v->type == VEH_TRAIN && !v->IsFrontEngine()) {