OpenTTD Source 20250524-master-gc366e6a48e
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 <http://www.gnu.org/licenses/>.
6 */
7
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
25std::array<std::vector<const CargoSpec *>, NUM_TPE> CargoSpec::town_production_cargoes{};
26
31CargoTypes _cargo_mask;
32
37
42static std::vector<CargoLabel> _default_cargo_labels;
43
49static std::array<CargoLabel, 12> _climate_dependent_cargo_labels;
50
56static std::array<CargoLabel, 32> _climate_independent_cargo_labels;
57
63{
64 assert(to_underlying(l) < std::size(_default_climate_cargo));
65
66 _cargo_mask = 0;
70
71 /* Copy from default cargo by label or index. */
72 auto insert = std::begin(CargoSpec::array);
73 for (const auto &cl : _default_climate_cargo[to_underlying(l)]) {
74
75 struct visitor {
76 const CargoSpec &operator()(const int &index)
77 {
78 /* Copy the default cargo by index. */
79 return _default_cargo[index];
80 }
81 const CargoSpec &operator()(const CargoLabel &label)
82 {
83 /* Search for label in default cargo types and copy if found. */
84 auto found = std::ranges::find(_default_cargo, label, &CargoSpec::label);
85 if (found != std::end(_default_cargo)) return *found;
86
87 /* Index or label is invalid, this should not happen. */
88 NOT_REACHED();
89 }
90 };
91
92 *insert = std::visit(visitor{}, cl);
93
94 if (insert->IsValid()) {
95 SetBit(_cargo_mask, insert->Index());
96 _default_cargo_labels.push_back(insert->label);
97 _climate_dependent_cargo_labels[insert->Index()] = insert->label;
98 _climate_independent_cargo_labels[insert->bitnum] = insert->label;
99 }
100 ++insert;
101 }
102
103 /* Reset and disable remaining cargo types. */
104 std::fill(insert, std::end(CargoSpec::array), CargoSpec{});
105
107}
108
113std::span<const CargoLabel> GetClimateDependentCargoTranslationTable()
114{
116}
117
123{
125}
126
133{
134 CargoSpec::label_map.clear();
135 for (const CargoSpec &cs : CargoSpec::array) {
136 /* During initialization, CargoSpec can be marked valid before the label has been set. */
137 if (!cs.IsValid() || cs.label == CargoLabel{} || cs.label == CT_INVALID) continue;
138 /* Label already exists, don't add again. */
139 if (CargoSpec::label_map.count(cs.label) != 0) continue;
140
141 CargoSpec::label_map.emplace(cs.label, cs.Index());
142 }
143}
144
150bool IsDefaultCargo(CargoType cargo_type)
151{
152 auto cs = CargoSpec::Get(cargo_type);
153 if (!cs->IsValid()) return false;
154
155 CargoLabel label = cs->label;
156 return std::any_of(std::begin(_default_cargo_labels), std::end(_default_cargo_labels), [&label](const CargoLabel &cl) { return cl == label; });
157}
158
164{
165 Dimension size = {0, 0};
166 for (const CargoSpec *cs : _sorted_cargo_specs) {
167 size = maxdim(size, GetSpriteSize(cs->GetCargoIcon()));
168 }
169 return size;
170}
171
177{
178 SpriteID sprite = this->sprite;
179 if (sprite == 0xFFFF) {
180 /* A value of 0xFFFF indicates we should draw a custom icon */
182 }
183
184 if (sprite == 0) sprite = SPR_CARGO_GOODS;
185
186 return sprite;
187}
188
189std::array<uint8_t, NUM_CARGO> _sorted_cargo_types;
190std::vector<const CargoSpec *> _sorted_cargo_specs;
191std::span<const CargoSpec *> _sorted_standard_cargo_specs;
192
194static bool CargoSpecNameSorter(const CargoSpec * const &a, const CargoSpec * const &b)
195{
196 std::string a_name = GetString(a->name);
197 std::string b_name = GetString(b->name);
198
199 int res = StrNaturalCompare(a_name, b_name); // Sort by name (natural sorting).
200
201 /* If the names are equal, sort by cargo bitnum. */
202 return (res != 0) ? res < 0 : (a->bitnum < b->bitnum);
203}
204
206static bool CargoSpecClassSorter(const CargoSpec * const &a, const CargoSpec * const &b)
207{
209 if (res == 0) {
211 if (res == 0) {
213 if (res == 0) {
214 return CargoSpecNameSorter(a, b);
215 }
216 }
217 }
218
219 return res < 0;
220}
221
224{
225 for (auto &tpc : CargoSpec::town_production_cargoes) tpc.clear();
226 _sorted_cargo_specs.clear();
227 /* Add each cargo spec to the list, and determine the largest cargo icon size. */
228 for (const CargoSpec *cargo : CargoSpec::Iterate()) {
229 _sorted_cargo_specs.push_back(cargo);
230 }
231
232 /* Sort cargo specifications by cargo class and name. */
234
235 /* Populate */
236 for (auto it = std::begin(_sorted_cargo_specs); it != std::end(_sorted_cargo_specs); ++it) {
237 _sorted_cargo_types[(*it)->Index()] = static_cast<uint8_t>(it - std::begin(_sorted_cargo_specs));
238 }
239
240 /* Count the number of standard cargos and fill the mask. */
242 uint8_t nb_standard_cargo = 0;
243 for (const auto &cargo : _sorted_cargo_specs) {
244 assert(cargo->town_production_effect != INVALID_TPE);
245 CargoSpec::town_production_cargoes[cargo->town_production_effect].push_back(cargo);
246 if (cargo->classes.Test(CargoClass::Special)) break;
247 nb_standard_cargo++;
248 SetBit(_standard_cargo_mask, cargo->Index());
249 }
250
251 /* _sorted_standard_cargo_specs is a subset of _sorted_cargo_specs. */
252 _sorted_standard_cargo_specs = { _sorted_cargo_specs.data(), nb_standard_cargo };
253}
254
255uint64_t CargoSpec::WeightOfNUnitsInTrain(uint32_t n) const
256{
258 return this->WeightOfNUnits(n);
259}
260
267std::optional<std::string> BuildCargoAcceptanceString(const CargoArray &acceptance, StringID label)
268{
269 std::string_view list_separator = GetListSeparator();
270
271 /* Cargo acceptance is displayed in a extra multiline */
272 std::stringstream line;
273 line << GetString(label);
274
275 bool found = false;
276 for (const CargoSpec *cs : _sorted_cargo_specs) {
277 CargoType cargo_type = cs->Index();
278 if (acceptance[cargo_type] > 0) {
279 /* Add a comma between each item. */
280 if (found) line << list_separator;
281 found = true;
282
283 /* If the accepted value is less than 8, show it in 1/8:ths */
284 if (acceptance[cargo_type] < 8) {
285 line << GetString(STR_LAND_AREA_INFORMATION_CARGO_EIGHTS, acceptance[cargo_type], cs->name);
286 } else {
287 line << GetString(cs->name);
288 }
289 }
290 }
291
292 if (found) return line.str();
293
294 return std::nullopt;
295}
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:72
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:23
static const CargoType NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:75
static std::array< CargoLabel, 32 > _climate_independent_cargo_labels
Default cargo translation for version 8+ NewGRFs.
Definition cargotype.cpp:56
static std::vector< CargoLabel > _default_cargo_labels
List of default cargo labels, used when setting up cargo types for default vehicles.
Definition cargotype.cpp:42
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:36
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:62
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:49
CargoTypes _cargo_mask
Bitmask of cargo types available.
Definition cargotype.cpp:31
Types/functions related to cargoes.
@ Mail
Mail.
@ Passengers
Passengers.
@ Special
Special bit used for livery refit tricks instead of normal cargoes.
@ INVALID_TPE
Invalid town production effect.
Definition cargotype.h:45
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:17
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:958
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:60
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:425
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:415
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:113
Specification of a cargo type.
Definition cargotype.h:74
CargoClasses classes
Classes of this cargo type.
Definition cargotype.h:81
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:137
uint8_t bitnum
Cargo bit number, is INVALID_CARGO_BITNUM for a non-used spec.
Definition cargotype.h:76
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:97
bool is_freight
Cargo type is considered to be freight (affects train freight multiplier).
Definition cargotype.h:85
CargoLabel label
Unique label of the cargo type.
Definition cargotype.h:75
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
StringID name
Name of this type of cargo.
Definition cargotype.h:91
static std::array< std::vector< const CargoSpec * >, NUM_TPE > town_production_cargoes
List of cargo specs for each Town Product Effect.
Definition cargotype.h:25
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