OpenTTD Source 20260311-master-g511d3794ce
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<uint32_t, 256> _grm_engines{};
33
35static std::array<uint32_t, NUM_CARGO * 2> _grm_cargoes{};
36
37void ResetGRM()
38{
39 _grm_engines.fill(0);
40 _grm_cargoes.fill(0);
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
135static uint32_t PerformGRM(std::span<uint32_t> grm, uint16_t count, uint8_t op, uint8_t target, std::string_view type)
136{
137 uint start = 0;
138 uint size = 0;
139
140 if (op == 6) {
141 /* Return GRFID of set that reserved ID */
142 return grm[_cur_gps.grffile->GetParam(target)];
143 }
144
145 /* With an operation of 2 or 3, we want to reserve a specific block of IDs */
146 if (op == 2 || op == 3) start = _cur_gps.grffile->GetParam(target);
147
148 for (uint i = start; i < std::size(grm); i++) {
149 if (grm[i] == 0) {
150 size++;
151 } else {
152 if (op == 2 || op == 3) break;
153 start = i + 1;
154 size = 0;
155 }
156
157 if (size == count) break;
158 }
159
160 if (size == count) {
161 /* Got the slot... */
162 if (op == 0 || op == 3) {
163 GrfMsg(2, "ParamSet: GRM: Reserving {} {} at {}", count, type, start);
164 for (uint i = 0; i < count; i++) grm[start + i] = _cur_gps.grffile->grfid;
165 }
166 return start;
167 }
168
169 /* Unable to allocate */
170 if (op != 4 && op != 5) {
171 /* Deactivate GRF */
172 GrfMsg(0, "ParamSet: GRM: Unable to allocate {} {}, deactivating", count, type);
173 DisableGrf(STR_NEWGRF_ERROR_GRM_FAILED);
174 return UINT_MAX;
175 }
176
177 GrfMsg(1, "ParamSet: GRM: Unable to allocate {} {}", count, type);
178 return UINT_MAX;
179}
180
185static void ParamSet(ByteReader &buf)
186{
187 /* <0D> <target> <operation> <source1> <source2> [<data>]
188 *
189 * B target parameter number where result is stored
190 * B operation operation to perform, see below
191 * B source1 first source operand
192 * B source2 second source operand
193 * D data data to use in the calculation, not necessary
194 * if both source1 and source2 refer to actual parameters
195 *
196 * Operations
197 * 00 Set parameter equal to source1
198 * 01 Addition, source1 + source2
199 * 02 Subtraction, source1 - source2
200 * 03 Unsigned multiplication, source1 * source2 (both unsigned)
201 * 04 Signed multiplication, source1 * source2 (both signed)
202 * 05 Unsigned bit shift, source1 by source2 (source2 taken to be a
203 * signed quantity; left shift if positive and right shift if
204 * negative, source1 is unsigned)
205 * 06 Signed bit shift, source1 by source2
206 * (source2 like in 05, and source1 as well)
207 */
208
209 uint8_t target = buf.ReadByte();
210 uint8_t oper = buf.ReadByte();
211 uint32_t src1 = buf.ReadByte();
212 uint32_t src2 = buf.ReadByte();
213
214 uint32_t data = 0;
215 if (buf.Remaining() >= 4) data = buf.ReadDWord();
216
217 /* You can add 80 to the operation to make it apply only if the target
218 * is not defined yet. In this respect, a parameter is taken to be
219 * defined if any of the following applies:
220 * - it has been set to any value in the newgrf(w).cfg parameter list
221 * - it OR A PARAMETER WITH HIGHER NUMBER has been set to any value by
222 * an earlier action D */
223 if (HasBit(oper, 7)) {
224 if (target < 0x80 && target < std::size(_cur_gps.grffile->param)) {
225 GrfMsg(7, "ParamSet: Param {} already defined, skipping", target);
226 return;
227 }
228
229 oper = GB(oper, 0, 7);
230 }
231
232 if (src2 == 0xFE) {
233 if (GB(data, 0, 8) == 0xFF) {
234 if (data == 0x0000FFFF) {
235 /* Patch variables */
236 src1 = GetPatchVariable(src1);
237 } else {
238 /* GRF Resource Management */
239 uint8_t op = src1;
240 GrfSpecFeature feature{static_cast<uint8_t>(GB(data, 8, 8))};
241 uint16_t count = GB(data, 16, 16);
242
243 if (_cur_gps.stage == GrfLoadingStage::Reserve) {
244 if (feature == GSF_GLOBALVAR) {
245 /* General sprites */
246 if (op == 0) {
247 /* Check if the allocated sprites will fit below the original sprite limit */
248 if (_cur_gps.spriteid + count >= 16384) {
249 GrfMsg(0, "ParamSet: GRM: Unable to allocate {} sprites; try changing NewGRF order", count);
250 DisableGrf(STR_NEWGRF_ERROR_GRM_FAILED);
251 return;
252 }
253
254 /* Reserve space at the current sprite ID */
255 GrfMsg(4, "ParamSet: GRM: Allocated {} sprites at {}", count, _cur_gps.spriteid);
256 _grm_sprites[GRFLocation(_cur_gps.grffile->grfid, _cur_gps.nfo_line)] = std::make_pair(_cur_gps.spriteid, count);
257 _cur_gps.spriteid += count;
258 }
259 }
260 /* Ignore GRM result during reservation */
261 src1 = 0;
262 } else if (_cur_gps.stage == GrfLoadingStage::Activation) {
263 switch (feature) {
264 case GSF_TRAINS:
265 case GSF_ROADVEHICLES:
266 case GSF_SHIPS:
267 case GSF_AIRCRAFT:
268 if (!_settings_game.vehicle.dynamic_engines) {
269 src1 = PerformGRM({std::begin(_grm_engines) + _engine_offsets[feature], _engine_counts[feature]}, count, op, target, "vehicles");
270 if (_cur_gps.skip_sprites == -1) return;
271 } else {
272 /* GRM does not apply for dynamic engine allocation. */
273 switch (op) {
274 case 2:
275 case 3:
276 src1 = _cur_gps.grffile->GetParam(target);
277 break;
278
279 default:
280 src1 = 0;
281 break;
282 }
283 }
284 break;
285
286 case GSF_GLOBALVAR: // General sprites
287 switch (op) {
288 case 0:
289 /* Return space reserved during reservation stage */
290 src1 = _grm_sprites[GRFLocation(_cur_gps.grffile->grfid, _cur_gps.nfo_line)].first;
291 GrfMsg(4, "ParamSet: GRM: Using pre-allocated sprites at {}", src1);
292 break;
293
294 case 1:
295 src1 = _cur_gps.spriteid;
296 break;
297
298 default:
299 GrfMsg(1, "ParamSet: GRM: Unsupported operation {} for general sprites", op);
300 return;
301 }
302 break;
303
304 case GSF_CARGOES: // Cargo
305 /* There are two ranges: one for cargo IDs and one for cargo bitmasks */
306 src1 = PerformGRM(_grm_cargoes, count, op, target, "cargoes");
307 if (_cur_gps.skip_sprites == -1) return;
308 break;
309
310 default: GrfMsg(1, "ParamSet: GRM: Unsupported feature 0x{:X}", feature); return;
311 }
312 } else {
313 /* Ignore GRM during initialization */
314 src1 = 0;
315 }
316 }
317 } else {
318 /* Read another GRF File's parameter */
319 const GRFFile *file = GetFileByGRFID(data);
320 GRFConfig *c = GetGRFConfig(data);
321 if (c != nullptr && c->flags.Test(GRFConfigFlag::Static) && !_cur_gps.grfconfig->flags.Test(GRFConfigFlag::Static) && _networking) {
322 /* Disable the read GRF if it is a static NewGRF. */
324 src1 = 0;
325 } else if (file == nullptr || c == nullptr || c->status == GCS_DISABLED) {
326 src1 = 0;
327 } else if (src1 == 0xFE) {
328 src1 = c->version;
329 } else {
330 src1 = file->GetParam(src1);
331 }
332 }
333 } else {
334 /* The source1 and source2 operands refer to the grf parameter number
335 * like in action 6 and 7. In addition, they can refer to the special
336 * variables available in action 7, or they can be FF to use the value
337 * of <data>. If referring to parameters that are undefined, a value
338 * of 0 is used instead. */
339 src1 = (src1 == 0xFF) ? data : GetParamVal(src1, nullptr);
340 src2 = (src2 == 0xFF) ? data : GetParamVal(src2, nullptr);
341 }
342
343 uint32_t res;
344 switch (oper) {
345 case 0x00:
346 res = src1;
347 break;
348
349 case 0x01:
350 res = src1 + src2;
351 break;
352
353 case 0x02:
354 res = src1 - src2;
355 break;
356
357 case 0x03:
358 res = src1 * src2;
359 break;
360
361 case 0x04:
362 res = (int32_t)src1 * (int32_t)src2;
363 break;
364
365 case 0x05:
366 if ((int32_t)src2 < 0) {
367 res = src1 >> -(int32_t)src2;
368 } else {
369 res = src1 << (src2 & 0x1F); // Same behaviour as in EvalAdjustT, mask 'value' to 5 bits, which should behave the same on all architectures.
370 }
371 break;
372
373 case 0x06:
374 if ((int32_t)src2 < 0) {
375 res = (int32_t)src1 >> -(int32_t)src2;
376 } else {
377 res = (int32_t)src1 << (src2 & 0x1F); // Same behaviour as in EvalAdjustT, mask 'value' to 5 bits, which should behave the same on all architectures.
378 }
379 break;
380
381 case 0x07: // Bitwise AND
382 res = src1 & src2;
383 break;
384
385 case 0x08: // Bitwise OR
386 res = src1 | src2;
387 break;
388
389 case 0x09: // Unsigned division
390 if (src2 == 0) {
391 res = src1;
392 } else {
393 res = src1 / src2;
394 }
395 break;
396
397 case 0x0A: // Signed division
398 if (src2 == 0) {
399 res = src1;
400 } else {
401 res = (int32_t)src1 / (int32_t)src2;
402 }
403 break;
404
405 case 0x0B: // Unsigned modulo
406 if (src2 == 0) {
407 res = src1;
408 } else {
409 res = src1 % src2;
410 }
411 break;
412
413 case 0x0C: // Signed modulo
414 if (src2 == 0) {
415 res = src1;
416 } else {
417 res = (int32_t)src1 % (int32_t)src2;
418 }
419 break;
420
421 default: GrfMsg(0, "ParamSet: Unknown operation {}, skipping", oper); return;
422 }
423
424 switch (target) {
425 case 0x8E: // Y-Offset for train sprites
426 _cur_gps.grffile->traininfo_vehicle_pitch = res;
427 break;
428
429 case 0x8F: { // Rail track type cost factors
430 extern RailTypeInfo _railtypes[RAILTYPE_END];
431 _railtypes[RAILTYPE_RAIL].cost_multiplier = GB(res, 0, 8);
432 if (_settings_game.vehicle.disable_elrails) {
433 _railtypes[RAILTYPE_ELECTRIC].cost_multiplier = GB(res, 0, 8);
434 _railtypes[RAILTYPE_MONO].cost_multiplier = GB(res, 8, 8);
435 } else {
436 _railtypes[RAILTYPE_ELECTRIC].cost_multiplier = GB(res, 8, 8);
437 _railtypes[RAILTYPE_MONO].cost_multiplier = GB(res, 16, 8);
438 }
439 _railtypes[RAILTYPE_MAGLEV].cost_multiplier = GB(res, 16, 8);
440 break;
441 }
442
443 /* not implemented */
444 case 0x93: // Tile refresh offset to left -- Intended to allow support for larger sprites, not necessary for OTTD
445 case 0x94: // Tile refresh offset to right
446 case 0x95: // Tile refresh offset upwards
447 case 0x96: // Tile refresh offset downwards
448 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
449 case 0x99: // Global ID offset -- Not necessary since IDs are remapped automatically
450 GrfMsg(7, "ParamSet: Skipping unimplemented target 0x{:02X}", target);
451 break;
452
453 case 0x9E: { // Miscellaneous GRF features
454 GrfMiscBits bits(res);
455
456 /* Set train list engine width */
457 _cur_gps.grffile->traininfo_vehicle_width = bits.Test(GrfMiscBit::TrainWidth32Pixels) ? VEHICLEINFO_FULL_VEHICLE_WIDTH : TRAININFO_DEFAULT_VEHICLE_WIDTH;
458 /* Remove the local flags from the global flags */
460
461 /* Only copy safe bits for static grfs */
462 if (_cur_gps.grfconfig->flags.Test(GRFConfigFlag::Static)) {
463 GrfMiscBits safe_bits = GrfMiscBit::SecondRockyTileSet;
464
465 _misc_grf_features.Reset(safe_bits);
466 _misc_grf_features.Set(bits & safe_bits);
467 } else {
468 _misc_grf_features = bits;
469 }
470 break;
471 }
472
473 case 0x9F: // locale-dependent settings
474 GrfMsg(7, "ParamSet: Skipping unimplemented target 0x{:02X}", target);
475 break;
476
477 default:
478 if (target < 0x80) {
479 /* Resize (and fill with zeroes) if needed. */
480 if (target >= std::size(_cur_gps.grffile->param)) _cur_gps.grffile->param.resize(target + 1);
481 _cur_gps.grffile->param[target] = res;
482 } else {
483 GrfMsg(7, "ParamSet: Skipping unknown target 0x{:02X}", target);
484 }
485 break;
486 }
487}
488
492template <> void GrfActionHandler<0x0D>::SafetyScan(ByteReader &buf) { SafeParamSet(buf); }
496template <> 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:115
uint16_t cost_multiplier
Cost multiplier for building this rail type.
Definition rail.h:205
static constexpr TimerGame< struct Calendar >::Year ORIGINAL_BASE_YEAR
Functions related to debugging.
const uint8_t _engine_counts[4]
Number of engines of each vehicle type in original engine data.
Definition engine.cpp:54
const uint8_t _engine_offsets[4]
Offset of the first engine of each vehicle type in original engine data.
Definition engine.cpp:62
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: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:172
GRFFile * GetFileByGRFID(uint32_t 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
Base for the NewGRF implementation.
@ Reserve
Third step of NewGRF loading; reserve features and GRMs.
Definition newgrf.h:52
@ Activation
Forth step of NewGRF loading; activate the features.
Definition newgrf.h:53
GrfSpecFeature
Definition newgrf.h:71
@ TrainWidth32Pixels
Use 32 pixels per train vehicle in depot gui and vehicle details. Never set in the global variable;.
Definition newgrf.h:63
@ SecondRockyTileSet
Enable using the second rocky tile set.
Definition newgrf.h:66
static std::array< uint32_t, NUM_CARGO *2 > _grm_cargoes
Contains the GRF ID of the owner of a cargo if it has been reserved.
static void ParamSet(ByteReader &buf)
Action 0x0D - Set parameter.
static std::array< uint32_t, 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(uint32_t grfid, uint32_t mask)
Retrieve a NewGRF from the current config by its grfid.
@ GCS_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
shore tiles - action 05-0D
Definition sprites.h:226
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:117
uint32_t GetParam(uint number) const
Get GRF Parameter with range checking.
Definition newgrf.h:174
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.