OpenTTD Source 20260721-master-g25ec12c62d
newgrf_actd.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
9
10#include "../stdafx.h"
11#include "../debug.h"
12#include "../newgrf.h"
13#include "../newgrf_engine.h"
14#include "../newgrf_cargo.h"
16#include "../error.h"
17#include "../engine_func.h"
18#include "../vehicle_base.h"
19#include "../rail.h"
20#include "../road.h"
21#include "newgrf_bytereader.h"
22#include "newgrf_internal.h"
23
24#include "table/strings.h"
25
26#include "../safeguards.h"
27
32static std::array<GrfID, 256> _grm_engines{};
33
35static std::array<GrfID, NUM_CARGO * 2> _grm_cargoes{};
36
37void ResetGRM()
38{
39 _grm_engines.fill({});
40 _grm_cargoes.fill({});
41}
42
43/* Action 0x0D (GrfLoadingStage::SafetyScan) */
44static void SafeParamSet(ByteReader &buf)
45{
46 uint8_t target = buf.ReadByte();
47
48 /* Writing GRF parameters and some bits of 'misc GRF features' are safe. */
49 if (target < 0x80 || target == 0x9E) return;
50
51 /* GRM could be unsafe, but as here it can only happen after other GRFs
52 * are loaded, it should be okay. If the GRF tried to use the slots it
53 * reserved, it would be marked unsafe anyway. GRM for (e.g. bridge)
54 * sprites is considered safe. */
55 GRFUnsafe(buf);
56}
57
58static uint32_t GetPatchVariable(uint8_t param)
59{
60 switch (param) {
61 /* start year - 1920 */
62 case 0x0B: return (std::max(_settings_game.game_creation.starting_year, CalendarTime::ORIGINAL_BASE_YEAR) - CalendarTime::ORIGINAL_BASE_YEAR).base();
63
64 /* freight trains weight factor */
65 case 0x0E: return _settings_game.vehicle.freight_trains;
66
67 /* empty wagon speed increase */
68 case 0x0F: return 0;
69
70 /* plane speed factor; our patch option is reversed from TTDPatch's,
71 * the following is good for 1x, 2x and 4x (most common?) and...
72 * well not really for 3x. */
73 case 0x10:
74 switch (_settings_game.vehicle.plane_speed) {
75 default:
76 case 4: return 1;
77 case 3: return 2;
78 case 2: return 2;
79 case 1: return 4;
80 }
81
82
83 /* 2CC colourmap base sprite */
84 case 0x11: return SPR_2CCMAP_BASE;
85
86 /* map size: format = -MABXYSS
87 * M : the type of map
88 * bit 0 : set : squared map. Bit 1 is now not relevant
89 * clear : rectangle map. Bit 1 will indicate the bigger edge of the map
90 * bit 1 : set : Y is the bigger edge. Bit 0 is clear
91 * clear : X is the bigger edge.
92 * A : minimum edge(log2) of the map
93 * B : maximum edge(log2) of the map
94 * XY : edges(log2) of each side of the map.
95 * SS : combination of both X and Y, thus giving the size(log2) of the map
96 */
97 case 0x13: {
98 uint8_t map_bits = 0;
99 uint8_t log_X = Map::LogX() - 6; // subtraction is required to make the minimal size (64) zero based
100 uint8_t log_Y = Map::LogY() - 6;
101 uint8_t max_edge = std::max(log_X, log_Y);
102
103 if (log_X == log_Y) { // we have a squared map, since both edges are identical
104 SetBit(map_bits, 0);
105 } else {
106 if (max_edge == log_Y) SetBit(map_bits, 1); // edge Y been the biggest, mark it
107 }
108
109 return (map_bits << 24) | (std::min(log_X, log_Y) << 20) | (max_edge << 16) |
110 (log_X << 12) | (log_Y << 8) | (log_X + log_Y);
111 }
112
113 /* The maximum height of the map. */
114 case 0x14:
115 return _settings_game.construction.map_height_limit;
116
117 /* Extra foundations base sprite */
118 case 0x15:
119 return SPR_SLOPES_BASE;
120
121 /* Shore base sprite */
122 case 0x16:
123 return SPR_SHORE_BASE;
124
125 /* Game map seed */
126 case 0x17:
127 return _settings_game.game_creation.generation_seed;
128
129 default:
130 GrfMsg(2, "ParamSet: Unknown Patch variable 0x{:02X}.", param);
131 return 0;
132 }
133}
134
144static uint32_t PerformGRM(std::span<GrfID> grm, uint16_t count, uint8_t op, uint8_t target, std::string_view type)
145{
146 uint start = 0;
147 uint size = 0;
148
149 if (op == 6) {
150 /* Return GRFID of set that reserved ID */
151 uint32_t index = _cur_gps.grffile->GetParam(target);
152 if (index < std::size(grm)) return FlattenNewGRFLabel(grm[index]);
153
154 GrfMsg(1, "ParamSet: GRM: Parameter {} refers to invalid {} id {}", target, type, index);
155 return 0;
156 }
157
158 /* With an operation of 2 or 3, we want to reserve a specific block of IDs */
159 if (op == 2 || op == 3) start = _cur_gps.grffile->GetParam(target);
160
161 for (uint i = start; i < std::size(grm); i++) {
162 if (grm[i].Empty()) {
163 size++;
164 } else {
165 if (op == 2 || op == 3) break;
166 start = i + 1;
167 size = 0;
168 }
169
170 if (size == count) break;
171 }
172
173 if (size == count) {
174 /* Got the slot... */
175 if (op == 0 || op == 3) {
176 GrfMsg(2, "ParamSet: GRM: Reserving {} {} at {}", count, type, start);
177 for (uint i = 0; i < count; i++) grm[start + i] = _cur_gps.grffile->grfid;
178 }
179 return start;
180 }
181
182 /* Unable to allocate */
183 if (op != 4 && op != 5) {
184 /* Deactivate GRF */
185 GrfMsg(0, "ParamSet: GRM: Unable to allocate {} {}, deactivating", count, type);
186 DisableGrf(STR_NEWGRF_ERROR_GRM_FAILED);
187 return UINT_MAX;
188 }
189
190 GrfMsg(1, "ParamSet: GRM: Unable to allocate {} {}", count, type);
191 return UINT_MAX;
192}
193
198static void ParamSet(ByteReader &buf)
199{
200 /* <0D> <target> <operation> <source1> <source2> [<data>]
201 *
202 * B target parameter number where result is stored
203 * B operation operation to perform, see below
204 * B source1 first source operand
205 * B source2 second source operand
206 * D data data to use in the calculation, not necessary
207 * if both source1 and source2 refer to actual parameters
208 *
209 * Operations
210 * 00 Set parameter equal to source1
211 * 01 Addition, source1 + source2
212 * 02 Subtraction, source1 - source2
213 * 03 Unsigned multiplication, source1 * source2 (both unsigned)
214 * 04 Signed multiplication, source1 * source2 (both signed)
215 * 05 Unsigned bit shift, source1 by source2 (source2 taken to be a
216 * signed quantity; left shift if positive and right shift if
217 * negative, source1 is unsigned)
218 * 06 Signed bit shift, source1 by source2
219 * (source2 like in 05, and source1 as well)
220 */
221
222 uint8_t target = buf.ReadByte();
223 uint8_t oper = buf.ReadByte();
224 uint32_t src1 = buf.ReadByte();
225 uint32_t src2 = buf.ReadByte();
226
227 uint32_t data = 0;
228 if (buf.Remaining() >= 4) data = buf.ReadDWord();
229
230 /* You can add 80 to the operation to make it apply only if the target
231 * is not defined yet. In this respect, a parameter is taken to be
232 * defined if any of the following applies:
233 * - it has been set to any value in the newgrf(w).cfg parameter list
234 * - it OR A PARAMETER WITH HIGHER NUMBER has been set to any value by
235 * an earlier action D */
236 if (HasBit(oper, 7)) {
237 if (target < 0x80 && target < std::size(_cur_gps.grffile->param)) {
238 GrfMsg(7, "ParamSet: Param {} already defined, skipping", target);
239 return;
240 }
241
242 oper = GB(oper, 0, 7);
243 }
244
245 if (src2 == 0xFE) {
246 if (GB(data, 0, 8) == 0xFF) {
247 if (data == 0x0000FFFF) {
248 /* Patch variables */
249 src1 = GetPatchVariable(src1);
250 } else {
251 /* GRF Resource Management */
252 uint8_t op = src1;
253 GrfSpecFeature feature{static_cast<uint8_t>(GB(data, 8, 8))};
254 uint16_t count = GB(data, 16, 16);
255
256 if (_cur_gps.stage == GrfLoadingStage::Reserve) {
257 if (feature == GrfSpecFeature::GlobalVar) {
258 /* General sprites */
259 if (op == 0) {
260 /* Check if the allocated sprites will fit below the original sprite limit */
261 if (_cur_gps.spriteid + count >= 16384) {
262 GrfMsg(0, "ParamSet: GRM: Unable to allocate {} sprites; try changing NewGRF order", count);
263 DisableGrf(STR_NEWGRF_ERROR_GRM_FAILED);
264 return;
265 }
266
267 /* Reserve space at the current sprite ID */
268 GrfMsg(4, "ParamSet: GRM: Allocated {} sprites at {}", count, _cur_gps.spriteid);
269 _grm_sprites[GRFLocation{_cur_gps.grffile->grfid, _cur_gps.nfo_line}] = std::make_pair(_cur_gps.spriteid, count);
270 _cur_gps.spriteid += count;
271 }
272 }
273 /* Ignore GRM result during reservation */
274 src1 = 0;
275 } else if (_cur_gps.stage == GrfLoadingStage::Activation) {
276 switch (feature) {
281 if (!_settings_game.vehicle.dynamic_engines) {
282 src1 = PerformGRM({std::begin(_grm_engines) + GetOriginalEngineOffset(GetVehicleType(feature)), GetOriginalEngineCount(GetVehicleType(feature))}, count, op, target, "vehicles");
283 if (_cur_gps.skip_sprites == -1) return;
284 } else {
285 /* GRM does not apply for dynamic engine allocation. */
286 switch (op) {
287 case 2:
288 case 3:
289 src1 = _cur_gps.grffile->GetParam(target);
290 break;
291
292 default:
293 src1 = 0;
294 break;
295 }
296 }
297 break;
298
299 case GrfSpecFeature::GlobalVar: // General sprites
300 switch (op) {
301 case 0:
302 /* Return space reserved during reservation stage */
303 src1 = _grm_sprites[GRFLocation{_cur_gps.grffile->grfid, _cur_gps.nfo_line}].first;
304 GrfMsg(4, "ParamSet: GRM: Using pre-allocated sprites at {}", src1);
305 break;
306
307 case 1:
308 src1 = _cur_gps.spriteid;
309 break;
310
311 default:
312 GrfMsg(1, "ParamSet: GRM: Unsupported operation {} for general sprites", op);
313 return;
314 }
315 break;
316
317 case GrfSpecFeature::Cargoes: // Cargo
318 /* There are two ranges: one for cargo IDs and one for cargo bitmasks */
319 src1 = PerformGRM(_grm_cargoes, count, op, target, "cargoes");
320 if (_cur_gps.skip_sprites == -1) return;
321 break;
322
323 default: GrfMsg(1, "ParamSet: GRM: Unsupported feature 0x{:X}", feature); return;
324 }
325 } else {
326 /* Ignore GRM during initialization */
327 src1 = 0;
328 }
329 }
330 } else {
331 /* Read another GRF File's parameter */
333 const GRFFile *file = GetFileByGRFID(grfid);
334 GRFConfig *c = GetGRFConfig(grfid);
335 if (c != nullptr && c->flags.Test(GRFConfigFlag::Static) && !_cur_gps.grfconfig->flags.Test(GRFConfigFlag::Static) && _networking) {
336 /* Disable the read GRF if it is a static NewGRF. */
338 src1 = 0;
339 } else if (file == nullptr || c == nullptr || c->status == GRFStatus::Disabled) {
340 src1 = 0;
341 } else if (src1 == 0xFE) {
342 src1 = c->version;
343 } else {
344 src1 = file->GetParam(src1);
345 }
346 }
347 } else {
348 /* The source1 and source2 operands refer to the grf parameter number
349 * like in action 6 and 7. In addition, they can refer to the special
350 * variables available in action 7, or they can be FF to use the value
351 * of <data>. If referring to parameters that are undefined, a value
352 * of 0 is used instead. */
353 src1 = (src1 == 0xFF) ? data : GetParamVal(src1, nullptr);
354 src2 = (src2 == 0xFF) ? data : GetParamVal(src2, nullptr);
355 }
356
357 uint32_t res;
358 switch (oper) {
359 case 0x00:
360 res = src1;
361 break;
362
363 case 0x01:
364 res = src1 + src2;
365 break;
366
367 case 0x02:
368 res = src1 - src2;
369 break;
370
371 case 0x03:
372 res = src1 * src2;
373 break;
374
375 case 0x04:
376 res = (int32_t)src1 * (int32_t)src2;
377 break;
378
379 case 0x05:
380 if ((int32_t)src2 < 0) {
381 res = src1 >> -(int32_t)src2;
382 } else {
383 res = src1 << (src2 & 0x1F); // Same behaviour as in EvalAdjustT, mask 'value' to 5 bits, which should behave the same on all architectures.
384 }
385 break;
386
387 case 0x06:
388 if ((int32_t)src2 < 0) {
389 res = (int32_t)src1 >> -(int32_t)src2;
390 } else {
391 res = (int32_t)src1 << (src2 & 0x1F); // Same behaviour as in EvalAdjustT, mask 'value' to 5 bits, which should behave the same on all architectures.
392 }
393 break;
394
395 case 0x07: // Bitwise AND
396 res = src1 & src2;
397 break;
398
399 case 0x08: // Bitwise OR
400 res = src1 | src2;
401 break;
402
403 case 0x09: // Unsigned division
404 if (src2 == 0) {
405 res = src1;
406 } else {
407 res = src1 / src2;
408 }
409 break;
410
411 case 0x0A: // Signed division
412 if (src2 == 0) {
413 res = src1;
414 } else {
415 res = (int32_t)src1 / (int32_t)src2;
416 }
417 break;
418
419 case 0x0B: // Unsigned modulo
420 if (src2 == 0) {
421 res = src1;
422 } else {
423 res = src1 % src2;
424 }
425 break;
426
427 case 0x0C: // Signed modulo
428 if (src2 == 0) {
429 res = src1;
430 } else {
431 res = (int32_t)src1 % (int32_t)src2;
432 }
433 break;
434
435 default: GrfMsg(0, "ParamSet: Unknown operation {}, skipping", oper); return;
436 }
437
438 switch (target) {
439 case 0x8E: // Y-Offset for train sprites
440 _cur_gps.grffile->traininfo_vehicle_pitch = res;
441 break;
442
443 case 0x8F: { // Rail track type cost factors
444 extern RailTypeInfo _railtypes[RAILTYPE_END];
445 _railtypes[RAILTYPE_RAIL].cost_multiplier = GB(res, 0, 8);
446 if (_settings_game.vehicle.disable_elrails) {
447 _railtypes[RAILTYPE_ELECTRIC].cost_multiplier = GB(res, 0, 8);
448 _railtypes[RAILTYPE_MONO].cost_multiplier = GB(res, 8, 8);
449 } else {
450 _railtypes[RAILTYPE_ELECTRIC].cost_multiplier = GB(res, 8, 8);
451 _railtypes[RAILTYPE_MONO].cost_multiplier = GB(res, 16, 8);
452 }
453 _railtypes[RAILTYPE_MAGLEV].cost_multiplier = GB(res, 16, 8);
454 break;
455 }
456
457 /* not implemented */
458 case 0x93: // Tile refresh offset to left -- Intended to allow support for larger sprites, not necessary for OTTD
459 case 0x94: // Tile refresh offset to right
460 case 0x95: // Tile refresh offset upwards
461 case 0x96: // Tile refresh offset downwards
462 case 0x97: // Snow line height -- Better supported by feature 8 property 10h (snow line table) TODO: implement by filling the entire snow line table with the given value
463 case 0x99: // Global ID offset -- Not necessary since IDs are remapped automatically
464 GrfMsg(7, "ParamSet: Skipping unimplemented target 0x{:02X}", target);
465 break;
466
467 case 0x9E: { // Miscellaneous GRF features
468 GrfMiscBits bits(res);
469
470 /* Set train list engine width */
471 _cur_gps.grffile->traininfo_vehicle_width = bits.Test(GrfMiscBit::TrainWidth32Pixels) ? VEHICLEINFO_FULL_VEHICLE_WIDTH : TRAININFO_DEFAULT_VEHICLE_WIDTH;
472 /* Remove the local flags from the global flags */
474
475 /* Only copy safe bits for static grfs */
476 if (_cur_gps.grfconfig->flags.Test(GRFConfigFlag::Static)) {
478
479 _misc_grf_features.Reset(safe_bits);
480 _misc_grf_features.Set(bits & safe_bits);
481 } else {
482 _misc_grf_features = bits;
483 }
484 break;
485 }
486
487 case 0x9F: // locale-dependent settings
488 GrfMsg(7, "ParamSet: Skipping unimplemented target 0x{:02X}", target);
489 break;
490
491 default:
492 if (target < 0x80) {
493 /* Resize (and fill with zeroes) if needed. */
494 if (target >= std::size(_cur_gps.grffile->param)) _cur_gps.grffile->param.resize(target + 1);
495 _cur_gps.grffile->param[target] = res;
496 } else {
497 GrfMsg(7, "ParamSet: Skipping unknown target 0x{:02X}", target);
498 }
499 break;
500 }
501}
502
506template <> void GrfActionHandler<0x0D>::SafetyScan(ByteReader &buf) { SafeParamSet(buf); }
510template <> void GrfActionHandler<0x0D>::Init(ByteReader &buf) { ParamSet(buf); }
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Reset()
Reset all bits.
Class to read from a NewGRF file.
uint32_t ReadDWord()
Read a single DWord (32 bits).
uint8_t ReadByte()
Read a single byte (8 bits).
This struct contains all the info that is needed to draw and construct tracks.
Definition rail.h:117
uint16_t cost_multiplier
Cost multiplier for building this rail type.
Definition rail.h:207
static constexpr TimerGame< struct Calendar >::Year ORIGINAL_BASE_YEAR
Functions related to debugging.
uint8_t GetOriginalEngineOffset(VehicleType type)
Get the index offset for original engines of a VehicleType.
Definition engine.cpp:77
uint8_t GetOriginalEngineCount(VehicleType type)
Get the number of original engines for a VehicleType.
Definition engine.cpp:58
Functions related to engines.
Functions related to errors.
@ Empty
Empty field.
bool _networking
are we in networking mode?
Definition network.cpp:67
void GRFUnsafe(ByteReader &)
Set the current NewGRF as unsafe for static use.
Definition newgrf.cpp:379
void DisableStaticNewGRFInfluencingNonStaticNewGRFs(GRFConfig &c)
Disable a static NewGRF when it is influencing another (non-static) NewGRF as this could cause desync...
Definition newgrf.cpp:173
GRFFile * GetFileByGRFID(GrfID grfid)
Obtain a NewGRF file by its grfID.
Definition newgrf.cpp:106
GrfMiscBits _misc_grf_features
Miscellaneous GRF features, set by Action 0x0D, parameter 0x9E.
Definition newgrf.cpp:73
GRFError * DisableGrf(StringID message, GRFConfig *config)
Disable a GRF.
Definition newgrf.cpp:140
VehicleType GetVehicleType(GrfSpecFeature feature)
Get the VehicleType associated with a GrfSpecFeature.
Definition newgrf.cpp:1905
Base for the NewGRF implementation.
constexpr uint32_t FlattenNewGRFLabel(T label)
Flatten a NewGRF related label to a 32 bits integer.
Definition newgrf.h:259
@ Reserve
Third step of NewGRF loading; reserve features and GRMs.
Definition newgrf.h:59
@ Activation
Forth step of NewGRF loading; activate the features.
Definition newgrf.h:60
constexpr T UnflattenNewGRFLabel(uint32_t value)
Unflatten a NewGRF related label from a 32 bits integer.
Definition newgrf.h:267
EnumBitSet< GrfMiscBit, uint8_t > GrfMiscBits
Bitset of GrfMiscBit elements.
Definition newgrf.h:76
GrfSpecFeature
Definition newgrf.h:78
@ Trains
Trains feature.
Definition newgrf.h:79
@ Cargoes
Cargoes feature.
Definition newgrf.h:90
@ RoadVehicles
Road vehicles feature.
Definition newgrf.h:80
@ Ships
Ships feature.
Definition newgrf.h:81
@ GlobalVar
Global variables feature.
Definition newgrf.h:87
@ Aircraft
Aircraft feature.
Definition newgrf.h:82
@ TrainWidth32Pixels
Use 32 pixels per train vehicle in depot gui and vehicle details. Never set in the global variable;.
Definition newgrf.h:69
@ SecondRockyTileSet
Enable using the second rocky tile set.
Definition newgrf.h:72
static uint32_t PerformGRM(std::span< GrfID > grm, uint16_t count, uint8_t op, uint8_t target, std::string_view type)
Performs the GRF Resource Management, where NewGRFs can cooperatively manage sprite resources.
static void ParamSet(ByteReader &buf)
Action 0x0D - Set parameter.
static std::array< GrfID, NUM_CARGO *2 > _grm_cargoes
Contains the GRF ID of the owner of a cargo if it has been reserved.
static std::array< GrfID, 256 > _grm_engines
Contains the GRF ID of the owner of a vehicle if it has been reserved.
NewGRF buffer reader definition.
Cargo support for NewGRFs.
GRFConfig * GetGRFConfig(GrfID grfid, uint32_t mask)
Retrieve a NewGRF from the current config by its grfid.
@ Disabled
GRF file is disabled.
@ Static
GRF file is used statically (can be used in any MP game).
Functions for NewGRF engines.
NewGRF internal processing state.
Label< struct GrfIDTag > GrfID
The unique identifier of a NewGRF.
Definition newgrf_type.h:17
Rail specific functions.
@ RAILTYPE_END
Used for iterations.
Definition rail_type.h:32
@ RAILTYPE_MONO
Monorail.
Definition rail_type.h:30
@ RAILTYPE_ELECTRIC
Electric rails.
Definition rail_type.h:29
@ RAILTYPE_RAIL
Standard non-electric rails.
Definition rail_type.h:28
@ RAILTYPE_MAGLEV
Maglev.
Definition rail_type.h:31
Road specific functions.
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:61
static const SpriteID SPR_SHORE_BASE
Definition sprites.h:244
Definition of base types and functions in a cross-platform compatible way.
Information about GRF, used in the game and (part of it) in savegames.
uint32_t version
NOSAVE: Version a NewGRF can set so only the newest NewGRF is shown.
GRFStatus status
NOSAVE: GRFStatus, enum.
GRFConfigFlags flags
NOSAVE: GCF_Flags, bitset.
Dynamic data of a loaded NewGRF.
Definition newgrf.h:124
uint32_t GetParam(uint number) const
Get GRF Parameter with range checking.
Definition newgrf.h:181
A location within a NewGRF, like file:line but in the context of NewGRFs.
static void FileScan(ByteReader &buf)
Implementation of the GrfLoadingStage::FileScan stage of this action.
static void SafetyScan(ByteReader &buf)
Implementation of the GrfLoadingStage::SafetyScan stage of this action.
static void Reserve(ByteReader &buf)
Implementation of the GrfLoadingStage::Reserve stage of this action.
static void Activation(ByteReader &buf)
Implementation of the GrfLoadingStage::Activation stage of this action.
static void Init(ByteReader &buf)
Implementation of the GrfLoadingStage::Init stage of this action.
static void LabelScan(ByteReader &buf)
Implementation of the GrfLoadingStage::LabelScan stage of this action.
static uint LogX()
Logarithm of the map size along the X side.
Definition map_func.h:243
static uint LogY()
Logarithm of the map size along the y side.
Definition map_func.h:253
Definition of the game-calendar-timer.
Base class for all vehicles.