OpenTTD Source 20250328-master-gc3457cd4c0
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 <http://www.gnu.org/licenses/>.
6 */
7
10#include "../stdafx.h"
11#include "../debug.h"
12#include "../newgrf.h"
13#include "../newgrf_engine.h"
14#include "../newgrf_cargo.h"
15#include "../timer/timer_game_calendar.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 (GLS_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 */
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:
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:
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:
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, const char *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.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.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.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
182static void ParamSet(ByteReader &buf)
183{
184 /* <0D> <target> <operation> <source1> <source2> [<data>]
185 *
186 * B target parameter number where result is stored
187 * B operation operation to perform, see below
188 * B source1 first source operand
189 * B source2 second source operand
190 * D data data to use in the calculation, not necessary
191 * if both source1 and source2 refer to actual parameters
192 *
193 * Operations
194 * 00 Set parameter equal to source1
195 * 01 Addition, source1 + source2
196 * 02 Subtraction, source1 - source2
197 * 03 Unsigned multiplication, source1 * source2 (both unsigned)
198 * 04 Signed multiplication, source1 * source2 (both signed)
199 * 05 Unsigned bit shift, source1 by source2 (source2 taken to be a
200 * signed quantity; left shift if positive and right shift if
201 * negative, source1 is unsigned)
202 * 06 Signed bit shift, source1 by source2
203 * (source2 like in 05, and source1 as well)
204 */
205
206 uint8_t target = buf.ReadByte();
207 uint8_t oper = buf.ReadByte();
208 uint32_t src1 = buf.ReadByte();
209 uint32_t src2 = buf.ReadByte();
210
211 uint32_t data = 0;
212 if (buf.Remaining() >= 4) data = buf.ReadDWord();
213
214 /* You can add 80 to the operation to make it apply only if the target
215 * is not defined yet. In this respect, a parameter is taken to be
216 * defined if any of the following applies:
217 * - it has been set to any value in the newgrf(w).cfg parameter list
218 * - it OR A PARAMETER WITH HIGHER NUMBER has been set to any value by
219 * an earlier action D */
220 if (HasBit(oper, 7)) {
221 if (target < 0x80 && target < std::size(_cur.grffile->param)) {
222 GrfMsg(7, "ParamSet: Param {} already defined, skipping", target);
223 return;
224 }
225
226 oper = GB(oper, 0, 7);
227 }
228
229 if (src2 == 0xFE) {
230 if (GB(data, 0, 8) == 0xFF) {
231 if (data == 0x0000FFFF) {
232 /* Patch variables */
233 src1 = GetPatchVariable(src1);
234 } else {
235 /* GRF Resource Management */
236 uint8_t op = src1;
237 uint8_t feature = GB(data, 8, 8);
238 uint16_t count = GB(data, 16, 16);
239
240 if (_cur.stage == GLS_RESERVE) {
241 if (feature == 0x08) {
242 /* General sprites */
243 if (op == 0) {
244 /* Check if the allocated sprites will fit below the original sprite limit */
245 if (_cur.spriteid + count >= 16384) {
246 GrfMsg(0, "ParamSet: GRM: Unable to allocate {} sprites; try changing NewGRF order", count);
247 DisableGrf(STR_NEWGRF_ERROR_GRM_FAILED);
248 return;
249 }
250
251 /* Reserve space at the current sprite ID */
252 GrfMsg(4, "ParamSet: GRM: Allocated {} sprites at {}", count, _cur.spriteid);
253 _grm_sprites[GRFLocation(_cur.grffile->grfid, _cur.nfo_line)] = std::make_pair(_cur.spriteid, count);
254 _cur.spriteid += count;
255 }
256 }
257 /* Ignore GRM result during reservation */
258 src1 = 0;
259 } else if (_cur.stage == GLS_ACTIVATION) {
260 switch (feature) {
261 case 0x00: // Trains
262 case 0x01: // Road Vehicles
263 case 0x02: // Ships
264 case 0x03: // Aircraft
266 src1 = PerformGRM({std::begin(_grm_engines) + _engine_offsets[feature], _engine_counts[feature]}, count, op, target, "vehicles");
267 if (_cur.skip_sprites == -1) return;
268 } else {
269 /* GRM does not apply for dynamic engine allocation. */
270 switch (op) {
271 case 2:
272 case 3:
273 src1 = _cur.grffile->GetParam(target);
274 break;
275
276 default:
277 src1 = 0;
278 break;
279 }
280 }
281 break;
282
283 case 0x08: // General sprites
284 switch (op) {
285 case 0:
286 /* Return space reserved during reservation stage */
287 src1 = _grm_sprites[GRFLocation(_cur.grffile->grfid, _cur.nfo_line)].first;
288 GrfMsg(4, "ParamSet: GRM: Using pre-allocated sprites at {}", src1);
289 break;
290
291 case 1:
292 src1 = _cur.spriteid;
293 break;
294
295 default:
296 GrfMsg(1, "ParamSet: GRM: Unsupported operation {} for general sprites", op);
297 return;
298 }
299 break;
300
301 case 0x0B: // Cargo
302 /* There are two ranges: one for cargo IDs and one for cargo bitmasks */
303 src1 = PerformGRM(_grm_cargoes, count, op, target, "cargoes");
304 if (_cur.skip_sprites == -1) return;
305 break;
306
307 default: GrfMsg(1, "ParamSet: GRM: Unsupported feature 0x{:X}", feature); return;
308 }
309 } else {
310 /* Ignore GRM during initialization */
311 src1 = 0;
312 }
313 }
314 } else {
315 /* Read another GRF File's parameter */
316 const GRFFile *file = GetFileByGRFID(data);
317 GRFConfig *c = GetGRFConfig(data);
319 /* Disable the read GRF if it is a static NewGRF. */
321 src1 = 0;
322 } else if (file == nullptr || c == nullptr || c->status == GCS_DISABLED) {
323 src1 = 0;
324 } else if (src1 == 0xFE) {
325 src1 = c->version;
326 } else {
327 src1 = file->GetParam(src1);
328 }
329 }
330 } else {
331 /* The source1 and source2 operands refer to the grf parameter number
332 * like in action 6 and 7. In addition, they can refer to the special
333 * variables available in action 7, or they can be FF to use the value
334 * of <data>. If referring to parameters that are undefined, a value
335 * of 0 is used instead. */
336 src1 = (src1 == 0xFF) ? data : GetParamVal(src1, nullptr);
337 src2 = (src2 == 0xFF) ? data : GetParamVal(src2, nullptr);
338 }
339
340 uint32_t res;
341 switch (oper) {
342 case 0x00:
343 res = src1;
344 break;
345
346 case 0x01:
347 res = src1 + src2;
348 break;
349
350 case 0x02:
351 res = src1 - src2;
352 break;
353
354 case 0x03:
355 res = src1 * src2;
356 break;
357
358 case 0x04:
359 res = (int32_t)src1 * (int32_t)src2;
360 break;
361
362 case 0x05:
363 if ((int32_t)src2 < 0) {
364 res = src1 >> -(int32_t)src2;
365 } else {
366 res = src1 << (src2 & 0x1F); // Same behaviour as in EvalAdjustT, mask 'value' to 5 bits, which should behave the same on all architectures.
367 }
368 break;
369
370 case 0x06:
371 if ((int32_t)src2 < 0) {
372 res = (int32_t)src1 >> -(int32_t)src2;
373 } else {
374 res = (int32_t)src1 << (src2 & 0x1F); // Same behaviour as in EvalAdjustT, mask 'value' to 5 bits, which should behave the same on all architectures.
375 }
376 break;
377
378 case 0x07: // Bitwise AND
379 res = src1 & src2;
380 break;
381
382 case 0x08: // Bitwise OR
383 res = src1 | src2;
384 break;
385
386 case 0x09: // Unsigned division
387 if (src2 == 0) {
388 res = src1;
389 } else {
390 res = src1 / src2;
391 }
392 break;
393
394 case 0x0A: // Signed division
395 if (src2 == 0) {
396 res = src1;
397 } else {
398 res = (int32_t)src1 / (int32_t)src2;
399 }
400 break;
401
402 case 0x0B: // Unsigned modulo
403 if (src2 == 0) {
404 res = src1;
405 } else {
406 res = src1 % src2;
407 }
408 break;
409
410 case 0x0C: // Signed modulo
411 if (src2 == 0) {
412 res = src1;
413 } else {
414 res = (int32_t)src1 % (int32_t)src2;
415 }
416 break;
417
418 default: GrfMsg(0, "ParamSet: Unknown operation {}, skipping", oper); return;
419 }
420
421 switch (target) {
422 case 0x8E: // Y-Offset for train sprites
424 break;
425
426 case 0x8F: { // Rail track type cost factors
427 extern RailTypeInfo _railtypes[RAILTYPE_END];
428 _railtypes[RAILTYPE_RAIL].cost_multiplier = GB(res, 0, 8);
430 _railtypes[RAILTYPE_ELECTRIC].cost_multiplier = GB(res, 0, 8);
431 _railtypes[RAILTYPE_MONO].cost_multiplier = GB(res, 8, 8);
432 } else {
433 _railtypes[RAILTYPE_ELECTRIC].cost_multiplier = GB(res, 8, 8);
434 _railtypes[RAILTYPE_MONO].cost_multiplier = GB(res, 16, 8);
435 }
436 _railtypes[RAILTYPE_MAGLEV].cost_multiplier = GB(res, 16, 8);
437 break;
438 }
439
440 /* not implemented */
441 case 0x93: // Tile refresh offset to left -- Intended to allow support for larger sprites, not necessary for OTTD
442 case 0x94: // Tile refresh offset to right
443 case 0x95: // Tile refresh offset upwards
444 case 0x96: // Tile refresh offset downwards
445 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
446 case 0x99: // Global ID offset -- Not necessary since IDs are remapped automatically
447 GrfMsg(7, "ParamSet: Skipping unimplemented target 0x{:02X}", target);
448 break;
449
450 case 0x9E: { // Miscellaneous GRF features
451 GrfMiscBits bits(res);
452
453 /* Set train list engine width */
454 _cur.grffile->traininfo_vehicle_width = bits.Test(GrfMiscBit::TrainWidth32Pixels) ? VEHICLEINFO_FULL_VEHICLE_WIDTH : TRAININFO_DEFAULT_VEHICLE_WIDTH;
455 /* Remove the local flags from the global flags */
457
458 /* Only copy safe bits for static grfs */
460 GrfMiscBits safe_bits = GrfMiscBit::SecondRockyTileSet;
461
462 _misc_grf_features.Reset(safe_bits);
463 _misc_grf_features.Set(bits & safe_bits);
464 } else {
465 _misc_grf_features = bits;
466 }
467 break;
468 }
469
470 case 0x9F: // locale-dependent settings
471 GrfMsg(7, "ParamSet: Skipping unimplemented target 0x{:02X}", target);
472 break;
473
474 default:
475 if (target < 0x80) {
476 /* Resize (and fill with zeroes) if needed. */
477 if (target >= std::size(_cur.grffile->param)) _cur.grffile->param.resize(target + 1);
478 _cur.grffile->param[target] = res;
479 } else {
480 GrfMsg(7, "ParamSet: Skipping unknown target 0x{:02X}", target);
481 }
482 break;
483 }
484}
485
486template <> void GrfActionHandler<0x0D>::FileScan(ByteReader &) { }
487template <> void GrfActionHandler<0x0D>::SafetyScan(ByteReader &buf) { SafeParamSet(buf); }
488template <> void GrfActionHandler<0x0D>::LabelScan(ByteReader &) { }
489template <> void GrfActionHandler<0x0D>::Init(ByteReader &buf) { ParamSet(buf); }
490template <> void GrfActionHandler<0x0D>::Reserve(ByteReader &buf) { ParamSet(buf); }
491template <> void GrfActionHandler<0x0D>::Activation(ByteReader &buf) { ParamSet(buf); }
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
debug_inline 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 bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Set()
Set all bits.
constexpr Timpl & Reset(Tvalue_type value)
Reset the value-th bit.
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).
Enum-as-bit-set wrapper.
This struct contains all the info that is needed to draw and construct tracks.
Definition rail.h:118
uint16_t cost_multiplier
Cost multiplier for building this rail type.
Definition rail.h:207
static constexpr TimerGame< struct Calendar >::Year ORIGINAL_BASE_YEAR
The minimum starting year/base year of the original TTD.
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
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:365
void DisableStaticNewGRFInfluencingNonStaticNewGRFs(GRFConfig &c)
Disable a static NewGRF when it is influencing another (non-static) NewGRF as this could cause desync...
Definition newgrf.cpp:161
GRFFile * GetFileByGRFID(uint32_t grfid)
Obtain a NewGRF file by its grfID.
Definition newgrf.cpp:98
GrfMiscBits _misc_grf_features
Miscellaneous GRF features, set by Action 0x0D, parameter 0x9E.
Definition newgrf.cpp:69
GRFError * DisableGrf(StringID message, GRFConfig *config)
Disable a GRF.
Definition newgrf.cpp:131
@ TrainWidth32Pixels
Use 32 pixels per train vehicle in depot gui and vehicle details. Never set in the global variable;.
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.
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)
NewGRF internal processing state.
@ 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
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:59
static const SpriteID SPR_SHORE_BASE
shore tiles - action 05-0D
Definition sprites.h:224
uint8_t map_height_limit
the maximum allowed heightlevel
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:113
uint32_t GetParam(uint number) const
Get GRF Parameter with range checking.
Definition newgrf.h:162
uint traininfo_vehicle_width
Width (in pixels) of a 8/8 train vehicle in depot GUI and vehicle details.
Definition newgrf.h:154
int traininfo_vehicle_pitch
Vertical offset for drawing train images in depot GUI and vehicle details.
Definition newgrf.h:153
TimerGameCalendar::Year starting_year
starting date
uint32_t generation_seed
noise seed for world generation
ConstructionSettings construction
construction of things in-game
GameCreationSettings game_creation
settings used during the creation of a game (map)
VehicleSettings vehicle
options for vehicles
GRF action handler.
GRFFile * grffile
Currently processed GRF file.
uint32_t nfo_line
Currently processed pseudo sprite number in the GRF.
SpriteID spriteid
First available SpriteID for loading realsprites.
GRFConfig * grfconfig
Config of the currently processed GRF file.
GrfLoadingStage stage
Current loading stage.
int skip_sprites
Number of pseudo sprites to skip before processing the next one. (-1 to skip to end of file)
static debug_inline uint LogX()
Logarithm of the map size along the X side.
Definition map_func.h:250
static uint LogY()
Logarithm of the map size along the y side.
Definition map_func.h:260
bool dynamic_engines
enable dynamic allocation of engine data
uint8_t freight_trains
value to multiply the weight of cargo by
uint8_t plane_speed
divisor for speed of aircraft
bool disable_elrails
when true, the elrails are disabled