diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index d97e315781b96..050a4cc0bc2df 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -8,3 +8,5 @@ updates:
actions:
patterns:
- "*"
+ commit-message:
+ prefix: "Upgrade: "
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 0aaaea5e00dce..904ad6feed63f 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -21,6 +21,7 @@ jobs:
actions: read
contents: read
security-events: write
+ packages: read
steps:
- name: Checkout
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 668d73d70091f..fe1687dacac98 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -196,6 +196,29 @@ These include:
You may also want the guide to [compiling OpenTTD](./COMPILING.md).
+## Use of AI
+
+OpenTTD is a labour of love, created by people.
+
+Please refrain from submitting issues or pull requests that have been generated by an LLM or other fully-automated tools.
+Any submission that is in violation of this policy will be closed, and the submitter may be blocked from this repository without warning.
+
+If you submit an issue, you need to understand what your issue description is saying.
+You need to be able to answer questions about your bug report or feature request.
+Using an AI tool to _proofread_ your issue/comment text is acceptable. Using an AI tool to _write_ your issue/comment text is not.
+
+If you submit a pull request, you need to understand what every line of code you've changed does.
+If you can't explain why your PR is doing something, then do not submit it.
+Using an AI tool to generate entire lines of code is unacceptable.
+
+The rationale behind this policy is that automated contributions are a waste of the maintainers' time.
+Humans spend their time and brainpower reviewing every submission.
+Issues or pull requests generated by automation tools create an imbalance of effort between the submitter and the reviewer.
+Nobody learns anything when a maintainer reviews code written by an LLM.
+
+Additionally, AI-generated code conflicts with this project's license (GPL v2), since you cannot truly release code for use if you didn't author it yourself.
+
+
## Project goals
### What are the goals of the official branch?
diff --git a/cmake/scripts/Regression.cmake b/cmake/scripts/Regression.cmake
index a6833e2dd1471..e9ce5ea6f29c1 100644
--- a/cmake/scripts/Regression.cmake
+++ b/cmake/scripts/Regression.cmake
@@ -25,6 +25,10 @@ if(EDITBIN_EXECUTABLE)
execute_process(COMMAND ${EDITBIN_EXECUTABLE} /nologo /subsystem:console ${OPENTTD_EXECUTABLE})
endif()
+# Remove previous crash files
+file(GLOB CRASH_FILES "regression/crash*")
+file(REMOVE ${CRASH_FILES})
+
# Run the regression test
execute_process(COMMAND ${OPENTTD_EXECUTABLE}
-x
@@ -40,6 +44,13 @@ execute_process(COMMAND ${OPENTTD_EXECUTABLE}
OUTPUT_STRIP_TRAILING_WHITESPACE
)
+# Detect any crash
+file(GLOB CRASH_FILES "regression/crash*.log")
+if (CRASH_FILES)
+ file(READ ${CRASH_FILES} CRASH_LOG)
+ message(FATAL_ERROR "OpenTTD crashed: ${CRASH_LOG}")
+endif()
+
if(REGRESSION_OUTPUT)
message(FATAL_ERROR "Unexpected output: ${REGRESSION_OUTPUT}")
endif()
diff --git a/media/baseset/openttd.grf b/media/baseset/openttd.grf
index 620cc8ab981eb..4464c415f3a7c 100644
Binary files a/media/baseset/openttd.grf and b/media/baseset/openttd.grf differ
diff --git a/media/baseset/openttd.grf.hash b/media/baseset/openttd.grf.hash
index 5b07da7ff6484..f940ca5d62c7d 100644
--- a/media/baseset/openttd.grf.hash
+++ b/media/baseset/openttd.grf.hash
@@ -1 +1 @@
-eb8390a0569e66ec417c64ad254f9d05
+b779126d7cd1567eb09a0a7871f70a71
diff --git a/media/baseset/openttd/CMakeLists.txt b/media/baseset/openttd/CMakeLists.txt
index f2df774d1b4eb..a7d768326e666 100644
--- a/media/baseset/openttd/CMakeLists.txt
+++ b/media/baseset/openttd/CMakeLists.txt
@@ -10,6 +10,7 @@ if(GRFCODEC_FOUND)
${CMAKE_CURRENT_SOURCE_DIR}/airport_preview.nfo
${CMAKE_CURRENT_SOURCE_DIR}/aqueduct.nfo
${CMAKE_CURRENT_SOURCE_DIR}/autorail.nfo
+ ${CMAKE_CURRENT_SOURCE_DIR}/bridge_decks.nfo
${CMAKE_CURRENT_SOURCE_DIR}/canals.nfo
${CMAKE_CURRENT_SOURCE_DIR}/chars.nfo
${CMAKE_CURRENT_SOURCE_DIR}/elrails.nfo
@@ -31,6 +32,7 @@ if(GRFCODEC_FOUND)
${CMAKE_CURRENT_SOURCE_DIR}/airport_preview.png
${CMAKE_CURRENT_SOURCE_DIR}/aqueduct.png
${CMAKE_CURRENT_SOURCE_DIR}/autorail.png
+ ${CMAKE_CURRENT_SOURCE_DIR}/bridge_decks.png
${CMAKE_CURRENT_SOURCE_DIR}/canals.png
${CMAKE_CURRENT_SOURCE_DIR}/canal_locks.png
${CMAKE_CURRENT_SOURCE_DIR}/chars.png
diff --git a/media/baseset/openttd/bridge_decks.nfo b/media/baseset/openttd/bridge_decks.nfo
new file mode 100644
index 0000000000000..beced3f59fee1
--- /dev/null
+++ b/media/baseset/openttd/bridge_decks.nfo
@@ -0,0 +1,36 @@
+// This file is part of OpenTTD.
+// OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+// OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see .
+//
+ -1 * 0 0C "Bridge decks"
+ -1 * 3 05 1B 18
+
+ -1 sprites/bridge_decks.png 8bpp 96 16 64 31 -31 0 normal
+ -1 sprites/bridge_decks.png 8bpp 16 16 64 31 -31 0 normal
+ -1 sprites/bridge_decks.png 8bpp 176 16 64 39 -31 -8 normal
+ -1 sprites/bridge_decks.png 8bpp 256 16 64 23 -31 0 normal
+ -1 sprites/bridge_decks.png 8bpp 336 16 64 23 -31 0 normal
+ -1 sprites/bridge_decks.png 8bpp 416 16 64 39 -31 -8 normal
+
+ -1 sprites/bridge_decks.png 8bpp 96 71 64 31 -31 0 normal
+ -1 sprites/bridge_decks.png 8bpp 16 71 64 31 -31 0 normal
+ -1 sprites/bridge_decks.png 8bpp 176 71 64 39 -31 -8 normal
+ -1 sprites/bridge_decks.png 8bpp 256 71 64 23 -31 0 normal
+ -1 sprites/bridge_decks.png 8bpp 336 71 64 23 -31 0 normal
+ -1 sprites/bridge_decks.png 8bpp 416 71 64 39 -31 -8 normal
+
+ -1 sprites/bridge_decks.png 8bpp 96 126 64 31 -31 0 normal
+ -1 sprites/bridge_decks.png 8bpp 16 126 64 31 -31 0 normal
+ -1 sprites/bridge_decks.png 8bpp 176 126 64 39 -31 -8 normal
+ -1 sprites/bridge_decks.png 8bpp 256 126 64 23 -31 0 normal
+ -1 sprites/bridge_decks.png 8bpp 336 126 64 23 -31 0 normal
+ -1 sprites/bridge_decks.png 8bpp 416 126 64 39 -31 -8 normal
+
+// X and Y axis are swapped for road surface.
+ -1 sprites/bridge_decks.png 8bpp 16 181 64 31 -31 0 normal
+ -1 sprites/bridge_decks.png 8bpp 96 181 64 31 -31 0 normal
+ -1 sprites/bridge_decks.png 8bpp 176 181 64 39 -31 -8 normal
+ -1 sprites/bridge_decks.png 8bpp 256 181 64 23 -31 0 normal
+ -1 sprites/bridge_decks.png 8bpp 336 181 64 23 -31 0 normal
+ -1 sprites/bridge_decks.png 8bpp 416 181 64 39 -31 -8 normal
diff --git a/media/baseset/openttd/bridge_decks.png b/media/baseset/openttd/bridge_decks.png
new file mode 100644
index 0000000000000..a602e0ed73a5e
Binary files /dev/null and b/media/baseset/openttd/bridge_decks.png differ
diff --git a/media/baseset/openttd/openttd.nfo b/media/baseset/openttd/openttd.nfo
index 9cfce9ffddda0..862345d11eaf2 100644
--- a/media/baseset/openttd/openttd.nfo
+++ b/media/baseset/openttd/openttd.nfo
@@ -100,3 +100,4 @@
#include "palette.nfo"
#include "road_waypoints.nfo"
#include "overlay_rocks.nfo"
+#include "bridge_decks.nfo"
diff --git a/regression/regression/main.nut b/regression/regression/main.nut
index b9df4ebb4a51b..d029cea9968d0 100644
--- a/regression/regression/main.nut
+++ b/regression/regression/main.nut
@@ -461,6 +461,21 @@ function Regression::Company()
}
}
+function Regression::CompanyGender()
+{
+ print("");
+ print("--Company Gender--");
+ /* Check gender switching behaviour matches API. */
+ print(" GetPresidentGender(): " + AICompany.GetPresidentGender(AICompany.COMPANY_SELF));
+ print(" SetPresidentGender(): " + AICompany.SetPresidentGender(AICompany.GENDER_MALE));
+ print(" GetPresidentGender(): " + AICompany.GetPresidentGender(AICompany.COMPANY_SELF));
+ print(" SetPresidentGender(): " + AICompany.SetPresidentGender(AICompany.GENDER_FEMALE));
+ print(" GetPresidentGender(): " + AICompany.GetPresidentGender(AICompany.COMPANY_SELF));
+ /* Setting to existing gender should fail. */
+ print(" SetPresidentGender(): " + AICompany.SetPresidentGender(AICompany.GENDER_FEMALE));
+ print(" GetPresidentGender(): " + AICompany.GetPresidentGender(AICompany.COMPANY_SELF));
+}
+
function Regression::Engine()
{
local j = 0;
@@ -2096,6 +2111,7 @@ function Regression::Start()
this.Vehicle();
/* Order has to be after Vehicle */
this.Order();
+ this.CompanyGender();
print("");
print(" First Subsidy Test");
PrintSubsidy(0);
diff --git a/regression/regression/result.txt b/regression/regression/result.txt
index 6a88a5297da70..ec60ce3651709 100644
--- a/regression/regression/result.txt
+++ b/regression/regression/result.txt
@@ -10006,6 +10006,15 @@ ERROR: IsEnd() is invalid as Begin() is never called
foreach():
20 => 23596
+--Company Gender--
+ GetPresidentGender(): 1
+ SetPresidentGender(): true
+ GetPresidentGender(): 0
+ SetPresidentGender(): true
+ GetPresidentGender(): 1
+ SetPresidentGender(): false
+ GetPresidentGender(): 1
+
First Subsidy Test
--Subsidy (0) --
IsValidSubsidy(): true
@@ -10107,7 +10116,7 @@ ERROR: IsEnd() is invalid as Begin() is never called
constructor failed with: excessive CPU usage in list filter function
Your script made an error: excessive CPU usage in valuator function
-*FUNCTION [Start()] regression/main.nut line [2168]
+*FUNCTION [Start()] regression/main.nut line [2184]
[Infinite] CLOSURE
[list] INSTANCE
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 16215e7f8d867..f0e44215211a7 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -541,6 +541,7 @@ add_files(
transparency.h
transparency_gui.cpp
transparency_gui.h
+ transport_mapping.hpp
transport_type.h
tree_cmd.cpp
tree_cmd.h
diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp
index c13e313130f94..4dd4a8c671a57 100644
--- a/src/ai/ai_gui.cpp
+++ b/src/ai/ai_gui.cpp
@@ -28,7 +28,7 @@
/** Widgets for the configure AI window. */
-static constexpr NWidgetPart _nested_ai_config_widgets[] = {
+static constexpr std::initializer_list _nested_ai_config_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_MAUVE),
NWidget(WWT_CAPTION, COLOUR_MAUVE), SetStringTip(STR_AI_CONFIG_CAPTION_AI, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
diff --git a/src/ai/ai_scanner.cpp b/src/ai/ai_scanner.cpp
index 70e5b55148133..f4b055268499c 100644
--- a/src/ai/ai_scanner.cpp
+++ b/src/ai/ai_scanner.cpp
@@ -137,5 +137,5 @@ AILibrary *AIScannerLibrary::FindLibrary(const std::string &library, int version
ScriptInfoList::iterator it = this->info_list.find(library_name);
if (it == this->info_list.end()) return nullptr;
- return static_cast((*it).second);
+ return static_cast(it->second);
}
diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp
index 7a1b8b7a8cbb5..94d976e112e2f 100644
--- a/src/aircraft_cmd.cpp
+++ b/src/aircraft_cmd.cpp
@@ -16,7 +16,6 @@
#include "news_func.h"
#include "newgrf_engine.h"
#include "newgrf_sound.h"
-#include "spritecache.h"
#include "error_func.h"
#include "strings_func.h"
#include "command_func.h"
@@ -136,7 +135,9 @@ static StationID FindNearestHangar(const Aircraft *v)
next_dest = Station::GetIfValid(v->current_order.GetDestination().ToStationID());
} else {
last_dest = GetTargetAirportIfValid(v);
- next_dest = Station::GetIfValid(v->GetNextStoppingStation().value);
+ std::vector next_station;
+ v->GetNextStoppingStation(next_station);
+ if (!next_station.empty()) next_dest = Station::GetIfValid(next_station.back());
}
}
@@ -200,7 +201,7 @@ void GetRotorImage(const Aircraft *v, EngineImageType image_type, VehicleSpriteS
static void GetAircraftIcon(EngineID engine, EngineImageType image_type, VehicleSpriteSeq *result)
{
const Engine *e = Engine::Get(engine);
- uint8_t spritenum = e->u.air.image_index;
+ uint8_t spritenum = e->VehInfo().image_index;
if (IsCustomVehicleSpriteNum(spritenum)) {
GetCustomVehicleIcon(engine, DIR_W, image_type, result);
@@ -267,7 +268,7 @@ void GetAircraftSpriteSize(EngineID engine, uint &width, uint &height, int &xoff
*/
CommandCost CmdBuildAircraft(DoCommandFlags flags, TileIndex tile, const Engine *e, Vehicle **ret)
{
- const AircraftVehicleInfo *avi = &e->u.air;
+ const AircraftVehicleInfo *avi = &e->VehInfo();
const Station *st = Station::GetByTile(tile);
/* Prevent building aircraft types at places which can't handle them */
@@ -438,7 +439,7 @@ static void CheckIfAircraftNeedsService(Aircraft *v)
Money Aircraft::GetRunningCost() const
{
const Engine *e = this->GetEngine();
- uint cost_factor = GetVehicleProperty(this, PROP_AIRCRAFT_RUNNING_COST_FACTOR, e->u.air.running_cost);
+ uint cost_factor = GetVehicleProperty(this, PROP_AIRCRAFT_RUNNING_COST_FACTOR, e->VehInfo().running_cost);
return GetPrice(PR_RUNNING_AIRCRAFT, cost_factor, e->GetGRF());
}
diff --git a/src/aircraft_gui.cpp b/src/aircraft_gui.cpp
index 5b7d67582b92b..3709dfb7211ac 100644
--- a/src/aircraft_gui.cpp
+++ b/src/aircraft_gui.cpp
@@ -14,7 +14,6 @@
#include "strings_func.h"
#include "vehicle_func.h"
#include "window_gui.h"
-#include "spritecache.h"
#include "zoom_func.h"
#include "table/strings.h"
diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp
index 48b34bbd00692..b0bdd7cbb8f8a 100644
--- a/src/airport_gui.cpp
+++ b/src/airport_gui.cpp
@@ -84,7 +84,7 @@ static void PlaceAirport(TileIndex tile)
/** Airport build toolbar window handler. */
struct BuildAirToolbarWindow : Window {
- int last_user_action = INVALID_WID_AT; // Last started user action.
+ WidgetID last_user_action = INVALID_WIDGET; // Last started user action.
BuildAirToolbarWindow(WindowDesc &desc, WindowNumber window_number) : Window(desc)
{
@@ -161,6 +161,11 @@ struct BuildAirToolbarWindow : Window {
VpSelectTilesWithMethod(pt.x, pt.y, select_method);
}
+ Point OnInitialPosition(int16_t sm_width, [[maybe_unused]] int16_t sm_height, [[maybe_unused]] int window_number) override
+ {
+ return AlignInitialConstructionToolbar(sm_width);
+ }
+
void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, TileIndex start_tile, TileIndex end_tile) override
{
if (pt.x != -1 && select_proc == DDSP_DEMOLISH_AREA) {
@@ -197,7 +202,7 @@ struct BuildAirToolbarWindow : Window {
}, AirportToolbarGlobalHotkeys};
};
-static constexpr NWidgetPart _nested_air_toolbar_widgets[] = {
+static constexpr std::initializer_list _nested_air_toolbar_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetStringTip(STR_TOOLBAR_AIRCRAFT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
@@ -211,7 +216,7 @@ static constexpr NWidgetPart _nested_air_toolbar_widgets[] = {
};
static WindowDesc _air_toolbar_desc(
- WDP_ALIGN_TOOLBAR, "toolbar_air", 0, 0,
+ WDP_MANUAL, "toolbar_air", 0, 0,
WC_BUILD_TOOLBAR, WC_NONE,
WindowDefaultFlag::Construction,
_nested_air_toolbar_widgets,
@@ -580,7 +585,7 @@ class BuildAirportWindow : public PickerWindowBase {
}};
};
-static constexpr NWidgetPart _nested_build_airport_widgets[] = {
+static constexpr std::initializer_list _nested_build_airport_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetStringTip(STR_STATION_BUILD_AIRPORT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
diff --git a/src/articulated_vehicles.cpp b/src/articulated_vehicles.cpp
index 9ffc0a6e8f943..08c3c4416c370 100644
--- a/src/articulated_vehicles.cpp
+++ b/src/articulated_vehicles.cpp
@@ -365,10 +365,10 @@ void AddArticulatedParts(Vehicle *first)
t->track = front->track;
t->railtypes = front->railtypes;
- t->spritenum = e_artic->u.rail.image_index;
+ t->spritenum = e_artic->VehInfo().image_index;
if (e_artic->CanCarryCargo()) {
t->cargo_type = e_artic->GetDefaultCargoType();
- t->cargo_cap = e_artic->u.rail.capacity; // Callback 36 is called when the consist is finished
+ t->cargo_cap = e_artic->VehInfo().capacity; // Callback 36 is called when the consist is finished
} else {
t->cargo_type = front->cargo_type; // Needed for livery selection
t->cargo_cap = 0;
@@ -392,11 +392,11 @@ void AddArticulatedParts(Vehicle *first)
rv->roadtype = front->roadtype;
rv->compatible_roadtypes = front->compatible_roadtypes;
- rv->spritenum = e_artic->u.road.image_index;
+ rv->spritenum = e_artic->VehInfo().image_index;
if (e_artic->CanCarryCargo()) {
rv->cargo_type = e_artic->GetDefaultCargoType();
assert(IsValidCargoType(rv->cargo_type));
- rv->cargo_cap = e_artic->u.road.capacity; // Callback 36 is called when the consist is finished
+ rv->cargo_cap = e_artic->VehInfo().capacity; // Callback 36 is called when the consist is finished
} else {
rv->cargo_type = front->cargo_type; // Needed for livery selection
rv->cargo_cap = 0;
diff --git a/src/autoreplace_cmd.cpp b/src/autoreplace_cmd.cpp
index 0798c679b3f3c..454450c6420d0 100644
--- a/src/autoreplace_cmd.cpp
+++ b/src/autoreplace_cmd.cpp
@@ -71,16 +71,16 @@ bool CheckAutoreplaceValidity(EngineID from, EngineID to, CompanyID company)
switch (type) {
case VEH_TRAIN: {
/* make sure the railtypes are compatible */
- if (!GetAllCompatibleRailTypes(e_from->u.rail.railtypes).Any(GetAllCompatibleRailTypes(e_to->u.rail.railtypes))) return false;
+ if (!GetAllCompatibleRailTypes(e_from->VehInfo().railtypes).Any(GetAllCompatibleRailTypes(e_to->VehInfo().railtypes))) return false;
/* make sure we do not replace wagons with engines or vice versa */
- if ((e_from->u.rail.railveh_type == RAILVEH_WAGON) != (e_to->u.rail.railveh_type == RAILVEH_WAGON)) return false;
+ if ((e_from->VehInfo().railveh_type == RAILVEH_WAGON) != (e_to->VehInfo().railveh_type == RAILVEH_WAGON)) return false;
break;
}
case VEH_ROAD:
/* make sure the roadtypes are compatible */
- if (!GetRoadTypeInfo(e_from->u.road.roadtype)->powered_roadtypes.Any(GetRoadTypeInfo(e_to->u.road.roadtype)->powered_roadtypes)) return false;
+ if (!GetRoadTypeInfo(e_from->VehInfo().roadtype)->powered_roadtypes.Any(GetRoadTypeInfo(e_to->VehInfo().roadtype)->powered_roadtypes)) return false;
/* make sure that we do not replace a tram with a normal road vehicles or vice versa */
if (e_from->info.misc_flags.Test(EngineMiscFlag::RoadIsTram) != e_to->info.misc_flags.Test(EngineMiscFlag::RoadIsTram)) return false;
@@ -88,7 +88,7 @@ bool CheckAutoreplaceValidity(EngineID from, EngineID to, CompanyID company)
case VEH_AIRCRAFT:
/* make sure that we do not replace a plane with a helicopter or vice versa */
- if ((e_from->u.air.subtype & AIR_CTOL) != (e_to->u.air.subtype & AIR_CTOL)) return false;
+ if ((e_from->VehInfo().subtype & AIR_CTOL) != (e_to->VehInfo().subtype & AIR_CTOL)) return false;
break;
default: break;
diff --git a/src/autoreplace_cmd.h b/src/autoreplace_cmd.h
index 5f9af672d2433..df4c268255367 100644
--- a/src/autoreplace_cmd.h
+++ b/src/autoreplace_cmd.h
@@ -18,7 +18,7 @@
CommandCost CmdAutoreplaceVehicle(DoCommandFlags flags, VehicleID veh_id);
CommandCost CmdSetAutoReplace(DoCommandFlags flags, GroupID id_g, EngineID old_engine_type, EngineID new_engine_type, bool when_old);
-DEF_CMD_TRAIT(CMD_AUTOREPLACE_VEHICLE, CmdAutoreplaceVehicle, {}, CMDT_VEHICLE_MANAGEMENT)
-DEF_CMD_TRAIT(CMD_SET_AUTOREPLACE, CmdSetAutoReplace, {}, CMDT_VEHICLE_MANAGEMENT)
+DEF_CMD_TRAIT(CMD_AUTOREPLACE_VEHICLE, CmdAutoreplaceVehicle, {}, CommandType::VehicleManagement)
+DEF_CMD_TRAIT(CMD_SET_AUTOREPLACE, CmdSetAutoReplace, {}, CommandType::VehicleManagement)
#endif /* AUTOREPLACE_CMD_H */
diff --git a/src/autoreplace_gui.cpp b/src/autoreplace_gui.cpp
index 081a8a8acee39..d38708ce6b1b0 100644
--- a/src/autoreplace_gui.cpp
+++ b/src/autoreplace_gui.cpp
@@ -140,7 +140,7 @@ class ReplaceVehicleWindow : public Window {
case VEH_ROAD:
if (draw_left && this->sel_roadtype != INVALID_ROADTYPE) {
/* Ensure that the roadtype is specific to the selected one */
- if (e->u.road.roadtype != this->sel_roadtype) continue;
+ if (e->VehInfo().roadtype != this->sel_roadtype) continue;
}
break;
@@ -698,7 +698,7 @@ class ReplaceVehicleWindow : public Window {
}
};
-static constexpr NWidgetPart _nested_replace_rail_vehicle_widgets[] = {
+static constexpr std::initializer_list _nested_replace_rail_vehicle_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_RV_CAPTION),
@@ -762,7 +762,7 @@ static WindowDesc _replace_rail_vehicle_desc(
_nested_replace_rail_vehicle_widgets
);
-static constexpr NWidgetPart _nested_replace_road_vehicle_widgets[] = {
+static constexpr std::initializer_list _nested_replace_road_vehicle_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_RV_CAPTION),
@@ -820,7 +820,7 @@ static WindowDesc _replace_road_vehicle_desc(
_nested_replace_road_vehicle_widgets
);
-static constexpr NWidgetPart _nested_replace_vehicle_widgets[] = {
+static constexpr std::initializer_list _nested_replace_vehicle_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_RV_CAPTION), SetMinimalSize(433, 14),
diff --git a/src/base_media_func.h b/src/base_media_func.h
index 8f1fac4c26d25..d5a96bcc93566 100644
--- a/src/base_media_func.h
+++ b/src/base_media_func.h
@@ -79,7 +79,7 @@ bool BaseSet::FillSetDetails(const IniFile &ini, const std::string &path, con
/* Add the translations of the descriptions too. */
for (const IniItem &titem : metadata->items) {
- if (titem.name.compare(0, 12, "description.") != 0) continue;
+ if (!titem.name.starts_with("description.")) continue;
this->description[titem.name.substr(12)] = titem.value.value_or("");
}
diff --git a/src/bitmap_type.h b/src/bitmap_type.h
index 4dd356e48a6bb..acf3b3d22b56f 100644
--- a/src/bitmap_type.h
+++ b/src/bitmap_type.h
@@ -118,9 +118,9 @@ class BitmapTileIterator : public OrthogonalTileIterator {
inline TileIterator& operator ++() override
{
- (*this).OrthogonalTileIterator::operator++();
+ this->OrthogonalTileIterator::operator++();
while (this->tile != INVALID_TILE && !this->bitmap->HasTile(TileIndex(this->tile))) {
- (*this).OrthogonalTileIterator::operator++();
+ this->OrthogonalTileIterator::operator++();
}
return *this;
}
diff --git a/src/blitter/32bpp_sse2.cpp b/src/blitter/32bpp_sse2.cpp
index 6fc08ca6cd4c0..791952a09522f 100644
--- a/src/blitter/32bpp_sse2.cpp
+++ b/src/blitter/32bpp_sse2.cpp
@@ -113,7 +113,7 @@ Sprite *Blitter_32bppSSE_Base::Encode(SpriteType sprite_type, const SpriteLoader
else break;
dst_rgba++;
}
- (*dst_rgba_line).data = nb_pix_transp;
+ dst_rgba_line->data = nb_pix_transp;
Colour *nb_right = dst_rgba_line + 1;
dst_rgba_line = reinterpret_cast(reinterpret_cast(dst_rgba_line) + info.sprite_line_size);
@@ -126,7 +126,7 @@ Sprite *Blitter_32bppSSE_Base::Encode(SpriteType sprite_type, const SpriteLoader
else break;
dst_rgba--;
}
- (*nb_right).data = nb_pix_transp;
+ nb_right->data = nb_pix_transp;
}
}
diff --git a/src/bootstrap_gui.cpp b/src/bootstrap_gui.cpp
index 80620f303b4ae..3dcdeae43aab5 100644
--- a/src/bootstrap_gui.cpp
+++ b/src/bootstrap_gui.cpp
@@ -33,7 +33,7 @@
#include "safeguards.h"
/** Widgets for the background window to prevent smearing. */
-static constexpr NWidgetPart _background_widgets[] = {
+static constexpr std::initializer_list _background_widgets = {
NWidget(WWT_PANEL, COLOUR_DARK_BLUE, WID_BB_BACKGROUND), SetResize(1, 1),
EndContainer(),
};
@@ -60,13 +60,13 @@ class BootstrapBackground : public Window {
void DrawWidget(const Rect &r, WidgetID) const override
{
- GfxFillRect(r.left, r.top, r.right, r.bottom, PixelColour{4}, FILLRECT_OPAQUE);
- GfxFillRect(r.left, r.top, r.right, r.bottom, PixelColour{0}, FILLRECT_CHECKER);
+ GfxFillRect(r, PixelColour{4}, FILLRECT_OPAQUE);
+ GfxFillRect(r, PixelColour{0}, FILLRECT_CHECKER);
}
};
/** Nested widgets for the error window. */
-static constexpr NWidgetPart _nested_bootstrap_errmsg_widgets[] = {
+static constexpr std::initializer_list _nested_bootstrap_errmsg_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_BEM_CAPTION), SetStringTip(STR_MISSING_GRAPHICS_ERROR_TITLE),
EndContainer(),
@@ -123,7 +123,7 @@ class BootstrapErrorWindow : public Window {
};
/** Nested widgets for the download window. */
-static constexpr NWidgetPart _nested_bootstrap_download_status_window_widgets[] = {
+static constexpr std::initializer_list _nested_bootstrap_download_status_window_widgets = {
NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_CONTENT_DOWNLOAD_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
NWidget(WWT_PANEL, COLOUR_GREY),
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_wide, 0), SetPadding(WidgetDimensions::unscaled.modalpopup),
@@ -174,7 +174,7 @@ struct BootstrapContentDownloadStatusWindow : public BaseNetworkContentDownloadS
};
/** The widgets for the query. It has no close box as that sprite does not exist yet. */
-static constexpr NWidgetPart _bootstrap_query_widgets[] = {
+static constexpr std::initializer_list _bootstrap_query_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_MISSING_GRAPHICS_SET_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
EndContainer(),
@@ -380,7 +380,7 @@ bool HandleBootstrap()
/* Initialise the font cache. */
InitializeUnicodeGlyphMap();
/* Next "force" finding a suitable non-sprite font as the local font is missing. */
- CheckForMissingGlyphs(false);
+ CheckForMissingGlyphs();
/* Initialise the palette. The biggest step is 'faking' some recolour sprites.
* This way the mauve and gray colours work and we can show the user interface. */
diff --git a/src/bridge_gui.cpp b/src/bridge_gui.cpp
index c29d8bb86db5a..f27cd65fe3242 100644
--- a/src/bridge_gui.cpp
+++ b/src/bridge_gui.cpp
@@ -54,7 +54,7 @@ typedef GUIList GUIBridgeList; ///< List of bridges, used in #B
* @param tile_start start tile
* @param transport_type transport type.
*/
-void CcBuildBridge(Commands, const CommandCost &result, TileIndex end_tile, TileIndex tile_start, TransportType transport_type, BridgeType, uint8_t)
+void CcBuildBridge(Commands, const CommandCost &result, TileIndex end_tile, TileIndex tile_start, TransportType transport_type, BridgeType, RailType, RoadType)
{
if (result.Failed()) return;
if (_settings_client.sound.confirm) SndPlayTileFx(SND_27_CONSTRUCTION_BRIDGE, end_tile);
@@ -86,7 +86,8 @@ class BuildBridgeWindow : public Window {
TileIndex start_tile = INVALID_TILE;
TileIndex end_tile = INVALID_TILE;
TransportType transport_type = INVALID_TRANSPORT;
- uint8_t road_rail_type = 0;
+ RailType railtype = INVALID_RAILTYPE;
+ RoadType roadtype = INVALID_ROADTYPE;
GUIBridgeList bridges{};
int icon_width = 0; ///< Scaled width of the the bridge icon sprite.
Scrollbar *vscroll = nullptr;
@@ -117,7 +118,7 @@ class BuildBridgeWindow : public Window {
default: break;
}
Command::Post(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE, CcBuildBridge,
- this->end_tile, this->start_tile, this->transport_type, type, this->road_rail_type);
+ this->end_tile, this->start_tile, this->transport_type, type, this->railtype, this->roadtype);
}
/** Sort the builable bridges */
@@ -154,11 +155,12 @@ class BuildBridgeWindow : public Window {
}
public:
- BuildBridgeWindow(WindowDesc &desc, TileIndex start, TileIndex end, TransportType transport_type, uint8_t road_rail_type, GUIBridgeList &&bl) : Window(desc),
+ BuildBridgeWindow(WindowDesc &desc, TileIndex start, TileIndex end, TransportType transport_type, RailType railtype, RoadType roadtype, GUIBridgeList &&bl) : Window(desc),
start_tile(start),
end_tile(end),
transport_type(transport_type),
- road_rail_type(road_rail_type),
+ railtype(railtype),
+ roadtype(roadtype),
bridges(std::move(bl))
{
this->CreateNestedTree();
@@ -309,7 +311,7 @@ const std::initializer_list BuildBridgeWind
};
/** Widgets of the bridge gui. */
-static constexpr NWidgetPart _nested_build_bridge_widgets[] = {
+static constexpr std::initializer_list _nested_build_bridge_widgets = {
/* Header */
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
@@ -354,7 +356,7 @@ static WindowDesc _build_bridge_desc(
* @param transport_type The transport type
* @param road_rail_type The road/rail type
*/
-void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transport_type, uint8_t road_rail_type)
+void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transport_type, RailType railtype, RoadType roadtype)
{
CloseWindowByClass(WC_BUILD_BRIDGE);
@@ -373,13 +375,13 @@ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transpo
default: break; // water ways and air routes don't have bridge types
}
if (_ctrl_pressed && CheckBridgeAvailability(last_bridge_type, bridge_len).Succeeded()) {
- Command::Post(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE, CcBuildBridge, end, start, transport_type, last_bridge_type, road_rail_type);
+ Command::Post(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE, CcBuildBridge, end, start, transport_type, last_bridge_type, railtype, roadtype);
return;
}
/* only query bridge building possibility once, result is the same for all bridges!
* returns CMD_ERROR on failure, and price on success */
- CommandCost ret = Command::Do(CommandFlagsToDCFlags(GetCommandFlags()) | DoCommandFlag::QueryCost, end, start, transport_type, 0, road_rail_type);
+ CommandCost ret = Command::Do(CommandFlagsToDCFlags(GetCommandFlags()) | DoCommandFlag::QueryCost, end, start, transport_type, 0, railtype, roadtype);
GUIBridgeList bl;
if (!ret.Failed()) {
@@ -396,10 +398,10 @@ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transpo
road_rt = GetRoadTypeRoad(start);
tram_rt = GetRoadTypeTram(start);
}
- if (RoadTypeIsRoad((RoadType)road_rail_type)) {
- road_rt = (RoadType)road_rail_type;
+ if (RoadTypeIsRoad(roadtype)) {
+ road_rt = roadtype;
} else {
- tram_rt = (RoadType)road_rail_type;
+ tram_rt = roadtype;
}
if (road_rt != INVALID_ROADTYPE) infra_cost += (bridge_len + 2) * 2 * RoadBuildCost(road_rt);
@@ -407,7 +409,7 @@ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transpo
break;
}
- case TRANSPORT_RAIL: infra_cost = (bridge_len + 2) * RailBuildCost((RailType)road_rail_type); break;
+ case TRANSPORT_RAIL: infra_cost = (bridge_len + 2) * RailBuildCost(railtype); break;
default: break;
}
@@ -432,7 +434,7 @@ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transpo
}
if (!bl.empty()) {
- new BuildBridgeWindow(_build_bridge_desc, start, end, transport_type, road_rail_type, std::move(bl));
+ new BuildBridgeWindow(_build_bridge_desc, start, end, transport_type, railtype, roadtype, std::move(bl));
} else {
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE), TileX(end) * TILE_SIZE, TileY(end) * TILE_SIZE, ret);
}
diff --git a/src/bridge_map.h b/src/bridge_map.h
index 5ced7b5d2f27b..28ca5f052c264 100644
--- a/src/bridge_map.h
+++ b/src/bridge_map.h
@@ -135,6 +135,7 @@ inline void MakeBridgeRamp(Tile t, Owner o, BridgeType bridgetype, DiagDirection
t.m4() = 0;
t.m5() = 1 << 7 | tt << 2 | d;
SB(t.m6(), 2, 4, bridgetype);
+ SB(t.m6(), 6, 2, 0);
t.m7() = 0;
t.m8() = 0;
}
@@ -147,15 +148,15 @@ inline void MakeBridgeRamp(Tile t, Owner o, BridgeType bridgetype, DiagDirection
* @param owner_tram the new owner of the tram on the bridge
* @param bridgetype the type of bridge this bridge ramp belongs to
* @param d the direction this ramp must be facing
- * @param road_rt the road type of the bridge
- * @param tram_rt the tram type of the bridge
+ * @param map_roadtype the map road type of the bridge
+ * @param map_tramtype the map tram type of the bridge
*/
-inline void MakeRoadBridgeRamp(Tile t, Owner o, Owner owner_road, Owner owner_tram, BridgeType bridgetype, DiagDirection d, RoadType road_rt, RoadType tram_rt)
+inline void MakeRoadBridgeRamp(Tile t, Owner o, Owner owner_road, Owner owner_tram, BridgeType bridgetype, DiagDirection d, MapRoadType map_roadtype, MapTramType map_tramtype)
{
MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_ROAD);
SetRoadOwner(t, RTT_ROAD, owner_road);
if (owner_tram != OWNER_TOWN) SetRoadOwner(t, RTT_TRAM, owner_tram);
- SetRoadTypes(t, road_rt, tram_rt);
+ SetMapRoadTypes(t, map_roadtype, map_tramtype);
}
/**
@@ -164,12 +165,12 @@ inline void MakeRoadBridgeRamp(Tile t, Owner o, Owner owner_road, Owner owner_tr
* @param o the new owner of the bridge ramp
* @param bridgetype the type of bridge this bridge ramp belongs to
* @param d the direction this ramp must be facing
- * @param rt the rail type of the bridge
+ * @param map_railtype the map rail type of the bridge
*/
-inline void MakeRailBridgeRamp(Tile t, Owner o, BridgeType bridgetype, DiagDirection d, RailType rt)
+inline void MakeRailBridgeRamp(Tile t, Owner o, BridgeType bridgetype, DiagDirection d, MapRailType map_railtype)
{
MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_RAIL);
- SetRailType(t, rt);
+ SetMapRailType(t, map_railtype);
}
/**
diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp
index a40ad4ef359e0..27deb5f430617 100644
--- a/src/build_vehicle_gui.cpp
+++ b/src/build_vehicle_gui.cpp
@@ -58,7 +58,7 @@ uint GetEngineListHeight(VehicleType type)
return std::max(GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.matrix.Vertical(), GetVehicleImageCellSize(type, EIT_PURCHASE).height);
}
-static constexpr NWidgetPart _nested_build_vehicle_widgets[] = {
+static constexpr std::initializer_list _nested_build_vehicle_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_BV_CAPTION), SetTextStyle(TC_WHITE),
@@ -726,8 +726,8 @@ static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_numb
/* Purchase cost - Max speed */
uint raw_speed = e->GetDisplayMaxSpeed();
- uint ocean_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, true);
- uint canal_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, false);
+ uint ocean_speed = e->VehInfo().ApplyWaterClassSpeedFrac(raw_speed, true);
+ uint canal_speed = e->VehInfo().ApplyWaterClassSpeedFrac(raw_speed, false);
if (ocean_speed == canal_speed) {
if (te.cost != 0) {
@@ -885,10 +885,10 @@ int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number,
switch (e->type) {
default: NOT_REACHED();
case VEH_TRAIN:
- if (e->u.rail.railveh_type == RAILVEH_WAGON) {
- y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, &e->u.rail, te);
+ if (e->VehInfo().railveh_type == RAILVEH_WAGON) {
+ y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, &e->VehInfo(), te);
} else {
- y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, &e->u.rail, te);
+ y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, &e->VehInfo(), te);
}
articulated_cargo = true;
break;
@@ -920,7 +920,7 @@ int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number,
}
/* Draw details that apply to all types except rail wagons. */
- if (e->type != VEH_TRAIN || e->u.rail.railveh_type != RAILVEH_WAGON) {
+ if (e->type != VEH_TRAIN || e->VehInfo().railveh_type != RAILVEH_WAGON) {
/* Design date - Life length */
DrawString(left, right, y, GetString(STR_PURCHASE_INFO_DESIGNED_LIFE, ymd.year, TimerGameCalendar::DateToYear(e->GetLifeLengthInDays())));
y += GetCharacterHeight(FS_NORMAL);
@@ -1030,7 +1030,7 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li
if (has_variants) {
Rect fr = tr.WithWidth(circle_width, rtl);
- DrawSpriteIgnorePadding(is_folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED, PAL_NONE, {fr.left, textr.top, fr.right, textr.bottom}, SA_CENTER);
+ DrawSpriteIgnorePadding(is_folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED, PAL_NONE, fr.WithY(textr), SA_CENTER);
}
tr = tr.Indent(circle_width + WidgetDimensions::scaled.hsep_normal, rtl);
@@ -1395,7 +1395,7 @@ struct BuildVehicleWindow : Window {
for (const Engine *e : Engine::IterateType(VEH_TRAIN)) {
if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
EngineID eid = e->index;
- const RailVehicleInfo *rvi = &e->u.rail;
+ const RailVehicleInfo *rvi = &e->VehInfo();
if (this->filter.railtype != INVALID_RAILTYPE && !HasPowerOnRail(rvi->railtypes, this->filter.railtype)) continue;
if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue;
@@ -1426,7 +1426,7 @@ struct BuildVehicleWindow : Window {
if (std::ranges::find(list, variant, &GUIEngineListItem::engine_id) == list.end()) {
const Engine *e = Engine::Get(variant);
list.emplace_back(variant, e->info.variant_id, e->display_flags | EngineDisplayFlag::Shaded, 0);
- if (e->u.rail.railveh_type != RAILVEH_WAGON) num_engines++;
+ if (e->VehInfo().railveh_type != RAILVEH_WAGON) num_engines++;
}
}
@@ -1461,7 +1461,7 @@ struct BuildVehicleWindow : Window {
if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
EngineID eid = e->index;
if (!IsEngineBuildable(eid, VEH_ROAD, _local_company)) continue;
- if (this->filter.roadtype != INVALID_ROADTYPE && !HasPowerOnRoad(e->u.road.roadtype, this->filter.roadtype)) continue;
+ if (this->filter.roadtype != INVALID_ROADTYPE && !HasPowerOnRoad(e->VehInfo().roadtype, this->filter.roadtype)) continue;
if (!bdf.Filter(e->badges)) continue;
/* Filter by name or NewGRF extra text */
@@ -1731,7 +1731,8 @@ struct BuildVehicleWindow : Window {
default:
if (IsInsideMM(widget, this->badge_filters.first, this->badge_filters.second)) {
- ShowDropDownList(this, this->GetWidget(widget)->GetDropDownList(), -1, widget, 0, false);
+ PaletteID palette = SPR_2CCMAP_BASE + Company::Get(_local_company)->GetCompanyRecolourOffset(LS_DEFAULT);
+ ShowDropDownList(this, this->GetWidget(widget)->GetDropDownList(palette), -1, widget, 0, false);
}
break;
}
@@ -1931,7 +1932,6 @@ struct BuildVehicleWindow : Window {
/* We need to refresh if a filter is removed. */
this->eng_list.ForceRebuild();
- this->SetDirty();
break;
}
@@ -1943,7 +1943,6 @@ struct BuildVehicleWindow : Window {
SetBadgeFilter(this->badge_filter_choices, BadgeID(index));
}
this->eng_list.ForceRebuild();
- this->SetDirty();
}
break;
}
diff --git a/src/cargopacket.cpp b/src/cargopacket.cpp
index 38d94894900ea..8be991034ecdd 100644
--- a/src/cargopacket.cpp
+++ b/src/cargopacket.cpp
@@ -404,13 +404,13 @@ void VehicleCargoList::AgeCargo()
* @return MoveToAction to be performed.
*/
/* static */ VehicleCargoList::MoveToAction VehicleCargoList::ChooseAction(const CargoPacket *cp, StationID cargo_next,
- StationID current_station, bool accepted, StationIDStack next_station)
+ StationID current_station, bool accepted, std::span next_station)
{
if (cargo_next == StationID::Invalid()) {
return (accepted && cp->first_station != current_station) ? MTA_DELIVER : MTA_KEEP;
} else if (cargo_next == current_station) {
return MTA_DELIVER;
- } else if (next_station.Contains(cargo_next)) {
+ } else if (std::ranges::find(next_station, cargo_next) != std::end(next_station)) {
return MTA_KEEP;
} else {
return MTA_TRANSFER;
@@ -432,7 +432,7 @@ void VehicleCargoList::AgeCargo()
* @param current_tile Current tile the cargo handling is happening on.
* return If any cargo will be unloaded.
*/
-bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationIDStack next_station, uint8_t order_flags, const GoodsEntry *ge, CargoType cargo, CargoPayment *payment, TileIndex current_tile)
+bool VehicleCargoList::Stage(bool accepted, StationID current_station, std::span next_station, uint8_t order_flags, const GoodsEntry *ge, CargoType cargo, CargoPayment *payment, TileIndex current_tile)
{
this->AssertCountConsistency();
assert(this->action_counts[MTA_LOAD] == 0);
@@ -468,9 +468,9 @@ bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationID
} else {
FlowStat new_shares = flow_it->second;
new_shares.ChangeShare(current_station, INT_MIN);
- StationIDStack excluded = next_station;
- while (!excluded.IsEmpty() && !new_shares.GetShares()->empty()) {
- new_shares.ChangeShare(excluded.Pop(), INT_MIN);
+ for (auto station_it = next_station.rbegin(); station_it != next_station.rend(); ++station_it) {
+ if (new_shares.GetShares()->empty()) break;
+ new_shares.ChangeShare(*station_it, INT_MIN);
}
if (new_shares.GetShares()->empty()) {
cargo_next = StationID::Invalid();
@@ -739,11 +739,11 @@ bool StationCargoList::ShiftCargo(Taction &action, StationID next)
* @return Amount of cargo actually moved.
*/
template
-uint StationCargoList::ShiftCargo(Taction action, StationIDStack next, bool include_invalid)
+uint StationCargoList::ShiftCargo(Taction action, std::span next, bool include_invalid)
{
uint max_move = action.MaxMove();
- while (!next.IsEmpty()) {
- this->ShiftCargo(action, next.Pop());
+ for (auto it = next.rbegin(); it != next.rend(); ++it) {
+ this->ShiftCargo(action, *it);
if (action.MaxMove() == 0) break;
}
if (include_invalid && action.MaxMove() > 0) {
@@ -814,7 +814,7 @@ uint StationCargoList::Truncate(uint max_move, StationCargoAmountMap *cargo_per_
* @param current_tile Current tile the cargo handling is happening on.
* @return Amount of cargo actually reserved.
*/
-uint StationCargoList::Reserve(uint max_move, VehicleCargoList *dest, StationIDStack next_station, TileIndex current_tile)
+uint StationCargoList::Reserve(uint max_move, VehicleCargoList *dest, std::span next_station, TileIndex current_tile)
{
return this->ShiftCargo(CargoReservation(this, dest, max_move, current_tile), next_station, true);
}
@@ -831,7 +831,7 @@ uint StationCargoList::Reserve(uint max_move, VehicleCargoList *dest, StationIDS
* modes of loading are exclusive, though. If cargo is reserved we don't
* need to load unreserved cargo.
*/
-uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, StationIDStack next_station, TileIndex current_tile)
+uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, std::span next_station, TileIndex current_tile)
{
uint move = std::min(dest->ActionCount(VehicleCargoList::MTA_LOAD), max_move);
if (move > 0) {
@@ -839,7 +839,7 @@ uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, StationIDStac
dest->Reassign(move);
return move;
} else {
- return this->ShiftCargo(CargoLoad(this, dest, max_move, current_tile), next_station, true);
+ return this->ShiftCargo(CargoLoad{this, dest, max_move, current_tile}, next_station, true);
}
}
@@ -853,7 +853,7 @@ uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, StationIDStac
*/
uint StationCargoList::Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge)
{
- return this->ShiftCargo(StationCargoReroute(this, dest, max_move, avoid, avoid2, ge), avoid, false);
+ return this->ShiftCargo(StationCargoReroute(this, dest, max_move, avoid, avoid2, ge), {&avoid, 1}, false);
}
/*
diff --git a/src/cargopacket.h b/src/cargopacket.h
index 8b4c7b6d40148..35cfd2cce466c 100644
--- a/src/cargopacket.h
+++ b/src/cargopacket.h
@@ -371,7 +371,7 @@ class VehicleCargoList : public CargoList {
void RemoveFromMeta(const CargoPacket *cp, MoveToAction action, uint count);
static MoveToAction ChooseAction(const CargoPacket *cp, StationID cargo_next,
- StationID current_station, bool accepted, StationIDStack next_station);
+ StationID current_station, bool accepted, std::span next_station);
public:
/** The station cargo list needs to control the unloading. */
@@ -469,7 +469,7 @@ class VehicleCargoList : public CargoList {
void InvalidateCache();
- bool Stage(bool accepted, StationID current_station, StationIDStack next_station, uint8_t order_flags, const GoodsEntry *ge, CargoType cargo, CargoPayment *payment, TileIndex current_tile);
+ bool Stage(bool accepted, StationID current_station, std::span next_station, uint8_t order_flags, const GoodsEntry *ge, CargoType cargo, CargoPayment *payment, TileIndex current_tile);
/**
* Marks all cargo in the vehicle as to be kept. This is mostly useful for
@@ -543,7 +543,7 @@ class StationCargoList : public CargoList
- uint ShiftCargo(Taction action, StationIDStack next, bool include_invalid);
+ uint ShiftCargo(Taction action, std::span next, bool include_invalid);
void Append(CargoPacket *cp, StationID next);
@@ -552,10 +552,10 @@ class StationCargoList : public CargoList next) const
{
- while (!next.IsEmpty()) {
- if (this->packets.find(next.Pop()) != this->packets.end()) return true;
+ for (const StationID &station : next) {
+ if (this->packets.find(station) != this->packets.end()) return true;
}
/* Packets for StationID::Invalid() can go anywhere. */
return this->packets.find(StationID::Invalid()) != this->packets.end();
@@ -603,8 +603,8 @@ class StationCargoList : public CargoList next, TileIndex current_tile);
+ uint Load(uint max_move, VehicleCargoList *dest, std::span next, TileIndex current_tile);
uint Truncate(uint max_move = UINT_MAX, StationCargoAmountMap *cargo_per_source = nullptr);
uint Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge);
diff --git a/src/cheat_gui.cpp b/src/cheat_gui.cpp
index 5cbdb1f78f4bc..af45b55ac727a 100644
--- a/src/cheat_gui.cpp
+++ b/src/cheat_gui.cpp
@@ -219,7 +219,7 @@ static const CheatEntry _cheats_ui[] = {
static_assert(CHT_NUM_CHEATS == lengthof(_cheats_ui));
/** Widget definitions of the cheat GUI. */
-static constexpr NWidgetPart _nested_cheat_widgets[] = {
+static constexpr std::initializer_list _nested_cheat_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_CHEATS, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
diff --git a/src/clear_map.h b/src/clear_map.h
index a1a58612ce489..6f24800f99d21 100644
--- a/src/clear_map.h
+++ b/src/clear_map.h
@@ -274,7 +274,7 @@ inline void MakeField(Tile t, uint field_type, IndustryID industry)
t.m3() = field_type;
t.m4() = 0 << 5 | 0 << 2;
SetClearGroundDensity(t, CLEAR_FIELDS, 3);
- SB(t.m6(), 2, 4, 0);
+ SB(t.m6(), 2, 6, 0);
t.m7() = 0;
t.m8() = 0;
}
diff --git a/src/command.cpp b/src/command.cpp
index c11289902e2fb..2cdc9ed3ad4ec 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -144,21 +144,21 @@ std::string_view GetCommandName(Commands cmd)
bool IsCommandAllowedWhilePaused(Commands cmd)
{
/* Lookup table for the command types that are allowed for a given pause level setting. */
- static const int command_type_lookup[] = {
- CMDPL_ALL_ACTIONS, ///< CMDT_LANDSCAPE_CONSTRUCTION
- CMDPL_NO_LANDSCAPING, ///< CMDT_VEHICLE_CONSTRUCTION
- CMDPL_NO_LANDSCAPING, ///< CMDT_MONEY_MANAGEMENT
- CMDPL_NO_CONSTRUCTION, ///< CMDT_VEHICLE_MANAGEMENT
- CMDPL_NO_CONSTRUCTION, ///< CMDT_ROUTE_MANAGEMENT
- CMDPL_NO_CONSTRUCTION, ///< CMDT_OTHER_MANAGEMENT
- CMDPL_NO_ACTIONS, ///< CMDT_COMPANY_SETTING
- CMDPL_NO_ACTIONS, ///< CMDT_SERVER_SETTING
- CMDPL_NO_ACTIONS, ///< CMDT_CHEAT
+ static constexpr CommandPauseLevel command_type_lookup[] = {
+ CommandPauseLevel::AllActions, // CommandType::LandscapeConstruction
+ CommandPauseLevel::NoLandscaping, // CommandType::VehicleConstruction
+ CommandPauseLevel::NoLandscaping, // CommandType::MoneyManagement
+ CommandPauseLevel::NoConstruction, // CommandType::VehicleManagement
+ CommandPauseLevel::NoConstruction, // CommandType::RouteManagement
+ CommandPauseLevel::NoConstruction, // CommandType::OtherManagement
+ CommandPauseLevel::NoActions, // CommandType::CompanySetting
+ CommandPauseLevel::NoActions, // CommandType::ServerSetting
+ CommandPauseLevel::NoActions, // CommandType::Cheat
};
- static_assert(lengthof(command_type_lookup) == CMDT_END);
+ static_assert(std::size(command_type_lookup) == to_underlying(CommandType::End));
assert(IsValidCommand(cmd));
- return _game_mode == GM_EDITOR || command_type_lookup[_command_proc_table[cmd].type] <= _settings_game.construction.command_pause_level;
+ return _game_mode == GM_EDITOR || command_type_lookup[to_underlying(_command_proc_table[cmd].type)] <= _settings_game.construction.command_pause_level;
}
/**
@@ -384,7 +384,7 @@ CommandCost CommandHelperBase::InternalExecuteProcessResult(Commands cmd, Comman
SubtractMoneyFromCompany(res_exec);
/* Record if there was a command issues during pause; ignore pause/other setting related changes. */
- if (_pause_mode.Any() && _command_proc_table[cmd].type != CMDT_SERVER_SETTING) _pause_mode.Set(PauseMode::CommandDuringPause);
+ if (_pause_mode.Any() && _command_proc_table[cmd].type != CommandType::ServerSetting) _pause_mode.Set(PauseMode::CommandDuringPause);
/* update signals if needed */
UpdateSignalsInBuffer();
diff --git a/src/command_type.h b/src/command_type.h
index 893a03d44cc8a..babf32dd5489f 100644
--- a/src/command_type.h
+++ b/src/command_type.h
@@ -380,7 +380,7 @@ enum Commands : uint8_t {
*
* This enums defines some flags which can be used for the commands.
*/
-enum DoCommandFlag : uint8_t {
+enum class DoCommandFlag : uint8_t {
Execute, ///< execute the given command
Auto, ///< don't allow building on structures
QueryCost, ///< query cost only, don't build.
@@ -417,26 +417,27 @@ enum class CommandFlag : uint8_t {
using CommandFlags = EnumBitSet;
/** Types of commands we have. */
-enum CommandType : uint8_t {
- CMDT_LANDSCAPE_CONSTRUCTION, ///< Construction and destruction of objects on the map.
- CMDT_VEHICLE_CONSTRUCTION, ///< Construction, modification (incl. refit) and destruction of vehicles.
- CMDT_MONEY_MANAGEMENT, ///< Management of money, i.e. loans.
- CMDT_VEHICLE_MANAGEMENT, ///< Stopping, starting, sending to depot, turning around, replace orders etc.
- CMDT_ROUTE_MANAGEMENT, ///< Modifications to route management (orders, groups, etc).
- CMDT_OTHER_MANAGEMENT, ///< Renaming stuff, changing company colours, placing signs, etc.
- CMDT_COMPANY_SETTING, ///< Changing settings related to a company.
- CMDT_SERVER_SETTING, ///< Pausing/removing companies/server settings.
- CMDT_CHEAT, ///< A cheat of some sorts.
-
- CMDT_END, ///< Magic end marker.
+enum class CommandType : uint8_t {
+ LandscapeConstruction, ///< Construction and destruction of objects on the map.
+ VehicleConstruction, ///< Construction, modification (incl. refit) and destruction of vehicles.
+ MoneyManagement, ///< Management of money, i.e. loans.
+ VehicleManagement, ///< Stopping, starting, sending to depot, turning around, replace orders etc.
+ RouteManagement, ///< Modifications to route management (orders, groups, etc).
+ OtherManagement, ///< Renaming stuff, changing company colours, placing signs, etc.
+ CompanySetting, ///< Changing settings related to a company.
+ ServerSetting, ///< Pausing/removing companies/server settings.
+ Cheat, ///< A cheat of some sorts.
+
+ End, ///< End marker.
};
/** Different command pause levels. */
-enum CommandPauseLevel : uint8_t {
- CMDPL_NO_ACTIONS, ///< No user actions may be executed.
- CMDPL_NO_CONSTRUCTION, ///< No construction actions may be executed.
- CMDPL_NO_LANDSCAPING, ///< No landscaping actions may be executed.
- CMDPL_ALL_ACTIONS, ///< All actions may be executed.
+
+enum class CommandPauseLevel : uint8_t {
+ NoActions, ///< No user actions may be executed.
+ NoConstruction, ///< No construction actions may be executed.
+ NoLandscaping, ///< No landscaping actions may be executed.
+ AllActions, ///< All actions may be executed.
};
diff --git a/src/company_base.h b/src/company_base.h
index cdaca96dc4a4c..a5b028aa06a6d 100644
--- a/src/company_base.h
+++ b/src/company_base.h
@@ -30,8 +30,8 @@ struct CompanyEconomyEntry {
};
struct CompanyInfrastructure {
- std::array rail{}; ///< Count of company owned track bits for each rail type.
- std::array road{}; ///< Count of company owned track bits for each road type.
+ std::map rail{}; ///< Count of company owned track bits for each rail type.
+ std::map road{}; ///< Count of company owned track bits for each road type.
uint32_t signal = 0; ///< Count of company owned signals.
uint32_t water = 0; ///< Count of company owned track bits for canals.
uint32_t station = 0; ///< Count of company owned station tiles.
@@ -39,14 +39,23 @@ struct CompanyInfrastructure {
auto operator<=>(const CompanyInfrastructure &) const = default;
- /** Get total sum of all owned track bits. */
- uint32_t GetRailTotal() const
+ uint32_t GetRailTotal() const;
+ uint32_t GetRoadTramTotal(RoadTramType rtt) const;
+
+ inline uint32_t GetRoadTotal() const { return GetRoadTramTotal(RTT_ROAD); }
+ inline uint32_t GetTramTotal() const { return GetRoadTramTotal(RTT_TRAM); }
+
+ inline uint32_t GetRailCount(RailType railtype) const
{
- return std::accumulate(std::begin(this->rail), std::end(this->rail), 0U);
+ auto it = this->rail.find(railtype);
+ return it == std::end(this->rail) ? 0 : it->second;
}
- uint32_t GetRoadTotal() const;
- uint32_t GetTramTotal() const;
+ inline uint32_t GetRoadCount(RoadType roadtype) const
+ {
+ auto it = this->road.find(roadtype);
+ return it == std::end(this->road) ? 0 : it->second;
+ }
};
class FreeUnitIDGenerator {
@@ -178,6 +187,18 @@ struct Company : CompanyProperties, CompanyPool::PoolItem<&_company_pool> {
return !Company::Get(index)->is_ai;
}
+ /**
+ * Get offset for recolour palette of specific company.
+ * @param livery_scheme Scheme to use for recolour.
+ * @param use_secondary Specify whether to add secondary colour offset to the result.
+ * @return palette offset.
+ */
+ inline uint8_t GetCompanyRecolourOffset(LiveryScheme livery_scheme, bool use_secondary = true) const
+ {
+ const Livery &l = this->livery[livery_scheme];
+ return use_secondary ? l.colour1 + l.colour2 * 16 : l.colour1;
+ }
+
static void PostDestructor(size_t index);
};
diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp
index e9fc5f94ff882..30414d1b7b4e9 100644
--- a/src/company_cmd.cpp
+++ b/src/company_cmd.cpp
@@ -574,14 +574,14 @@ restart:;
void ResetCompanyLivery(Company *c)
{
for (LiveryScheme scheme = LS_BEGIN; scheme < LS_END; scheme++) {
- c->livery[scheme].in_use = 0;
+ c->livery[scheme].in_use.Reset();
c->livery[scheme].colour1 = c->colour;
c->livery[scheme].colour2 = c->colour;
}
for (Group *g : Group::Iterate()) {
if (g->owner == c->index) {
- g->livery.in_use = 0;
+ g->livery.in_use.Reset();
g->livery.colour1 = c->colour;
g->livery.colour2 = c->colour;
}
@@ -925,7 +925,7 @@ CommandCost CmdCompanyCtrl(DoCommandFlags flags, CompanyCtrlAction cca, CompanyI
if (!_company_manager_face.empty()) {
auto cmf = ParseCompanyManagerFaceCode(_company_manager_face);
if (cmf.has_value()) {
- Command::SendNet(STR_NULL, c->index, cmf->bits, cmf->style);
+ Command::SendNet(STR_NULL, c->index, cmf->style, cmf->bits);
}
}
@@ -1050,11 +1050,11 @@ CommandCost CmdCompanyAllowListCtrl(DoCommandFlags flags, CompanyAllowListCtrlAc
/**
* Change the company manager's face.
* @param flags operation to perform
- * @param bits The bits of company manager face.
* @param style The style of the company manager face.
+ * @param bits The bits of company manager face.
* @return the cost of this operation or an error
*/
-CommandCost CmdSetCompanyManagerFace(DoCommandFlags flags, uint32_t bits, uint style)
+CommandCost CmdSetCompanyManagerFace(DoCommandFlags flags, uint style, uint32_t bits)
{
CompanyManagerFace tmp_face{style, bits, {}};
if (!IsValidCompanyManagerFace(tmp_face)) return CMD_ERROR;
@@ -1077,8 +1077,8 @@ CommandCost CmdSetCompanyManagerFace(DoCommandFlags flags, uint32_t bits, uint s
void UpdateCompanyLiveries(Company *c)
{
for (int i = 1; i < LS_END; i++) {
- if (!HasBit(c->livery[i].in_use, 0)) c->livery[i].colour1 = c->livery[LS_DEFAULT].colour1;
- if (!HasBit(c->livery[i].in_use, 1)) c->livery[i].colour2 = c->livery[LS_DEFAULT].colour2;
+ if (!c->livery[i].in_use.Test(Livery::Flag::Primary)) c->livery[i].colour1 = c->livery[LS_DEFAULT].colour1;
+ if (!c->livery[i].in_use.Test(Livery::Flag::Secondary)) c->livery[i].colour2 = c->livery[LS_DEFAULT].colour2;
}
UpdateCompanyGroupLiveries(c);
}
@@ -1109,7 +1109,7 @@ CommandCost CmdSetCompanyColour(DoCommandFlags flags, LiveryScheme scheme, bool
if (flags.Test(DoCommandFlag::Execute)) {
if (primary) {
- if (scheme != LS_DEFAULT) AssignBit(c->livery[scheme].in_use, 0, colour != INVALID_COLOUR);
+ if (scheme != LS_DEFAULT) c->livery[scheme].in_use.Set(Livery::Flag::Primary, colour != INVALID_COLOUR);
if (colour == INVALID_COLOUR) colour = c->livery[LS_DEFAULT].colour1;
c->livery[scheme].colour1 = colour;
@@ -1122,7 +1122,7 @@ CommandCost CmdSetCompanyColour(DoCommandFlags flags, LiveryScheme scheme, bool
CompanyAdminUpdate(c);
}
} else {
- if (scheme != LS_DEFAULT) AssignBit(c->livery[scheme].in_use, 1, colour != INVALID_COLOUR);
+ if (scheme != LS_DEFAULT) c->livery[scheme].in_use.Set(Livery::Flag::Secondary, colour != INVALID_COLOUR);
if (colour == INVALID_COLOUR) colour = c->livery[LS_DEFAULT].colour2;
c->livery[scheme].colour2 = colour;
@@ -1131,16 +1131,16 @@ CommandCost CmdSetCompanyColour(DoCommandFlags flags, LiveryScheme scheme, bool
}
}
- if (c->livery[scheme].in_use != 0) {
+ if (c->livery[scheme].in_use.Any({Livery::Flag::Primary, Livery::Flag::Secondary})) {
/* If enabling a scheme, set the default scheme to be in use too */
- c->livery[LS_DEFAULT].in_use = 1;
+ c->livery[LS_DEFAULT].in_use.Set(Livery::Flag::Primary);
} else {
/* Else loop through all schemes to see if any are left enabled.
* If not, disable the default scheme too. */
- c->livery[LS_DEFAULT].in_use = 0;
+ c->livery[LS_DEFAULT].in_use.Reset({Livery::Flag::Primary, Livery::Flag::Secondary});
for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
- if (c->livery[scheme].in_use != 0) {
- c->livery[LS_DEFAULT].in_use = 1;
+ if (c->livery[scheme].in_use.Any({Livery::Flag::Primary, Livery::Flag::Secondary})) {
+ c->livery[LS_DEFAULT].in_use.Set(Livery::Flag::Primary);
break;
}
}
@@ -1290,27 +1290,29 @@ int CompanyServiceInterval(const Company *c, VehicleType type)
}
/**
- * Get total sum of all owned road bits.
- * @return Combined total road road bits.
+ * Get total sum of all owned track bits.
+ * @return Combined total rail track bits.
*/
-uint32_t CompanyInfrastructure::GetRoadTotal() const
+uint32_t CompanyInfrastructure::GetRailTotal() const
{
uint32_t total = 0;
- for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) {
- if (RoadTypeIsRoad(rt)) total += this->road[rt];
+ for (const auto &[_, count] : this->rail) {
+ total += count;
}
return total;
}
/**
- * Get total sum of all owned tram bits.
- * @return Combined total of tram road bits.
+ * Get total sum of all owned road bits.
+ * @param rtt RoadTramType to get total for.
+ * @return Combined total road road bits.
*/
-uint32_t CompanyInfrastructure::GetTramTotal() const
+uint32_t CompanyInfrastructure::GetRoadTramTotal(RoadTramType rtt) const
{
uint32_t total = 0;
- for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) {
- if (RoadTypeIsTram(rt)) total += this->road[rt];
+ auto mask = GetMaskForRoadTramType(rtt);
+ for (const auto &[roadtype, count] : this->road) {
+ if (mask.Test(roadtype)) total += count;
}
return total;
}
diff --git a/src/company_cmd.h b/src/company_cmd.h
index eb30f9b361b07..a18af2f8cb7eb 100644
--- a/src/company_cmd.h
+++ b/src/company_cmd.h
@@ -25,12 +25,12 @@ CommandCost CmdRenamePresident(DoCommandFlags flags, const std::string &text);
CommandCost CmdSetCompanyManagerFace(DoCommandFlags flags, uint style, uint32_t bits);
CommandCost CmdSetCompanyColour(DoCommandFlags flags, LiveryScheme scheme, bool primary, Colours colour);
-DEF_CMD_TRAIT(CMD_COMPANY_CTRL, CmdCompanyCtrl, CommandFlags({CommandFlag::Spectator, CommandFlag::ClientID, CommandFlag::NoEst}), CMDT_SERVER_SETTING)
-DEF_CMD_TRAIT(CMD_COMPANY_ALLOW_LIST_CTRL, CmdCompanyAllowListCtrl, CommandFlag::NoEst, CMDT_SERVER_SETTING)
-DEF_CMD_TRAIT(CMD_GIVE_MONEY, CmdGiveMoney, {}, CMDT_MONEY_MANAGEMENT)
-DEF_CMD_TRAIT(CMD_RENAME_COMPANY, CmdRenameCompany, {}, CMDT_COMPANY_SETTING)
-DEF_CMD_TRAIT(CMD_RENAME_PRESIDENT, CmdRenamePresident, {}, CMDT_COMPANY_SETTING)
-DEF_CMD_TRAIT(CMD_SET_COMPANY_MANAGER_FACE, CmdSetCompanyManagerFace, {}, CMDT_COMPANY_SETTING)
-DEF_CMD_TRAIT(CMD_SET_COMPANY_COLOUR, CmdSetCompanyColour, {}, CMDT_COMPANY_SETTING)
+DEF_CMD_TRAIT(CMD_COMPANY_CTRL, CmdCompanyCtrl, CommandFlags({CommandFlag::Spectator, CommandFlag::ClientID, CommandFlag::NoEst}), CommandType::ServerSetting)
+DEF_CMD_TRAIT(CMD_COMPANY_ALLOW_LIST_CTRL, CmdCompanyAllowListCtrl, CommandFlag::NoEst, CommandType::ServerSetting)
+DEF_CMD_TRAIT(CMD_GIVE_MONEY, CmdGiveMoney, {}, CommandType::MoneyManagement)
+DEF_CMD_TRAIT(CMD_RENAME_COMPANY, CmdRenameCompany, {}, CommandType::CompanySetting)
+DEF_CMD_TRAIT(CMD_RENAME_PRESIDENT, CmdRenamePresident, {}, CommandType::CompanySetting)
+DEF_CMD_TRAIT(CMD_SET_COMPANY_MANAGER_FACE, CmdSetCompanyManagerFace, {}, CommandType::CompanySetting)
+DEF_CMD_TRAIT(CMD_SET_COMPANY_COLOUR, CmdSetCompanyColour, {}, CommandType::CompanySetting)
#endif /* COMPANY_CMD_H */
diff --git a/src/company_gui.cpp b/src/company_gui.cpp
index 9debd59c5bbed..30c77add9cc9e 100644
--- a/src/company_gui.cpp
+++ b/src/company_gui.cpp
@@ -286,7 +286,7 @@ static void DrawYearColumn(const Rect &r, TimerGameEconomy::Year year, const Exp
DrawPrice(sum, r.left, r.right, y, TC_WHITE);
}
-static constexpr NWidgetPart _nested_company_finances_widgets[] = {
+static constexpr std::initializer_list _nested_company_finances_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_CF_CAPTION),
@@ -655,7 +655,7 @@ struct SelectCompanyLiveryWindow : public Window {
}
uint8_t sel;
- if (default_livery == nullptr || HasBit(livery->in_use, primary ? 0 : 1)) {
+ if (default_livery == nullptr || livery->in_use.Test(primary ? Livery::Flag::Primary : Livery::Flag::Secondary)) {
sel = primary ? livery->colour1 : livery->colour2;
} else {
sel = default_col;
@@ -819,7 +819,7 @@ struct SelectCompanyLiveryWindow : public Window {
}
if (scheme == LS_END) scheme = LS_DEFAULT;
const Livery *livery = &c->livery[scheme];
- if (scheme == LS_DEFAULT || HasBit(livery->in_use, primary ? 0 : 1)) {
+ if (scheme == LS_DEFAULT || livery->in_use.Test(primary ? Livery::Flag::Primary : Livery::Flag::Secondary)) {
colour = STR_COLOUR_DARK_BLUE + (primary ? livery->colour1 : livery->colour2);
}
}
@@ -827,7 +827,7 @@ struct SelectCompanyLiveryWindow : public Window {
if (this->sel != GroupID::Invalid()) {
const Group *g = Group::Get(this->sel);
const Livery *livery = &g->livery;
- if (HasBit(livery->in_use, primary ? 0 : 1)) {
+ if (livery->in_use.Test(primary ? Livery::Flag::Primary : Livery::Flag::Secondary)) {
colour = STR_COLOUR_DARK_BLUE + (primary ? livery->colour1 : livery->colour2);
}
}
@@ -875,12 +875,12 @@ struct SelectCompanyLiveryWindow : public Window {
/* Text below the first dropdown. */
DrawSprite(SPR_SQUARE, GetColourPalette(livery.colour1), pri_squ.left, y + square_offs);
- DrawString(pri.left, pri.right, y + text_offs, (is_default_scheme || HasBit(livery.in_use, 0)) ? STR_COLOUR_DARK_BLUE + livery.colour1 : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
+ DrawString(pri.left, pri.right, y + text_offs, (is_default_scheme || livery.in_use.Test(Livery::Flag::Primary)) ? STR_COLOUR_DARK_BLUE + livery.colour1 : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
/* Text below the second dropdown. */
if (sec.right > sec.left) { // Second dropdown has non-zero size.
DrawSprite(SPR_SQUARE, GetColourPalette(livery.colour2), sec_squ.left, y + square_offs);
- DrawString(sec.left, sec.right, y + text_offs, (is_default_scheme || HasBit(livery.in_use, 1)) ? STR_COLOUR_DARK_BLUE + livery.colour2 : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
+ DrawString(sec.left, sec.right, y + text_offs, (is_default_scheme || livery.in_use.Test(Livery::Flag::Secondary)) ? STR_COLOUR_DARK_BLUE + livery.colour2 : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
}
y += this->line_height;
@@ -1062,7 +1062,7 @@ struct SelectCompanyLiveryWindow : public Window {
}
};
-static constexpr NWidgetPart _nested_select_company_livery_widgets[] = {
+static constexpr std::initializer_list _nested_select_company_livery_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_SCL_CAPTION),
@@ -1161,7 +1161,7 @@ void DrawCompanyManagerFace(const CompanyManagerFace &cmf, Colours colour, const
}
/** Nested widget description for the company manager face selection dialog */
-static constexpr NWidgetPart _nested_select_company_manager_face_widgets[] = {
+static constexpr std::initializer_list _nested_select_company_manager_face_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_SCMF_CAPTION), SetStringTip(STR_FACE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
@@ -1333,8 +1333,8 @@ class SelectCompanyManagerFaceWindow : public Window
Rect ir = r.Shrink(WidgetDimensions::scaled.frametext, RectPadding::zero).WithHeight(this->line_height);
bool rtl = _current_text_dir == TD_RTL;
- Rect br = ir.CentreTo(ir.Width(), SETTING_BUTTON_HEIGHT).WithWidth(SETTING_BUTTON_WIDTH, rtl);
- Rect tr = ir.Shrink(RectPadding::zero, WidgetDimensions::scaled.matrix).CentreTo(ir.Width(), GetCharacterHeight(FS_NORMAL)).Indent(SETTING_BUTTON_WIDTH + WidgetDimensions::scaled.hsep_wide, rtl);
+ Rect br = ir.CentreToHeight(SETTING_BUTTON_HEIGHT).WithWidth(SETTING_BUTTON_WIDTH, rtl);
+ Rect tr = ir.Shrink(RectPadding::zero, WidgetDimensions::scaled.matrix).CentreToHeight(GetCharacterHeight(FS_NORMAL)).Indent(SETTING_BUTTON_WIDTH + WidgetDimensions::scaled.hsep_wide, rtl);
DrawArrowButtons(br.left, br.top, COLOUR_YELLOW, this->selected_var == UINT_MAX - 1 ? this->click_state : 0, true, true);
DrawString(tr, GetString(STR_FACE_SETTING_NUMERIC, STR_FACE_STYLE, this->face.style + 1, GetNumCompanyManagerFaceStyles()), TC_WHITE);
@@ -1352,8 +1352,8 @@ class SelectCompanyManagerFaceWindow : public Window
const uint8_t var = static_cast(*it - vars.data());
const FaceVar &facevar = **it;
- Rect br = ir.CentreTo(ir.Width(), SETTING_BUTTON_HEIGHT).WithWidth(SETTING_BUTTON_WIDTH, rtl);
- Rect tr = ir.Shrink(RectPadding::zero, WidgetDimensions::scaled.matrix).CentreTo(ir.Width(), GetCharacterHeight(FS_NORMAL)).Indent(SETTING_BUTTON_WIDTH + WidgetDimensions::scaled.hsep_wide, rtl);
+ Rect br = ir.CentreToHeight(SETTING_BUTTON_HEIGHT).WithWidth(SETTING_BUTTON_WIDTH, rtl);
+ Rect tr = ir.Shrink(RectPadding::zero, WidgetDimensions::scaled.matrix).CentreToHeight(GetCharacterHeight(FS_NORMAL)).Indent(SETTING_BUTTON_WIDTH + WidgetDimensions::scaled.hsep_wide, rtl);
uint val = vars[var].GetBits(this->face);
if (facevar.type == FaceVarType::Toggle) {
@@ -1384,7 +1384,7 @@ class SelectCompanyManagerFaceWindow : public Window
/* OK button */
case WID_SCMF_ACCEPT:
- Command::Post(this->face.bits, this->face.style);
+ Command::Post(this->face.style, this->face.bits);
[[fallthrough]];
/* Cancel button */
@@ -1536,7 +1536,7 @@ static void DoSelectCompanyManagerFace(Window *parent)
new SelectCompanyManagerFaceWindow(_select_company_manager_face_desc, parent);
}
-static constexpr NWidgetPart _nested_company_infrastructure_widgets[] = {
+static constexpr std::initializer_list _nested_company_infrastructure_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_CI_CAPTION),
@@ -1604,10 +1604,11 @@ struct CompanyInfrastructureWindow : Window
this->list.emplace_back(InfrastructureItemType::Header, STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT);
for (const RailType &rt : _sorted_railtypes) {
- if (c->infrastructure.rail[rt] == 0) continue;
- Money monthly_cost = RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total);
+ auto it = c->infrastructure.rail.find(rt);
+ if (it == std::end(c->infrastructure.rail) || it->second == 0) continue;
+ Money monthly_cost = RailMaintenanceCost(rt, it->second, rail_total);
total_monthly_cost += monthly_cost;
- this->list.emplace_back(InfrastructureItemType::Value, GetRailTypeInfo(rt)->strings.name, c->infrastructure.rail[rt], monthly_cost);
+ this->list.emplace_back(InfrastructureItemType::Value, GetRailTypeInfo(rt)->strings.name, it->second, monthly_cost);
}
if (c->infrastructure.signal > 0) {
@@ -1624,10 +1625,11 @@ struct CompanyInfrastructureWindow : Window
for (const RoadType &rt : _sorted_roadtypes) {
if (!RoadTypeIsRoad(rt)) continue;
- if (c->infrastructure.road[rt] == 0) continue;
- Money monthly_cost = RoadMaintenanceCost(rt, c->infrastructure.road[rt], road_total);
+ auto it = c->infrastructure.road.find(rt);
+ if (it == std::end(c->infrastructure.road) || it->second == 0) continue;
+ Money monthly_cost = RoadMaintenanceCost(rt, it->second, road_total);
total_monthly_cost += monthly_cost;
- this->list.emplace_back(InfrastructureItemType::Value, GetRoadTypeInfo(rt)->strings.name, c->infrastructure.road[rt], monthly_cost);
+ this->list.emplace_back(InfrastructureItemType::Value, GetRoadTypeInfo(rt)->strings.name, it->second, monthly_cost);
}
}
@@ -1638,10 +1640,11 @@ struct CompanyInfrastructureWindow : Window
for (const RoadType &rt : _sorted_roadtypes) {
if (!RoadTypeIsTram(rt)) continue;
- if (c->infrastructure.road[rt] == 0) continue;
- Money monthly_cost = RoadMaintenanceCost(rt, c->infrastructure.road[rt], tram_total);
+ auto it = c->infrastructure.road.find(rt);
+ if (it == std::end(c->infrastructure.road) || it->second == 0) continue;
+ Money monthly_cost = RoadMaintenanceCost(rt, it->second, tram_total);
total_monthly_cost += monthly_cost;
- this->list.emplace_back(InfrastructureItemType::Value, GetRoadTypeInfo(rt)->strings.name, c->infrastructure.road[rt], monthly_cost);
+ this->list.emplace_back(InfrastructureItemType::Value, GetRoadTypeInfo(rt)->strings.name, it->second, monthly_cost);
}
}
@@ -1840,7 +1843,7 @@ static void ShowCompanyInfrastructure(CompanyID company)
AllocateWindowDescFront(_company_infrastructure_desc, company);
}
-static constexpr NWidgetPart _nested_company_widgets[] = {
+static constexpr std::initializer_list _nested_company_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_C_CAPTION),
@@ -2072,8 +2075,7 @@ struct CompanyWindow : Window
y += GetCharacterHeight(FS_NORMAL);
}
- /* GetRoadTotal() skips tram pieces, but we actually want road and tram here. */
- uint road_pieces = std::accumulate(std::begin(c->infrastructure.road), std::end(c->infrastructure.road), 0U);
+ uint road_pieces = c->infrastructure.GetRoadTotal() + c->infrastructure.GetTramTotal();
if (road_pieces != 0) {
DrawString(r.left, r.right, y, GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD, road_pieces));
y += GetCharacterHeight(FS_NORMAL);
@@ -2405,7 +2407,7 @@ struct BuyCompanyWindow : Window {
Money company_value{}; ///< The value of the company for which the user can buy it.
};
-static constexpr NWidgetPart _nested_buy_company_widgets[] = {
+static constexpr std::initializer_list _nested_buy_company_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE, WID_BC_CAPTION),
diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp
index 338c9a209ab0d..1e4479fc162b4 100644
--- a/src/console_cmds.cpp
+++ b/src/console_cmds.cpp
@@ -46,6 +46,10 @@
#include "company_cmd.h"
#include "misc_cmd.h"
+#if defined(WITH_ZLIB)
+#include "network/network_content.h"
+#endif /* WITH_ZLIB */
+
#include "table/strings.h"
#include "safeguards.h"
@@ -2163,7 +2167,7 @@ static bool ConNetworkAuthorizedKey(std::span argv)
}
for (auto [name, authorized_keys] : _console_cmd_authorized_keys) {
- if (StrEqualsIgnoreCase(type, name)) continue;
+ if (!StrEqualsIgnoreCase(type, name)) continue;
PerformNetworkAuthorizedKeyAction(name, authorized_keys, action, authorized_key);
return true;
@@ -2176,7 +2180,6 @@ static bool ConNetworkAuthorizedKey(std::span argv)
/* Content downloading only is available with ZLIB */
#if defined(WITH_ZLIB)
-#include "network/network_content.h"
/** Resolve a string to a content type. */
static ContentType StringToContentType(std::string_view str)
@@ -2699,7 +2702,7 @@ static std::string FormatLabel(uint32_t label)
return fmt::format("{:c}{:c}{:c}{:c}", GB(label, 24, 8), GB(label, 16, 8), GB(label, 8, 8), GB(label, 0, 8));
}
- return fmt::format("{:08X}", std::byteswap(label));
+ return fmt::format("{:08X}", label);
}
static void ConDumpRoadTypes()
@@ -2712,7 +2715,7 @@ static void ConDumpRoadTypes()
IConsolePrint(CC_DEFAULT, " T = buildable by towns");
std::map grfs;
- for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) {
+ for (RoadType rt = ROADTYPE_BEGIN; rt < GetNumRoadTypes(); rt++) {
const RoadTypeInfo *rti = GetRoadTypeInfo(rt);
if (rti->label == 0) continue;
uint32_t grfid = 0;
@@ -2750,7 +2753,7 @@ static void ConDumpRailTypes()
IConsolePrint(CC_DEFAULT, " d = always disallow 90 degree turns");
std::map grfs;
- for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) {
+ for (RailType rt = RAILTYPE_BEGIN; rt < GetNumRailTypes(); rt++) {
const RailTypeInfo *rti = GetRailTypeInfo(rt);
if (rti->label == 0) continue;
uint32_t grfid = 0;
diff --git a/src/console_gui.cpp b/src/console_gui.cpp
index db8831f25923e..1dba122e92c2d 100644
--- a/src/console_gui.cpp
+++ b/src/console_gui.cpp
@@ -133,7 +133,7 @@ static inline void IConsoleResetHistoryPos()
static std::optional IConsoleHistoryAdd(std::string_view cmd);
static void IConsoleHistoryNavigate(int direction);
-static constexpr NWidgetPart _nested_console_window_widgets[] = {
+static constexpr std::initializer_list _nested_console_window_widgets = {
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_BACKGROUND), SetResize(1, 1),
};
@@ -453,7 +453,7 @@ void IConsoleClose()
static std::optional IConsoleHistoryAdd(std::string_view cmd)
{
/* Strip all spaces at the begin */
- while (IsWhitespace(cmd[0])) cmd.remove_prefix(1);
+ while (!cmd.empty() && IsWhitespace(cmd[0])) cmd.remove_prefix(1);
/* Do not put empty command in history */
if (cmd.empty()) return std::nullopt;
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 224cfba0eba13..fa76393137a7d 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -22,7 +22,6 @@ add_files(
pool_type.hpp
random_func.cpp
random_func.hpp
- smallstack_type.hpp
string_builder.cpp
string_builder.hpp
string_consumer.cpp
diff --git a/src/core/base_bitset_type.hpp b/src/core/base_bitset_type.hpp
index 9ce8528d3160a..3b50d4e033b9f 100644
--- a/src/core/base_bitset_type.hpp
+++ b/src/core/base_bitset_type.hpp
@@ -254,8 +254,8 @@ class BaseBitSet {
return std::nullopt;
}
- auto begin() const { return SetBitIterator(this->data).begin(); }
- auto end() const { return SetBitIterator(this->data).end(); }
+ auto begin() const { return SetBitIterator(this->data).begin(); }
+ auto end() const { return SetBitIterator(this->data).end(); }
private:
Tstorage data; ///< Bitmask of values.
diff --git a/src/core/flatset_type.hpp b/src/core/flatset_type.hpp
index 2dc42d0b48107..f114c302f316a 100644
--- a/src/core/flatset_type.hpp
+++ b/src/core/flatset_type.hpp
@@ -54,7 +54,7 @@ class FlatSet {
* @param key Key to test.
* @return true iff the key exists in the set.
*/
- bool contains(const Tkey &key)
+ bool contains(const Tkey &key) const
{
return std::ranges::binary_search(this->data, key, Tcompare{});
}
@@ -73,4 +73,61 @@ class FlatSet {
auto operator<=>(const FlatSet &) const = default;
};
+/**
+ * Adapter for FlatSet that provides part of the (Base)BitSet-like interface.
+ * @tparam Tkey key type.
+ * @tparam Tcompare key comparator.
+ */
+template >
+struct FlatBitSet : FlatSet {
+ FlatBitSet() = default;
+
+ FlatBitSet(Tkey value)
+ {
+ this->Set(value);
+ }
+
+ FlatBitSet(std::initializer_list values)
+ {
+ for (const Tkey &value : values) {
+ this->Set(value);
+ }
+ }
+
+ void Set(Tkey value) { this->insert(value); }
+
+ void Set(Tkey value, bool set)
+ {
+ if (set) {
+ this->insert(value);
+ } else {
+ this->erase(value);
+ }
+ }
+
+ bool Test(Tkey value) const { return this->contains(value); }
+
+ bool Any() const { return this->size() != 0; }
+
+ void Set(const FlatBitSet &other)
+ {
+ std::ranges::for_each(other, [this](const Tkey &value) { this->insert(value); });
+ }
+
+ void Reset(const FlatBitSet &other)
+ {
+ std::ranges::for_each(other, [this](const Tkey &value) { this->erase(value); });
+ }
+
+ bool Any(const FlatBitSet &other) const
+ {
+ return std::ranges::any_of(other, [this](const Tkey &value) { return this->contains(value); });
+ }
+
+ bool All(const FlatBitSet &other) const
+ {
+ return std::ranges::all_of(other, [this](const Tkey &value) { return this->contains(value); });
+ }
+};
+
#endif /* FLATSET_TYPE_HPP */
diff --git a/src/core/geometry_type.hpp b/src/core/geometry_type.hpp
index b3400c2cc3eff..e46315899ebb0 100644
--- a/src/core/geometry_type.hpp
+++ b/src/core/geometry_type.hpp
@@ -62,14 +62,14 @@ struct Dimension {
bool operator< (const Dimension &other) const
{
- int x = (*this).width - other.width;
+ int x = this->width - other.width;
if (x != 0) return x < 0;
- return (*this).height < other.height;
+ return this->height < other.height;
}
bool operator== (const Dimension &other) const
{
- return (*this).width == other.width && (*this).height == other.height;
+ return this->width == other.width && this->height == other.height;
}
};
@@ -211,8 +211,8 @@ struct Rect {
[[nodiscard]] inline Rect WithWidth(int width, bool end) const
{
return end
- ? Rect {this->right - width + 1, this->top, this->right, this->bottom}
- : Rect {this->left, this->top, this->left + width - 1, this->bottom};
+ ? this->WithX(this->right - width + 1, this->right)
+ : this->WithX(this->left, this->left + width - 1);
}
/**
@@ -224,21 +224,21 @@ struct Rect {
[[nodiscard]] inline Rect Indent(int indent, bool end) const
{
return end
- ? Rect {this->left, this->top, this->right - indent, this->bottom}
- : Rect {this->left + indent, this->top, this->right, this->bottom};
+ ? this->WithX(this->left, this->right - indent)
+ : this->WithX(this->left + indent, this->right);
}
/**
* Copy Rect and set its height.
- * @param width height in pixels for new Rect.
+ * @param height height in pixels for new Rect.
* @param end if set, set height at end of Rect, i.e. at bottom.
* @return the new resized Rect.
*/
[[nodiscard]] inline Rect WithHeight(int height, bool end = false) const
{
return end
- ? Rect {this->left, this->bottom - height + 1, this->right, this->bottom}
- : Rect {this->left, this->top, this->right, this->top + height - 1};
+ ? this->WithY(this->bottom - height + 1, this->bottom)
+ : this->WithY(this->top, this->top + height - 1);
}
/**
@@ -253,17 +253,45 @@ struct Rect {
}
/**
- * Centre a dimension within this Rect.
- * @param width The horizontal dimension.
+ * Centre a vertical dimension within this Rect.
* @param height The vertical dimension.
* @return the new resized Rect.
*/
- [[nodiscard]] inline Rect CentreTo(int width, int height) const
+ [[nodiscard]] inline Rect CentreToHeight(int height) const
{
- int new_left = CentreBounds(this->left, this->right, width);
- int new_right = CentreBounds(this->top, this->bottom, height);
- return {new_left, new_right, new_left + width, new_right + height};
+ int new_top = CentreBounds(this->top, this->bottom, height);
+ return {this->left, new_top, this->right, new_top + height - 1};
}
+
+ /**
+ * Create a new Rect, replacing the left and right coordiates.
+ * @param new_left New left coordinate.
+ * @param new_right New right coordinate.
+ * @return The new Rect.
+ */
+ [[nodiscard]] inline Rect WithX(int new_left, int new_right) const { return {new_left, this->top, new_right, this->bottom}; }
+
+ /**
+ * Create a new Rect, replacing the top and bottom coordiates.
+ * @param new_top New top coordinate.
+ * @param new_bottom New bottom coordinate.
+ * @return The new Rect.
+ */
+ [[nodiscard]] inline Rect WithY(int new_top, int new_bottom) const { return {this->left, new_top, this->right, new_bottom}; }
+
+ /**
+ * Create a new Rect, replacing the left and right coordiates.
+ * @param other Rect containing the new left and right coordinates.
+ * @return The new Rect.
+ */
+ [[nodiscard]] inline Rect WithX(const Rect &other) const { return this->WithX(other.left, other.right); }
+
+ /**
+ * Create a new Rect, replacing the top and bottom coordiates.
+ * @param other Rect containing the new top and bottom coordinates.
+ * @return The new Rect.
+ */
+ [[nodiscard]] inline Rect WithY(const Rect &other) const { return this->WithY(other.top, other.bottom); }
};
/**
diff --git a/src/core/smallstack_type.hpp b/src/core/smallstack_type.hpp
deleted file mode 100644
index 3b26951453bbf..0000000000000
--- a/src/core/smallstack_type.hpp
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * This file is part of OpenTTD.
- * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
- * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see .
- */
-
-/** @file smallstack_type.hpp Minimal stack that uses a pool to avoid pointers and doesn't allocate any heap memory if there is only one valid item. */
-
-#ifndef SMALLSTACK_TYPE_HPP
-#define SMALLSTACK_TYPE_HPP
-
-/**
- * A simplified pool which stores values instead of pointers and doesn't
- * redefine operator new/delete. It also never zeroes memory and always reuses
- * it.
- */
-template
-class SimplePool {
-public:
- inline SimplePool() : first_unused(0), first_free(0) {}
-
- /**
- * Get the item at position index.
- * @return Item at index.
- */
- inline Titem &Get(Tindex index) { return this->data[index]; }
-
- /**
- * Create a new item and return its index.
- * @return Index of new item.
- */
- inline Tindex Create()
- {
- Tindex index = this->FindFirstFree();
- if (index < Tmax_size) {
- this->data[index].valid = true;
- this->first_free = index + 1;
- this->first_unused = std::max(this->first_unused, this->first_free);
- }
- return index;
- }
-
- /**
- * Destroy (or rather invalidate) the item at the given index.
- * @param index Index of item to be destroyed.
- */
- inline void Destroy(Tindex index)
- {
- this->data[index].valid = false;
- this->first_free = std::min(this->first_free, index);
- }
-
-private:
-
- inline Tindex FindFirstFree()
- {
- Tindex index = this->first_free;
- for (; index < this->first_unused; index++) {
- if (!this->data[index].valid) return index;
- }
-
- if (index >= this->data.size() && index < Tmax_size) {
- this->data.resize(index + 1);
- }
- return index;
- }
-
- struct SimplePoolPoolItem : public Titem {
- bool valid;
- };
-
- Tindex first_unused;
- Tindex first_free;
-
- std::vector data;
-};
-
-/**
- * Base class for SmallStack. We cannot add this into SmallStack itself as
- * certain compilers don't like it.
- */
-template
-struct SmallStackItem {
- Tindex next; ///< Pool index of next item.
- Titem value; ///< Value of current item.
-
- /**
- * Create a new item.
- * @param value Value of the item.
- * @param next Next item in the stack.
- */
- inline SmallStackItem(const Titem &value, Tindex next) :
- next(next), value(value) {}
- SmallStackItem() = default;
-};
-
-/**
- * Minimal stack that uses a pool to avoid pointers. It has some peculiar
- * properties that make it useful for passing around lists of IDs but not much
- * else:
- * 1. It always includes an invalid item as bottom.
- * 2. It doesn't have a deep copy operation but uses smart pointers instead.
- * Every copy is thus implicitly shared.
- * 3. Its items are immutable.
- * 4. Due to 2. and 3. memory management can be done by "branch counting".
- * Whenever you copy a smallstack, the first item on the heap increases its
- * branch_count, signifying that there are multiple items "in front" of it.
- * When deleting a stack items are deleted up to the point where
- * branch_count > 0.
- * 5. You can choose your own index type, so that you can align it with your
- * value type. E.G. value types of 16 bits length like to be combined with
- * index types of the same length.
- * @tparam Titem Value type to be used.
- * @tparam Tindex Index type to use for the pool.
- * @tparam Tinvalid_value Value to construct invalid item to keep at the bottom of each stack.
- * @tparam Tgrowth_step Growth step for pool.
- * @tparam Tmax_size Maximum size for pool.
- */
-template
-class SmallStack : public SmallStackItem {
-public:
- static constexpr Titem Tinvalid{Tinvalid_value};
-
- typedef SmallStackItem Item;
-
- /**
- * SmallStack item that can be kept in a pool.
- */
- struct PooledSmallStack : public Item {
- Tindex branch_count; ///< Number of branches in the tree structure this item is parent of
- };
-
- typedef SimplePool SmallStackPool;
-
- /**
- * Constructor for a stack with one or two items in it.
- * @param value Initial item. If not missing or Tinvalid there will be Tinvalid below it.
- */
- inline SmallStack(const Titem &value = Tinvalid) : Item(value, Tmax_size) {}
-
- /**
- * Remove the head of stack and all other items members that are unique to it.
- */
- inline ~SmallStack()
- {
- while (this->next != Tmax_size) this->Pop();
- }
-
- /**
- * Shallow copy the stack, marking the first item as branched.
- * @param other Stack to copy from
- */
- inline SmallStack(const SmallStack &other) : Item(other) { this->Branch(); }
-
- /**
- * Shallow copy the stack, marking the first item as branched.
- * @param other Stack to copy from
- * @return This smallstack.
- */
- inline SmallStack &operator=(const SmallStack &other)
- {
- if (this == &other) return *this;
- while (this->next != Tmax_size) this->Pop();
- this->next = other.next;
- this->value = other.value;
- /* Deleting and branching are independent operations, so it's fine to
- * acquire separate locks for them. */
- this->Branch();
- return *this;
- }
-
- /**
- * Pushes a new item onto the stack if there is still space in the
- * underlying pool. Otherwise the topmost item's value gets overwritten.
- * @param item Item to be pushed.
- */
- inline void Push(const Titem &item)
- {
- if (this->value != Tinvalid) {
- Tindex new_item = SmallStack::GetPool().Create();
- if (new_item != Tmax_size) {
- PooledSmallStack &pushed = SmallStack::GetPool().Get(new_item);
- pushed.value = this->value;
- pushed.next = this->next;
- pushed.branch_count = 0;
- this->next = new_item;
- }
- }
- this->value = item;
- }
-
- /**
- * Pop an item from the stack.
- * @return Current top of stack.
- */
- inline Titem Pop()
- {
- Titem ret = this->value;
- if (this->next == Tmax_size) {
- this->value = Tinvalid;
- } else {
- PooledSmallStack &popped = SmallStack::GetPool().Get(this->next);
- this->value = popped.value;
- if (popped.branch_count == 0) {
- SmallStack::GetPool().Destroy(this->next);
- } else {
- --popped.branch_count;
- if (popped.next != Tmax_size) {
- ++(SmallStack::GetPool().Get(popped.next).branch_count);
- }
- }
- /* Accessing popped here is no problem as the pool will only set
- * the validity flag, not actually delete the item, on Destroy(). */
- this->next = popped.next;
- }
- return ret;
- }
-
- /**
- * Check if the stack is empty.
- * @return If the stack is empty.
- */
- inline bool IsEmpty() const
- {
- return this->value == Tinvalid && this->next == Tmax_size;
- }
-
- /**
- * Check if the given item is contained in the stack.
- * @param item Item to look for.
- * @return If the item is in the stack.
- */
- inline bool Contains(const Titem &item) const
- {
- if (item == Tinvalid || item == this->value) return true;
- if (this->next != Tmax_size) {
- const SmallStack *in_list = this;
- do {
- in_list = static_cast(
- static_cast(&SmallStack::GetPool().Get(in_list->next)));
- if (in_list->value == item) return true;
- } while (in_list->next != Tmax_size);
- }
- return false;
- }
-
-protected:
- static SmallStackPool &GetPool()
- {
- static SmallStackPool pool;
- return pool;
- }
-
- /**
- * Create a branch in the pool if necessary.
- */
- inline void Branch()
- {
- if (this->next != Tmax_size) {
- ++(SmallStack::GetPool().Get(this->next).branch_count);
- }
- }
-};
-
-#endif
diff --git a/src/core/strong_typedef_type.hpp b/src/core/strong_typedef_type.hpp
index a89ec0460f08d..e818228d5057c 100644
--- a/src/core/strong_typedef_type.hpp
+++ b/src/core/strong_typedef_type.hpp
@@ -158,4 +158,31 @@ namespace StrongType {
};
}
+/**
+ * Implementation of std::hash for StrongType::Typedef.
+ *
+ * This specialization of std::hash allows hashing of StrongType::Typedef instances
+ * by leveraging the hash of the base type.
+ *
+ * Example Usage:
+ * using MyType = StrongType::Typedef;
+ * std::unordered_map my_map;
+ *
+ * @tparam TBaseType The underlying type of the StrongType::Typedef.
+ * @tparam TProperties Additional properties for the StrongType::Typedef.
+ */
+template
+struct std::hash> {
+ /**
+ * Computes the hash value for a StrongType::Typedef instance.
+ *
+ * @param t The StrongType::Typedef instance to hash.
+ * @return The hash value of the base type of t.
+ */
+ std::size_t operator()(const StrongType::Typedef &t) const noexcept
+ {
+ return std::hash()(t.base());
+ }
+};
+
#endif /* STRONG_TYPEDEF_TYPE_HPP */
diff --git a/src/date_gui.cpp b/src/date_gui.cpp
index 02ab436d6335d..81dbbd5ffcfdf 100644
--- a/src/date_gui.cpp
+++ b/src/date_gui.cpp
@@ -173,7 +173,7 @@ struct SetDateWindow : Window {
};
/** Widgets for the date setting window. */
-static constexpr NWidgetPart _nested_set_date_widgets[] = {
+static constexpr std::initializer_list _nested_set_date_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
NWidget(WWT_CAPTION, COLOUR_BROWN), SetStringTip(STR_DATE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
diff --git a/src/depot_cmd.h b/src/depot_cmd.h
index abd3e1900e9fe..69f558f6c5cab 100644
--- a/src/depot_cmd.h
+++ b/src/depot_cmd.h
@@ -16,7 +16,7 @@
CommandCost CmdRenameDepot(DoCommandFlags flags, DepotID depot_id, const std::string &text);
-DEF_CMD_TRAIT(CMD_RENAME_DEPOT, CmdRenameDepot, {}, CMDT_OTHER_MANAGEMENT)
+DEF_CMD_TRAIT(CMD_RENAME_DEPOT, CmdRenameDepot, {}, CommandType::OtherManagement)
void CcCloneVehicle(Commands cmd, const CommandCost &result, VehicleID veh_id);
diff --git a/src/depot_gui.cpp b/src/depot_gui.cpp
index d4ad2baa9ce43..bfec17d9aafa5 100644
--- a/src/depot_gui.cpp
+++ b/src/depot_gui.cpp
@@ -17,7 +17,7 @@
#include "viewport_func.h"
#include "command_func.h"
#include "depot_base.h"
-#include "spritecache.h"
+#include "spritecache_type.h"
#include "strings_func.h"
#include "sound_func.h"
#include "vehicle_func.h"
@@ -47,7 +47,7 @@
*/
/** Nested widget definition for train depots. */
-static constexpr NWidgetPart _nested_train_depot_widgets[] = {
+static constexpr std::initializer_list _nested_train_depot_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_D_SHOW_RENAME), SetAspect(WidgetDimensions::ASPECT_RENAME), // rename button
@@ -229,7 +229,7 @@ void InitDepotWindowBlockSizes()
if (!e->IsEnabled()) continue;
uint w = TRAININFO_DEFAULT_VEHICLE_WIDTH;
- if (e->GetGRF() != nullptr && IsCustomVehicleSpriteNum(e->u.rail.image_index)) {
+ if (e->GetGRF() != nullptr && IsCustomVehicleSpriteNum(e->VehInfo().image_index)) {
w = e->GetGRF()->traininfo_vehicle_width;
if (w != VEHICLEINFO_FULL_VEHICLE_WIDTH) {
/* Hopeless.
@@ -260,7 +260,7 @@ struct DepotWindow : Window {
VehicleType type = VEH_INVALID;
bool generate_list = true;
bool check_unitnumber_digits = true;
- WidgetID hovered_widget = -1; ///< Index of the widget being hovered during drag/drop. -1 if no drag is in progress.
+ WidgetID hovered_widget = INVALID_WIDGET; ///< Index of the widget being hovered during drag/drop. \c INVALID_WIDGET if no drag is in progress.
VehicleList vehicle_list{};
VehicleList wagon_list{};
uint unitnumber_digits = 2;
@@ -1001,10 +1001,10 @@ struct DepotWindow : Window {
this->vehicle_over = VehicleID::Invalid();
this->SetWidgetDirty(WID_D_MATRIX);
- if (this->hovered_widget != -1) {
+ if (this->hovered_widget != INVALID_WIDGET) {
this->SetWidgetLoweredState(this->hovered_widget, false);
this->SetWidgetDirty(this->hovered_widget);
- this->hovered_widget = -1;
+ this->hovered_widget = INVALID_WIDGET;
}
}
@@ -1116,7 +1116,7 @@ struct DepotWindow : Window {
this->SetDirty();
break;
}
- this->hovered_widget = -1;
+ this->hovered_widget = INVALID_WIDGET;
_cursor.vehchain = false;
}
diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp
index 4e44efc3d992a..82aec53970eb5 100644
--- a/src/dock_gui.cpp
+++ b/src/dock_gui.cpp
@@ -98,7 +98,7 @@ static TileIndex GetOtherAqueductEnd(TileIndex tile_from, TileIndex *tile_to = n
/** Toolbar window for constructing water infrastructure. */
struct BuildDocksToolbarWindow : Window {
- DockToolbarWidgets last_clicked_widget = WID_DT_INVALID; ///< Contains the last widget that has been clicked on this toolbar.
+ WidgetID last_clicked_widget = INVALID_WIDGET; ///< Contains the last widget that has been clicked on this toolbar.
BuildDocksToolbarWindow(WindowDesc &desc, WindowNumber window_number) : Window(desc)
{
@@ -189,7 +189,7 @@ struct BuildDocksToolbarWindow : Window {
default: return;
}
- this->last_clicked_widget = (DockToolbarWidgets)widget;
+ this->last_clicked_widget = widget;
}
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
@@ -238,7 +238,7 @@ struct BuildDocksToolbarWindow : Window {
break;
case WID_DT_BUILD_AQUEDUCT: // Build aqueduct button
- Command::Post(STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE, CcBuildBridge, tile, GetOtherAqueductEnd(tile), TRANSPORT_WATER, 0, 0);
+ Command::Post(STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE, CcBuildBridge, tile, GetOtherAqueductEnd(tile), TRANSPORT_WATER, 0, INVALID_RAILTYPE, INVALID_ROADTYPE);
break;
default: NOT_REACHED();
@@ -250,6 +250,11 @@ struct BuildDocksToolbarWindow : Window {
VpSelectTilesWithMethod(pt.x, pt.y, select_method);
}
+ Point OnInitialPosition(int16_t sm_width, [[maybe_unused]] int16_t sm_height, [[maybe_unused]] int window_number) override
+ {
+ return AlignInitialConstructionToolbar(sm_width);
+ }
+
void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, TileIndex start_tile, TileIndex end_tile) override
{
if (pt.x != -1) {
@@ -333,7 +338,7 @@ struct BuildDocksToolbarWindow : Window {
* Nested widget parts of docks toolbar, game version.
* Position of #WID_DT_RIVER widget has changed.
*/
-static constexpr NWidgetPart _nested_build_docks_toolbar_widgets[] = {
+static constexpr std::initializer_list _nested_build_docks_toolbar_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetStringTip(STR_WATERWAYS_TOOLBAR_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
@@ -352,7 +357,7 @@ static constexpr NWidgetPart _nested_build_docks_toolbar_widgets[] = {
};
static WindowDesc _build_docks_toolbar_desc(
- WDP_ALIGN_TOOLBAR, "toolbar_water", 0, 0,
+ WDP_MANUAL, "toolbar_water", 0, 0,
WC_BUILD_TOOLBAR, WC_NONE,
WindowDefaultFlag::Construction,
_nested_build_docks_toolbar_widgets,
@@ -378,7 +383,7 @@ Window *ShowBuildDocksToolbar()
* Nested widget parts of docks toolbar, scenario editor version.
* Positions of #WID_DT_DEPOT, #WID_DT_STATION, and #WID_DT_BUOY widgets have changed.
*/
-static constexpr NWidgetPart _nested_build_docks_scen_toolbar_widgets[] = {
+static constexpr std::initializer_list _nested_build_docks_scen_toolbar_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetStringTip(STR_WATERWAYS_TOOLBAR_CAPTION_SE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
@@ -412,21 +417,12 @@ Window *ShowBuildDocksScenToolbar()
return AllocateWindowDescFront(_build_docks_scen_toolbar_desc, TRANSPORT_WATER);
}
-/** Widget numbers of the build-dock GUI. */
-enum BuildDockStationWidgets {
- BDSW_BACKGROUND, ///< Background panel.
- BDSW_LT_OFF, ///< 'Off' button of coverage high light.
- BDSW_LT_ON, ///< 'On' button of coverage high light.
- BDSW_INFO, ///< 'Coverage highlight' label.
- BDSW_ACCEPTANCE, ///< Acceptance info.
-};
-
struct BuildDocksStationWindow : public PickerWindowBase {
public:
BuildDocksStationWindow(WindowDesc &desc, Window *parent) : PickerWindowBase(desc, parent)
{
this->InitNested(TRANSPORT_WATER);
- this->LowerWidget(_settings_client.gui.station_show_coverage + BDSW_LT_OFF);
+ this->LowerWidget(_settings_client.gui.station_show_coverage + WID_BDSW_LT_OFF);
}
void Close([[maybe_unused]] int data = 0) override
@@ -448,7 +444,7 @@ struct BuildDocksStationWindow : public PickerWindowBase {
}
/* strings such as 'Size' and 'Coverage Area' */
- Rect r = this->GetWidget(BDSW_ACCEPTANCE)->GetCurrentRect();
+ Rect r = this->GetWidget(WID_BDSW_ACCEPTANCE)->GetCurrentRect();
const int bottom = r.bottom;
r.bottom = INT_MAX; // Allow overflow as we want to know the required height.
r.top = DrawStationCoverageAreaText(r, SCT_ALL, rad, false) + WidgetDimensions::scaled.vsep_normal;
@@ -464,11 +460,11 @@ struct BuildDocksStationWindow : public PickerWindowBase {
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
{
switch (widget) {
- case BDSW_LT_OFF:
- case BDSW_LT_ON:
- this->RaiseWidget(_settings_client.gui.station_show_coverage + BDSW_LT_OFF);
- _settings_client.gui.station_show_coverage = (widget != BDSW_LT_OFF);
- this->LowerWidget(_settings_client.gui.station_show_coverage + BDSW_LT_OFF);
+ case WID_BDSW_LT_OFF:
+ case WID_BDSW_LT_ON:
+ this->RaiseWidget(_settings_client.gui.station_show_coverage + WID_BDSW_LT_OFF);
+ _settings_client.gui.station_show_coverage = (widget != WID_BDSW_LT_OFF);
+ this->LowerWidget(_settings_client.gui.station_show_coverage + WID_BDSW_LT_OFF);
SndClickBeep();
this->SetDirty();
SetViewportCatchmentStation(nullptr, true);
@@ -487,21 +483,21 @@ struct BuildDocksStationWindow : public PickerWindowBase {
};
/** Nested widget parts of a build dock station window. */
-static constexpr NWidgetPart _nested_build_dock_station_widgets[] = {
+static constexpr std::initializer_list _nested_build_dock_station_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetStringTip(STR_STATION_BUILD_DOCK_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
EndContainer(),
- NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BDSW_BACKGROUND),
+ NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BDSW_BACKGROUND),
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0), SetPadding(WidgetDimensions::unscaled.picker),
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_picker, 0),
- NWidget(WWT_LABEL, INVALID_COLOUR, BDSW_INFO), SetStringTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE), SetFill(1, 0),
+ NWidget(WWT_LABEL, INVALID_COLOUR, WID_BDSW_INFO), SetStringTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE), SetFill(1, 0),
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize), SetPIP(14, 0, 14),
- NWidget(WWT_TEXTBTN, COLOUR_GREY, BDSW_LT_OFF), SetMinimalSize(60, 12), SetFill(1, 0), SetStringTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP),
- NWidget(WWT_TEXTBTN, COLOUR_GREY, BDSW_LT_ON), SetMinimalSize(60, 12), SetFill(1, 0), SetStringTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP),
+ NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BDSW_LT_OFF), SetMinimalSize(60, 12), SetFill(1, 0), SetStringTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP),
+ NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BDSW_LT_ON), SetMinimalSize(60, 12), SetFill(1, 0), SetStringTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP),
EndContainer(),
EndContainer(),
- NWidget(WWT_EMPTY, INVALID_COLOUR, BDSW_ACCEPTANCE), SetResize(0, 1), SetMinimalTextLines(2, WidgetDimensions::unscaled.vsep_normal),
+ NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BDSW_ACCEPTANCE), SetResize(0, 1), SetMinimalTextLines(2, WidgetDimensions::unscaled.vsep_normal),
EndContainer(),
EndContainer(),
};
@@ -588,7 +584,7 @@ struct BuildDocksDepotWindow : public PickerWindowBase {
}
};
-static constexpr NWidgetPart _nested_build_docks_depot_widgets[] = {
+static constexpr std::initializer_list _nested_build_docks_depot_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetStringTip(STR_DEPOT_BUILD_SHIP_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
diff --git a/src/driver.cpp b/src/driver.cpp
index 70e2071524379..10b0f890b4dc1 100644
--- a/src/driver.cpp
+++ b/src/driver.cpp
@@ -145,11 +145,12 @@ bool DriverFactoryBase::SelectDriverImpl(const std::string &name, Driver::Type t
/* Keep old driver in case we need to switch back, or may still need to process an OS callback. */
auto oldd = std::move(GetActiveDriver(type));
- GetActiveDriver(type) = d->CreateInstance();
+ auto newd = d->CreateInstance();
- auto err = GetActiveDriver(type)->Start({});
+ auto err = newd->Start({});
if (!err) {
Debug(driver, 1, "Successfully probed {} driver '{}'", GetDriverTypeName(type), d->name);
+ GetActiveDriver(type) = std::move(newd);
return true;
}
diff --git a/src/dropdown.cpp b/src/dropdown.cpp
index 2b2570f3db8ad..30e56c3fb2b30 100644
--- a/src/dropdown.cpp
+++ b/src/dropdown.cpp
@@ -56,7 +56,7 @@ std::unique_ptr MakeDropDownListCheckedItem(bool checked, Stri
return std::make_unique(indent, checked, GetString(str), value, masked, shaded);
}
-static constexpr NWidgetPart _nested_dropdown_menu_widgets[] = {
+static constexpr std::initializer_list _nested_dropdown_menu_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_PANEL, COLOUR_END, WID_DM_ITEMS), SetScrollbar(WID_DM_SCROLL), EndContainer(),
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_DM_SHOW_SCROLL),
@@ -248,7 +248,7 @@ struct DropdownWindow : Window {
if (y < item_height) {
if (item->masked || !item->Selectable()) return false;
result = item->result;
- click_result = item->OnClick({r.left, 0, r.right, item_height - 1}, {_cursor.pos.x - this->left, y});
+ click_result = item->OnClick(r.WithY(0, item_height - 1), {_cursor.pos.x - this->left, y});
return true;
}
@@ -274,7 +274,7 @@ struct DropdownWindow : Window {
if (--pos >= 0) continue;
if (y + item_height - 1 <= ir.bottom) {
- Rect full{ir.left, y, ir.right, y + item_height - 1};
+ Rect full = ir.WithY(y, y + item_height - 1);
bool selected = (this->selected_result == item->result) && item->Selectable();
if (selected) GfxFillRect(full, PC_BLACK);
diff --git a/src/dropdown_common_type.h b/src/dropdown_common_type.h
index 80362f6712f17..dac1500d46139 100644
--- a/src/dropdown_common_type.h
+++ b/src/dropdown_common_type.h
@@ -41,8 +41,8 @@ class DropDownDivider : public TBase {
PixelColour c2 = GetColourGradient(bg_colour, SHADE_LIGHTEST);
int mid = CentreBounds(full.top, full.bottom, 0);
- GfxFillRect(full.left, mid - WidgetDimensions::scaled.bevel.bottom, full.right, mid - 1, c1);
- GfxFillRect(full.left, mid, full.right, mid + WidgetDimensions::scaled.bevel.top - 1, c2);
+ GfxFillRect(full.WithY(mid - WidgetDimensions::scaled.bevel.bottom, mid - 1), c1);
+ GfxFillRect(full.WithY(mid, mid + WidgetDimensions::scaled.bevel.top - 1), c2);
}
};
@@ -216,7 +216,7 @@ class DropDownToggle : public TBase {
bool rtl = TEnd ^ (_current_text_dir == TD_RTL);
int w = SETTING_BUTTON_WIDTH;
- if (r.WithWidth(w, rtl).CentreTo(w, SETTING_BUTTON_HEIGHT).Contains(pt)) return this->click;
+ if (r.WithWidth(w, rtl).CentreToHeight(SETTING_BUTTON_HEIGHT).Contains(pt)) return this->click;
return this->TBase::OnClick(r.Indent(w + WidgetDimensions::scaled.hsep_wide, rtl), pt);
}
@@ -226,7 +226,7 @@ class DropDownToggle : public TBase {
bool rtl = TEnd ^ (_current_text_dir == TD_RTL);
int w = SETTING_BUTTON_WIDTH;
- Rect br = r.WithWidth(w, rtl).CentreTo(w, SETTING_BUTTON_HEIGHT);
+ Rect br = r.WithWidth(w, rtl).CentreToHeight(SETTING_BUTTON_HEIGHT);
DrawBoolButton(br.left, br.top, this->button_colour, this->background_colour, this->on, true);
this->TBase::Draw(full, r.Indent(w + WidgetDimensions::scaled.hsep_wide, rtl), sel, click_result, bg_colour);
@@ -260,6 +260,32 @@ class DropDownIndent : public TBase {
}
};
+/**
+ * Drop down spacer component.
+ * @tparam TBase Base component.
+ * @tparam TEnd Position space at end if true, or start if false.
+ */
+template
+class DropDownSpacer : public TBase {
+public:
+ template
+ explicit DropDownSpacer(Args&&... args) : TBase(std::forward(args)...) {}
+
+ uint Width() const override { return WidgetDimensions::scaled.hsep_wide + this->TBase::Width(); }
+
+ int OnClick(const Rect &r, const Point &pt) const override
+ {
+ bool rtl = TEnd ^ (_current_text_dir == TD_RTL);
+ return this->TBase::OnClick(r.Indent(WidgetDimensions::scaled.hsep_wide, rtl), pt);
+ }
+
+ void Draw(const Rect &full, const Rect &r, bool sel, int click_result, Colours bg_colour) const override
+ {
+ bool rtl = TEnd ^ (_current_text_dir == TD_RTL);
+ this->TBase::Draw(full, r.Indent(WidgetDimensions::scaled.hsep_wide, rtl), sel, click_result, bg_colour);
+ }
+};
+
/**
* Drop down component that makes the item unselectable.
* @tparam TBase Base component.
diff --git a/src/economy.cpp b/src/economy.cpp
index 824066e898e2b..d8d4cecc5926c 100644
--- a/src/economy.cpp
+++ b/src/economy.cpp
@@ -655,14 +655,14 @@ static void CompaniesGenStatistics()
CommandCost cost(EXPENSES_PROPERTY);
uint32_t rail_total = c->infrastructure.GetRailTotal();
- for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) {
- if (c->infrastructure.rail[rt] != 0) cost.AddCost(RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total));
+ for (const auto &[railtype, count] : c->infrastructure.rail) {
+ if (count != 0) cost.AddCost(RailMaintenanceCost(railtype, count, rail_total));
}
cost.AddCost(SignalMaintenanceCost(c->infrastructure.signal));
uint32_t road_total = c->infrastructure.GetRoadTotal();
uint32_t tram_total = c->infrastructure.GetTramTotal();
- for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) {
- if (c->infrastructure.road[rt] != 0) cost.AddCost(RoadMaintenanceCost(rt, c->infrastructure.road[rt], RoadTypeIsRoad(rt) ? road_total : tram_total));
+ for (const auto &[roadtype, count] : c->infrastructure.road) {
+ if (count != 0) cost.AddCost(RoadMaintenanceCost(roadtype, count, RoadTypeIsRoad(roadtype) ? road_total : tram_total));
}
cost.AddCost(CanalMaintenanceCost(c->infrastructure.water));
cost.AddCost(StationMaintenanceCost(c->infrastructure.station));
@@ -1270,7 +1270,8 @@ void PrepareUnload(Vehicle *front_v)
assert(CargoPayment::CanAllocateItem());
front_v->cargo_payment = new CargoPayment(front_v);
- StationIDStack next_station = front_v->GetNextStoppingStation();
+ std::vector next_station;
+ front_v->GetNextStoppingStation(next_station);
if (front_v->orders == nullptr || (front_v->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) {
Station *st = Station::Get(front_v->last_station_visited);
for (Vehicle *v = front_v; v != nullptr; v = v->Next()) {
@@ -1433,7 +1434,7 @@ struct FinalizeRefitAction
{
CargoArray &consist_capleft; ///< Capacities left in the consist.
Station *st; ///< Station to reserve cargo from.
- StationIDStack &next_station; ///< Next hops to reserve cargo for.
+ std::span next_station; ///< Next hops to reserve cargo for.
bool do_reserve; ///< If the vehicle should reserve.
/**
@@ -1443,7 +1444,7 @@ struct FinalizeRefitAction
* @param next_station Next hops to reserve cargo for.
* @param do_reserve If we should reserve cargo or just add up the capacities.
*/
- FinalizeRefitAction(CargoArray &consist_capleft, Station *st, StationIDStack &next_station, bool do_reserve) :
+ FinalizeRefitAction(CargoArray &consist_capleft, Station *st, std::span next_station, bool do_reserve) :
consist_capleft(consist_capleft), st(st), next_station(next_station), do_reserve(do_reserve) {}
/**
@@ -1471,7 +1472,7 @@ struct FinalizeRefitAction
* @param next_station Possible next stations the vehicle can travel to.
* @param new_cargo_type Target cargo for refit.
*/
-static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station *st, StationIDStack next_station, CargoType new_cargo_type)
+static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station *st, std::span next_station, CargoType new_cargo_type)
{
Vehicle *v_start = v->GetFirstEnginePart();
if (!IterateVehicleParts(v_start, IsEmptyAction())) return;
@@ -1538,16 +1539,16 @@ static bool MayLoadUnderExclusiveRights(const Station *st, const Vehicle *v)
struct ReserveCargoAction {
Station *st;
- StationIDStack *next_station;
+ std::span next_station;
- ReserveCargoAction(Station *st, StationIDStack *next_station) :
+ ReserveCargoAction(Station *st, std::span next_station) :
st(st), next_station(next_station) {}
bool operator()(Vehicle *v)
{
if (v->cargo_cap > v->cargo.RemainingCount() && MayLoadUnderExclusiveRights(st, v)) {
st->goods[v->cargo_type].GetOrCreateData().cargo.Reserve(v->cargo_cap - v->cargo.RemainingCount(),
- &v->cargo, *next_station, v->GetCargoTile());
+ &v->cargo, next_station, v->GetCargoTile());
}
return true;
@@ -1563,7 +1564,7 @@ struct ReserveCargoAction {
* @param consist_capleft If given, save free capacities after reserving there.
* @param next_station Station(s) the vehicle will stop at next.
*/
-static void ReserveConsist(Station *st, Vehicle *u, CargoArray *consist_capleft, StationIDStack *next_station)
+static void ReserveConsist(Station *st, Vehicle *u, CargoArray *consist_capleft, std::span next_station)
{
/* If there is a cargo payment not all vehicles of the consist have tried to do the refit.
* In that case, only reserve if it's a fixed refit and the equivalent of "articulated chain"
@@ -1618,14 +1619,15 @@ static void LoadUnloadVehicle(Vehicle *front)
StationID last_visited = front->last_station_visited;
Station *st = Station::Get(last_visited);
- StationIDStack next_station = front->GetNextStoppingStation();
+ std::vector next_station;
+ front->GetNextStoppingStation(next_station);
bool use_autorefit = front->current_order.IsRefit() && front->current_order.GetRefitCargo() == CARGO_AUTO_REFIT;
CargoArray consist_capleft{};
if (_settings_game.order.improved_load && use_autorefit ?
front->cargo_payment == nullptr : (front->current_order.GetLoadType() & OLFB_FULL_LOAD) != 0) {
ReserveConsist(st, front,
(use_autorefit && front->load_unload_ticks != 0) ? &consist_capleft : nullptr,
- &next_station);
+ next_station);
}
/* We have not waited enough time till the next round of loading/unloading */
diff --git a/src/economy_cmd.h b/src/economy_cmd.h
index 15825aa7b8ff5..37aa5eb38e8e4 100644
--- a/src/economy_cmd.h
+++ b/src/economy_cmd.h
@@ -15,6 +15,6 @@
CommandCost CmdBuyCompany(DoCommandFlags flags, CompanyID target_company, bool hostile_takeover);
-DEF_CMD_TRAIT(CMD_BUY_COMPANY, CmdBuyCompany, {}, CMDT_MONEY_MANAGEMENT)
+DEF_CMD_TRAIT(CMD_BUY_COMPANY, CmdBuyCompany, {}, CommandType::MoneyManagement)
#endif /* ECONOMY_CMD_H */
diff --git a/src/elrail.cpp b/src/elrail.cpp
index 720da0f26ba0b..14b145713c8b0 100644
--- a/src/elrail.cpp
+++ b/src/elrail.cpp
@@ -582,7 +582,7 @@ void UpdateDisableElrailSettingState(bool disable, bool update_vehicles)
{
/* walk through all train engines */
for (Engine *e : Engine::IterateType(VEH_TRAIN)) {
- RailVehicleInfo *rv_info = &e->u.rail;
+ RailVehicleInfo *rv_info = &e->VehInfo();
/* update railtype of engines intended to use elrail */
if (rv_info->intended_railtypes.Test(RAILTYPE_ELECTRIC)) {
rv_info->railtypes.Set(RAILTYPE_ELECTRIC, !disable);
diff --git a/src/engine.cpp b/src/engine.cpp
index 68b9e1b0d1a9d..2b80951da8274 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -78,24 +78,19 @@ Engine::Engine(VehicleType type, uint16_t local_id)
/* Check if this base engine is within the original engine data range */
if (local_id >= _engine_counts[type]) {
- /* 'power' defaults to zero, so we also have to default to 'wagon' */
- if (type == VEH_TRAIN) this->u.rail.railveh_type = RAILVEH_WAGON;
+ /* Initialise default type-specific information. */
+ switch (type) {
+ case VEH_TRAIN: this->vehicle_info.emplace(); break;
+ case VEH_ROAD: this->vehicle_info.emplace(); break;
+ case VEH_SHIP: this->vehicle_info.emplace(); break;
+ case VEH_AIRCRAFT: this->vehicle_info.emplace(); break;
+ default: break;
+ }
/* Set model life to maximum to make wagons available */
this->info.base_life = TimerGameCalendar::Year{0xFF};
- /* Set road vehicle tractive effort to the default value */
- if (type == VEH_ROAD) this->u.road.tractive_effort = 0x4C;
/* Aircraft must have CT_INVALID as default, as there is no property */
this->info.cargo_type = INVALID_CARGO;
this->info.cargo_label = (type == VEH_AIRCRAFT) ? CT_INVALID : CT_PASSENGERS;
- /* Ships must have a non-zero acceleration. */
- if (type == VEH_SHIP) this->u.ship.acceleration = 1;
- /* Set visual effect to the default value */
- switch (type) {
- case VEH_TRAIN: this->u.rail.visual_effect = VE_DEFAULT; break;
- case VEH_ROAD: this->u.road.visual_effect = VE_DEFAULT; break;
- case VEH_SHIP: this->u.ship.visual_effect = VE_DEFAULT; break;
- default: break; // The aircraft, disasters and especially visual effects have no NewGRF configured visual effects
- }
/* Set cargo aging period to the default value. */
this->info.cargo_age_period = Ticks::CARGO_AGING_TICKS;
/* Not a variant */
@@ -110,33 +105,37 @@ Engine::Engine(VehicleType type, uint16_t local_id)
switch (type) {
default: NOT_REACHED();
- case VEH_TRAIN:
- this->u.rail = _orig_rail_vehicle_info[local_id];
- this->original_image_index = this->u.rail.image_index;
+ case VEH_TRAIN: {
+ RailVehicleInfo &rvi = this->vehicle_info.emplace(_orig_rail_vehicle_info[local_id]);
+ this->original_image_index = rvi.image_index;
this->info.string_id = STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KIRBY_PAUL_TANK_STEAM + local_id;
/* Set the default model life of original wagons to "infinite" */
- if (this->u.rail.railveh_type == RAILVEH_WAGON) this->info.base_life = TimerGameCalendar::Year{0xFF};
+ if (rvi.railveh_type == RAILVEH_WAGON) this->info.base_life = TimerGameCalendar::Year{0xFF};
break;
+ }
- case VEH_ROAD:
- this->u.road = _orig_road_vehicle_info[local_id];
- this->original_image_index = this->u.road.image_index;
+ case VEH_ROAD: {
+ RoadVehicleInfo &rvi = this->vehicle_info.emplace(_orig_road_vehicle_info[local_id]);
+ this->original_image_index = rvi.image_index;
this->info.string_id = STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_REGAL_BUS + local_id;
break;
+ }
- case VEH_SHIP:
- this->u.ship = _orig_ship_vehicle_info[local_id];
- this->original_image_index = this->u.ship.image_index;
+ case VEH_SHIP: {
+ ShipVehicleInfo &svi = this->vehicle_info.emplace(_orig_ship_vehicle_info[local_id]);
+ this->original_image_index = svi.image_index;
this->info.string_id = STR_VEHICLE_NAME_SHIP_MPS_OIL_TANKER + local_id;
break;
+ }
- case VEH_AIRCRAFT:
- this->u.air = _orig_aircraft_vehicle_info[local_id];
- this->original_image_index = this->u.air.image_index;
+ case VEH_AIRCRAFT: {
+ AircraftVehicleInfo &avi = this->vehicle_info.emplace(_orig_aircraft_vehicle_info[local_id]);
+ this->original_image_index = avi.image_index;
this->info.string_id = STR_VEHICLE_NAME_AIRCRAFT_SAMPSON_U52 + local_id;
break;
+ }
}
}
@@ -174,11 +173,11 @@ bool Engine::CanCarryCargo() const
*/
switch (this->type) {
case VEH_TRAIN:
- if (this->u.rail.capacity == 0) return false;
+ if (this->VehInfo().capacity == 0) return false;
break;
case VEH_ROAD:
- if (this->u.road.capacity == 0) return false;
+ if (this->VehInfo().capacity == 0) return false;
break;
case VEH_SHIP:
@@ -210,7 +209,7 @@ uint Engine::DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity) const
CargoType cargo_type = (v != nullptr) ? v->cargo_type : default_cargo;
if (mail_capacity != nullptr && this->type == VEH_AIRCRAFT && IsCargoInClass(cargo_type, CargoClass::Passengers)) {
- *mail_capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->u.air.mail_capacity, v);
+ *mail_capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->VehInfo().mail_capacity, v);
}
/* Check the refit capacity callback if we are not in the default configuration, or if we are using the new multiplier algorithm. */
@@ -225,24 +224,24 @@ uint Engine::DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity) const
uint extra_mail_cap = 0;
switch (this->type) {
case VEH_TRAIN:
- capacity = GetEngineProperty(this->index, PROP_TRAIN_CARGO_CAPACITY, this->u.rail.capacity, v);
+ capacity = GetEngineProperty(this->index, PROP_TRAIN_CARGO_CAPACITY, this->VehInfo().capacity, v);
/* In purchase list add the capacity of the second head. Always use the plain property for this. */
- if (v == nullptr && this->u.rail.railveh_type == RAILVEH_MULTIHEAD) capacity += this->u.rail.capacity;
+ if (v == nullptr && this->VehInfo().railveh_type == RAILVEH_MULTIHEAD) capacity += this->VehInfo().capacity;
break;
case VEH_ROAD:
- capacity = GetEngineProperty(this->index, PROP_ROADVEH_CARGO_CAPACITY, this->u.road.capacity, v);
+ capacity = GetEngineProperty(this->index, PROP_ROADVEH_CARGO_CAPACITY, this->VehInfo().capacity, v);
break;
case VEH_SHIP:
- capacity = GetEngineProperty(this->index, PROP_SHIP_CARGO_CAPACITY, this->u.ship.capacity, v);
+ capacity = GetEngineProperty(this->index, PROP_SHIP_CARGO_CAPACITY, this->VehInfo().capacity, v);
break;
case VEH_AIRCRAFT:
- capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_PASSENGER_CAPACITY, this->u.air.passenger_capacity, v);
+ capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_PASSENGER_CAPACITY, this->VehInfo().passenger_capacity, v);
if (!IsCargoInClass(cargo_type, CargoClass::Passengers)) {
- extra_mail_cap = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->u.air.mail_capacity, v);
+ extra_mail_cap = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->VehInfo().mail_capacity, v);
}
if (IsValidCargoType(GetCargoTypeByLabel(CT_MAIL))) {
if (!new_multipliers && cargo_type == GetCargoTypeByLabel(CT_MAIL)) return capacity + extra_mail_cap;
@@ -284,25 +283,25 @@ Money Engine::GetRunningCost() const
uint cost_factor;
switch (this->type) {
case VEH_ROAD:
- base_price = this->u.road.running_cost_class;
+ base_price = this->VehInfo().running_cost_class;
if (base_price == INVALID_PRICE) return 0;
- cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_RUNNING_COST_FACTOR, this->u.road.running_cost);
+ cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_RUNNING_COST_FACTOR, this->VehInfo().running_cost);
break;
case VEH_TRAIN:
- base_price = this->u.rail.running_cost_class;
+ base_price = this->VehInfo().running_cost_class;
if (base_price == INVALID_PRICE) return 0;
- cost_factor = GetEngineProperty(this->index, PROP_TRAIN_RUNNING_COST_FACTOR, this->u.rail.running_cost);
+ cost_factor = GetEngineProperty(this->index, PROP_TRAIN_RUNNING_COST_FACTOR, this->VehInfo().running_cost);
break;
case VEH_SHIP:
base_price = PR_RUNNING_SHIP;
- cost_factor = GetEngineProperty(this->index, PROP_SHIP_RUNNING_COST_FACTOR, this->u.ship.running_cost);
+ cost_factor = GetEngineProperty(this->index, PROP_SHIP_RUNNING_COST_FACTOR, this->VehInfo().running_cost);
break;
case VEH_AIRCRAFT:
base_price = PR_RUNNING_AIRCRAFT;
- cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_RUNNING_COST_FACTOR, this->u.air.running_cost);
+ cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_RUNNING_COST_FACTOR, this->VehInfo().running_cost);
break;
default: NOT_REACHED();
@@ -322,27 +321,27 @@ Money Engine::GetCost() const
switch (this->type) {
case VEH_ROAD:
base_price = PR_BUILD_VEHICLE_ROAD;
- cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_COST_FACTOR, this->u.road.cost_factor);
+ cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_COST_FACTOR, this->VehInfo().cost_factor);
break;
case VEH_TRAIN:
- if (this->u.rail.railveh_type == RAILVEH_WAGON) {
+ if (this->VehInfo().railveh_type == RAILVEH_WAGON) {
base_price = PR_BUILD_VEHICLE_WAGON;
- cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->u.rail.cost_factor);
+ cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->VehInfo().cost_factor);
} else {
base_price = PR_BUILD_VEHICLE_TRAIN;
- cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->u.rail.cost_factor);
+ cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->VehInfo().cost_factor);
}
break;
case VEH_SHIP:
base_price = PR_BUILD_VEHICLE_SHIP;
- cost_factor = GetEngineProperty(this->index, PROP_SHIP_COST_FACTOR, this->u.ship.cost_factor);
+ cost_factor = GetEngineProperty(this->index, PROP_SHIP_COST_FACTOR, this->VehInfo().cost_factor);
break;
case VEH_AIRCRAFT:
base_price = PR_BUILD_VEHICLE_AIRCRAFT;
- cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_COST_FACTOR, this->u.air.cost_factor);
+ cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_COST_FACTOR, this->VehInfo().cost_factor);
break;
default: NOT_REACHED();
@@ -359,22 +358,22 @@ uint Engine::GetDisplayMaxSpeed() const
{
switch (this->type) {
case VEH_TRAIN:
- return GetEngineProperty(this->index, PROP_TRAIN_SPEED, this->u.rail.max_speed);
+ return GetEngineProperty(this->index, PROP_TRAIN_SPEED, this->VehInfo().max_speed);
case VEH_ROAD: {
uint max_speed = GetEngineProperty(this->index, PROP_ROADVEH_SPEED, 0);
- return (max_speed != 0) ? max_speed * 2 : this->u.road.max_speed / 2;
+ return (max_speed != 0) ? max_speed * 2 : this->VehInfo().max_speed / 2;
}
case VEH_SHIP:
- return GetEngineProperty(this->index, PROP_SHIP_SPEED, this->u.ship.max_speed) / 2;
+ return GetEngineProperty(this->index, PROP_SHIP_SPEED, this->VehInfo().max_speed) / 2;
case VEH_AIRCRAFT: {
uint max_speed = GetEngineProperty(this->index, PROP_AIRCRAFT_SPEED, 0);
if (max_speed != 0) {
return (max_speed * 128) / 10;
}
- return this->u.air.max_speed;
+ return this->VehInfo().max_speed;
}
default: NOT_REACHED();
@@ -392,9 +391,9 @@ uint Engine::GetPower() const
/* Only trains and road vehicles have 'power'. */
switch (this->type) {
case VEH_TRAIN:
- return GetEngineProperty(this->index, PROP_TRAIN_POWER, this->u.rail.power);
+ return GetEngineProperty(this->index, PROP_TRAIN_POWER, this->VehInfo().power);
case VEH_ROAD:
- return GetEngineProperty(this->index, PROP_ROADVEH_POWER, this->u.road.power) * 10;
+ return GetEngineProperty(this->index, PROP_ROADVEH_POWER, this->VehInfo().power) * 10;
default: NOT_REACHED();
}
@@ -410,9 +409,9 @@ uint Engine::GetDisplayWeight() const
/* Only trains and road vehicles have 'weight'. */
switch (this->type) {
case VEH_TRAIN:
- return GetEngineProperty(this->index, PROP_TRAIN_WEIGHT, this->u.rail.weight) << (this->u.rail.railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
+ return GetEngineProperty(this->index, PROP_TRAIN_WEIGHT, this->VehInfo().weight) << (this->VehInfo().railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
case VEH_ROAD:
- return GetEngineProperty(this->index, PROP_ROADVEH_WEIGHT, this->u.road.weight) / 4;
+ return GetEngineProperty(this->index, PROP_ROADVEH_WEIGHT, this->VehInfo().weight) / 4;
default: NOT_REACHED();
}
@@ -428,9 +427,9 @@ uint Engine::GetDisplayMaxTractiveEffort() const
/* Only trains and road vehicles have 'tractive effort'. */
switch (this->type) {
case VEH_TRAIN:
- return (GROUND_ACCELERATION * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_TRAIN_TRACTIVE_EFFORT, this->u.rail.tractive_effort)) / 256;
+ return (GROUND_ACCELERATION * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_TRAIN_TRACTIVE_EFFORT, this->VehInfo().tractive_effort)) / 256;
case VEH_ROAD:
- return (GROUND_ACCELERATION * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_ROADVEH_TRACTIVE_EFFORT, this->u.road.tractive_effort)) / 256;
+ return (GROUND_ACCELERATION * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_ROADVEH_TRACTIVE_EFFORT, this->VehInfo().tractive_effort)) / 256;
default: NOT_REACHED();
}
@@ -454,7 +453,7 @@ uint16_t Engine::GetRange() const
{
switch (this->type) {
case VEH_AIRCRAFT:
- return GetEngineProperty(this->index, PROP_AIRCRAFT_RANGE, this->u.air.max_range);
+ return GetEngineProperty(this->index, PROP_AIRCRAFT_RANGE, this->VehInfo().max_range);
default: NOT_REACHED();
}
@@ -468,7 +467,7 @@ StringID Engine::GetAircraftTypeText() const
{
switch (this->type) {
case VEH_AIRCRAFT:
- switch (this->u.air.subtype) {
+ switch (this->VehInfo().subtype) {
case AIR_HELI: return STR_LIVERY_HELICOPTER;
case AIR_CTOL: return STR_LIVERY_SMALL_PLANE;
case AIR_CTOL | AIR_FAST: return STR_LIVERY_LARGE_PLANE;
@@ -625,7 +624,7 @@ void ShowEnginePreviewWindow(EngineID engine);
static bool IsWagon(EngineID index)
{
const Engine *e = Engine::Get(index);
- return e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON;
+ return e->type == VEH_TRAIN && e->VehInfo().railveh_type == RAILVEH_WAGON;
}
/**
@@ -700,7 +699,7 @@ void SetYearEngineAgingStops()
/* Exclude certain engines */
if (!ei->climates.Test(_settings_game.game_creation.landscape)) continue;
- if (e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON) continue;
+ if (e->type == VEH_TRAIN && e->VehInfo().railveh_type == RAILVEH_WAGON) continue;
/* Base year ending date on half the model life */
TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(ei->base_intro + (ei->lifelength.base() * CalendarTime::DAYS_IN_LEAP_YEAR) / 2);
@@ -1107,13 +1106,19 @@ static void NewVehicleAvailable(Engine *e)
if (e->type == VEH_TRAIN) {
/* maybe make another rail type available */
- assert(e->u.rail.railtypes != RailTypes{});
- RailTypes introduced = GetAllIntroducesRailTypes(e->u.rail.railtypes);
- for (Company *c : Company::Iterate()) c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | introduced, TimerGameCalendar::date);
+ assert(e->VehInfo().railtypes != RailTypes{});
+ RailTypes introduced = GetAllIntroducesRailTypes(e->VehInfo().railtypes);
+ for (Company *c : Company::Iterate()) {
+ c->avail_railtypes.Set(introduced);
+ c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes, TimerGameCalendar::date);
+ }
} else if (e->type == VEH_ROAD) {
/* maybe make another road type available */
- assert(e->u.road.roadtype < ROADTYPE_END);
- for (Company *c : Company::Iterate()) c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes | GetRoadTypeInfo(e->u.road.roadtype)->introduces_roadtypes, TimerGameCalendar::date);
+ assert(e->VehInfo().roadtype < GetNumRoadTypes());
+ for (Company *c : Company::Iterate()) {
+ c->avail_roadtypes.Set(GetRoadTypeInfo(e->VehInfo().roadtype)->introduces_roadtypes);
+ c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes, TimerGameCalendar::date);
+ }
}
/* Only broadcast event if AIs are able to build this vehicle type. */
@@ -1268,12 +1273,12 @@ bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company)
if (type == VEH_TRAIN && company != OWNER_DEITY) {
/* Check if the rail type is available to this company */
const Company *c = Company::Get(company);
- if (!GetAllCompatibleRailTypes(e->u.rail.railtypes).Any(c->avail_railtypes)) return false;
+ if (!GetAllCompatibleRailTypes(e->VehInfo().railtypes).Any(c->avail_railtypes)) return false;
}
if (type == VEH_ROAD && company != OWNER_DEITY) {
/* Check if the road type is available to this company */
const Company *c = Company::Get(company);
- if (!GetRoadTypeInfo(e->u.road.roadtype)->powered_roadtypes.Any(c->avail_roadtypes)) return false;
+ if (!GetRoadTypeInfo(e->VehInfo().roadtype)->powered_roadtypes.Any(c->avail_roadtypes)) return false;
}
return true;
@@ -1319,7 +1324,7 @@ void CheckEngines()
if (!e->IsEnabled()) continue;
/* Don't consider train wagons, we need a powered engine available. */
- if (e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON) continue;
+ if (e->type == VEH_TRAIN && e->VehInfo().railveh_type == RAILVEH_WAGON) continue;
/* We have an available engine... yay! */
if (e->flags.Test(EngineFlag::Available) && e->company_avail.Any()) return;
diff --git a/src/engine_base.h b/src/engine_base.h
index 82ea41cd8ffec..d8e6052524b11 100644
--- a/src/engine_base.h
+++ b/src/engine_base.h
@@ -35,7 +35,8 @@ using EngineDisplayFlags = EnumBitSet;
typedef Pool EnginePool;
extern EnginePool _engine_pool;
-struct Engine : EnginePool::PoolItem<&_engine_pool> {
+class Engine : public EnginePool::PoolItem<&_engine_pool> {
+public:
CompanyMask company_avail{}; ///< Bit for each company whether the engine is available for that company.
CompanyMask company_hidden{}; ///< Bit for each company whether the engine is normally hidden in the build gui for that company.
CompanyMask preview_asked{}; ///< Bit for each company which has already been offered a preview.
@@ -64,13 +65,6 @@ struct Engine : EnginePool::PoolItem<&_engine_pool> {
EngineID display_last_variant = EngineID::Invalid(); ///< NOSAVE client-side-only last variant selected.
EngineInfo info{};
- union {
- RailVehicleInfo rail;
- RoadVehicleInfo road;
- ShipVehicleInfo ship;
- AircraftVehicleInfo air;
- } u{};
-
uint16_t list_position = 0;
/* NewGRF related data */
@@ -78,6 +72,11 @@ struct Engine : EnginePool::PoolItem<&_engine_pool> {
std::vector overrides{};
std::vector badges{};
+private:
+ /* Vehicle-type specific information. */
+ std::variant vehicle_info{};
+
+public:
Engine() {}
Engine(VehicleType type, uint16_t local_id);
bool IsEnabled() const;
@@ -177,6 +176,18 @@ struct Engine : EnginePool::PoolItem<&_engine_pool> {
bool operator() (size_t index) { return Engine::Get(index)->type == this->vt; }
};
+ template
+ inline T &VehInfo()
+ {
+ return std::get(this->vehicle_info);
+ }
+
+ template
+ inline const T &VehInfo() const
+ {
+ return std::get(this->vehicle_info);
+ }
+
/**
* Returns an iterable ensemble of all valid engines of the given type
* @param vt the VehicleType for engines to be valid
@@ -234,22 +245,22 @@ inline const EngineInfo *EngInfo(EngineID e)
inline const RailVehicleInfo *RailVehInfo(EngineID e)
{
- return &Engine::Get(e)->u.rail;
+ return &Engine::Get(e)->VehInfo();
}
inline const RoadVehicleInfo *RoadVehInfo(EngineID e)
{
- return &Engine::Get(e)->u.road;
+ return &Engine::Get(e)->VehInfo();
}
inline const ShipVehicleInfo *ShipVehInfo(EngineID e)
{
- return &Engine::Get(e)->u.ship;
+ return &Engine::Get(e)->VehInfo();
}
inline const AircraftVehicleInfo *AircraftVehInfo(EngineID e)
{
- return &Engine::Get(e)->u.air;
+ return &Engine::Get(e)->VehInfo();
}
#endif /* ENGINE_BASE_H */
diff --git a/src/engine_cmd.h b/src/engine_cmd.h
index 0f9911914577d..153a5055e1a0c 100644
--- a/src/engine_cmd.h
+++ b/src/engine_cmd.h
@@ -17,9 +17,9 @@ CommandCost CmdEngineCtrl(DoCommandFlags flags, EngineID engine_id, CompanyID co
CommandCost CmdRenameEngine(DoCommandFlags flags, EngineID engine_id, const std::string &text);
CommandCost CmdSetVehicleVisibility(DoCommandFlags flags, EngineID engine_id, bool hide);
-DEF_CMD_TRAIT(CMD_WANT_ENGINE_PREVIEW, CmdWantEnginePreview, {}, CMDT_VEHICLE_MANAGEMENT)
-DEF_CMD_TRAIT(CMD_ENGINE_CTRL, CmdEngineCtrl, CommandFlag::Deity, CMDT_VEHICLE_MANAGEMENT)
-DEF_CMD_TRAIT(CMD_RENAME_ENGINE, CmdRenameEngine, CommandFlag::Server, CMDT_OTHER_MANAGEMENT)
-DEF_CMD_TRAIT(CMD_SET_VEHICLE_VISIBILITY, CmdSetVehicleVisibility, {}, CMDT_COMPANY_SETTING)
+DEF_CMD_TRAIT(CMD_WANT_ENGINE_PREVIEW, CmdWantEnginePreview, {}, CommandType::VehicleManagement)
+DEF_CMD_TRAIT(CMD_ENGINE_CTRL, CmdEngineCtrl, CommandFlag::Deity, CommandType::VehicleManagement)
+DEF_CMD_TRAIT(CMD_RENAME_ENGINE, CmdRenameEngine, CommandFlag::Server, CommandType::OtherManagement)
+DEF_CMD_TRAIT(CMD_SET_VEHICLE_VISIBILITY, CmdSetVehicleVisibility, {}, CommandType::CompanySetting)
#endif /* ENGINE_CMD_H */
diff --git a/src/engine_gui.cpp b/src/engine_gui.cpp
index 210cf3bdf190a..d942a7a80ed5b 100644
--- a/src/engine_gui.cpp
+++ b/src/engine_gui.cpp
@@ -43,16 +43,16 @@ StringID GetEngineCategoryName(EngineID engine)
switch (e->type) {
default: NOT_REACHED();
case VEH_ROAD:
- return GetRoadTypeInfo(e->u.road.roadtype)->strings.new_engine;
+ return GetRoadTypeInfo(e->VehInfo().roadtype)->strings.new_engine;
case VEH_AIRCRAFT: return STR_ENGINE_PREVIEW_AIRCRAFT;
case VEH_SHIP: return STR_ENGINE_PREVIEW_SHIP;
case VEH_TRAIN:
- assert(e->u.rail.railtypes.Any());
- return GetRailTypeInfo(e->u.rail.railtypes.GetNthSetBit(0).value())->strings.new_loco;
+ assert(e->VehInfo().railtypes.Any());
+ return GetRailTypeInfo(*e->VehInfo().railtypes.begin())->strings.new_loco;
}
}
-static constexpr NWidgetPart _nested_engine_preview_widgets[] = {
+static constexpr std::initializer_list _nested_engine_preview_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetStringTip(STR_ENGINE_PREVIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
@@ -182,12 +182,12 @@ static std::string GetTrainEngineInfoString(const Engine &e)
res << GetString(STR_ENGINE_PREVIEW_COST_WEIGHT, e.GetCost(), e.GetDisplayWeight());
res << '\n';
- if (e.u.rail.railtypes.Count() > 1) {
+ if (e.VehInfo().railtypes.size() > 1) {
std::string railtypes{};
std::string_view list_separator = GetListSeparator();
for (const auto &rt : _sorted_railtypes) {
- if (!e.u.rail.railtypes.Test(rt)) continue;
+ if (!e.VehInfo().railtypes.Test(rt)) continue;
if (!railtypes.empty()) railtypes += list_separator;
AppendStringInPlace(railtypes, GetRailTypeInfo(rt)->strings.name);
@@ -197,7 +197,7 @@ static std::string GetTrainEngineInfoString(const Engine &e)
}
bool is_maglev = true;
- for (RailType rt : e.u.rail.railtypes) {
+ for (RailType rt : e.VehInfo().railtypes) {
is_maglev &= GetRailTypeInfo(rt)->acceleration_type == VehicleAccelerationModel::Maglev;
}
diff --git a/src/engine_type.h b/src/engine_type.h
index 1fefbe1ba1fa0..640a99b73f1b6 100644
--- a/src/engine_type.h
+++ b/src/engine_type.h
@@ -25,7 +25,7 @@
/** Unique identification number of an engine. */
using EngineID = PoolID;
-struct Engine;
+class Engine;
/** Available types of rail vehicles. */
enum RailVehicleTypes : uint8_t {
@@ -50,10 +50,30 @@ enum class VehicleAccelerationModel : uint8_t {
Maglev, ///< Maglev acceleration model.
};
+/** Meaning of the various bits of the visual effect. */
+enum VisualEffect : uint8_t {
+ VE_OFFSET_START = 0, ///< First bit that contains the offset (0 = front, 8 = centre, 15 = rear)
+ VE_OFFSET_COUNT = 4, ///< Number of bits used for the offset
+ VE_OFFSET_CENTRE = 8, ///< Value of offset corresponding to a position above the centre of the vehicle
+
+ VE_TYPE_START = 4, ///< First bit used for the type of effect
+ VE_TYPE_COUNT = 2, ///< Number of bits used for the effect type
+ VE_TYPE_DEFAULT = 0, ///< Use default from engine class
+ VE_TYPE_STEAM = 1, ///< Steam plumes
+ VE_TYPE_DIESEL = 2, ///< Diesel fumes
+ VE_TYPE_ELECTRIC = 3, ///< Electric sparks
+
+ VE_DISABLE_EFFECT = 6, ///< Flag to disable visual effect
+ VE_ADVANCED_EFFECT = VE_DISABLE_EFFECT, ///< Flag for advanced effects
+ VE_DISABLE_WAGON_POWER = 7, ///< Flag to disable wagon power
+
+ VE_DEFAULT = 0xFF, ///< Default value to indicate that visual effect should be based on engine class
+};
+
/** Information about a rail vehicle. */
struct RailVehicleInfo {
uint8_t image_index = 0;
- RailVehicleTypes railveh_type{};
+ RailVehicleTypes railveh_type = RAILVEH_WAGON;
uint8_t cost_factor = 0; ///< Purchase cost factor; For multiheaded engines the sum of both engine prices.
RailTypes railtypes{}; ///< Railtypes, mangled if elrail is disabled.
RailTypes intended_railtypes{}; ///< Intended railtypes, regardless of elrail being enabled or disabled.
@@ -67,7 +87,7 @@ struct RailVehicleInfo {
uint8_t capacity = 0; ///< Cargo capacity of vehicle; For multiheaded engines the capacity of each single engine.
uint16_t pow_wag_power = 0; ///< Extra power applied to consist if wagon should be powered
uint8_t pow_wag_weight = 0; ///< Extra weight applied to consist if wagon should be powered
- uint8_t visual_effect = 0; ///< Bitstuffed NewGRF visual effect data
+ uint8_t visual_effect = VE_DEFAULT; ///< Bitstuffed NewGRF visual effect data
uint8_t shorten_factor = 0; ///< length on main map for this type is 8 - shorten_factor
uint8_t tractive_effort = 0; ///< Tractive effort coefficient
uint8_t air_drag = 0; ///< Coefficient of air drag
@@ -80,12 +100,12 @@ struct ShipVehicleInfo {
uint8_t image_index = 0;
uint8_t cost_factor = 0;
uint8_t running_cost = 0;
- uint8_t acceleration = 0; ///< Acceleration (1 unit = 1/3.2 mph per tick = 0.5 km-ish/h per tick)
+ uint8_t acceleration = 1; ///< Acceleration (1 unit = 1/3.2 mph per tick = 0.5 km-ish/h per tick)
uint16_t max_speed = 0; ///< Maximum speed (1 unit = 1/3.2 mph = 0.5 km-ish/h)
uint16_t capacity = 0;
SoundID sfx{};
bool old_refittable = 0; ///< Is ship refittable; only used during initialisation. Later use EngineInfo::refit_mask.
- uint8_t visual_effect = 0; ///< Bitstuffed NewGRF visual effect data
+ uint8_t visual_effect = VE_DEFAULT; ///< Bitstuffed NewGRF visual effect data
uint8_t ocean_speed_frac = 0; ///< Fraction of maximum speed for ocean tiles.
uint8_t canal_speed_frac = 0; ///< Fraction of maximum speed for canal/river tiles.
@@ -133,9 +153,9 @@ struct RoadVehicleInfo {
uint8_t capacity = 0;
uint8_t weight = 0; ///< Weight in 1/4t units
uint8_t power = 0; ///< Power in 10hp units
- uint8_t tractive_effort = 0; ///< Coefficient of tractive effort
+ uint8_t tractive_effort = 0x4C; ///< Coefficient of tractive effort
uint8_t air_drag = 0; ///< Coefficient of air drag
- uint8_t visual_effect = 0; ///< Bitstuffed NewGRF visual effect data
+ uint8_t visual_effect = VE_DEFAULT; ///< Bitstuffed NewGRF visual effect data
uint8_t shorten_factor = 0; ///< length on main map for this type is 8 - shorten_factor
RoadType roadtype{}; ///< Road type
};
diff --git a/src/error_gui.cpp b/src/error_gui.cpp
index 182ac7229fa5a..7fe4cc6f12b23 100644
--- a/src/error_gui.cpp
+++ b/src/error_gui.cpp
@@ -33,7 +33,7 @@
#include "safeguards.h"
-static constexpr NWidgetPart _nested_errmsg_widgets[] = {
+static constexpr std::initializer_list _nested_errmsg_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_RED),
NWidget(WWT_CAPTION, COLOUR_RED, WID_EM_CAPTION), SetStringTip(STR_ERROR_MESSAGE_CAPTION),
@@ -50,7 +50,7 @@ static WindowDesc _errmsg_desc(
_nested_errmsg_widgets
);
-static constexpr NWidgetPart _nested_errmsg_face_widgets[] = {
+static constexpr std::initializer_list _nested_errmsg_face_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_RED),
NWidget(WWT_CAPTION, COLOUR_RED, WID_EM_CAPTION),
@@ -209,7 +209,7 @@ struct ErrmsgWindow : public Window, ErrorMessageData {
/* Note: NewGRF supplied error message often do not start with a colour code, so default to white. */
Rect top_section = r.WithHeight(this->height_summary + extra, false);
Rect bottom_section = r.WithHeight(this->height_extra + extra, true);
- Rect middle_section = { top_section.left, top_section.bottom, top_section.right, bottom_section.top };
+ Rect middle_section = top_section.WithY(top_section.bottom, bottom_section.top);
DrawStringMultiLineWithClipping(top_section, this->summary_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
DrawStringMultiLineWithClipping(middle_section, this->detailed_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
DrawStringMultiLineWithClipping(bottom_section, this->extra_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
diff --git a/src/fileio.cpp b/src/fileio.cpp
index 981d37c8cde90..da9ae826abfd5 100644
--- a/src/fileio.cpp
+++ b/src/fileio.cpp
@@ -593,7 +593,7 @@ bool ExtractTar(const std::string &tar_filename, Subdirectory subdir)
/* We don't know the file. */
if (it == _tar_list[subdir].end()) return false;
- const auto &dirname = (*it).second;
+ const auto &dirname = it->second;
/* The file doesn't have a sub directory! */
if (dirname.empty()) {
diff --git a/src/fios.cpp b/src/fios.cpp
index fc02d43da789c..67eec48b44594 100644
--- a/src/fios.cpp
+++ b/src/fios.cpp
@@ -507,7 +507,7 @@ std::tuple FiosGetHeightmapListCallback(SaveLoadOperation
for (Searchpath sp : _valid_searchpaths) {
std::string buf = FioGetDirectory(sp, HEIGHTMAP_DIR);
- if (buf.compare(0, buf.size(), it->second.tar_filename, 0, buf.size()) == 0) {
+ if (it->second.tar_filename.starts_with(buf)) {
match = true;
break;
}
diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp
index 10e05908eb788..a4d593dbcfbce 100644
--- a/src/fios_gui.cpp
+++ b/src/fios_gui.cpp
@@ -65,7 +65,7 @@ void LoadCheckData::Clear()
}
/** Load game/scenario with optional content download */
-static constexpr NWidgetPart _nested_load_dialog_widgets[] = {
+static constexpr std::initializer_list _nested_load_dialog_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_SL_CAPTION),
@@ -128,7 +128,7 @@ static constexpr NWidgetPart _nested_load_dialog_widgets[] = {
};
/** Load heightmap with content download */
-static constexpr NWidgetPart _nested_load_heightmap_dialog_widgets[] = {
+static constexpr std::initializer_list _nested_load_heightmap_dialog_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_SL_CAPTION),
@@ -175,7 +175,7 @@ static constexpr NWidgetPart _nested_load_heightmap_dialog_widgets[] = {
};
/** Load town data */
-static constexpr NWidgetPart _nested_load_town_data_dialog_widgets[] = {
+static constexpr std::initializer_list _nested_load_town_data_dialog_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_SL_CAPTION),
@@ -217,7 +217,7 @@ static constexpr NWidgetPart _nested_load_town_data_dialog_widgets[] = {
};
/** Save game/scenario */
-static constexpr NWidgetPart _nested_save_dialog_widgets[] = {
+static constexpr std::initializer_list _nested_save_dialog_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_SL_CAPTION),
@@ -527,9 +527,9 @@ struct SaveLoadWindow : public Window {
const FiosItem *item = *it;
if (item == this->selected) {
- GfxFillRect(br.left, tr.top, br.right, tr.bottom, PC_DARK_BLUE);
+ GfxFillRect(br.WithY(tr), PC_DARK_BLUE);
} else if (item == this->highlighted) {
- GfxFillRect(br.left, tr.top, br.right, tr.bottom, PC_VERY_DARK_BLUE);
+ GfxFillRect(br.WithY(tr), PC_VERY_DARK_BLUE);
}
DrawString(tr, item->title.GetDecodedString(), _fios_colours[item->type.detailed]);
tr = tr.Translate(0, this->resize.step_height);
diff --git a/src/fontcache.h b/src/fontcache.h
index 099f9b17e631a..b03f84514d25e 100644
--- a/src/fontcache.h
+++ b/src/fontcache.h
@@ -10,9 +10,9 @@
#ifndef FONTCACHE_H
#define FONTCACHE_H
+#include "gfx_type.h"
#include "provider_manager.h"
-#include "string_type.h"
-#include "spritecache.h"
+#include "spritecache_type.h"
/** Glyphs are characters from a font. */
typedef uint32_t GlyphID;
@@ -229,8 +229,8 @@ class FontCacheFactory : public BaseProvider {
ProviderManager::Unregister(*this);
}
- virtual std::unique_ptr LoadFont(FontSize fs, FontType fonttype) = 0;
- virtual bool FindFallbackFont(struct FontCacheSettings *settings, const std::string &language_isocode, class MissingGlyphSearcher *callback) = 0;
+ virtual std::unique_ptr LoadFont(FontSize fs, FontType fonttype) const = 0;
+ virtual bool FindFallbackFont(struct FontCacheSettings *settings, const std::string &language_isocode, class MissingGlyphSearcher *callback) const = 0;
};
class FontProviderManager : ProviderManager {
diff --git a/src/fontcache/freetypefontcache.cpp b/src/fontcache/freetypefontcache.cpp
index 9d52ab8f77c32..254b7224158c6 100644
--- a/src/fontcache/freetypefontcache.cpp
+++ b/src/fontcache/freetypefontcache.cpp
@@ -7,6 +7,8 @@
/** @file freetypefontcache.cpp FreeType font cache implementation. */
+#ifdef WITH_FREETYPE
+
#include "../stdafx.h"
#include "../debug.h"
@@ -20,14 +22,13 @@
#include "../table/control_codes.h"
-#include "../safeguards.h"
-
-#ifdef WITH_FREETYPE
#include
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include FT_TRUETYPE_TABLES_H
+#include "../safeguards.h"
+
/** Font cache for fonts that are based on a freetype font. */
class FreeTypeFontCache : public TrueTypeFontCache {
private:
@@ -225,7 +226,7 @@ class FreeTypeFontCacheFactory : public FontCacheFactory {
* format is 'font family name' or 'font family name, font style'.
* @param fs The font size to load.
*/
- std::unique_ptr LoadFont(FontSize fs, FontType fonttype) override
+ std::unique_ptr LoadFont(FontSize fs, FontType fonttype) const override
{
if (fonttype != FontType::TrueType) return nullptr;
@@ -271,7 +272,7 @@ class FreeTypeFontCacheFactory : public FontCacheFactory {
return LoadFont(fs, face, font, GetFontCacheFontSize(fs));
}
- bool FindFallbackFont(struct FontCacheSettings *settings, const std::string &language_isocode, class MissingGlyphSearcher *callback) override
+ bool FindFallbackFont(struct FontCacheSettings *settings, const std::string &language_isocode, class MissingGlyphSearcher *callback) const override
{
#ifdef WITH_FONTCONFIG
if (FontConfigFindFallbackFont(settings, language_isocode, callback)) return true;
diff --git a/src/fontcache/spritefontcache.cpp b/src/fontcache/spritefontcache.cpp
index 96f9fd8cc3d67..8d6723726696c 100644
--- a/src/fontcache/spritefontcache.cpp
+++ b/src/fontcache/spritefontcache.cpp
@@ -10,6 +10,7 @@
#include "../stdafx.h"
#include "../fontcache.h"
#include "../gfx_layout.h"
+#include "../spritecache.h"
#include "../string_func.h"
#include "../zoom_func.h"
#include "spritefontcache.h"
@@ -93,6 +94,7 @@ void InitializeUnicodeGlyphMap(FontSize fs)
SetUnicodeGlyph(fs, unicode_map.code, 0);
} else {
SpriteID sprite = base + key - ASCII_LETTERSTART;
+ if (!SpriteExists(sprite)) continue;
SetUnicodeGlyph(fs, unicode_map.code, sprite);
}
}
@@ -156,14 +158,14 @@ class SpriteFontCacheFactory : public FontCacheFactory {
public:
SpriteFontCacheFactory() : FontCacheFactory("sprite", "Sprite font provider") {}
- std::unique_ptr LoadFont(FontSize fs, FontType fonttype) override
+ std::unique_ptr LoadFont(FontSize fs, FontType fonttype) const override
{
if (fonttype != FontType::Sprite) return nullptr;
return std::make_unique(fs);
}
- bool FindFallbackFont(struct FontCacheSettings *, const std::string &, class MissingGlyphSearcher *) override
+ bool FindFallbackFont(struct FontCacheSettings *, const std::string &, class MissingGlyphSearcher *) const override
{
return false;
}
diff --git a/src/framerate_gui.cpp b/src/framerate_gui.cpp
index 72c0aa2f970b7..df390d28223b6 100644
--- a/src/framerate_gui.cpp
+++ b/src/framerate_gui.cpp
@@ -377,7 +377,7 @@ static std::string_view GetAIName(int ai_index)
}
/** @hideinitializer */
-static constexpr NWidgetPart _framerate_window_widgets[] = {
+static constexpr std::initializer_list _framerate_window_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_FRW_CAPTION),
@@ -695,7 +695,7 @@ static WindowDesc _framerate_display_desc(
/** @hideinitializer */
-static constexpr NWidgetPart _frametime_graph_window_widgets[] = {
+static constexpr std::initializer_list _frametime_graph_window_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_FGW_CAPTION), SetTextStyle(TC_WHITE),
diff --git a/src/game/game_gui.cpp b/src/game/game_gui.cpp
index ec47cd6eb5b19..34e2e30342d41 100644
--- a/src/game/game_gui.cpp
+++ b/src/game/game_gui.cpp
@@ -33,7 +33,7 @@
/** Widgets for the configure GS window. */
-static constexpr NWidgetPart _nested_gs_config_widgets[] = {
+static constexpr std::initializer_list _nested_gs_config_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_MAUVE),
NWidget(WWT_CAPTION, COLOUR_MAUVE), SetStringTip(STR_AI_CONFIG_CAPTION_GAMESCRIPT, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
diff --git a/src/game/game_text.cpp b/src/game/game_text.cpp
index 27e4314f5ac8c..021d5fec57a64 100644
--- a/src/game/game_text.cpp
+++ b/src/game/game_text.cpp
@@ -225,15 +225,15 @@ static std::shared_ptr LoadTranslations()
if (!tar_filename.empty() && (iter = _tar_list[GAME_DIR].find(tar_filename)) != _tar_list[GAME_DIR].end()) {
/* The main script is in a tar file, so find all files that
* are in the same tar and add them to the langfile scanner. */
- for (const auto &tar : _tar_filelist[GAME_DIR]) {
+ for (const auto &[name, entry] : _tar_filelist[GAME_DIR]) {
/* Not in the same tar. */
- if (tar.second.tar_filename != iter->first) continue;
+ if (entry.tar_filename != iter->first) continue;
/* Check the path and extension. */
- if (tar.first.size() <= ldir.size() || tar.first.compare(0, ldir.size(), ldir) != 0) continue;
- if (tar.first.compare(tar.first.size() - 4, 4, ".txt") != 0) continue;
+ if (!name.starts_with(ldir)) continue;
+ if (!name.ends_with(".txt")) continue;
- scanner.AddFile(tar.first, 0, tar_filename);
+ scanner.AddFile(name, 0, tar_filename);
}
} else {
/* Scan filesystem */
diff --git a/src/genworld.cpp b/src/genworld.cpp
index effa9e16e72ec..1e52fd9a24efa 100644
--- a/src/genworld.cpp
+++ b/src/genworld.cpp
@@ -139,11 +139,13 @@ static void _GenerateWorld()
if (_game_mode != GM_MENU) FlatEmptyWorld(_settings_game.game_creation.se_flat_world_height);
ConvertGroundTilesIntoWaterTiles();
+ Map::CountLandTiles();
IncreaseGeneratingWorldProgress(GWP_OBJECT);
_settings_game.game_creation.snow_line_height = DEF_SNOWLINE_HEIGHT;
} else {
GenerateClearTile();
+ Map::CountLandTiles();
/* Only generate towns, tree and industries in newgame mode. */
if (_game_mode != GM_EDITOR) {
diff --git a/src/genworld.h b/src/genworld.h
index 0bfd8455ec2ea..f571971260aaf 100644
--- a/src/genworld.h
+++ b/src/genworld.h
@@ -64,7 +64,8 @@ enum GenWorldProgress : uint8_t {
GWP_RIVER, ///< Create the rivers
GWP_ROUGH_ROCKY, ///< Make rough and rocky areas
GWP_TOWN, ///< Generate towns
- GWP_INDUSTRY, ///< Generate industries
+ GWP_LAND_INDUSTRY, ///< Generate industries
+ GWP_WATER_INDUSTRY, ///< Generate industries
GWP_OBJECT, ///< Generate objects (radio tower, light houses)
GWP_TREE, ///< Generate trees
GWP_GAME_INIT, ///< Initialize the game
diff --git a/src/genworld_gui.cpp b/src/genworld_gui.cpp
index b91a51945e323..602ae8d406b9e 100644
--- a/src/genworld_gui.cpp
+++ b/src/genworld_gui.cpp
@@ -74,7 +74,7 @@ void SetNewLandscapeType(LandscapeType landscape)
}
/** Widgets of GenerateLandscapeWindow when generating world */
-static constexpr NWidgetPart _nested_generate_landscape_widgets[] = {
+static constexpr std::initializer_list _nested_generate_landscape_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
NWidget(WWT_CAPTION, COLOUR_BROWN), SetStringTip(STR_MAPGEN_WORLD_GENERATION_CAPTION),
@@ -115,7 +115,7 @@ static constexpr NWidgetPart _nested_generate_landscape_widgets[] = {
NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_VARIETY_PULLDOWN), SetToolTip(STR_CONFIG_SETTING_VARIETY_HELPTEXT), SetFill(1, 1),
NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_SMOOTHNESS_PULLDOWN), SetToolTip(STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT), SetFill(1, 1),
NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_RIVER_PULLDOWN), SetToolTip(STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT), SetFill(1, 1),
- NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_BORDERS_RANDOM), SetToolTip(STR_MAPGEN_BORDER_TYPE_TOOLTIP), SetFill(1, 1),
+ NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_BORDERS_PULLDOWN), SetToolTip(STR_MAPGEN_BORDER_TYPE_TOOLTIP), SetFill(1, 1),
EndContainer(),
EndContainer(),
@@ -172,14 +172,14 @@ static constexpr NWidgetPart _nested_generate_landscape_widgets[] = {
NWidget(NWID_VERTICAL),
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_MAPGEN_NORTHWEST), SetPadding(0, WidgetDimensions::unscaled.hsep_normal, 0, 0), SetFill(1, 1), SetAlignment(SA_RIGHT | SA_VERT_CENTER),
- NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_WATER_NW), SetToolTip(STR_MAPGEN_NORTHWEST), SetFill(1, 1),
- NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_WATER_NE), SetToolTip(STR_MAPGEN_NORTHEAST), SetFill(1, 1),
+ NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_WATER_NW), SetToolTip(STR_MAPGEN_NORTHWEST_TOOLTIP), SetFill(1, 1),
+ NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_WATER_NE), SetToolTip(STR_MAPGEN_NORTHEAST_TOOLTIP), SetFill(1, 1),
NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_MAPGEN_NORTHEAST), SetPadding(0, 0, 0, WidgetDimensions::unscaled.hsep_normal), SetFill(1, 1),
EndContainer(),
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_MAPGEN_SOUTHWEST), SetPadding(0, WidgetDimensions::unscaled.hsep_normal, 0, 0), SetFill(1, 1), SetAlignment(SA_RIGHT | SA_VERT_CENTER),
- NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_WATER_SW), SetToolTip(STR_MAPGEN_SOUTHWEST), SetFill(1, 1),
- NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_WATER_SE), SetToolTip(STR_MAPGEN_SOUTHEAST), SetFill(1, 1),
+ NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_WATER_SW), SetToolTip(STR_MAPGEN_SOUTHWEST_TOOLTIP), SetFill(1, 1),
+ NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_WATER_SE), SetToolTip(STR_MAPGEN_SOUTHEAST_TOOLTIP), SetFill(1, 1),
NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_MAPGEN_SOUTHEAST), SetPadding(0, 0, 0, WidgetDimensions::unscaled.hsep_normal), SetFill(1, 1),
EndContainer(),
EndContainer(),
@@ -198,7 +198,7 @@ static constexpr NWidgetPart _nested_generate_landscape_widgets[] = {
};
/** Widgets of GenerateLandscapeWindow when loading heightmap */
-static constexpr NWidgetPart _nested_heightmap_load_widgets[] = {
+static constexpr std::initializer_list _nested_heightmap_load_widgets = {
/* Window header. */
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
@@ -379,6 +379,7 @@ static DropDownList BuildTownNameDropDown()
static const StringID _elevations[] = {STR_TERRAIN_TYPE_VERY_FLAT, STR_TERRAIN_TYPE_FLAT, STR_TERRAIN_TYPE_HILLY, STR_TERRAIN_TYPE_MOUNTAINOUS, STR_TERRAIN_TYPE_ALPINIST, STR_TERRAIN_TYPE_CUSTOM};
static const StringID _sea_lakes[] = {STR_SEA_LEVEL_VERY_LOW, STR_SEA_LEVEL_LOW, STR_SEA_LEVEL_MEDIUM, STR_SEA_LEVEL_HIGH, STR_SEA_LEVEL_CUSTOM};
static const StringID _rivers[] = {STR_RIVERS_NONE, STR_RIVERS_FEW, STR_RIVERS_MODERATE, STR_RIVERS_LOT};
+static const StringID _borders[] = {STR_MAPGEN_BORDER_RANDOMIZE, STR_MAPGEN_BORDER_MANUAL, STR_MAPGEN_BORDER_INFINITE_WATER};
static const StringID _smoothness[] = {STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH, STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH, STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_ROUGH, STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_ROUGH};
static const StringID _rotation[] = {STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE, STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_CLOCKWISE};
static const StringID _num_towns[] = {STR_NUM_VERY_LOW, STR_NUM_LOW, STR_NUM_NORMAL, STR_NUM_HIGH, STR_NUM_CUSTOM};
@@ -471,7 +472,7 @@ struct GenerateLandscapeWindow : public Window {
case WID_GL_RIVER_PULLDOWN: return GetString(_rivers[_settings_newgame.game_creation.amount_of_rivers]);
case WID_GL_SMOOTHNESS_PULLDOWN: return GetString(_smoothness[_settings_newgame.game_creation.tgen_smoothness]);
case WID_GL_VARIETY_PULLDOWN: return GetString(_variety[_settings_newgame.game_creation.variety]);
- case WID_GL_BORDERS_RANDOM: return GetString((_settings_newgame.game_creation.water_borders == BorderFlag::Random) ? STR_MAPGEN_BORDER_RANDOMIZE : STR_MAPGEN_BORDER_MANUAL);
+ case WID_GL_BORDERS_PULLDOWN: return GetString(_borders[_settings_newgame.game_creation.water_border_presets]);
case WID_GL_WATER_NE: return GetString((_settings_newgame.game_creation.water_borders == BorderFlag::Random) ? STR_MAPGEN_BORDER_RANDOM : _settings_newgame.game_creation.water_borders.Test(BorderFlag::NorthEast) ? STR_MAPGEN_BORDER_WATER : STR_MAPGEN_BORDER_FREEFORM);
case WID_GL_WATER_NW: return GetString((_settings_newgame.game_creation.water_borders == BorderFlag::Random) ? STR_MAPGEN_BORDER_RANDOM : _settings_newgame.game_creation.water_borders.Test(BorderFlag::NorthWest) ? STR_MAPGEN_BORDER_WATER : STR_MAPGEN_BORDER_FREEFORM);
case WID_GL_WATER_SE: return GetString((_settings_newgame.game_creation.water_borders == BorderFlag::Random) ? STR_MAPGEN_BORDER_RANDOM : _settings_newgame.game_creation.water_borders.Test(BorderFlag::SouthEast) ? STR_MAPGEN_BORDER_WATER : STR_MAPGEN_BORDER_FREEFORM);
@@ -507,12 +508,10 @@ struct GenerateLandscapeWindow : public Window {
if (mode == GLWM_GENERATE) {
this->SetWidgetDisabledState(WID_GL_SMOOTHNESS_PULLDOWN, _settings_newgame.game_creation.land_generator == LG_ORIGINAL);
this->SetWidgetDisabledState(WID_GL_VARIETY_PULLDOWN, _settings_newgame.game_creation.land_generator == LG_ORIGINAL);
- this->SetWidgetDisabledState(WID_GL_BORDERS_RANDOM, _settings_newgame.game_creation.land_generator == LG_ORIGINAL || !_settings_newgame.construction.freeform_edges);
+ this->SetWidgetDisabledState(WID_GL_BORDERS_PULLDOWN, _settings_newgame.game_creation.land_generator == LG_ORIGINAL);
this->SetWidgetsDisabledState(_settings_newgame.game_creation.land_generator == LG_ORIGINAL || !_settings_newgame.construction.freeform_edges || _settings_newgame.game_creation.water_borders == BorderFlag::Random,
WID_GL_WATER_NW, WID_GL_WATER_NE, WID_GL_WATER_SE, WID_GL_WATER_SW);
- this->SetWidgetLoweredState(WID_GL_BORDERS_RANDOM, _settings_newgame.game_creation.water_borders == BorderFlag::Random);
-
this->SetWidgetLoweredState(WID_GL_WATER_NW, _settings_newgame.game_creation.water_borders.Test(BorderFlag::NorthWest));
this->SetWidgetLoweredState(WID_GL_WATER_NE, _settings_newgame.game_creation.water_borders.Test(BorderFlag::NorthEast));
this->SetWidgetLoweredState(WID_GL_WATER_SE, _settings_newgame.game_creation.water_borders.Test(BorderFlag::SouthEast));
@@ -622,10 +621,7 @@ struct GenerateLandscapeWindow : public Window {
case WID_GL_SMOOTHNESS_PULLDOWN: strs = _smoothness; break;
case WID_GL_VARIETY_PULLDOWN: strs = _variety; break;
case WID_GL_HEIGHTMAP_ROTATION_PULLDOWN: strs = _rotation; break;
- case WID_GL_BORDERS_RANDOM:
- d = maxdim(GetStringBoundingBox(STR_MAPGEN_BORDER_RANDOMIZE), GetStringBoundingBox(STR_MAPGEN_BORDER_MANUAL));
- break;
-
+ case WID_GL_BORDERS_PULLDOWN: strs = _borders; break;
case WID_GL_WATER_NE:
case WID_GL_WATER_NW:
case WID_GL_WATER_SE:
@@ -807,7 +803,11 @@ struct GenerateLandscapeWindow : public Window {
ShowDropDownMenu(this, _variety, _settings_newgame.game_creation.variety, WID_GL_VARIETY_PULLDOWN, 0, 0);
break;
- /* Freetype map borders */
+ /* Map borders */
+ case WID_GL_BORDERS_PULLDOWN:
+ ShowDropDownMenu(this, _borders, _settings_newgame.game_creation.water_border_presets, WID_GL_BORDERS_PULLDOWN, 0, 0);
+ break;
+
case WID_GL_WATER_NW:
_settings_newgame.game_creation.water_borders.Flip(BorderFlag::NorthWest);
SndClickBeep();
@@ -832,16 +832,6 @@ struct GenerateLandscapeWindow : public Window {
this->InvalidateData();
break;
- case WID_GL_BORDERS_RANDOM:
- if (_settings_newgame.game_creation.water_borders == BorderFlag::Random) {
- _settings_newgame.game_creation.water_borders.Reset();
- } else {
- _settings_newgame.game_creation.water_borders = BorderFlag::Random;
- }
- SndClickBeep();
- this->InvalidateData();
- break;
-
case WID_GL_AI_BUTTON: ///< AI Settings
ShowAIConfigWindow();
break;
@@ -908,6 +898,25 @@ struct GenerateLandscapeWindow : public Window {
break;
}
+ case WID_GL_BORDERS_PULLDOWN: {
+ switch (index) {
+ case BFP_RANDOM:
+ _settings_newgame.game_creation.water_borders = BorderFlag::Random;
+ _settings_newgame.construction.freeform_edges = true;
+ break;
+ case BFP_MANUAL:
+ _settings_newgame.game_creation.water_borders = {};
+ _settings_newgame.construction.freeform_edges = true;
+ break;
+ case BFP_INFINITE_WATER:
+ _settings_newgame.game_creation.water_borders = BORDERFLAGS_ALL;
+ _settings_newgame.construction.freeform_edges = false;
+ break;
+ }
+ _settings_newgame.game_creation.water_border_presets = static_cast(index);
+ break;
+ }
+
case WID_GL_WATER_PULLDOWN: {
if ((uint)index == CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY) {
this->widget_id = widget;
@@ -1235,7 +1244,7 @@ struct CreateScenarioWindow : public Window
}
};
-static constexpr NWidgetPart _nested_create_scenario_widgets[] = {
+static constexpr std::initializer_list _nested_create_scenario_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
NWidget(WWT_CAPTION, COLOUR_BROWN), SetStringTip(STR_SE_MAPGEN_CAPTION),
@@ -1308,7 +1317,7 @@ void ShowCreateScenario()
new CreateScenarioWindow(_create_scenario_desc, GLWM_SCENARIO);
}
-static constexpr NWidgetPart _nested_generate_progress_widgets[] = {
+static constexpr std::initializer_list _nested_generate_progress_widgets = {
NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_GENERATION_WORLD, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
NWidget(WWT_PANEL, COLOUR_GREY),
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_wide, 0), SetPadding(WidgetDimensions::unscaled.modalpopup),
@@ -1340,7 +1349,8 @@ static const StringID _generation_class_table[] = {
STR_GENERATION_RIVER_GENERATION,
STR_GENERATION_CLEARING_TILES,
STR_GENERATION_TOWN_GENERATION,
- STR_GENERATION_INDUSTRY_GENERATION,
+ STR_GENERATION_LAND_INDUSTRY_GENERATION,
+ STR_GENERATION_WATER_INDUSTRY_GENERATION,
STR_GENERATION_OBJECT_GENERATION,
STR_GENERATION_TREE_GENERATION,
STR_GENERATION_SETTINGUP_GAME,
@@ -1410,8 +1420,7 @@ struct GenerateProgressWindow : public Window {
DrawFrameRect(r, COLOUR_GREY, {FrameFlag::BorderOnly, FrameFlag::Lowered});
Rect br = r.Shrink(WidgetDimensions::scaled.bevel);
DrawFrameRect(br.WithWidth(br.Width() * GenWorldStatus::percent / 100, _current_text_dir == TD_RTL), COLOUR_MAUVE, {});
- DrawString(br.left, br.right, CentreBounds(br.top, br.bottom, GetCharacterHeight(FS_NORMAL)),
- GetString(STR_GENERATION_PROGRESS, GenWorldStatus::percent), TC_FROMSTRING, SA_HOR_CENTER);
+ DrawString(br.CentreToHeight(GetCharacterHeight(FS_NORMAL)), GetString(STR_GENERATION_PROGRESS, GenWorldStatus::percent), TC_FROMSTRING, SA_HOR_CENTER);
break;
}
@@ -1448,7 +1457,7 @@ void ShowGenerateWorldProgress()
static void _SetGeneratingWorldProgress(GenWorldProgress cls, uint progress, uint total)
{
- static const int percent_table[] = {0, 5, 14, 17, 20, 40, 60, 65, 80, 85, 95, 99, 100 };
+ static const int percent_table[] = {0, 5, 14, 17, 20, 40, 55, 60, 65, 80, 85, 95, 99, 100 };
static_assert(lengthof(percent_table) == GWP_CLASS_COUNT + 1);
assert(cls < GWP_CLASS_COUNT);
diff --git a/src/goal_cmd.h b/src/goal_cmd.h
index 4cb017ede9f52..7002bad775f32 100644
--- a/src/goal_cmd.h
+++ b/src/goal_cmd.h
@@ -22,13 +22,13 @@ CommandCost CmdSetGoalCompleted(DoCommandFlags flags, GoalID goal, bool complete
CommandCost CmdGoalQuestion(DoCommandFlags flags, uint16_t uniqueid, uint32_t target, bool is_client, uint32_t button_mask, GoalQuestionType type, const EncodedString &text);
CommandCost CmdGoalQuestionAnswer(DoCommandFlags flags, uint16_t uniqueid, uint8_t button);
-DEF_CMD_TRAIT(CMD_CREATE_GOAL, CmdCreateGoal, CommandFlags({CommandFlag::Deity, CommandFlag::StrCtrl}), CMDT_OTHER_MANAGEMENT)
-DEF_CMD_TRAIT(CMD_REMOVE_GOAL, CmdRemoveGoal, CommandFlag::Deity, CMDT_OTHER_MANAGEMENT)
-DEF_CMD_TRAIT(CMD_SET_GOAL_DESTINATION, CmdSetGoalDestination, CommandFlags({CommandFlag::Deity, CommandFlag::StrCtrl}), CMDT_OTHER_MANAGEMENT)
-DEF_CMD_TRAIT(CMD_SET_GOAL_TEXT, CmdSetGoalText, CommandFlags({CommandFlag::Deity, CommandFlag::StrCtrl}), CMDT_OTHER_MANAGEMENT)
-DEF_CMD_TRAIT(CMD_SET_GOAL_PROGRESS, CmdSetGoalProgress, CommandFlags({CommandFlag::Deity, CommandFlag::StrCtrl}), CMDT_OTHER_MANAGEMENT)
-DEF_CMD_TRAIT(CMD_SET_GOAL_COMPLETED, CmdSetGoalCompleted, CommandFlags({CommandFlag::Deity, CommandFlag::StrCtrl}), CMDT_OTHER_MANAGEMENT)
-DEF_CMD_TRAIT(CMD_GOAL_QUESTION, CmdGoalQuestion, CommandFlags({CommandFlag::Deity, CommandFlag::StrCtrl}), CMDT_OTHER_MANAGEMENT)
-DEF_CMD_TRAIT(CMD_GOAL_QUESTION_ANSWER, CmdGoalQuestionAnswer, CommandFlag::Deity, CMDT_OTHER_MANAGEMENT)
+DEF_CMD_TRAIT(CMD_CREATE_GOAL, CmdCreateGoal, CommandFlags({CommandFlag::Deity, CommandFlag::StrCtrl}), CommandType::OtherManagement)
+DEF_CMD_TRAIT(CMD_REMOVE_GOAL, CmdRemoveGoal, CommandFlag::Deity, CommandType::OtherManagement)
+DEF_CMD_TRAIT(CMD_SET_GOAL_DESTINATION, CmdSetGoalDestination, CommandFlags({CommandFlag::Deity, CommandFlag::StrCtrl}), CommandType::OtherManagement)
+DEF_CMD_TRAIT(CMD_SET_GOAL_TEXT, CmdSetGoalText, CommandFlags({CommandFlag::Deity, CommandFlag::StrCtrl}), CommandType::OtherManagement)
+DEF_CMD_TRAIT(CMD_SET_GOAL_PROGRESS, CmdSetGoalProgress, CommandFlags({CommandFlag::Deity, CommandFlag::StrCtrl}), CommandType::OtherManagement)
+DEF_CMD_TRAIT(CMD_SET_GOAL_COMPLETED, CmdSetGoalCompleted, CommandFlags({CommandFlag::Deity, CommandFlag::StrCtrl}), CommandType::OtherManagement)
+DEF_CMD_TRAIT(CMD_GOAL_QUESTION, CmdGoalQuestion, CommandFlags({CommandFlag::Deity, CommandFlag::StrCtrl}), CommandType::OtherManagement)
+DEF_CMD_TRAIT(CMD_GOAL_QUESTION_ANSWER, CmdGoalQuestionAnswer, CommandFlag::Deity, CommandType::OtherManagement)
#endif /* GOAL_CMD_H */
diff --git a/src/goal_gui.cpp b/src/goal_gui.cpp
index ccf9d98b1efe3..e44e66644ccaa 100644
--- a/src/goal_gui.cpp
+++ b/src/goal_gui.cpp
@@ -275,7 +275,7 @@ struct GoalListWindow : public Window {
};
/** Widgets of the #GoalListWindow. */
-static constexpr NWidgetPart _nested_goals_list_widgets[] = {
+static constexpr std::initializer_list _nested_goals_list_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
NWidget(WWT_CAPTION, COLOUR_BROWN, WID_GOAL_CAPTION),
diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp
index 962b201405f51..74b916c168caf 100644
--- a/src/graph_gui.cpp
+++ b/src/graph_gui.cpp
@@ -133,7 +133,7 @@ static std::unique_ptr MakeNWidgetCompanyLines()
return vert;
}
-static constexpr NWidgetPart _nested_graph_legend_widgets[] = {
+static constexpr std::initializer_list _nested_graph_legend_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
NWidget(WWT_CAPTION, COLOUR_BROWN), SetStringTip(STR_GRAPH_KEY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
@@ -935,7 +935,7 @@ struct OperatingProfitGraphWindow : BaseCompanyGraphWindow {
}
};
-static constexpr NWidgetPart _nested_operating_profit_widgets[] = {
+static constexpr std::initializer_list _nested_operating_profit_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
NWidget(WWT_CAPTION, COLOUR_BROWN), SetStringTip(STR_GRAPH_OPERATING_PROFIT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
@@ -988,7 +988,7 @@ struct IncomeGraphWindow : BaseCompanyGraphWindow {
}
};
-static constexpr NWidgetPart _nested_income_graph_widgets[] = {
+static constexpr std::initializer_list _nested_income_graph_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
NWidget(WWT_CAPTION, COLOUR_BROWN), SetStringTip(STR_GRAPH_INCOME_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
@@ -1039,7 +1039,7 @@ struct DeliveredCargoGraphWindow : BaseCompanyGraphWindow {
}
};
-static constexpr NWidgetPart _nested_delivered_cargo_graph_widgets[] = {
+static constexpr std::initializer_list _nested_delivered_cargo_graph_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
NWidget(WWT_CAPTION, COLOUR_BROWN), SetStringTip(STR_GRAPH_CARGO_DELIVERED_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
@@ -1096,7 +1096,7 @@ struct PerformanceHistoryGraphWindow : BaseCompanyGraphWindow {
}
};
-static constexpr NWidgetPart _nested_performance_history_widgets[] = {
+static constexpr std::initializer_list _nested_performance_history_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
NWidget(WWT_CAPTION, COLOUR_BROWN), SetStringTip(STR_GRAPH_COMPANY_PERFORMANCE_RATINGS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
@@ -1148,7 +1148,7 @@ struct CompanyValueGraphWindow : BaseCompanyGraphWindow {
}
};
-static constexpr NWidgetPart _nested_company_value_graph_widgets[] = {
+static constexpr std::initializer_list _nested_company_value_graph_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
NWidget(WWT_CAPTION, COLOUR_BROWN), SetStringTip(STR_GRAPH_COMPANY_VALUES_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
@@ -1412,7 +1412,7 @@ struct PaymentRatesGraphWindow : BaseCargoGraphWindow {
}
};
-static constexpr NWidgetPart _nested_cargo_payment_rates_widgets[] = {
+static constexpr std::initializer_list