Fix #9521: Don't load at just removed docks that were part of a multi-dock station...
[openttd-github.git] / src / cargotype.cpp
blobe35c94d2fefb4885bbee3c74835c47862adab786
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 */
8 /** @file cargotype.cpp Implementation of cargoes. */
10 #include "stdafx.h"
11 #include "cargotype.h"
12 #include "newgrf_cargo.h"
13 #include "string_func.h"
14 #include "strings_func.h"
16 #include "table/sprites.h"
17 #include "table/strings.h"
18 #include "table/cargo_const.h"
20 #include "safeguards.h"
22 CargoSpec CargoSpec::array[NUM_CARGO];
24 /**
25 * Bitmask of cargo types available. This includes phony cargoes like regearing cargoes.
26 * Initialized during a call to #SetupCargoForClimate.
28 CargoTypes _cargo_mask;
30 /**
31 * Bitmask of real cargo types available. Phony cargoes like regearing cargoes are excluded.
33 CargoTypes _standard_cargo_mask;
35 /**
36 * Set up the default cargo types for the given landscape type.
37 * @param l Landscape
39 void SetupCargoForClimate(LandscapeID l)
41 assert(l < lengthof(_default_climate_cargo));
43 /* Reset and disable all cargo types */
44 for (CargoID i = 0; i < lengthof(CargoSpec::array); i++) {
45 *CargoSpec::Get(i) = {};
46 CargoSpec::Get(i)->bitnum = INVALID_CARGO;
48 /* Set defaults for newer properties, which old GRFs do not know */
49 CargoSpec::Get(i)->multiplier = 0x100;
52 _cargo_mask = 0;
54 for (CargoID i = 0; i < lengthof(_default_climate_cargo[l]); i++) {
55 CargoLabel cl = _default_climate_cargo[l][i];
57 /* Bzzt: check if cl is just an index into the cargo table */
58 if (cl < lengthof(_default_cargo)) {
59 /* Copy the indexed cargo */
60 CargoSpec *cargo = CargoSpec::Get(i);
61 *cargo = _default_cargo[cl];
62 if (cargo->bitnum != INVALID_CARGO) SetBit(_cargo_mask, i);
63 continue;
66 /* Loop through each of the default cargo types to see if
67 * the label matches */
68 for (uint j = 0; j < lengthof(_default_cargo); j++) {
69 if (_default_cargo[j].label == cl) {
70 *CargoSpec::Get(i) = _default_cargo[j];
72 /* Populate the available cargo mask */
73 SetBit(_cargo_mask, i);
74 break;
80 /**
81 * Get the cargo ID of a default cargo, if present.
82 * @param l Landscape
83 * @param ct Default cargo type.
84 * @return ID number if the cargo exists, else #CT_INVALID
86 CargoID GetDefaultCargoID(LandscapeID l, CargoType ct)
88 assert(l < lengthof(_default_climate_cargo));
90 if (ct == CT_INVALID) return CT_INVALID;
92 assert(ct < lengthof(_default_climate_cargo[0]));
93 CargoLabel cl = _default_climate_cargo[l][ct];
94 /* Bzzt: check if cl is just an index into the cargo table */
95 if (cl < lengthof(_default_cargo)) {
96 cl = _default_cargo[cl].label;
99 return GetCargoIDByLabel(cl);
103 * Get the cargo ID by cargo label.
104 * @param cl Cargo type to get.
105 * @return ID number if the cargo exists, else #CT_INVALID
107 CargoID GetCargoIDByLabel(CargoLabel cl)
109 for (const CargoSpec *cs : CargoSpec::Iterate()) {
110 if (cs->label == cl) return cs->Index();
113 /* No matching label was found, so it is invalid */
114 return CT_INVALID;
119 * Find the CargoID of a 'bitnum' value.
120 * @param bitnum 'bitnum' to find.
121 * @return First CargoID with the given bitnum, or #CT_INVALID if not found or if the provided \a bitnum is invalid.
123 CargoID GetCargoIDByBitnum(uint8 bitnum)
125 if (bitnum == INVALID_CARGO) return CT_INVALID;
127 for (const CargoSpec *cs : CargoSpec::Iterate()) {
128 if (cs->bitnum == bitnum) return cs->Index();
131 /* No matching label was found, so it is invalid */
132 return CT_INVALID;
136 * Get sprite for showing cargo of this type.
137 * @return Sprite number to use.
139 SpriteID CargoSpec::GetCargoIcon() const
141 SpriteID sprite = this->sprite;
142 if (sprite == 0xFFFF) {
143 /* A value of 0xFFFF indicates we should draw a custom icon */
144 sprite = GetCustomCargoSprite(this);
147 if (sprite == 0) sprite = SPR_CARGO_GOODS;
149 return sprite;
152 std::vector<const CargoSpec *> _sorted_cargo_specs; ///< Cargo specifications sorted alphabetically by name.
153 span<const CargoSpec *> _sorted_standard_cargo_specs; ///< Standard cargo specifications sorted alphabetically by name.
155 /** Sort cargo specifications by their name. */
156 static bool CargoSpecNameSorter(const CargoSpec * const &a, const CargoSpec * const &b)
158 static char a_name[64];
159 static char b_name[64];
161 GetString(a_name, a->name, lastof(a_name));
162 GetString(b_name, b->name, lastof(b_name));
164 int res = strnatcmp(a_name, b_name); // Sort by name (natural sorting).
166 /* If the names are equal, sort by cargo bitnum. */
167 return (res != 0) ? res < 0 : (a->bitnum < b->bitnum);
170 /** Sort cargo specifications by their cargo class. */
171 static bool CargoSpecClassSorter(const CargoSpec * const &a, const CargoSpec * const &b)
173 int res = (b->classes & CC_PASSENGERS) - (a->classes & CC_PASSENGERS);
174 if (res == 0) {
175 res = (b->classes & CC_MAIL) - (a->classes & CC_MAIL);
176 if (res == 0) {
177 res = (a->classes & CC_SPECIAL) - (b->classes & CC_SPECIAL);
178 if (res == 0) {
179 return CargoSpecNameSorter(a, b);
184 return res < 0;
187 /** Initialize the list of sorted cargo specifications. */
188 void InitializeSortedCargoSpecs()
190 _sorted_cargo_specs.clear();
191 /* Add each cargo spec to the list. */
192 for (const CargoSpec *cargo : CargoSpec::Iterate()) {
193 _sorted_cargo_specs.push_back(cargo);
196 /* Sort cargo specifications by cargo class and name. */
197 std::sort(_sorted_cargo_specs.begin(), _sorted_cargo_specs.end(), &CargoSpecClassSorter);
199 /* Count the number of standard cargos and fill the mask. */
200 _standard_cargo_mask = 0;
201 uint8 nb_standard_cargo = 0;
202 for (const auto &cargo : _sorted_cargo_specs) {
203 if (cargo->classes & CC_SPECIAL) break;
204 nb_standard_cargo++;
205 SetBit(_standard_cargo_mask, cargo->Index());
208 /* _sorted_standard_cargo_specs is a subset of _sorted_cargo_specs. */
209 _sorted_standard_cargo_specs = { _sorted_cargo_specs.data(), nb_standard_cargo };