OpenTTD Source 20260421-master-gc2fbc6fdeb
cargotype.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "stdafx.h"
11#include "cargotype.h"
13#include "newgrf_cargo.h"
14#include "string_func.h"
15#include "strings_func.h"
16#include "settings_type.h"
17
18#include "table/sprites.h"
19#include "table/strings.h"
20#include "table/cargo_const.h"
21
22#include "safeguards.h"
23
25
30CargoTypes _cargo_mask;
31
36
41static std::vector<CargoLabel> _default_cargo_labels;
42
48static std::array<CargoLabel, 12> _climate_dependent_cargo_labels;
49
55static std::array<CargoLabel, 32> _climate_independent_cargo_labels;
56
62{
63 assert(to_underlying(l) < std::size(_default_climate_cargo));
64
65 _cargo_mask = 0;
69
70 /* Copy from default cargo by label or index. */
71 auto insert = std::begin(CargoSpec::array);
72 for (const auto &cl : _default_climate_cargo[to_underlying(l)]) {
73
74 struct visitor {
75 const CargoSpec &operator()(const int &index)
76 {
77 /* Copy the default cargo by index. */
78 return _default_cargo[index];
79 }
80 const CargoSpec &operator()(const CargoLabel &label)
81 {
82 /* Search for label in default cargo types and copy if found. */
83 auto found = std::ranges::find(_default_cargo, label, &CargoSpec::label);
84 if (found != std::end(_default_cargo)) return *found;
85
86 /* Index or label is invalid, this should not happen. */
87 NOT_REACHED();
88 }
89 };
90
91 *insert = std::visit(visitor{}, cl);
92
93 if (insert->IsValid()) {
94 SetBit(_cargo_mask, insert->Index());
95 _default_cargo_labels.push_back(insert->label);
96 _climate_dependent_cargo_labels[insert->Index()] = insert->label;
97 _climate_independent_cargo_labels[insert->bitnum] = insert->label;
98 }
99 ++insert;
100 }
101
102 /* Reset and disable remaining cargo types. */
103 std::fill(insert, std::end(CargoSpec::array), CargoSpec{});
104
106}
107
112std::span<const CargoLabel> GetClimateDependentCargoTranslationTable()
113{
115}
116
122{
124}
125
132{
133 CargoSpec::label_map.clear();
134 for (const CargoSpec &cs : CargoSpec::array) {
135 /* During initialization, CargoSpec can be marked valid before the label has been set. */
136 if (!cs.IsValid() || cs.label == CargoLabel{} || cs.label == CT_INVALID) continue;
137 /* Label already exists, don't add again. */
138 if (CargoSpec::label_map.count(cs.label) != 0) continue;
139
140 CargoSpec::label_map.emplace(cs.label, cs.Index());
141 }
142}
143
149bool IsDefaultCargo(CargoType cargo_type)
150{
151 auto cs = CargoSpec::Get(cargo_type);
152 if (!cs->IsValid()) return false;
153
154 CargoLabel label = cs->label;
155 return std::any_of(std::begin(_default_cargo_labels), std::end(_default_cargo_labels), [&label](const CargoLabel &cl) { return cl == label; });
156}
157
163{
164 Dimension size = {0, 0};
165 for (const CargoSpec *cs : _sorted_cargo_specs) {
166 size = maxdim(size, GetSpriteSize(cs->GetCargoIcon()));
167 }
168 return size;
169}
170
176{
177 SpriteID sprite = this->sprite;
178 if (sprite == 0xFFFF) {
179 /* A value of 0xFFFF indicates we should draw a custom icon */
181 }
182
183 if (sprite == 0) sprite = SPR_CARGO_GOODS;
184
185 return sprite;
186}
187
188std::array<uint8_t, NUM_CARGO> _sorted_cargo_types;
189std::vector<const CargoSpec *> _sorted_cargo_specs;
190std::span<const CargoSpec *> _sorted_standard_cargo_specs;
191
193static bool CargoSpecNameSorter(const CargoSpec * const &a, const CargoSpec * const &b)
194{
195 std::string a_name = GetString(a->name);
196 std::string b_name = GetString(b->name);
197
198 int res = StrNaturalCompare(a_name, b_name); // Sort by name (natural sorting).
199
200 /* If the names are equal, sort by cargo bitnum. */
201 return (res != 0) ? res < 0 : (a->bitnum < b->bitnum);
203
205static bool CargoSpecClassSorter(const CargoSpec * const &a, const CargoSpec * const &b)
206{
208 if (res == 0) {
210 if (res == 0) {
212 if (res == 0) {
213 return CargoSpecNameSorter(a, b);
214 }
215 }
216 }
217
218 return res < 0;
219}
220
223{
224 for (auto &tpc : CargoSpec::town_production_cargoes) tpc.clear();
225 _sorted_cargo_specs.clear();
226 /* Add each cargo spec to the list, and determine the largest cargo icon size. */
227 for (const CargoSpec *cargo : CargoSpec::Iterate()) {
228 _sorted_cargo_specs.push_back(cargo);
229 }
230
231 /* Sort cargo specifications by cargo class and name. */
233
234 /* Populate */
235 for (auto it = std::begin(_sorted_cargo_specs); it != std::end(_sorted_cargo_specs); ++it) {
236 _sorted_cargo_types[(*it)->Index()] = static_cast<uint8_t>(it - std::begin(_sorted_cargo_specs));
237 }
238
239 /* Count the number of standard cargos and fill the mask. */
241 uint8_t nb_standard_cargo = 0;
242 for (const auto &cargo : _sorted_cargo_specs) {
243 assert(cargo->town_production_effect != TownProductionEffect::Invalid);
244 CargoSpec::town_production_cargoes[cargo->town_production_effect].push_back(cargo);
245 if (cargo->classes.Test(CargoClass::Special)) break;
246 nb_standard_cargo++;
247 SetBit(_standard_cargo_mask, cargo->Index());
248 }
249
250 /* _sorted_standard_cargo_specs is a subset of _sorted_cargo_specs. */
251 _sorted_standard_cargo_specs = { _sorted_cargo_specs.data(), nb_standard_cargo };
252}
253
254uint64_t CargoSpec::WeightOfNUnitsInTrain(uint32_t n) const
255{
257 return this->WeightOfNUnits(n);
258}
259
266std::optional<std::string> BuildCargoAcceptanceString(const CargoArray &acceptance, StringID label)
267{
268 std::string_view list_separator = GetListSeparator();
269
270 std::stringstream line;
271
272 bool found = false;
273 for (const CargoSpec *cs : _sorted_cargo_specs) {
274 CargoType cargo_type = cs->Index();
275 if (acceptance[cargo_type] > 0) {
276 /* Add a comma between each item. */
277 if (found) line << list_separator;
278 found = true;
279
280 /* If the accepted value is less than 8, show it in 1/8:ths */
281 if (acceptance[cargo_type] < 8) {
282 line << GetString(STR_LAND_AREA_INFORMATION_CARGO_EIGHTS, acceptance[cargo_type], cs->name);
283 } else {
284 line << GetString(cs->name);
285 }
286 }
287 }
288
289 if (found) return GetString(label, line.str());
290
291 return std::nullopt;
292}
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
Table of all default cargo types.
static const CargoSpec _default_cargo[]
Cargo types available by default.
Definition cargo_const.h:57
static const std::variant< CargoLabel, int > _default_climate_cargo[NUM_LANDSCAPE][NUM_ORIGINAL_CARGO]
Table of cargo types available in each climate, by default.
static constexpr CargoLabel CT_INVALID
Invalid cargo type.
Definition cargo_type.h:70
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:21
StrongType::Typedef< uint32_t, struct CargoLabelTag, StrongType::Compare > CargoLabel
Globally unique label of a cargo type.
Definition cargo_type.h:16
static const CargoType NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:73
static std::array< CargoLabel, 32 > _climate_independent_cargo_labels
Default cargo translation for version 8+ NewGRFs.
Definition cargotype.cpp:55
static std::vector< CargoLabel > _default_cargo_labels
List of default cargo labels, used when setting up cargo types for default vehicles.
Definition cargotype.cpp:41
std::span< const CargoLabel > GetClimateDependentCargoTranslationTable()
Get default climate-dependent cargo translation table for a NewGRF, used if the NewGRF does not provi...
std::array< uint8_t, NUM_CARGO > _sorted_cargo_types
Sort order of cargoes by cargo type.
static bool CargoSpecClassSorter(const CargoSpec *const &a, const CargoSpec *const &b)
Sort cargo specifications by their cargo class.
Dimension GetLargestCargoIconSize()
Get dimensions of largest cargo icon.
bool IsDefaultCargo(CargoType cargo_type)
Test if a cargo is a default cargo type.
std::span< const CargoSpec * > _sorted_standard_cargo_specs
Standard cargo specifications sorted alphabetically by name.
CargoTypes _standard_cargo_mask
Bitmask of real cargo types available.
Definition cargotype.cpp:35
std::span< const CargoLabel > GetClimateIndependentCargoTranslationTable()
Get default climate-independent cargo translation table for a NewGRF, used if the NewGRF does not pro...
void BuildCargoLabelMap()
Build cargo label map.
std::optional< std::string > BuildCargoAcceptanceString(const CargoArray &acceptance, StringID label)
Build comma-separated cargo acceptance string.
void SetupCargoForClimate(LandscapeType l)
Set up the default cargo types for the given landscape type.
Definition cargotype.cpp:61
std::vector< const CargoSpec * > _sorted_cargo_specs
Cargo specifications sorted alphabetically by name.
static bool CargoSpecNameSorter(const CargoSpec *const &a, const CargoSpec *const &b)
Sort cargo specifications by their name.
void InitializeSortedCargoSpecs()
Initialize the list of sorted cargo specifications.
static std::array< CargoLabel, 12 > _climate_dependent_cargo_labels
Default cargo translation for up to version 7 NewGRFs.
Definition cargotype.cpp:48
CargoTypes _cargo_mask
Bitmask of cargo types available.
Definition cargotype.cpp:30
Types/functions related to cargoes.
@ Mail
Mail.
Definition cargotype.h:52
@ Passengers
Passengers.
Definition cargotype.h:51
@ Special
Special bit used for livery refit tricks instead of normal cargoes.
Definition cargotype.h:66
@ Invalid
Invalid town production effect.
Definition cargotype.h:46
CargoTypes _cargo_mask
Bitmask of cargo types available.
Definition cargotype.cpp:30
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
Definition enum_type.hpp:21
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition gfx.cpp:972
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
LandscapeType
Landscape types.
SpriteID GetCustomCargoSprite(const CargoSpec *cs)
Get the custom sprite for the given cargo type.
Cargo support for NewGRFs.
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
Types related to global configuration settings.
This file contains all sprite-related enums and defines.
Definition of base types and functions in a cross-platform compatible way.
int StrNaturalCompare(std::string_view s1, std::string_view s2, bool ignore_garbage_at_front)
Compares two strings using case insensitive natural sort.
Definition string.cpp:429
Functions related to low-level strings.
std::string_view GetListSeparator()
Get the list separator string for the current language.
Definition strings.cpp:299
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Class for storing amounts of cargo.
Definition cargo_type.h:115
Specification of a cargo type.
Definition cargotype.h:75
CargoClasses classes
Classes of this cargo type.
Definition cargotype.h:82
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:139
uint8_t bitnum
Cargo bit number, is INVALID_CARGO_BITNUM for a non-used spec.
Definition cargotype.h:77
static std::map< CargoLabel, CargoType > label_map
Translation map from CargoLabel to Cargo type.
Definition cargotype.h:199
SpriteID GetCargoIcon() const
Get sprite for showing cargo of this type.
SpriteID sprite
Icon to display this cargo type, may be 0xFFF (which means to resolve an action123 chain).
Definition cargotype.h:98
bool is_freight
Cargo type is considered to be freight (affects train freight multiplier).
Definition cargotype.h:86
CargoLabel label
Unique label of the cargo type.
Definition cargotype.h:76
static IterateWrapper Iterate(size_t from=0)
Returns an iterable ensemble of all valid CargoSpec.
Definition cargotype.h:192
static CargoSpec array[NUM_CARGO]
Array holding all CargoSpecs.
Definition cargotype.h:198
static EnumClassIndexContainer< std::array< std::vector< const CargoSpec * >, to_underlying(TownProductionEffect::End)>, TownProductionEffect > town_production_cargoes
List of cargo specs for each Town Product Effect.
Definition cargotype.h:195
StringID name
Name of this type of cargo.
Definition cargotype.h:92
Dimensions (a width and height) of a rectangle in 2D.
VehicleSettings vehicle
options for vehicles
uint8_t freight_trains
value to multiply the weight of cargo by