OpenTTD Source: src/cargotype.cpp Source File

OpenTTD Source 15.0-beta1

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"
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 <sstream>
23
24#include "safeguards.h"
25
26 CargoSpec CargoSpec::array[NUM_CARGO];
27std::array<std::vector<const CargoSpec *>, NUM_TPE> CargoSpec::town_production_cargoes{};
28
33CargoTypes _cargo_mask;
34
38CargoTypes _standard_cargo_mask;
39
44 static std::vector<CargoLabel> _default_cargo_labels;
45
51 static std::array<CargoLabel, 12> _climate_dependent_cargo_labels;
52
58 static std::array<CargoLabel, 32> _climate_independent_cargo_labels;
59
64 void SetupCargoForClimate(LandscapeID l)
65{
66 assert(l < lengthof(_default_climate_cargo));
67
68 _cargo_mask = 0;
69 _default_cargo_labels.clear();
70 _climate_dependent_cargo_labels.fill(CT_INVALID);
71 _climate_independent_cargo_labels.fill(CT_INVALID);
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
108 BuildCargoLabelMap();
109}
110
115std::span<const CargoLabel> GetClimateDependentCargoTranslationTable()
116{
117 return _climate_dependent_cargo_labels;
118}
119
124std::span<const CargoLabel> GetClimateIndependentCargoTranslationTable()
125{
126 return _climate_independent_cargo_labels;
127}
128
134 void BuildCargoLabelMap()
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
152 bool IsDefaultCargo(CargoID cid)
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
165 Dimension GetLargestCargoIconSize()
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
178 SpriteID CargoSpec::GetCargoIcon() const
179{
180 SpriteID sprite = this->sprite;
181 if (sprite == 0xFFFF) {
182 /* A value of 0xFFFF indicates we should draw a custom icon */
183 sprite = GetCustomCargoSprite(this);
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
196 static 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);
205}
206
208 static 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
225 void InitializeSortedCargoSpecs()
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. */
235 std::sort(_sorted_cargo_specs.begin(), _sorted_cargo_specs.end(), &CargoSpecClassSorter);
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. */
243 _standard_cargo_mask = 0;
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{
259 if (this->is_freight) n *= _settings_game.vehicle.freight_trains;
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}
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:52
_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:99
CT_INVALID
static constexpr CargoLabel CT_INVALID
Invalid cargo type.
Definition cargo_type.h:71
CargoID
uint8_t CargoID
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:22
NUM_CARGO
static const CargoID NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:74
IsDefaultCargo
bool IsDefaultCargo(CargoID cid)
Test if a cargo is a default cargo type.
Definition cargotype.cpp:152
_climate_independent_cargo_labels
static std::array< CargoLabel, 32 > _climate_independent_cargo_labels
Default cargo translation for version 8+ NewGRFs.
Definition cargotype.cpp:58
_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:44
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:115
_sorted_cargo_types
std::array< uint8_t, NUM_CARGO > _sorted_cargo_types
Sort order of cargoes by cargo ID.
Definition cargotype.cpp:191
CargoSpecClassSorter
static bool CargoSpecClassSorter(const CargoSpec *const &a, const CargoSpec *const &b)
Sort cargo specifications by their cargo class.
Definition cargotype.cpp:208
GetLargestCargoIconSize
Dimension GetLargestCargoIconSize()
Get dimensions of largest cargo icon.
Definition cargotype.cpp:165
_sorted_standard_cargo_specs
std::span< const CargoSpec * > _sorted_standard_cargo_specs
Standard cargo specifications sorted alphabetically by name.
Definition cargotype.cpp:193
_standard_cargo_mask
CargoTypes _standard_cargo_mask
Bitmask of real cargo types available.
Definition cargotype.cpp:38
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:124
BuildCargoLabelMap
void BuildCargoLabelMap()
Build cargo label map.
Definition cargotype.cpp:134
BuildCargoAcceptanceString
std::optional< std::string > BuildCargoAcceptanceString(const CargoArray &acceptance, StringID label)
Build comma-separated cargo acceptance string.
Definition cargotype.cpp:269
_sorted_cargo_specs
std::vector< const CargoSpec * > _sorted_cargo_specs
Cargo specifications sorted alphabetically by name.
Definition cargotype.cpp:192
CargoSpecNameSorter
static bool CargoSpecNameSorter(const CargoSpec *const &a, const CargoSpec *const &b)
Sort cargo specifications by their name.
Definition cargotype.cpp:196
InitializeSortedCargoSpecs
void InitializeSortedCargoSpecs()
Initialize the list of sorted cargo specifications.
Definition cargotype.cpp:225
SetupCargoForClimate
void SetupCargoForClimate(LandscapeID l)
Set up the default cargo types for the given landscape type.
Definition cargotype.cpp:64
_climate_dependent_cargo_labels
static std::array< CargoLabel, 12 > _climate_dependent_cargo_labels
Default cargo translation for upto version 7 NewGRFs.
Definition cargotype.cpp:51
_cargo_mask
CargoTypes _cargo_mask
Bitmask of cargo types available.
Definition cargotype.cpp:33
cargotype.h
Types/functions related to cargoes.
CC_MAIL
@ CC_MAIL
Mail.
Definition cargotype.h:51
CC_PASSENGERS
@ CC_PASSENGERS
Passengers.
Definition cargotype.h:50
CC_SPECIAL
@ CC_SPECIAL
Special bit used for livery refit tricks instead of normal cargoes.
Definition cargotype.h:65
INVALID_TPE
@ INVALID_TPE
Invalid town production effect.
Definition cargotype.h:44
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:922
SpriteID
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:18
LandscapeID
uint8_t LandscapeID
Landscape type.
Definition landscape_type.h:13
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:57
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.
lengthof
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:280
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:589
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:229
SetDParam
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
GetString
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
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:16
CargoArray
Class for storing amounts of cargo.
Definition cargo_type.h:114
CargoSpec
Specification of a cargo type.
Definition cargotype.h:76
CargoSpec::classes
CargoClasses classes
Classes of this cargo type.
Definition cargotype.h:83
CargoSpec::Get
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo ID.
Definition cargotype.h:139
CargoSpec::bitnum
uint8_t bitnum
Cargo bit number, is INVALID_CARGO_BITNUM for a non-used spec.
Definition cargotype.h:78
CargoSpec::GetCargoIcon
SpriteID GetCargoIcon() const
Get sprite for showing cargo of this type.
Definition cargotype.cpp:178
CargoSpec::sprite
SpriteID sprite
Icon to display this cargo type, may be 0xFFF (which means to resolve an action123 chain).
Definition cargotype.h:99
CargoSpec::is_freight
bool is_freight
Cargo type is considered to be freight (affects train freight multiplier).
Definition cargotype.h:87
CargoSpec::label
CargoLabel label
Unique label of the cargo type.
Definition cargotype.h:77
CargoSpec::Iterate
static IterateWrapper Iterate(size_t from=0)
Returns an iterable ensemble of all valid CargoSpec.
Definition cargotype.h:195
CargoSpec::array
static CargoSpec array[NUM_CARGO]
Array holding all CargoSpecs.
Definition cargotype.h:201
CargoSpec::name
StringID name
Name of this type of cargo.
Definition cargotype.h:93
CargoSpec::label_map
static std::map< CargoLabel, CargoID > label_map
Translation map from CargoLabel to Cargo ID.
Definition cargotype.h:202
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:27
Dimension
Dimensions (a width and height) of a rectangle in 2D.
Definition geometry_type.hpp:30
GameSettings::vehicle
VehicleSettings vehicle
options for vehicles
Definition settings_type.h:601
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:504