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