From 2183fd4dabe72bd96b264bf8cdb3a2a8be625cf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20=C5=A0efl?= Date: Sun, 15 Aug 2021 11:17:05 +0200 Subject: [PATCH] Feature: [NewGRF] Maximum curve speed modifier for rail vehicles (#9346) --- src/engine_type.h | 1 + src/newgrf.cpp | 4 ++++ src/newgrf_engine.cpp | 15 +++++++++++---- src/newgrf_engine.h | 4 ++-- src/newgrf_properties.h | 1 + src/table/engines.h | 2 +- src/train.h | 10 ++++++++++ src/train_cmd.cpp | 8 ++++++++ 8 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/engine_type.h b/src/engine_type.h index 83f8dc307e..f0b6ea5450 100644 --- a/src/engine_type.h +++ b/src/engine_type.h @@ -59,6 +59,7 @@ struct RailVehicleInfo { byte tractive_effort; ///< Tractive effort coefficient byte air_drag; ///< Coefficient of air drag byte user_def_data; ///< Property 0x25: "User-defined bit mask" Used only for (very few) NewGRF vehicles + int16 curve_speed_mod; ///< Modifier to maximum speed in curves (fixed-point binary with 8 fractional bits) }; /** Information about a ship vehicle. */ diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 7c7d55dea7..8d2f5f9f90 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -1331,6 +1331,10 @@ static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop break; } + case PROP_TRAIN_CURVE_SPEED_MOD: // 0x2E Curve speed modifier + rvi->curve_speed_mod = buf->ReadWord(); + break; + default: ret = CommonVehicleChangeInfo(ei, prop, buf); break; diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index fa26f7b68f..e574102247 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -1177,16 +1177,23 @@ uint16 GetVehicleCallbackParent(CallbackID callback, uint32 param1, uint32 param /* Callback 36 handlers */ -uint GetVehicleProperty(const Vehicle *v, PropertyID property, uint orig_value) +int GetVehicleProperty(const Vehicle *v, PropertyID property, int orig_value, bool is_signed) { - return GetEngineProperty(v->engine_type, property, orig_value, v); + return GetEngineProperty(v->engine_type, property, orig_value, v, is_signed); } -uint GetEngineProperty(EngineID engine, PropertyID property, uint orig_value, const Vehicle *v) +int GetEngineProperty(EngineID engine, PropertyID property, int orig_value, const Vehicle *v, bool is_signed) { uint16 callback = GetVehicleCallback(CBID_VEHICLE_MODIFY_PROPERTY, property, 0, engine, v); - if (callback != CALLBACK_FAILED) return callback; + if (callback != CALLBACK_FAILED) { + if (is_signed) { + /* Sign extend 15 bit integer */ + return static_cast(callback << 1) >> 1; + } else { + return callback; + } + } return orig_value; } diff --git a/src/newgrf_engine.h b/src/newgrf_engine.h index 90d755d3c4..f63134d9f6 100644 --- a/src/newgrf_engine.h +++ b/src/newgrf_engine.h @@ -100,8 +100,8 @@ bool UsesWagonOverride(const Vehicle *v); /* Handler to Evaluate callback 36. If the callback fails (i.e. most of the * time) orig_value is returned */ -uint GetVehicleProperty(const Vehicle *v, PropertyID property, uint orig_value); -uint GetEngineProperty(EngineID engine, PropertyID property, uint orig_value, const Vehicle *v = nullptr); +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 VehicleTrigger { VEHICLE_TRIGGER_NEW_CARGO = 0x01, diff --git a/src/newgrf_properties.h b/src/newgrf_properties.h index 835a873847..a33e02f165 100644 --- a/src/newgrf_properties.h +++ b/src/newgrf_properties.h @@ -28,6 +28,7 @@ enum PropertyID { PROP_TRAIN_SHORTEN_FACTOR = 0x21, ///< Shorter vehicles PROP_TRAIN_USER_DATA = 0x25, ///< User defined data for vehicle variable 0x42 PROP_TRAIN_CARGO_AGE_PERIOD = 0x2B, ///< Number of ticks before carried cargo is aged + PROP_TRAIN_CURVE_SPEED_MOD = 0x2E, ///< Modifier to maximum speed in curves PROP_ROADVEH_RUNNING_COST_FACTOR = 0x09, ///< Yearly runningcost PROP_ROADVEH_CARGO_CAPACITY = 0x0F, ///< Capacity diff --git a/src/table/engines.h b/src/table/engines.h index f6ce10bf13..ab6ba77467 100644 --- a/src/table/engines.h +++ b/src/table/engines.h @@ -386,7 +386,7 @@ static const EngineInfo _orig_engine_info[] = { * Tractive effort coefficient by default is the same as TTDPatch, 0.30*256=76 * Air drag value depends on the top speed of the vehicle. */ -#define RVI(a, b, c, d, e, f, g, h, i, j, k) { a, b, c, j, d, e, f, g, h, k, i, 0, 0, 0, VE_DEFAULT, 0, 76, 0, 0 } +#define RVI(a, b, c, d, e, f, g, h, i, j, k) { a, b, c, j, d, e, f, g, h, k, i, 0, 0, 0, VE_DEFAULT, 0, 76, 0, 0, 0 } #define M RAILVEH_MULTIHEAD #define W RAILVEH_WAGON #define G RAILVEH_SINGLEHEAD diff --git a/src/train.h b/src/train.h index af638c283d..0b7b7be5bf 100644 --- a/src/train.h +++ b/src/train.h @@ -72,6 +72,7 @@ struct TrainCache { /* cached values, recalculated on load and each time a vehicle is added to/removed from the consist. */ bool cached_tilt; ///< train can tilt; feature provides a bonus in curves + int cached_curve_speed_mod; ///< curve speed modifier of the entire train byte user_def_data; ///< Cached property 0x25. Can be set by Callback 0x36. @@ -312,6 +313,15 @@ protected: // These functions should not be called outside acceleration code. return GetRailTypeInfo(GetRailType(this->tile))->max_speed; } + /** + * Returns the curve speed modifier of this vehicle. + * @return Current curve speed modifier, in fixed-point binary representation with 8 fractional bits. + */ + inline int GetCurveSpeedModifier() const + { + return GetVehicleProperty(this, PROP_TRAIN_CURVE_SPEED_MOD, RailVehInfo(this->engine_type)->curve_speed_mod, true); + } + /** * Checks if the vehicle is at a tile that can be sloped. * @return True if the tile can be sloped. diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 17e298c33d..1498a5fad5 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -115,6 +115,7 @@ void Train::ConsistChanged(ConsistChangeFlags allowed_changes) this->compatible_railtypes = RAILTYPES_NONE; bool train_can_tilt = true; + int min_curve_speed_mod = INT_MAX; for (Train *u = this; u != nullptr; u = u->Next()) { const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type); @@ -146,6 +147,7 @@ void Train::ConsistChanged(ConsistChangeFlags allowed_changes) const RailVehicleInfo *rvi_u = &e_u->u.rail; if (!HasBit(e_u->info.misc_flags, EF_RAIL_TILTS)) train_can_tilt = false; + min_curve_speed_mod = std::min(min_curve_speed_mod, u->GetCurveSpeedModifier()); /* Cache wagon override sprite group. nullptr is returned if there is none */ u->tcache.cached_override = GetWagonOverrideSpriteSet(u->engine_type, u->cargo_type, u->gcache.first_engine); @@ -229,6 +231,7 @@ void Train::ConsistChanged(ConsistChangeFlags allowed_changes) /* store consist weight/max speed in cache */ this->vcache.cached_max_speed = max_speed; this->tcache.cached_tilt = train_can_tilt; + this->tcache.cached_curve_speed_mod = min_curve_speed_mod; this->tcache.cached_max_curve_speed = this->GetCurveSpeedLimit(); /* recalculate cached weights and power too (we do this *after* the rest, so it is known which wagons are powered and need extra weight added) */ @@ -357,6 +360,11 @@ int Train::GetCurveSpeedLimit() const /* Apply max_speed bonus of 20% for a tilting train */ max_speed += max_speed / 5; } + + /* Apply max_speed modifier (cached value is fixed-point binary with 8 fractional bits) + * and clamp the result to an acceptable range. */ + max_speed += (max_speed * this->tcache.cached_curve_speed_mod) >> 8; + max_speed = Clamp(max_speed, 2, absolute_max_speed); } return max_speed;