OpenTTD Source 20260711-master-g3fb3006dff
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 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] == 0) {
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 */
332 const GRFFile *file = GetFileByGRFID(data);
333 GRFConfig *c = GetGRFConfig(data);
334 if (c != nullptr && c->flags.Test(GRFConfigFlag::Static) && !_cur_gps.grfconfig->flags.Test(GRFConfigFlag::Static) && _networking) {
335 /* Disable the read GRF if it is a static NewGRF. */
337 src1 = 0;
338 } else if (file == nullptr || c == nullptr || c->status == GRFStatus::Disabled) {
339 src1 = 0;
340 } else if (src1 == 0xFE) {
341 src1 = c->version;
342 } else {
343 src1 = file->GetParam(src1);
344 }
345 }
346 } else {
347 /* The source1 and source2 operands refer to the grf parameter number
348 * like in action 6 and 7. In addition, they can refer to the special
349 * variables available in action 7, or they can be FF to use the value
350 * of <data>. If referring to parameters that are undefined, a value
351 * of 0 is used instead. */
352 src1 = (src1 == 0xFF) ? data : GetParamVal(src1, nullptr);
353 src2 = (src2 == 0xFF) ? data : GetParamVal(src2, nullptr);
354 }
355
356 uint32_t res;
357 switch (oper) {
358 case 0x00:
359 res = src1;
360 break;
361
362 case 0x01:
363 res = src1 + src2;
364 break;
365
366 case 0x02:
367 res = src1 - src2;
368 break;
369
370 case 0x03:
371 res = src1 * src2;
372 break;
373
374 case 0x04:
375 res = (int32_t)src1 * (int32_t)src2;
376 break;
377
378 case 0x05:
379 if ((int32_t)src2 < 0) {
380 res = src1 >> -(int32_t)src2;
381 } else {
382 res = src1 << (src2 & 0x1F); // Same behaviour as in EvalAdjustT, mask 'value' to 5 bits, which should behave the same on all architectures.
383 }
384 break;
385
386 case 0x06:
387 if ((int32_t)src2 < 0) {
388 res = (int32_t)src1 >> -(int32_t)src2;
389 } else {
390 res = (int32_t)src1 << (src2 & 0x1F); // Same behaviour as in EvalAdjustT, mask 'value' to 5 bits, which should behave the same on all architectures.
391 }
392 break;
393
394 case 0x07: // Bitwise AND
395 res = src1 & src2;
396 break;
397
398 case 0x08: // Bitwise OR
399 res = src1 | src2;
400 break;
401
402 case 0x09: // Unsigned division
403 if (src2 == 0) {
404 res = src1;
405 } else {
406 res = src1 / src2;
407 }
408 break;
409
410 case 0x0A: // Signed division
411 if (src2 == 0) {
412 res = src1;
413 } else {
414 res = (int32_t)src1 / (int32_t)src2;
415 }
416 break;
417
418 case 0x0B: // Unsigned modulo
419 if (src2 == 0) {
420 res = src1;
421 } else {
422 res = src1 % src2;
423 }
424 break;
425
426 case 0x0C: // Signed modulo
427 if (src2 == 0) {
428 res = src1;
429 } else {
430 res = (int32_t)src1 % (int32_t)src2;
431 }
432 break;
433
434 default: GrfMsg(0, "ParamSet: Unknown operation {}, skipping", oper); return;
435 }
436
437 switch (target) {
438 case 0x8E: // Y-Offset for train sprites
439 _cur_gps.grffile->traininfo_vehicle_pitch = res;
440 break;
441
442 case 0x8F: { // Rail track type cost factors
443 extern RailTypeInfo _railtypes[RAILTYPE_END];
444 _railtypes[RAILTYPE_RAIL].cost_multiplier = GB(res, 0, 8);
445 if (_settings_game.vehicle.disable_elrails) {
446 _railtypes[RAILTYPE_ELECTRIC].cost_multiplier = GB(res, 0, 8);
447 _railtypes[RAILTYPE_MONO].cost_multiplier = GB(res, 8, 8);
448 } else {
449 _railtypes[RAILTYPE_ELECTRIC].cost_multiplier = GB(res, 8, 8);
450 _railtypes[RAILTYPE_MONO].cost_multiplier = GB(res, 16, 8);
451 }
452 _railtypes[RAILTYPE_MAGLEV].cost_multiplier = GB(res, 16, 8);
453 break;
454 }
455
456 /* not implemented */
457 case 0x93: // Tile refresh offset to left -- Intended to allow support for larger sprites, not necessary for OTTD
458 case 0x94: // Tile refresh offset to right
459 case 0x95: // Tile refresh offset upwards
460 case 0x96: // Tile refresh offset downwards
461 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
462 case 0x99: // Global ID offset -- Not necessary since IDs are remapped automatically
463 GrfMsg(7, "ParamSet: Skipping unimplemented target 0x{:02X}", target);
464 break;
465
466 case 0x9E: { // Miscellaneous GRF features
467 GrfMiscBits bits(res);
468
469 /* Set train list engine width */
470 _cur_gps.grffile->traininfo_vehicle_width = bits.Test(GrfMiscBit::TrainWidth32Pixels) ? VEHICLEINFO_FULL_VEHICLE_WIDTH : TRAININFO_DEFAULT_VEHICLE_WIDTH;
471 /* Remove the local flags from the global flags */
473
474 /* Only copy safe bits for static grfs */
475 if (_cur_gps.grfconfig->flags.Test(GRFConfigFlag::Static)) {
477
478 _misc_grf_features.Reset(safe_bits);
479 _misc_grf_features.Set(bits & safe_bits);
480 } else {
481 _misc_grf_features = bits;
482 }
483 break;
484 }
485
486 case 0x9F: // locale-dependent settings
487 GrfMsg(7, "ParamSet: Skipping unimplemented target 0x{:02X}", target);
488 break;
489
490 default:
491 if (target < 0x80) {
492 /* Resize (and fill with zeroes) if needed. */
493 if (target >= std::size(_cur_gps.grffile->param)) _cur_gps.grffile->param.resize(target + 1);
494 _cur_gps.grffile->param[target] = res;
495 } else {
496 GrfMsg(7, "ParamSet: Skipping unknown target 0x{:02X}", target);
497 }
498 break;
499 }
500}
501
505template <> void GrfActionHandler<0x0D>::SafetyScan(ByteReader &buf) { SafeParamSet(buf); }
509template <> 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.
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:378
void DisableStaticNewGRFInfluencingNonStaticNewGRFs(GRFConfig &c)
Disable a static NewGRF when it is influencing another (non-static) NewGRF as this could cause desync...
Definition newgrf.cpp:172
GRFFile * GetFileByGRFID(GrfID grfid)
Obtain a NewGRF file by its grfID.
Definition newgrf.cpp:105
GrfMiscBits _misc_grf_features
Miscellaneous GRF features, set by Action 0x0D, parameter 0x9E.
Definition newgrf.cpp:72
GRFError * DisableGrf(StringID message, GRFConfig *config)
Disable a GRF.
Definition newgrf.cpp:139
VehicleType GetVehicleType(GrfSpecFeature feature)
Get the VehicleType associated with a GrfSpecFeature.
Definition newgrf.cpp:1908
Base for the NewGRF implementation.
@ 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
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.
Rail specific functions.
@ RAILTYPE_END
Used for iterations.
Definition rail_type.h:31
@ RAILTYPE_MONO
Monorail.
Definition rail_type.h:29
@ RAILTYPE_ELECTRIC
Electric rails.
Definition rail_type.h:28
@ RAILTYPE_RAIL
Standard non-electric rails.
Definition rail_type.h:27
@ RAILTYPE_MAGLEV
Maglev.
Definition rail_type.h:30
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:243
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.