OpenTTD Source: src/cargotype.cpp Source File

OpenTTD Source 15.0-RC2

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
10#include "stdafx.h"
11#include "cargotype.h"
12#include "core/geometry_func.hpp"
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
24 CargoSpec CargoSpec::array[NUM_CARGO];
25std::array<std::vector<const CargoSpec *>, NUM_TPE> CargoSpec::town_production_cargoes{};
26
31CargoTypes _cargo_mask;
32
36CargoTypes _standard_cargo_mask;
37
42 static std::vector<CargoLabel> _default_cargo_labels;
43
49 static std::array<CargoLabel, 12> _climate_dependent_cargo_labels;
50
56 static std::array<CargoLabel, 32> _climate_independent_cargo_labels;
57
62 void SetupCargoForClimate(LandscapeType l)
63{
64 assert(to_underlying(l) < std::size(_default_climate_cargo));
65
66 _cargo_mask = 0;
67 _default_cargo_labels.clear();
68 _climate_dependent_cargo_labels.fill(CT_INVALID);
69 _climate_independent_cargo_labels.fill(CT_INVALID);
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
106 BuildCargoLabelMap();
107}
108
113std::span<const CargoLabel> GetClimateDependentCargoTranslationTable()
114{
115 return _climate_dependent_cargo_labels;
116}
117
122std::span<const CargoLabel> GetClimateIndependentCargoTranslationTable()
123{
124 return _climate_independent_cargo_labels;
125}
126
132 void BuildCargoLabelMap()
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
150 bool 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
163 Dimension GetLargestCargoIconSize()
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
176 SpriteID CargoSpec::GetCargoIcon() const
177{
178 SpriteID sprite = this->sprite;
179 if (sprite == 0xFFFF) {
180 /* A value of 0xFFFF indicates we should draw a custom icon */
181 sprite = GetCustomCargoSprite(this);
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
194 static 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
206 static bool CargoSpecClassSorter(const CargoSpec * const &a, const CargoSpec * const &b)
207{
208 int res = b->classes.Test(CargoClass::Passengers) - a->classes.Test(CargoClass::Passengers);
209 if (res == 0) {
210 res = b->classes.Test(CargoClass::Mail) - a->classes.Test(CargoClass::Mail);
211 if (res == 0) {
212 res = a->classes.Test(CargoClass::Special) - b->classes.Test(CargoClass::Special);
213 if (res == 0) {
214 return CargoSpecNameSorter(a, b);
215 }
216 }
217 }
218
219 return res < 0;
220}
221
223 void InitializeSortedCargoSpecs()
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. */
233 std::sort(_sorted_cargo_specs.begin(), _sorted_cargo_specs.end(), &CargoSpecClassSorter);
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. */
241 _standard_cargo_mask = 0;
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{
257 if (this->is_freight) n *= _settings_game.vehicle.freight_trains;
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}
SetBit
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
Definition bitmath_func.hpp:121
cargo_const.h
Table of all default cargo types.
_default_cargo
static const CargoSpec _default_cargo[]
Cargo types available by default.
Definition cargo_const.h:57
_default_climate_cargo
static const std::variant< CargoLabel, int > _default_climate_cargo[NUM_LANDSCAPE][NUM_ORIGINAL_CARGO]
Table of cargo types available in each climate, by default.
Definition cargo_const.h:104
CT_INVALID
static constexpr CargoLabel CT_INVALID
Invalid cargo type.
Definition cargo_type.h:70
CargoType
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:21
NUM_CARGO
static const CargoType NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:73
_climate_independent_cargo_labels
static std::array< CargoLabel, 32 > _climate_independent_cargo_labels
Default cargo translation for version 8+ NewGRFs.
Definition cargotype.cpp:56
_default_cargo_labels
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
GetClimateDependentCargoTranslationTable
std::span< const CargoLabel > GetClimateDependentCargoTranslationTable()
Get default climate-dependent cargo translation table for a NewGRF, used if the NewGRF does not provi...
Definition cargotype.cpp:113
_sorted_cargo_types
std::array< uint8_t, NUM_CARGO > _sorted_cargo_types
Sort order of cargoes by cargo type.
Definition cargotype.cpp:189
CargoSpecClassSorter
static bool CargoSpecClassSorter(const CargoSpec *const &a, const CargoSpec *const &b)
Sort cargo specifications by their cargo class.
Definition cargotype.cpp:206
GetLargestCargoIconSize
Dimension GetLargestCargoIconSize()
Get dimensions of largest cargo icon.
Definition cargotype.cpp:163
IsDefaultCargo
bool IsDefaultCargo(CargoType cargo_type)
Test if a cargo is a default cargo type.
Definition cargotype.cpp:150
_sorted_standard_cargo_specs
std::span< const CargoSpec * > _sorted_standard_cargo_specs
Standard cargo specifications sorted alphabetically by name.
Definition cargotype.cpp:191
_standard_cargo_mask
CargoTypes _standard_cargo_mask
Bitmask of real cargo types available.
Definition cargotype.cpp:36
GetClimateIndependentCargoTranslationTable
std::span< const CargoLabel > GetClimateIndependentCargoTranslationTable()
Get default climate-independent cargo translation table for a NewGRF, used if the NewGRF does not pro...
Definition cargotype.cpp:122
BuildCargoLabelMap
void BuildCargoLabelMap()
Build cargo label map.
Definition cargotype.cpp:132
BuildCargoAcceptanceString
std::optional< std::string > BuildCargoAcceptanceString(const CargoArray &acceptance, StringID label)
Build comma-separated cargo acceptance string.
Definition cargotype.cpp:267
SetupCargoForClimate
void SetupCargoForClimate(LandscapeType l)
Set up the default cargo types for the given landscape type.
Definition cargotype.cpp:62
_sorted_cargo_specs
std::vector< const CargoSpec * > _sorted_cargo_specs
Cargo specifications sorted alphabetically by name.
Definition cargotype.cpp:190
CargoSpecNameSorter
static bool CargoSpecNameSorter(const CargoSpec *const &a, const CargoSpec *const &b)
Sort cargo specifications by their name.
Definition cargotype.cpp:194
InitializeSortedCargoSpecs
void InitializeSortedCargoSpecs()
Initialize the list of sorted cargo specifications.
Definition cargotype.cpp:223
_climate_dependent_cargo_labels
static std::array< CargoLabel, 12 > _climate_dependent_cargo_labels
Default cargo translation for up to version 7 NewGRFs.
Definition cargotype.cpp:49
_cargo_mask
CargoTypes _cargo_mask
Bitmask of cargo types available.
Definition cargotype.cpp:31
cargotype.h
Types/functions related to cargoes.
CargoClass::Mail
@ Mail
Mail.
CargoClass::Passengers
@ Passengers
Passengers.
CargoClass::Special
@ Special
Special bit used for livery refit tricks instead of normal cargoes.
INVALID_TPE
@ INVALID_TPE
Invalid town production effect.
Definition cargotype.h:45
BaseBitSet::Test
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
Definition base_bitset_type.hpp:141
to_underlying
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
maxdim
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Definition geometry_func.cpp:22
geometry_func.hpp
Geometry functions.
GetSpriteSize
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition gfx.cpp:965
SpriteID
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
LandscapeType
LandscapeType
Landscape types.
Definition landscape_type.h:16
GetCustomCargoSprite
SpriteID GetCustomCargoSprite(const CargoSpec *cs)
Get the custom sprite for the given cargo type.
Definition newgrf_cargo.cpp:55
newgrf_cargo.h
Cargo support for NewGRFs.
safeguards.h
A number of safeguards to prevent using unsafe methods.
_settings_game
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
settings_type.h
Types related to global configuration settings.
sprites.h
This file contains all sprite-related enums and defines.
stdafx.h
Definition of base types and functions in a cross-platform compatible way.
StrNaturalCompare
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:427
string_func.h
Functions related to low-level strings.
GetListSeparator
std::string_view GetListSeparator()
Get the list separator string for the current language.
Definition strings.cpp:299
GetString
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
strings_func.h
Functions related to OTTD's strings.
StringID
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition strings_type.h:19
CargoArray
Class for storing amounts of cargo.
Definition cargo_type.h:111
CargoSpec
Specification of a cargo type.
Definition cargotype.h:74
CargoSpec::classes
CargoClasses classes
Classes of this cargo type.
Definition cargotype.h:81
CargoSpec::Get
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:137
CargoSpec::bitnum
uint8_t bitnum
Cargo bit number, is INVALID_CARGO_BITNUM for a non-used spec.
Definition cargotype.h:76
CargoSpec::label_map
static std::map< CargoLabel, CargoType > label_map
Translation map from CargoLabel to Cargo type.
Definition cargotype.h:199
CargoSpec::GetCargoIcon
SpriteID GetCargoIcon() const
Get sprite for showing cargo of this type.
Definition cargotype.cpp:176
CargoSpec::sprite
SpriteID sprite
Icon to display this cargo type, may be 0xFFF (which means to resolve an action123 chain).
Definition cargotype.h:97
CargoSpec::is_freight
bool is_freight
Cargo type is considered to be freight (affects train freight multiplier).
Definition cargotype.h:85
CargoSpec::label
CargoLabel label
Unique label of the cargo type.
Definition cargotype.h:75
CargoSpec::Iterate
static IterateWrapper Iterate(size_t from=0)
Returns an iterable ensemble of all valid CargoSpec.
Definition cargotype.h:192
CargoSpec::array
static CargoSpec array[NUM_CARGO]
Array holding all CargoSpecs.
Definition cargotype.h:198
CargoSpec::name
StringID name
Name of this type of cargo.
Definition cargotype.h:91
CargoSpec::town_production_cargoes
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
Dimension
Dimensions (a width and height) of a rectangle in 2D.
Definition geometry_type.hpp:56
GameSettings::vehicle
VehicleSettings vehicle
options for vehicles
Definition settings_type.h:641
StrongType::Typedef< uint32_t, struct CargoLabelTag, StrongType::Compare >
VehicleSettings::freight_trains
uint8_t freight_trains
value to multiply the weight of cargo by
Definition settings_type.h:531