OpenTTD Source 20241224-master-gf74b0cf984
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 <sstream>
23
24#include "safeguards.h"
25
27std::array<std::vector<const CargoSpec *>, NUM_TPE> CargoSpec::town_production_cargoes{};
28
33CargoTypes _cargo_mask;
34
39
44static std::vector<CargoLabel> _default_cargo_labels;
45
51static std::array<CargoLabel, 12> _climate_dependent_cargo_labels;
52
58static std::array<CargoLabel, 32> _climate_independent_cargo_labels;
59
65{
67
68 _cargo_mask = 0;
72
73 /* Copy from default cargo by label or index. */
74 auto insert = std::begin(CargoSpec::array);
75 for (const auto &cl : _default_climate_cargo[l]) {
76
77 struct visitor {
78 const CargoSpec &operator()(const int &index)
79 {
80 /* Copy the default cargo by index. */
81 return _default_cargo[index];
82 }
83 const CargoSpec &operator()(const CargoLabel &label)
84 {
85 /* Search for label in default cargo types and copy if found. */
86 auto found = std::ranges::find(_default_cargo, label, &CargoSpec::label);
87 if (found != std::end(_default_cargo)) return *found;
88
89 /* Index or label is invalid, this should not happen. */
90 NOT_REACHED();
91 }
92 };
93
94 *insert = std::visit(visitor{}, cl);
95
96 if (insert->IsValid()) {
97 SetBit(_cargo_mask, insert->Index());
98 _default_cargo_labels.push_back(insert->label);
99 _climate_dependent_cargo_labels[insert->Index()] = insert->label;
100 _climate_independent_cargo_labels[insert->bitnum] = insert->label;
101 }
102 ++insert;
103 }
104
105 /* Reset and disable remaining cargo types. */
106 std::fill(insert, std::end(CargoSpec::array), CargoSpec{});
107
109}
110
115std::span<const CargoLabel> GetClimateDependentCargoTranslationTable()
116{
118}
119
125{
127}
128
135{
136 CargoSpec::label_map.clear();
137 for (const CargoSpec &cs : CargoSpec::array) {
138 /* During initialization, CargoSpec can be marked valid before the label has been set. */
139 if (!cs.IsValid() || cs.label == CargoLabel{0} || cs.label == CT_INVALID) continue;
140 /* Label already exists, don't addd again. */
141 if (CargoSpec::label_map.count(cs.label) != 0) continue;
142
143 CargoSpec::label_map.emplace(cs.label, cs.Index());
144 }
145}
146
153{
154 auto cs = CargoSpec::Get(cid);
155 if (!cs->IsValid()) return false;
156
157 CargoLabel label = cs->label;
158 return std::any_of(std::begin(_default_cargo_labels), std::end(_default_cargo_labels), [&label](const CargoLabel &cl) { return cl == label; });
159}
160
166{
167 Dimension size = {0, 0};
168 for (const CargoSpec *cs : _sorted_cargo_specs) {
169 size = maxdim(size, GetSpriteSize(cs->GetCargoIcon()));
170 }
171 return size;
172}
173
179{
180 SpriteID sprite = this->sprite;
181 if (sprite == 0xFFFF) {
182 /* A value of 0xFFFF indicates we should draw a custom icon */
184 }
185
186 if (sprite == 0) sprite = SPR_CARGO_GOODS;
187
188 return sprite;
189}
190
191std::array<uint8_t, NUM_CARGO> _sorted_cargo_types;
192std::vector<const CargoSpec *> _sorted_cargo_specs;
193std::span<const CargoSpec *> _sorted_standard_cargo_specs;
194
196static bool CargoSpecNameSorter(const CargoSpec * const &a, const CargoSpec * const &b)
197{
198 std::string a_name = GetString(a->name);
199 std::string b_name = GetString(b->name);
200
201 int res = StrNaturalCompare(a_name, b_name); // Sort by name (natural sorting).
202
203 /* If the names are equal, sort by cargo bitnum. */
204 return (res != 0) ? res < 0 : (a->bitnum < b->bitnum);
206
208static bool CargoSpecClassSorter(const CargoSpec * const &a, const CargoSpec * const &b)
209{
210 int res = (b->classes & CC_PASSENGERS) - (a->classes & CC_PASSENGERS);
211 if (res == 0) {
212 res = (b->classes & CC_MAIL) - (a->classes & CC_MAIL);
213 if (res == 0) {
214 res = (a->classes & CC_SPECIAL) - (b->classes & CC_SPECIAL);
215 if (res == 0) {
216 return CargoSpecNameSorter(a, b);
217 }
218 }
219 }
220
221 return res < 0;
222}
223
226{
227 for (auto &tpc : CargoSpec::town_production_cargoes) tpc.clear();
228 _sorted_cargo_specs.clear();
229 /* Add each cargo spec to the list, and determine the largest cargo icon size. */
230 for (const CargoSpec *cargo : CargoSpec::Iterate()) {
231 _sorted_cargo_specs.push_back(cargo);
232 }
233
234 /* Sort cargo specifications by cargo class and name. */
236
237 /* Populate */
238 for (auto it = std::begin(_sorted_cargo_specs); it != std::end(_sorted_cargo_specs); ++it) {
239 _sorted_cargo_types[(*it)->Index()] = static_cast<uint8_t>(it - std::begin(_sorted_cargo_specs));
240 }
241
242 /* Count the number of standard cargos and fill the mask. */
244 uint8_t nb_standard_cargo = 0;
245 for (const auto &cargo : _sorted_cargo_specs) {
246 assert(cargo->town_production_effect != INVALID_TPE);
247 CargoSpec::town_production_cargoes[cargo->town_production_effect].push_back(cargo);
248 if (cargo->classes & CC_SPECIAL) break;
249 nb_standard_cargo++;
250 SetBit(_standard_cargo_mask, cargo->Index());
251 }
252
253 /* _sorted_standard_cargo_specs is a subset of _sorted_cargo_specs. */
254 _sorted_standard_cargo_specs = { _sorted_cargo_specs.data(), nb_standard_cargo };
255}
256
257uint64_t CargoSpec::WeightOfNUnitsInTrain(uint32_t n) const
258{
260 return this->WeightOfNUnits(n);
261}
262
269std::optional<std::string> BuildCargoAcceptanceString(const CargoArray &acceptance, StringID label)
270{
271 std::string_view list_separator = GetListSeparator();
272
273 /* Cargo acceptance is displayed in a extra multiline */
274 std::stringstream line;
275 line << GetString(label);
276
277 bool found = false;
278 for (const CargoSpec *cs : _sorted_cargo_specs) {
279 CargoID cid = cs->Index();
280 if (acceptance[cid] > 0) {
281 /* Add a comma between each item. */
282 if (found) line << list_separator;
283 found = true;
284
285 /* If the accepted value is less than 8, show it in 1/8:ths */
286 if (acceptance[cid] < 8) {
287 SetDParam(0, acceptance[cid]);
288 SetDParam(1, cs->name);
289 line << GetString(STR_LAND_AREA_INFORMATION_CARGO_EIGHTS);
290 } else {
291 line << GetString(cs->name);
292 }
293 }
294 }
295
296 if (found) return line.str();
297
298 return std::nullopt;
299}
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:52
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:99
static constexpr CargoLabel CT_INVALID
Invalid cargo type.
Definition cargo_type.h:71
uint8_t CargoID
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:22
static const CargoID NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:74
bool IsDefaultCargo(CargoID cid)
Test if a cargo is a default cargo type.
static std::array< CargoLabel, 32 > _climate_independent_cargo_labels
Default cargo translation for version 8+ NewGRFs.
Definition cargotype.cpp:58
static std::vector< CargoLabel > _default_cargo_labels
List of default cargo labels, used when setting up cargo types for default vehicles.
Definition cargotype.cpp:44
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 ID.
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.
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:38
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.
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.
void SetupCargoForClimate(LandscapeID l)
Set up the default cargo types for the given landscape type.
Definition cargotype.cpp:64
static std::array< CargoLabel, 12 > _climate_dependent_cargo_labels
Default cargo translation for upto version 7 NewGRFs.
Definition cargotype.cpp:51
CargoTypes _cargo_mask
Bitmask of cargo types available.
Definition cargotype.cpp:33
Types/functions related to cargoes.
@ CC_MAIL
Mail.
Definition cargotype.h:51
@ CC_PASSENGERS
Passengers.
Definition cargotype.h:50
@ CC_SPECIAL
Special bit used for livery refit tricks instead of normal cargoes.
Definition cargotype.h:65
@ INVALID_TPE
Invalid town production effect.
Definition cargotype.h:44
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:922
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:18
uint8_t LandscapeID
Landscape type.
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:57
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.
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:280
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:589
Functions related to low-level strings.
std::string_view GetListSeparator()
Get the list separator string for the current language.
Definition strings.cpp:229
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition strings.cpp:104
std::string GetString(StringID string)
Resolve the given StringID into a std::string with all the associated DParam lookups and formatting.
Definition strings.cpp:333
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:114
Specification of a cargo type.
Definition cargotype.h:76
CargoClasses classes
Classes of this cargo type.
Definition cargotype.h:83
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo ID.
Definition cargotype.h:139
uint8_t bitnum
Cargo bit number, is INVALID_CARGO_BITNUM for a non-used spec.
Definition cargotype.h:78
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:99
bool is_freight
Cargo type is considered to be freight (affects train freight multiplier).
Definition cargotype.h:87
CargoLabel label
Unique label of the cargo type.
Definition cargotype.h:77
static IterateWrapper Iterate(size_t from=0)
Returns an iterable ensemble of all valid CargoSpec.
Definition cargotype.h:195
static CargoSpec array[NUM_CARGO]
Array holding all CargoSpecs.
Definition cargotype.h:201
StringID name
Name of this type of cargo.
Definition cargotype.h:93
static std::map< CargoLabel, CargoID > label_map
Translation map from CargoLabel to Cargo ID.
Definition cargotype.h:202
static std::array< std::vector< const CargoSpec * >, NUM_TPE > town_production_cargoes
List of cargo specs for each Town Product Effect.
Definition cargotype.h:27
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