From ddd609ce9b9c8b021aa2b851f15c1da8af574c59 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 29 Nov 2023 22:40:09 +0000 Subject: [PATCH] Feature: Randomize direction of rail vehicle on build based on probability callback. (#11489) This allows NewGRF authors to indicate that the game should randomly flip rail vehicles on build, without needing to use random bits nor duplicate sprites to handle it themselves. To use this functionality, test for callback 162 (CBID_VEHICLE_BUILD_PROBABILITY) and var10 = 0 (values other than 0 are reserved for future use), and return a value between 0 and 100 inclusive. The return value is a percentage chance of reversing the vehicle. A value of 0 will always build a forward facing vehicle, and 100 will always build a reverse facing vehicle. --- src/newgrf_callbacks.h | 3 +++ src/newgrf_engine.cpp | 14 ++++++++++++++ src/newgrf_engine.h | 6 ++++++ src/train_cmd.cpp | 3 +++ 4 files changed, 26 insertions(+) diff --git a/src/newgrf_callbacks.h b/src/newgrf_callbacks.h index 482031cec0..056461c006 100644 --- a/src/newgrf_callbacks.h +++ b/src/newgrf_callbacks.h @@ -282,6 +282,9 @@ enum CallbackID { /** Called to determine the engine name to show. */ CBID_VEHICLE_NAME = 0x161, // 15 bit callback + + /** Called to determine probability during build. */ + CBID_VEHICLE_BUILD_PROBABILITY = 0x162, // 15 bit callback }; /** diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index df3be19561..bea6c1d2e8 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -1192,6 +1192,20 @@ int GetEngineProperty(EngineID engine, PropertyID property, int orig_value, cons return orig_value; } +/** + * 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. + */ +bool TestVehicleBuildProbability(Vehicle *v, EngineID engine, BuildProbabilityType type) +{ + uint16_t p = GetVehicleCallback(CBID_VEHICLE_BUILD_PROBABILITY, std::underlying_type::type(type), 0, engine, v); + if (p == CALLBACK_FAILED) return false; + + const uint16_t PROBABILITY_RANGE = 100; + return p + RandomRange(PROBABILITY_RANGE) >= PROBABILITY_RANGE; +} static void DoTriggerVehicle(Vehicle *v, VehicleTrigger trigger, uint16_t base_random_bits, bool first) { diff --git a/src/newgrf_engine.h b/src/newgrf_engine.h index 4452ad9caf..da37602b81 100644 --- a/src/newgrf_engine.h +++ b/src/newgrf_engine.h @@ -103,6 +103,12 @@ bool UsesWagonOverride(const Vehicle *v); int GetVehicleProperty(const Vehicle *v, PropertyID property, int orig_value, bool is_signed = false); int GetEngineProperty(EngineID engine, PropertyID property, int orig_value, const Vehicle *v = nullptr, bool is_signed = false); +enum class BuildProbabilityType { + Reversed = 0, +}; + +bool TestVehicleBuildProbability(Vehicle *v, EngineID engine, BuildProbabilityType type); + enum VehicleTrigger { VEHICLE_TRIGGER_NEW_CARGO = 0x01, /* Externally triggered only for the first vehicle in chain */ diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 67e233f9d7..848a1bad4e 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -661,6 +661,7 @@ static CommandCost CmdBuildRailWagon(DoCommandFlag flags, TileIndex tile, const v->group_id = DEFAULT_GROUP; + if (TestVehicleBuildProbability(v, v->engine_type, BuildProbabilityType::Reversed)) SetBit(v->flags, VRF_REVERSE_DIRECTION); AddArticulatedParts(v); v->UpdatePosition(); @@ -728,6 +729,7 @@ static void AddRearEngineToMultiheadedTrain(Train *v) v->SetMultiheaded(); u->SetMultiheaded(); v->SetNext(u); + if (TestVehicleBuildProbability(u, u->engine_type, BuildProbabilityType::Reversed)) SetBit(u->flags, VRF_REVERSE_DIRECTION); u->UpdatePosition(); /* Now we need to link the front and rear engines together */ @@ -799,6 +801,7 @@ CommandCost CmdBuildRailVehicle(DoCommandFlag flags, TileIndex tile, const Engin v->SetFrontEngine(); v->SetEngine(); + if (TestVehicleBuildProbability(v, v->engine_type, BuildProbabilityType::Reversed)) SetBit(v->flags, VRF_REVERSE_DIRECTION); v->UpdatePosition(); if (rvi->railveh_type == RAILVEH_MULTIHEAD) {