Changeset - r27050:d85c65824c1e
[Not reviewed]
master
0 17 0
PeterN - 14 months ago 2023-04-08 16:26:13
peter1138@openttd.org
Feature: Separate rail/road and sea/air velocity units, and add knots. (#10594)

This is achieved by packing vehicle type along with the velocity so that
the string system can decode and pick the appropriate unit.
17 files changed with 117 insertions and 60 deletions:
0 comments (0 inline, 0 general)
src/bridge_gui.cpp
Show inline comments
 
@@ -135,13 +135,13 @@ private:
 
	 * @param bridge_data the bridge to get the StringID of.
 
	 * @return the StringID.
 
	 */
 
	StringID GetBridgeSelectString(const BuildBridgeData &bridge_data) const
 
	{
 
		SetDParam(0, bridge_data.spec->material);
 
		SetDParam(1, bridge_data.spec->speed);
 
		SetDParam(1, PackVelocity(bridge_data.spec->speed, static_cast<VehicleType>(this->transport_type)));
 
		SetDParam(2, bridge_data.cost);
 
		/* If the bridge has no meaningful speed limit, don't display it. */
 
		if (bridge_data.spec->speed == UINT16_MAX) {
 
			return _game_mode == GM_EDITOR ? STR_SELECT_BRIDGE_INFO_NAME : STR_SELECT_BRIDGE_INFO_NAME_COST;
 
		}
 
		return _game_mode == GM_EDITOR ? STR_SELECT_BRIDGE_INFO_NAME_MAX_SPEED : STR_SELECT_BRIDGE_INFO_NAME_MAX_SPEED_COST;
src/build_vehicle_gui.cpp
Show inline comments
 
@@ -608,13 +608,13 @@ static int DrawRailWagonPurchaseInfo(int
 
	y += FONT_HEIGHT_NORMAL;
 

	
 
	/* Wagon speed limit, displayed if above zero */
 
	if (_settings_game.vehicle.wagon_speed_limits) {
 
		uint max_speed = e->GetDisplayMaxSpeed();
 
		if (max_speed > 0) {
 
			SetDParam(0, max_speed);
 
			SetDParam(0, PackVelocity(max_speed, e->type));
 
			DrawString(left, right, y, STR_PURCHASE_INFO_SPEED);
 
			y += FONT_HEIGHT_NORMAL;
 
		}
 
	}
 

	
 
	/* Running cost */
 
@@ -643,13 +643,13 @@ static int DrawRailEnginePurchaseInfo(in
 
		SetDParam(1, e->GetDisplayWeight());
 
		DrawString(left, right, y, STR_PURCHASE_INFO_COST_WEIGHT);
 
	}
 
	y += FONT_HEIGHT_NORMAL;
 

	
 
	/* Max speed - Engine power */
 
	SetDParam(0, e->GetDisplayMaxSpeed());
 
	SetDParam(0, PackVelocity(e->GetDisplayMaxSpeed(), e->type));
 
	SetDParam(1, e->GetPower());
 
	DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_POWER);
 
	y += FONT_HEIGHT_NORMAL;
 

	
 
	/* Max tractive effort - not applicable if old acceleration or maglev */
 
	if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && GetRailTypeInfo(rvi->railtype)->acceleration_type != 2) {
 
@@ -698,13 +698,13 @@ static int DrawRoadVehPurchaseInfo(int l
 
		SetDParam(0, weight);
 
		SetDParam(1, GetCargoWeight(te.all_capacities, VEH_ROAD) + weight);
 
		DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT);
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		/* Max speed - Engine power */
 
		SetDParam(0, e->GetDisplayMaxSpeed());
 
		SetDParam(0, PackVelocity(e->GetDisplayMaxSpeed(), e->type));
 
		SetDParam(1, e->GetPower());
 
		DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_POWER);
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		/* Max tractive effort */
 
		SetDParam(0, e->GetDisplayMaxTractiveEffort());
 
@@ -712,17 +712,17 @@ static int DrawRoadVehPurchaseInfo(int l
 
		y += FONT_HEIGHT_NORMAL;
 
	} else {
 
		/* Purchase cost - Max speed */
 
		if (te.cost != 0) {
 
			SetDParam(0, e->GetCost() + te.cost);
 
			SetDParam(1, te.cost);
 
			SetDParam(2, e->GetDisplayMaxSpeed());
 
			SetDParam(2, PackVelocity(e->GetDisplayMaxSpeed(), e->type));
 
			DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_SPEED);
 
		} else {
 
			SetDParam(0, e->GetCost());
 
			SetDParam(1, e->GetDisplayMaxSpeed());
 
			SetDParam(1, PackVelocity(e->GetDisplayMaxSpeed(), e->type));
 
			DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
 
		}
 
		y += FONT_HEIGHT_NORMAL;
 
	}
 

	
 
	/* Running cost */
 
@@ -744,17 +744,17 @@ static int DrawShipPurchaseInfo(int left
 
	uint canal_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, false);
 

	
 
	if (ocean_speed == canal_speed) {
 
		if (te.cost != 0) {
 
			SetDParam(0, e->GetCost() + te.cost);
 
			SetDParam(1, te.cost);
 
			SetDParam(2, ocean_speed);
 
			SetDParam(2, PackVelocity(ocean_speed, e->type));
 
			DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_SPEED);
 
		} else {
 
			SetDParam(0, e->GetCost());
 
			SetDParam(1, ocean_speed);
 
			SetDParam(1, PackVelocity(ocean_speed, e->type));
 
			DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
 
		}
 
		y += FONT_HEIGHT_NORMAL;
 
	} else {
 
		if (te.cost != 0) {
 
			SetDParam(0, e->GetCost() + te.cost);
 
@@ -763,17 +763,17 @@ static int DrawShipPurchaseInfo(int left
 
		} else {
 
			SetDParam(0, e->GetCost());
 
			DrawString(left, right, y, STR_PURCHASE_INFO_COST);
 
		}
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		SetDParam(0, ocean_speed);
 
		SetDParam(0, PackVelocity(ocean_speed, e->type));
 
		DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_OCEAN);
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		SetDParam(0, canal_speed);
 
		SetDParam(0, PackVelocity(canal_speed, e->type));
 
		DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_CANAL);
 
		y += FONT_HEIGHT_NORMAL;
 
	}
 

	
 
	/* Cargo type + capacity */
 
	SetDParam(0, te.cargo);
 
@@ -804,17 +804,17 @@ static int DrawAircraftPurchaseInfo(int 
 
	const Engine *e = Engine::Get(engine_number);
 

	
 
	/* Purchase cost - Max speed */
 
	if (te.cost != 0) {
 
		SetDParam(0, e->GetCost() + te.cost);
 
		SetDParam(1, te.cost);
 
		SetDParam(2, e->GetDisplayMaxSpeed());
 
		SetDParam(2, PackVelocity(e->GetDisplayMaxSpeed(), e->type));
 
		DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_SPEED);
 
	} else {
 
		SetDParam(0, e->GetCost());
 
		SetDParam(1, e->GetDisplayMaxSpeed());
 
		SetDParam(1, PackVelocity(e->GetDisplayMaxSpeed(), e->type));
 
		DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
 
	}
 
	y += FONT_HEIGHT_NORMAL;
 

	
 
	/* Cargo capacity */
 
	if (te.mail_capacity > 0) {
src/engine_gui.cpp
Show inline comments
 
@@ -167,13 +167,13 @@ uint GetTotalCapacityOfArticulatedParts(
 
	return cap.GetSum<uint>();
 
}
 

	
 
static StringID GetTrainEngineInfoString(const Engine *e)
 
{
 
	SetDParam(0, e->GetCost());
 
	SetDParam(2, e->GetDisplayMaxSpeed());
 
	SetDParam(2, PackVelocity(e->GetDisplayMaxSpeed(), e->type));
 
	SetDParam(3, e->GetPower());
 
	SetDParam(1, e->GetDisplayWeight());
 
	SetDParam(7, e->GetDisplayMaxTractiveEffort());
 

	
 
	SetDParam(4, e->GetRunningCost());
 

	
 
@@ -193,13 +193,13 @@ static StringID GetAircraftEngineInfoStr
 
	uint16 mail_capacity;
 
	uint capacity = e->GetDisplayDefaultCapacity(&mail_capacity);
 
	uint16 range = e->GetRange();
 

	
 
	uint i = 0;
 
	SetDParam(i++, e->GetCost());
 
	SetDParam(i++, e->GetDisplayMaxSpeed());
 
	SetDParam(i++, PackVelocity(e->GetDisplayMaxSpeed(), e->type));
 
	SetDParam(i++, e->GetAircraftTypeText());
 
	if (range > 0) SetDParam(i++, range);
 
	SetDParam(i++, cargo);
 
	SetDParam(i++, capacity);
 

	
 
	if (mail_capacity > 0) {
 
@@ -214,25 +214,25 @@ static StringID GetAircraftEngineInfoStr
 
}
 

	
 
static StringID GetRoadVehEngineInfoString(const Engine *e)
 
{
 
	if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) {
 
		SetDParam(0, e->GetCost());
 
		SetDParam(1, e->GetDisplayMaxSpeed());
 
		SetDParam(1, PackVelocity(e->GetDisplayMaxSpeed(), e->type));
 
		uint capacity = GetTotalCapacityOfArticulatedParts(e->index);
 
		if (capacity != 0) {
 
			SetDParam(2, e->GetDefaultCargoType());
 
			SetDParam(3, capacity);
 
		} else {
 
			SetDParam(2, CT_INVALID);
 
		}
 
		SetDParam(4, e->GetRunningCost());
 
		return STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST;
 
	} else {
 
		SetDParam(0, e->GetCost());
 
		SetDParam(2, e->GetDisplayMaxSpeed());
 
		SetDParam(2, PackVelocity(e->GetDisplayMaxSpeed(), e->type));
 
		SetDParam(3, e->GetPower());
 
		SetDParam(1, e->GetDisplayWeight());
 
		SetDParam(7, e->GetDisplayMaxTractiveEffort());
 

	
 
		SetDParam(4, e->GetRunningCost());
 

	
 
@@ -247,13 +247,13 @@ static StringID GetRoadVehEngineInfoStri
 
	}
 
}
 

	
 
static StringID GetShipEngineInfoString(const Engine *e)
 
{
 
	SetDParam(0, e->GetCost());
 
	SetDParam(1, e->GetDisplayMaxSpeed());
 
	SetDParam(1, PackVelocity(e->GetDisplayMaxSpeed(), e->type));
 
	SetDParam(2, e->GetDefaultCargoType());
 
	SetDParam(3, e->GetDisplayDefaultCapacity());
 
	SetDParam(4, e->GetRunningCost());
 
	return STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST;
 
}
 

	
src/lang/english.txt
Show inline comments
 
@@ -192,12 +192,13 @@ STR_COLOUR_RANDOM                       
 

	
 
# Units used in OpenTTD
 
STR_UNITS_VELOCITY_IMPERIAL                                     :{COMMA}{NBSP}mph
 
STR_UNITS_VELOCITY_METRIC                                       :{COMMA}{NBSP}km/h
 
STR_UNITS_VELOCITY_SI                                           :{COMMA}{NBSP}m/s
 
STR_UNITS_VELOCITY_GAMEUNITS                                    :{DECIMAL}{NBSP}tiles/day
 
STR_UNITS_VELOCITY_KNOTS                                        :{COMMA}{NBSP}knots
 

	
 
STR_UNITS_POWER_IMPERIAL                                        :{COMMA}{NBSP}hp
 
STR_UNITS_POWER_METRIC                                          :{COMMA}{NBSP}hp
 
STR_UNITS_POWER_SI                                              :{COMMA}{NBSP}kW
 

	
 
STR_UNITS_POWER_IMPERIAL_TO_WEIGHT_IMPERIAL                     :{DECIMAL}{NBSP}hp/t
 
@@ -1948,19 +1949,21 @@ STR_CONFIG_SETTING_DEMAND_DISTANCE_HELPT
 
STR_CONFIG_SETTING_DEMAND_SIZE                                  :Amount of returning cargo for symmetric mode: {STRING2}
 
STR_CONFIG_SETTING_DEMAND_SIZE_HELPTEXT                         :Setting this to less than 100% makes the symmetric distribution behave more like the asymmetric one. Less cargo will be forcibly sent back if a certain amount is sent to a station. If you set it to 0% the symmetric distribution behaves just like the asymmetric one.
 

	
 
STR_CONFIG_SETTING_SHORT_PATH_SATURATION                        :Saturation of short paths before using high-capacity paths: {STRING2}
 
STR_CONFIG_SETTING_SHORT_PATH_SATURATION_HELPTEXT               :Frequently there are multiple paths between two given stations. Cargodist will saturate the shortest path first, then use the second shortest path until that is saturated and so on. Saturation is determined by an estimation of capacity and planned usage. Once it has saturated all paths, if there is still demand left, it will overload all paths, prefering the ones with high capacity. Most of the time the algorithm will not estimate the capacity accurately, though. This setting allows you to specify up to which percentage a shorter path must be saturated in the first pass before choosing the next longer one. Set it to less than 100% to avoid overcrowded stations in case of overestimated capacity.
 

	
 
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY                  :Speed units: {STRING2}
 
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY                  :Speed units (land): {STRING2}
 
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_NAUTICAL         :Speed units (nautical): {STRING2}
 
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT         :Whenever a speed is shown in the user interface, show it in the selected units
 
###length 4
 
###length 5
 
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL         :Imperial (mph)
 
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_METRIC           :Metric (km/h)
 
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_SI               :SI (m/s)
 
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_GAMEUNITS        :Game units (tiles/day)
 
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_KNOTS            :Knots
 

	
 
STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER                     :Vehicle power units: {STRING2}
 
STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_HELPTEXT            :Whenever a vehicle's power is shown in the user interface, show it in the selected units
 
###length 3
 
STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_IMPERIAL            :Imperial (hp)
 
STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_METRIC              :Metric (hp)
src/misc_gui.cpp
Show inline comments
 
@@ -264,37 +264,37 @@ public:
 
			SetDParam(0, td.railtype);
 
			this->landinfo_data.push_back(GetString(STR_LANG_AREA_INFORMATION_RAIL_TYPE));
 
		}
 

	
 
		/* Rail speed limit */
 
		if (td.rail_speed != 0) {
 
			SetDParam(0, td.rail_speed);
 
			SetDParam(0, PackVelocity(td.rail_speed, VEH_TRAIN));
 
			this->landinfo_data.push_back(GetString(STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT));
 
		}
 

	
 
		/* Road type name */
 
		if (td.roadtype != STR_NULL) {
 
			SetDParam(0, td.roadtype);
 
			this->landinfo_data.push_back(GetString(STR_LANG_AREA_INFORMATION_ROAD_TYPE));
 
		}
 

	
 
		/* Road speed limit */
 
		if (td.road_speed != 0) {
 
			SetDParam(0, td.road_speed);
 
			SetDParam(0, PackVelocity(td.road_speed, VEH_ROAD));
 
			this->landinfo_data.push_back(GetString(STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT));
 
		}
 

	
 
		/* Tram type name */
 
		if (td.tramtype != STR_NULL) {
 
			SetDParam(0, td.tramtype);
 
			this->landinfo_data.push_back(GetString(STR_LANG_AREA_INFORMATION_TRAM_TYPE));
 
		}
 

	
 
		/* Tram speed limit */
 
		if (td.tram_speed != 0) {
 
			SetDParam(0, td.tram_speed);
 
			SetDParam(0, PackVelocity(td.tram_speed, VEH_ROAD));
 
			this->landinfo_data.push_back(GetString(STR_LANG_AREA_INFORMATION_TRAM_SPEED_LIMIT));
 
		}
 

	
 
		/* NewGRF name */
 
		if (td.grf != nullptr) {
 
			SetDParamStr(0, td.grf);
src/order_gui.cpp
Show inline comments
 
@@ -174,14 +174,14 @@ static const StringID _order_conditional
 
	STR_ORDER_CONDITIONAL_COMPARATOR_MORE_EQUALS,
 
	STR_ORDER_CONDITIONAL_COMPARATOR_IS_TRUE,
 
	STR_ORDER_CONDITIONAL_COMPARATOR_IS_FALSE,
 
	INVALID_STRING_ID,
 
};
 

	
 
extern uint ConvertSpeedToDisplaySpeed(uint speed);
 
extern uint ConvertDisplaySpeedToSpeed(uint speed);
 
extern uint ConvertSpeedToDisplaySpeed(uint speed, VehicleType type);
 
extern uint ConvertDisplaySpeedToSpeed(uint speed, VehicleType type);
 

	
 
static const StringID _order_depot_action_dropdown[] = {
 
	STR_ORDER_DROP_GO_ALWAYS_DEPOT,
 
	STR_ORDER_DROP_SERVICE_DEPOT,
 
	STR_ORDER_DROP_HALT_DEPOT,
 
	INVALID_STRING_ID
 
@@ -342,13 +342,13 @@ void DrawOrderString(const Vehicle *v, c
 
				OrderConditionComparator occ = order->GetConditionComparator();
 
				SetDParam(0, (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) ? STR_ORDER_CONDITIONAL_TRUE_FALSE : STR_ORDER_CONDITIONAL_NUM);
 
				SetDParam(2, STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE + order->GetConditionVariable());
 
				SetDParam(3, STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS + occ);
 

	
 
				uint value = order->GetConditionValue();
 
				if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value);
 
				if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value, v->type);
 
				SetDParam(4, value);
 
			}
 

	
 
			if (timetable && order->GetWaitTime() > 0) {
 
				SetDParam(5, order->IsWaitTimetabled() ? STR_TIMETABLE_AND_TRAVEL_FOR : STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED);
 
				SetTimetableParams(6, 7, order->GetWaitTime());
 
@@ -1146,13 +1146,13 @@ public:
 
			case WID_O_COND_VALUE: {
 
				VehicleOrderID sel = this->OrderGetSel();
 
				const Order *order = this->vehicle->GetOrder(sel);
 

	
 
				if (order != nullptr && order->IsType(OT_CONDITIONAL)) {
 
					uint value = order->GetConditionValue();
 
					if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value);
 
					if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value, this->vehicle->type);
 
					SetDParam(0, value);
 
				}
 
				break;
 
			}
 

	
 
			case WID_O_CAPTION:
 
@@ -1314,13 +1314,13 @@ public:
 
			}
 

	
 
			case WID_O_COND_VALUE: {
 
				const Order *order = this->vehicle->GetOrder(this->OrderGetSel());
 
				assert(order != nullptr);
 
				uint value = order->GetConditionValue();
 
				if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value);
 
				if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value, this->vehicle->type);
 
				SetDParam(0, value);
 
				ShowQueryString(STR_JUST_INT, STR_ORDER_CONDITIONAL_VALUE_CAPT, 5, this, CS_NUMERAL, QSF_NONE);
 
				break;
 
			}
 

	
 
			case WID_O_SHARED_ORDER_LIST:
 
@@ -1334,13 +1334,13 @@ public:
 
		if (!StrEmpty(str)) {
 
			VehicleOrderID sel = this->OrderGetSel();
 
			uint value = atoi(str);
 

	
 
			switch (this->vehicle->GetOrder(sel)->GetConditionVariable()) {
 
				case OCV_MAX_SPEED:
 
					value = ConvertDisplaySpeedToSpeed(value);
 
					value = ConvertDisplaySpeedToSpeed(value, this->vehicle->type);
 
					break;
 

	
 
				case OCV_RELIABILITY:
 
				case OCV_LOAD_PERCENTAGE:
 
					value = Clamp(value, 0, 100);
 
					break;
src/rail_gui.cpp
Show inline comments
 
@@ -490,13 +490,13 @@ struct BuildRailToolbarWindow : Window {
 
	{
 
		if (widget == WID_RAT_CAPTION) {
 
			const RailtypeInfo *rti = GetRailTypeInfo(this->railtype);
 
			if (rti->max_speed > 0) {
 
				SetDParam(0, STR_TOOLBAR_RAILTYPE_VELOCITY);
 
				SetDParam(1, rti->strings.toolbar_caption);
 
				SetDParam(2, rti->max_speed);
 
				SetDParam(2, PackVelocity(rti->max_speed, VEH_TRAIN));
 
			} else {
 
				SetDParam(0, rti->strings.toolbar_caption);
 
			}
 
		}
 
	}
 

	
src/road_gui.cpp
Show inline comments
 
@@ -408,13 +408,13 @@ struct BuildRoadToolbarWindow : Window {
 
	void SetStringParameters(int widget) const override
 
	{
 
		if (widget == WID_ROT_CAPTION) {
 
			if (this->rti->max_speed > 0) {
 
				SetDParam(0, STR_TOOLBAR_RAILTYPE_VELOCITY);
 
				SetDParam(1, this->rti->strings.toolbar_caption);
 
				SetDParam(2, this->rti->max_speed / 2);
 
				SetDParam(2, PackVelocity(this->rti->max_speed / 2, VEH_ROAD));
 
			} else {
 
				SetDParam(0, this->rti->strings.toolbar_caption);
 
			}
 
		}
 
	}
 

	
src/saveload/afterload.cpp
Show inline comments
 
@@ -2874,12 +2874,17 @@ bool AfterLoadGame()
 
		_settings_game.locale.units_weight   = Clamp(_old_units, 1, 2);
 
		_settings_game.locale.units_volume   = Clamp(_old_units, 1, 2);
 
		_settings_game.locale.units_force    = 2;
 
		_settings_game.locale.units_height   = Clamp(_old_units, 0, 2);
 
	}
 

	
 
	if (IsSavegameVersionBefore(SLV_VELOCITY_NAUTICAL)) {
 
		/* Match nautical velocity with land velocity units. */
 
		_settings_game.locale.units_velocity_nautical = _settings_game.locale.units_velocity;
 
	}
 

	
 
	if (IsSavegameVersionBefore(SLV_186)) {
 
		/* Move ObjectType from map to pool */
 
		for (auto t : Map::Iterate()) {
 
			if (IsTileType(t, MP_OBJECT)) {
 
				Object *o = Object::Get(t.m2());
 
				o->type = t.m5();
src/saveload/saveload.h
Show inline comments
 
@@ -344,12 +344,14 @@ enum SaveLoadVersion : uint16 {
 
	SLV_U64_TICK_COUNTER,                   ///< 300  PR#10035 Make _tick_counter 64bit to avoid wrapping.
 
	SLV_LAST_LOADING_TICK,                  ///< 301  PR#9693 Store tick of last loading for vehicles.
 
	SLV_MULTITRACK_LEVEL_CROSSINGS,         ///< 302  PR#9931 v13.0  Multi-track level crossings.
 
	SLV_NEWGRF_ROAD_STOPS,                  ///< 303  PR#10144 NewGRF road stops.
 
	SLV_LINKGRAPH_EDGES,                    ///< 304  PR#10314 Explicitly store link graph edges destination, PR#10471 int64 instead of uint64 league rating
 

	
 
	SLV_VELOCITY_NAUTICAL,                  ///< 305  PR#10594 Separation of land and nautical velocity (knots!)
 

	
 
	SL_MAX_VERSION,                         ///< Highest possible saveload version
 
};
 

	
 
/** Save or load result codes. */
 
enum SaveOrLoadResult {
 
	SL_OK     = 0, ///< completed successfully
src/settings_gui.cpp
Show inline comments
 
@@ -1597,12 +1597,13 @@ static SettingsContainer &GetSettingsTre
 
		/* Build up the dynamic settings-array only once per OpenTTD session */
 
		main = new SettingsContainer();
 

	
 
		SettingsPage *localisation = main->Add(new SettingsPage(STR_CONFIG_SETTING_LOCALISATION));
 
		{
 
			localisation->Add(new SettingEntry("locale.units_velocity"));
 
			localisation->Add(new SettingEntry("locale.units_velocity_nautical"));
 
			localisation->Add(new SettingEntry("locale.units_power"));
 
			localisation->Add(new SettingEntry("locale.units_weight"));
 
			localisation->Add(new SettingEntry("locale.units_volume"));
 
			localisation->Add(new SettingEntry("locale.units_force"));
 
			localisation->Add(new SettingEntry("locale.units_height"));
 
			localisation->Add(new SettingEntry("gui.date_format_in_default_names"));
src/settings_type.h
Show inline comments
 
@@ -231,13 +231,14 @@ struct MusicSettings {
 
	bool shuffle;      ///< Whether to shuffle the music
 
};
 

	
 
/** Settings related to currency/unit systems. */
 
struct LocaleSettings {
 
	byte        currency;                         ///< currency we currently use
 
	byte        units_velocity;                   ///< unit system for velocity
 
	byte        units_velocity;                   ///< unit system for velocity of trains and road vehicles
 
	byte        units_velocity_nautical;          ///< unit system for velocity of ships and aircraft
 
	byte        units_power;                      ///< unit system for power
 
	byte        units_weight;                     ///< unit system for weight
 
	byte        units_volume;                     ///< unit system for volume
 
	byte        units_force;                      ///< unit system for force
 
	byte        units_height;                     ///< unit system for height
 
	std::string digit_group_separator;            ///< thousand separator for non-currencies
src/strings.cpp
Show inline comments
 
@@ -700,16 +700,17 @@ struct UnitsLong {
 
	StringID s;       ///< String for the short variant of the unit
 
	StringID l;       ///< String for the long variant of the unit
 
};
 

	
 
/** Unit conversions for velocity. */
 
static const Units _units_velocity[] = {
 
	{ {    1,  0}, STR_UNITS_VELOCITY_IMPERIAL,     0 },
 
	{ {  103,  6}, STR_UNITS_VELOCITY_METRIC,       0 },
 
	{ { 1831, 12}, STR_UNITS_VELOCITY_SI,           0 },
 
	{ {37888, 16}, STR_UNITS_VELOCITY_GAMEUNITS,    1 },
 
	{ {       1,  0}, STR_UNITS_VELOCITY_IMPERIAL,     0 },
 
	{ {     103,  6}, STR_UNITS_VELOCITY_METRIC,       0 },
 
	{ {    1831, 12}, STR_UNITS_VELOCITY_SI,           0 },
 
	{ {   37888, 16}, STR_UNITS_VELOCITY_GAMEUNITS,    1 },
 
	{ { 7289499, 23}, STR_UNITS_VELOCITY_KNOTS,        0 },
 
};
 

	
 
/** Unit conversions for power. */
 
static const Units _units_power[] = {
 
	{ {   1,  0}, STR_UNITS_POWER_IMPERIAL, 0 },
 
	{ {4153, 12}, STR_UNITS_POWER_METRIC,   0 },
 
@@ -755,52 +756,64 @@ static const Units _units_height[] = {
 
	{ {   3,  0}, STR_UNITS_HEIGHT_IMPERIAL, 0 }, // "Wrong" conversion factor for more nicer GUI values
 
	{ {   1,  0}, STR_UNITS_HEIGHT_METRIC,   0 },
 
	{ {   1,  0}, STR_UNITS_HEIGHT_SI,       0 },
 
};
 

	
 
/**
 
 * Get index for velocity conversion units for a vehicle type.
 
 * @param type VehicleType to convert velocity for.
 
 * @return Index within velocity conversion units for vehicle type.
 
 */
 
static byte GetVelocityUnits(VehicleType type)
 
{
 
	if (type == VEH_SHIP || type == VEH_AIRCRAFT) return _settings_game.locale.units_velocity_nautical;
 

	
 
	return _settings_game.locale.units_velocity;
 
}
 

	
 
/**
 
 * Convert the given (internal) speed to the display speed.
 
 * @param speed the speed to convert
 
 * @return the converted speed.
 
 */
 
uint ConvertSpeedToDisplaySpeed(uint speed)
 
uint ConvertSpeedToDisplaySpeed(uint speed, VehicleType type)
 
{
 
	/* For historical reasons we don't want to mess with the
 
	 * conversion for speed. So, don't round it and keep the
 
	 * original conversion factors instead of the real ones. */
 
	return _units_velocity[_settings_game.locale.units_velocity].c.ToDisplay(speed, false);
 
	return _units_velocity[GetVelocityUnits(type)].c.ToDisplay(speed, false);
 
}
 

	
 
/**
 
 * Convert the given display speed to the (internal) speed.
 
 * @param speed the speed to convert
 
 * @return the converted speed.
 
 */
 
uint ConvertDisplaySpeedToSpeed(uint speed)
 
uint ConvertDisplaySpeedToSpeed(uint speed, VehicleType type)
 
{
 
	return _units_velocity[_settings_game.locale.units_velocity].c.FromDisplay(speed);
 
	return _units_velocity[GetVelocityUnits(type)].c.FromDisplay(speed);
 
}
 

	
 
/**
 
 * Convert the given km/h-ish speed to the display speed.
 
 * @param speed the speed to convert
 
 * @return the converted speed.
 
 */
 
uint ConvertKmhishSpeedToDisplaySpeed(uint speed)
 
uint ConvertKmhishSpeedToDisplaySpeed(uint speed, VehicleType type)
 
{
 
	return _units_velocity[_settings_game.locale.units_velocity].c.ToDisplay(speed * 10, false) / 16;
 
	return _units_velocity[GetVelocityUnits(type)].c.ToDisplay(speed * 10, false) / 16;
 
}
 

	
 
/**
 
 * Convert the given display speed to the km/h-ish speed.
 
 * @param speed the speed to convert
 
 * @return the converted speed.
 
 */
 
uint ConvertDisplaySpeedToKmhishSpeed(uint speed)
 
uint ConvertDisplaySpeedToKmhishSpeed(uint speed, VehicleType type)
 
{
 
	return _units_velocity[_settings_game.locale.units_velocity].c.FromDisplay(speed * 16, true, 10);
 
	return _units_velocity[GetVelocityUnits(type)].c.FromDisplay(speed * 16, true, 10);
 
}
 

	
 
static std::vector<const char *> _game_script_raw_strings;
 

	
 
/**
 
 * Parse most format codes within a string and write the result to a buffer.
 
@@ -1288,17 +1301,21 @@ static char *FormatString(char *buff, co
 
				StringParameters tmp_params(args_array);
 
				buff = FormatString(buff, GetStringPtr(x.s), &tmp_params, last);
 
				break;
 
			}
 

	
 
			case SCC_VELOCITY: { // {VELOCITY}
 
				assert(_settings_game.locale.units_velocity < lengthof(_units_velocity));
 
				unsigned int decimal_places = _units_velocity[_settings_game.locale.units_velocity].decimal_places;
 
				uint64 args_array[] = {ConvertKmhishSpeedToDisplaySpeed(args->GetInt64(SCC_VELOCITY)), decimal_places};
 
				int64 arg = args->GetInt64(SCC_VELOCITY);
 
				// Unpack vehicle type from packed argument to get desired units.
 
				VehicleType vt = static_cast<VehicleType>(GB(arg, 56, 8));
 
				byte units = GetVelocityUnits(vt);
 
				assert(units < lengthof(_units_velocity));
 
				unsigned int decimal_places = _units_velocity[units].decimal_places;
 
				uint64 args_array[] = {ConvertKmhishSpeedToDisplaySpeed(GB(arg, 0, 56), vt), decimal_places};
 
				StringParameters tmp_params(args_array, decimal_places ? 2 : 1, nullptr);
 
				buff = FormatString(buff, GetStringPtr(_units_velocity[_settings_game.locale.units_velocity].s), &tmp_params, last);
 
				buff = FormatString(buff, GetStringPtr(_units_velocity[units].s), &tmp_params, last);
 
				break;
 
			}
 

	
 
			case SCC_VOLUME_SHORT: { // {VOLUME_SHORT}
 
				assert(_settings_game.locale.units_volume < lengthof(_units_volume));
 
				int64 args_array[1] = {_units_volume[_settings_game.locale.units_volume].c.ToDisplay(args->GetInt64())};
src/strings_func.h
Show inline comments
 
@@ -11,12 +11,13 @@
 
#define STRINGS_FUNC_H
 

	
 
#include "strings_type.h"
 
#include "string_type.h"
 
#include "gfx_type.h"
 
#include "core/bitmath_func.hpp"
 
#include "vehicle_type.h"
 

	
 
/**
 
 * Extract the StringTab from a StringID.
 
 * @param str String identifier
 
 * @return StringTab from \a str
 
 */
 
@@ -171,14 +172,27 @@ extern StringParameters _global_string_p
 

	
 
char *GetString(char *buffr, StringID string, const char *last);
 
std::string GetString(StringID string);
 
char *GetStringWithArgs(char *buffr, StringID string, StringParameters *args, const char *last, uint case_index = 0, bool game_script = false);
 
const char *GetStringPtr(StringID string);
 

	
 
uint ConvertKmhishSpeedToDisplaySpeed(uint speed);
 
uint ConvertDisplaySpeedToKmhishSpeed(uint speed);
 
uint ConvertKmhishSpeedToDisplaySpeed(uint speed, VehicleType type);
 
uint ConvertDisplaySpeedToKmhishSpeed(uint speed, VehicleType type);
 

	
 
/**
 
 * Pack velocity and vehicle type for use with SCC_VELOCITY string parameter.
 
 * @param speed Display speed for parameter.
 
 * @param type Type of vehicle for parameter.
 
 * @return Bit-packed velocity and vehicle type, for use with SetDParam().
 
 */
 
static inline int64 PackVelocity(uint speed, VehicleType type)
 
{
 
	/* Vehicle type is a byte, so packed into the top 8 bits of the 64-bit
 
	 * parameter, although only values from 0-3 are relevant. */
 
	return speed | (static_cast<uint64>(type) << 56);
 
}
 

	
 
/**
 
 * Set a string parameter \a v at index \a n in a given array \a s.
 
 * @param s Array of string parameters.
 
 * @param n Index of the string parameter.
 
 * @param v Value of the string parameter.
src/table/settings/locale_settings.ini
Show inline comments
 
@@ -70,21 +70,35 @@ cat      = SC_BASIC
 
[SDT_OMANY]
 
var      = locale.units_velocity
 
type     = SLE_UINT8
 
from     = SLV_184
 
flags    = SF_NO_NETWORK_SYNC | SF_GUI_DROPDOWN
 
def      = 1
 
max      = 3
 
max      = 4
 
full     = _locale_units
 
post_cb  = [](auto) { MarkWholeScreenDirty(); }
 
cat      = SC_BASIC
 
str      = STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY
 
strhelp  = STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT
 
strval   = STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL
 

	
 
[SDT_OMANY]
 
var      = locale.units_velocity_nautical
 
type     = SLE_UINT8
 
from     = SLV_VELOCITY_NAUTICAL
 
flags    = SF_NO_NETWORK_SYNC | SF_GUI_DROPDOWN
 
def      = 1
 
max      = 4
 
full     = _locale_units
 
post_cb  = [](auto) { MarkWholeScreenDirty(); }
 
cat      = SC_BASIC
 
str      = STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_NAUTICAL
 
strhelp  = STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT
 
strval   = STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL
 

	
 
[SDT_OMANY]
 
var      = locale.units_power
 
type     = SLE_UINT8
 
from     = SLV_184
 
flags    = SF_NO_NETWORK_SYNC | SF_GUI_DROPDOWN
 
def      = 1
 
max      = 2
src/timetable_gui.cpp
Show inline comments
 
@@ -405,13 +405,13 @@ struct TimetableWindow : Window {
 
							}
 
						} else {
 
							SetTimetableParams(0, 1, order->GetTimetabledTravel());
 
							string = order->GetMaxSpeed() != UINT16_MAX ?
 
									STR_TIMETABLE_TRAVEL_FOR_SPEED : STR_TIMETABLE_TRAVEL_FOR;
 
						}
 
						SetDParam(2, order->GetMaxSpeed());
 
						SetDParam(2, PackVelocity(order->GetMaxSpeed(), v->type));
 

	
 
						DrawString(rtl ? tr.left : middle, rtl ? middle : tr.right, tr.top, string, colour);
 

	
 
						if (final_order) break;
 
					}
 

	
 
@@ -565,13 +565,13 @@ struct TimetableWindow : Window {
 
				if (real >= v->GetNumOrders()) real = 0;
 

	
 
				StringID current = STR_EMPTY;
 
				const Order *order = v->GetOrder(real);
 
				if (order != nullptr) {
 
					if (order->GetMaxSpeed() != UINT16_MAX) {
 
						SetDParam(0, ConvertKmhishSpeedToDisplaySpeed(order->GetMaxSpeed()));
 
						SetDParam(0, ConvertKmhishSpeedToDisplaySpeed(order->GetMaxSpeed(), v->type));
 
						current = STR_JUST_INT;
 
					}
 
				}
 

	
 
				this->query_is_speed_query = true;
 
				this->change_timetable_all = _ctrl_pressed && (order != nullptr);
 
@@ -625,13 +625,13 @@ struct TimetableWindow : Window {
 
		if (str == nullptr) return;
 

	
 
		const Vehicle *v = this->vehicle;
 

	
 
		uint64 val = StrEmpty(str) ? 0 : strtoul(str, nullptr, 10);
 
		if (this->query_is_speed_query) {
 
			val = ConvertDisplaySpeedToKmhishSpeed(val);
 
			val = ConvertDisplaySpeedToKmhishSpeed(val, v->type);
 
		} else {
 
			if (!_settings_client.gui.timetable_in_ticks) val *= DAY_TICKS;
 
		}
 

	
 
		auto [order_id, mtf] = PackTimetableArgs(v, this->sel_index, this->query_is_speed_query);
 

	
src/vehicle_gui.cpp
Show inline comments
 
@@ -2490,24 +2490,24 @@ struct VehicleDetailsWindow : Window {
 

	
 
				/* Draw max speed */
 
				StringID string;
 
				if (v->type == VEH_TRAIN ||
 
						(v->type == VEH_ROAD && _settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL)) {
 
					const GroundVehicleCache *gcache = v->GetGroundVehicleCache();
 
					SetDParam(2, v->GetDisplayMaxSpeed());
 
					SetDParam(2, PackVelocity(v->GetDisplayMaxSpeed(), v->type));
 
					SetDParam(1, gcache->cached_power);
 
					SetDParam(0, gcache->cached_weight);
 
					SetDParam(3, gcache->cached_max_te / 1000);
 
					if (v->type == VEH_TRAIN && (_settings_game.vehicle.train_acceleration_model == AM_ORIGINAL ||
 
							GetRailTypeInfo(Train::From(v)->railtype)->acceleration_type == 2)) {
 
						string = STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED;
 
					} else {
 
						string = STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE;
 
					}
 
				} else {
 
					SetDParam(0, v->GetDisplayMaxSpeed());
 
					SetDParam(0, PackVelocity(v->GetDisplayMaxSpeed(), v->type));
 
					if (v->type == VEH_AIRCRAFT) {
 
						SetDParam(1, v->GetEngine()->GetAircraftTypeText());
 
						if (Aircraft::From(v)->GetRange() > 0) {
 
							SetDParam(2, Aircraft::From(v)->GetRange());
 
							string = STR_VEHICLE_INFO_MAX_SPEED_TYPE_RANGE;
 
						} else {
 
@@ -2996,13 +2996,13 @@ public:
 
					if (Train::From(v)->gcache.cached_power == 0) {
 
						str = STR_VEHICLE_STATUS_TRAIN_NO_POWER;
 
					} else {
 
						str = STR_VEHICLE_STATUS_STOPPED;
 
					}
 
				} else {
 
					SetDParam(0, v->GetDisplaySpeed());
 
					SetDParam(0, PackVelocity(v->GetDisplaySpeed(), v->type));
 
					str = STR_VEHICLE_STATUS_TRAIN_STOPPING_VEL;
 
				}
 
			} else { // no train
 
				str = STR_VEHICLE_STATUS_STOPPED;
 
			}
 
		} else if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_TRAIN_STUCK) && !v->current_order.IsType(OT_LOADING)) {
 
@@ -3017,21 +3017,21 @@ public:
 
					text_colour = TC_ORANGE | TC_FORCED;
 
				}
 
			}
 
			switch (v->current_order.GetType()) {
 
				case OT_GOTO_STATION: {
 
					SetDParam(0, v->current_order.GetDestination());
 
					SetDParam(1, v->GetDisplaySpeed());
 
					SetDParam(1, PackVelocity(v->GetDisplaySpeed(), v->type));
 
					str = HasBit(v->vehicle_flags, VF_PATHFINDER_LOST) ? STR_VEHICLE_STATUS_CANNOT_REACH_STATION_VEL : STR_VEHICLE_STATUS_HEADING_FOR_STATION_VEL;
 
					break;
 
				}
 

	
 
				case OT_GOTO_DEPOT: {
 
					SetDParam(0, v->type);
 
					SetDParam(1, v->current_order.GetDestination());
 
					SetDParam(2, v->GetDisplaySpeed());
 
					SetDParam(2, PackVelocity(v->GetDisplaySpeed(), v->type));
 
					if (v->current_order.GetDestination() == INVALID_DEPOT) {
 
						/* This case *only* happens when multiple nearest depot orders
 
						 * follow each other (including an order list only one order: a
 
						 * nearest depot order) and there are no reachable depots.
 
						 * It is primarily to guard for the case that there is no
 
						 * depot with index 0, which would be used as fallback for
 
@@ -3050,26 +3050,26 @@ public:
 
					break;
 

	
 
				case OT_GOTO_WAYPOINT: {
 
					assert(v->type == VEH_TRAIN || v->type == VEH_SHIP);
 
					SetDParam(0, v->current_order.GetDestination());
 
					str = HasBit(v->vehicle_flags, VF_PATHFINDER_LOST) ? STR_VEHICLE_STATUS_CANNOT_REACH_WAYPOINT_VEL : STR_VEHICLE_STATUS_HEADING_FOR_WAYPOINT_VEL;
 
					SetDParam(1, v->GetDisplaySpeed());
 
					SetDParam(1, PackVelocity(v->GetDisplaySpeed(), v->type));
 
					break;
 
				}
 

	
 
				case OT_LEAVESTATION:
 
					if (v->type != VEH_AIRCRAFT) {
 
						str = STR_VEHICLE_STATUS_LEAVING;
 
						break;
 
					}
 
					FALLTHROUGH;
 
				default:
 
					if (v->GetNumManualOrders() == 0) {
 
						str = STR_VEHICLE_STATUS_NO_ORDERS_VEL;
 
						SetDParam(0, v->GetDisplaySpeed());
 
						SetDParam(0, PackVelocity(v->GetDisplaySpeed(), v->type));
 
					} else {
 
						str = STR_EMPTY;
 
					}
 
					break;
 
			}
 
		}
0 comments (0 inline, 0 general)