OpenTTD Source 20260731-master-g77ba2b244a
newgrf_act7_9.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 "../genworld.h"
13#include "../network/network.h"
14#include "../newgrf_engine.h"
15#include "../newgrf_cargo.h"
16#include "../rail.h"
17#include "../road.h"
18#include "../settings_type.h"
19#include "../string_func.h"
20#include "newgrf_bytereader.h"
21#include "newgrf_internal.h"
22
23#include "../safeguards.h"
24
26static std::array<uint32_t, 8> _ttdpatch_flags;
27
34{
35 switch (_settings_game.construction.train_signal_side) {
39 default: NOT_REACHED();
40 }
41}
42
45{
46 _ttdpatch_flags[0] = ((_settings_game.station.never_expire_airports ? 1U : 0U) << 0x0C) // keepsmallairport
47 | (1U << 0x0D) // newairports
48 | (1U << 0x0E) // largestations
49 | ((_settings_game.construction.max_bridge_length > 16 ? 1U : 0U) << 0x0F) // longbridges
50 | (0U << 0x10) // loadtime
51 | (1U << 0x12) // presignals
52 | (1U << 0x13) // extpresignals
53 | ((_settings_game.vehicle.never_expire_vehicles ? 1U : 0U) << 0x16) // enginespersist
54 | (1U << 0x1B) // multihead
55 | (1U << 0x1D) // lowmemory
56 | (1U << 0x1E); // generalfixes
57
58 _ttdpatch_flags[1] = ((_settings_game.economy.station_noise_level ? 1U : 0U) << 0x07) // moreairports - based on units of noise
59 | (1U << 0x08) // mammothtrains
60 | (1U << 0x09) // trainrefit
61 | (0U << 0x0B) // subsidiaries
62 | ((_settings_game.order.gradual_loading ? 1U : 0U) << 0x0C) // gradualloading
63 | (1U << 0x12) // unifiedmaglevmode - set bit 0 mode. Not relevant to OTTD
64 | (1U << 0x13) // unifiedmaglevmode - set bit 1 mode
65 | (1U << 0x14) // bridgespeedlimits
66 | (1U << 0x16) // eternalgame
67 | (1U << 0x17) // newtrains
68 | (1U << 0x18) // newrvs
69 | (1U << 0x19) // newships
70 | (1U << 0x1A) // newplanes
71 | ((IsSignalSideOnTrafficSide() ? 1U : 0U) << 0x1B) // signalsontrafficside
72 | ((_settings_game.vehicle.disable_elrails ? 0U : 1U) << 0x1C); // electrifiedrailway
73
74 _ttdpatch_flags[2] = (1U << 0x01) // loadallgraphics - obsolete
75 | (1U << 0x03) // semaphores
76 | (1U << 0x0A) // newobjects
77 | (0U << 0x0B) // enhancedgui
78 | (0U << 0x0C) // newagerating
79 | ((_settings_game.construction.build_on_slopes ? 1U : 0U) << 0x0D) // buildonslopes
80 | (1U << 0x0E) // fullloadany
81 | (1U << 0x0F) // planespeed
82 | (0U << 0x10) // moreindustriesperclimate - obsolete
83 | (0U << 0x11) // moretoylandfeatures
84 | (1U << 0x12) // newstations
85 | (1U << 0x13) // tracktypecostdiff
86 | (1U << 0x14) // manualconvert
87 | ((_settings_game.construction.build_on_slopes ? 1U : 0U) << 0x15) // buildoncoasts
88 | (1U << 0x16) // canals
89 | (1U << 0x17) // newstartyear
90 | ((_settings_game.vehicle.freight_trains > 1 ? 1U : 0U) << 0x18) // freighttrains
91 | (1U << 0x19) // newhouses
92 | (1U << 0x1A) // newbridges
93 | (1U << 0x1B) // newtownnames
94 | (1U << 0x1C) // moreanimation
95 | ((_settings_game.vehicle.wagon_speed_limits ? 1U : 0U) << 0x1D) // wagonspeedlimits
96 | (1U << 0x1E) // newshistory
97 | (0U << 0x1F); // custombridgeheads
98
99 _ttdpatch_flags[3] = (0U << 0x00) // newcargodistribution
100 | (1U << 0x01) // windowsnap
101 | ((_settings_game.economy.allow_town_roads || _generating_world ? 0U : 1U) << 0x02) // townbuildnoroad
102 | (1U << 0x03) // pathbasedsignalling
103 | (0U << 0x04) // aichoosechance
104 | (1U << 0x05) // resolutionwidth
105 | (1U << 0x06) // resolutionheight
106 | (1U << 0x07) // newindustries
107 | ((_settings_game.order.improved_load ? 1U : 0U) << 0x08) // fifoloading
108 | (0U << 0x09) // townroadbranchprob
109 | (0U << 0x0A) // tempsnowline
110 | (1U << 0x0B) // newcargo
111 | (1U << 0x0C) // enhancemultiplayer
112 | (1U << 0x0D) // onewayroads
113 | (1U << 0x0E) // irregularstations
114 | (1U << 0x0F) // statistics
115 | (1U << 0x10) // newsounds
116 | (1U << 0x11) // autoreplace
117 | (1U << 0x12) // autoslope
118 | (0U << 0x13) // followvehicle
119 | (1U << 0x14) // trams
120 | (0U << 0x15) // enhancetunnels
121 | (1U << 0x16) // shortrvs
122 | (1U << 0x17) // articulatedrvs
123 | ((_settings_game.vehicle.dynamic_engines ? 1U : 0U) << 0x18) // dynamic engines
124 | (1U << 0x1E) // variablerunningcosts
125 | (1U << 0x1F); // any switch is on
126
127 _ttdpatch_flags[4] = (1U << 0x00) // larger persistent storage
128 | ((_settings_game.economy.inflation ? 1U : 0U) << 0x01) // inflation is on
129 | (1U << 0x02); // extended string range
130}
131
132uint32_t GetParamVal(uint8_t param, uint32_t *cond_val)
133{
134 /* First handle variable common with VarAction2 */
135 uint32_t value;
136 if (GetGlobalVariable(param - 0x80, &value, _cur_gps.grffile)) return value;
137
138
139 /* Non-common variable */
140 switch (param) {
141 case 0x84: { // GRF loading stage
142 uint32_t res = 0;
143
144 if (_cur_gps.stage > GrfLoadingStage::Init) SetBit(res, 0);
145 if (_cur_gps.stage == GrfLoadingStage::Reserve) SetBit(res, 8);
146 if (_cur_gps.stage == GrfLoadingStage::Activation) SetBit(res, 9);
147 return res;
148 }
149
150 case 0x85: // TTDPatch flags, only for bit tests
151 if (cond_val == nullptr) {
152 /* Supported in Action 0x07 and 0x09, not 0x0D */
153 return 0;
154 } else {
155 uint32_t index = *cond_val / 0x20;
156 uint32_t param_val = index < std::size(_ttdpatch_flags) ? _ttdpatch_flags[index] : 0;
157 *cond_val %= 0x20;
158 return param_val;
159 }
160
161 case 0x88: // GRF ID check
162 return 0;
163
164 /* case 0x99: Global ID offset not implemented */
165
166 default:
167 /* GRF Parameter */
168 if (param < 0x80) return _cur_gps.grffile->GetParam(param);
169
170 /* In-game variable. */
171 GrfMsg(1, "Unsupported in-game variable 0x{:02X}", param);
172 return UINT_MAX;
173 }
174}
175
176/* Action 0x07
177 * Action 0x09 */
178static void SkipIf(ByteReader &buf)
179{
180 /* <07/09> <param-num> <param-size> <condition-type> <value> <num-sprites>
181 *
182 * B param-num
183 * B param-size
184 * B condition-type
185 * V value
186 * B num-sprites */
187 uint32_t cond_val = 0;
188 uint32_t mask = 0;
189 bool result;
190
191 uint8_t param = buf.ReadByte();
192 uint8_t paramsize = buf.ReadByte();
193 uint8_t condtype = buf.ReadByte();
194
195 if (condtype < 2) {
196 /* Always 1 for bit tests, the given value should be ignored. */
197 paramsize = 1;
198 }
199
200 switch (paramsize) {
201 case 8: cond_val = buf.ReadDWord(); mask = buf.ReadDWord(); break;
202 case 4: cond_val = buf.ReadDWord(); mask = 0xFFFFFFFF; break;
203 case 2: cond_val = buf.ReadWord(); mask = 0x0000FFFF; break;
204 case 1: cond_val = buf.ReadByte(); mask = 0x000000FF; break;
205 default: break;
206 }
207
208 if (param < 0x80 && std::size(_cur_gps.grffile->param) <= param) {
209 GrfMsg(7, "SkipIf: Param {} undefined, skipping test", param);
210 return;
211 }
212
213 GrfMsg(7, "SkipIf: Test condtype {}, param 0x{:02X}, condval 0x{:08X}", condtype, param, cond_val);
214
215 /* condtypes that do not use 'param' are always valid.
216 * condtypes that use 'param' are either not valid for param 0x88, or they are only valid for param 0x88.
217 */
218 if (condtype >= 0x0B) {
219 /* Tests that ignore 'param' */
220 switch (condtype) {
221 case 0x0B: result = !IsValidCargoType(GetCargoTypeByLabel(UnflattenNewGRFLabel<CargoLabel>(cond_val)));
222 break;
223 case 0x0C: result = IsValidCargoType(GetCargoTypeByLabel(UnflattenNewGRFLabel<CargoLabel>(cond_val)));
224 break;
226 break;
228 break;
229 case 0x0F: {
231 result = rt == INVALID_ROADTYPE || !RoadTypeIsRoad(rt);
232 break;
233 }
234 case 0x10: {
236 result = rt != INVALID_ROADTYPE && RoadTypeIsRoad(rt);
237 break;
238 }
239 case 0x11: {
241 result = rt == INVALID_ROADTYPE || !RoadTypeIsTram(rt);
242 break;
243 }
244 case 0x12: {
246 result = rt != INVALID_ROADTYPE && RoadTypeIsTram(rt);
247 break;
248 }
249 default: GrfMsg(1, "SkipIf: Unsupported condition type {:02X}. Ignoring", condtype); return;
250 }
251 } else if (param == 0x88) {
252 /* GRF ID checks */
253
254 GrfID grfid = UnflattenNewGRFLabel<GrfID>(cond_val);
255 GRFConfig *c = GetGRFConfig(grfid, std::byteswap(mask));
256
257 if (c != nullptr && c->flags.Test(GRFConfigFlag::Static) && !_cur_gps.grfconfig->flags.Test(GRFConfigFlag::Static) && _networking) {
259 c = nullptr;
260 }
261
262 if (condtype != 10 && c == nullptr) {
263 GrfMsg(7, "SkipIf: GRFID {} unknown, skipping test", FormatArrayAsHex(grfid));
264 return;
265 }
266
267 switch (condtype) {
268 /* Tests 0x06 to 0x0A are only for param 0x88, GRFID checks */
269 case 0x06: // Is GRFID active?
270 result = c->status == GRFStatus::Activated;
271 break;
272
273 case 0x07: // Is GRFID non-active?
274 result = c->status != GRFStatus::Activated;
275 break;
276
277 case 0x08: // GRFID is not but will be active?
278 result = c->status == GRFStatus::Initialised;
279 break;
280
281 case 0x09: // GRFID is or will be active?
283 break;
284
285 case 0x0A: // GRFID is not nor will be active
286 /* This is the only condtype that doesn't get ignored if the GRFID is not found */
287 result = c == nullptr || c->status == GRFStatus::Disabled || c->status == GRFStatus::NotFound;
288 break;
289
290 default: GrfMsg(1, "SkipIf: Unsupported GRF condition type {:02X}. Ignoring", condtype); return;
291 }
292 } else {
293 /* Tests that use 'param' and are not GRF ID checks. */
294 uint32_t param_val = GetParamVal(param, &cond_val); // cond_val is modified for param == 0x85
295 switch (condtype) {
296 case 0x00: result = !!(param_val & (1 << cond_val));
297 break;
298 case 0x01: result = !(param_val & (1 << cond_val));
299 break;
300 case 0x02: result = (param_val & mask) == cond_val;
301 break;
302 case 0x03: result = (param_val & mask) != cond_val;
303 break;
304 case 0x04: result = (param_val & mask) < cond_val;
305 break;
306 case 0x05: result = (param_val & mask) > cond_val;
307 break;
308 default: GrfMsg(1, "SkipIf: Unsupported condition type {:02X}. Ignoring", condtype); return;
309 }
310 }
311
312 if (!result) {
313 GrfMsg(2, "SkipIf: Not skipping sprites, test was false");
314 return;
315 }
316
317 uint8_t numsprites = buf.ReadByte();
318
319 /* numsprites can be a GOTO label if it has been defined in the GRF
320 * file. The jump will always be the first matching label that follows
321 * the current nfo_line. If no matching label is found, the first matching
322 * label in the file is used. */
323 const GRFLabel *choice = nullptr;
324 for (const auto &label : _cur_gps.grffile->labels) {
325 if (label.label != numsprites) continue;
326
327 /* Remember a goto before the current line */
328 if (choice == nullptr) choice = &label;
329 /* If we find a label here, this is definitely good */
330 if (label.nfo_line > _cur_gps.nfo_line) {
331 choice = &label;
332 break;
333 }
334 }
335
336 if (choice != nullptr) {
337 GrfMsg(2, "SkipIf: Jumping to label 0x{:X} at line {}, test was true", choice->label, choice->nfo_line);
338 _cur_gps.file->SeekTo(choice->pos, SEEK_SET);
339 _cur_gps.nfo_line = choice->nfo_line;
340 return;
341 }
342
343 GrfMsg(2, "SkipIf: Skipping {} sprites, test was true", numsprites);
344 _cur_gps.skip_sprites = numsprites;
345 if (_cur_gps.skip_sprites == 0) {
346 /* Zero means there are no sprites to skip, so
347 * we use -1 to indicate that all further
348 * sprites should be skipped. */
349 _cur_gps.skip_sprites = -1;
350
351 /* If an action 8 hasn't been encountered yet, disable the grf. */
352 if (_cur_gps.grfconfig->status != (_cur_gps.stage < GrfLoadingStage::Reserve ? GRFStatus::Initialised : GRFStatus::Activated)) {
353 DisableGrf();
354 }
355 }
356}
357
367template <> void GrfActionHandler<0x07>::Reserve(ByteReader &buf) { SkipIf(buf); }
369template <> void GrfActionHandler<0x07>::Activation(ByteReader &buf) { SkipIf(buf); }
370
378template <> void GrfActionHandler<0x09>::Init(ByteReader &buf) { SkipIf(buf); }
380template <> void GrfActionHandler<0x09>::Reserve(ByteReader &buf) { SkipIf(buf); }
382template <> void GrfActionHandler<0x09>::Activation(ByteReader &buf) { SkipIf(buf); }
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr enable_if_t< is_integral_v< T >, T > byteswap(T x) noexcept
Custom implementation of std::byteswap; remove once we build with C++23.
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:110
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
Class to read from a NewGRF file.
uint32_t ReadDWord()
Read a single DWord (32 bits).
uint16_t ReadWord()
Read a single Word (16 bits).
uint8_t ReadByte()
Read a single byte (8 bits).
Functions related to debugging.
bool _generating_world
Whether we are generating the map or not.
Definition genworld.cpp:74
Functions related to world/map generation.
bool _networking
are we in networking mode?
Definition network.cpp:67
Basic functions/variables used all over the place.
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
GRFError * DisableGrf(StringID message, GRFConfig *config)
Disable a GRF.
Definition newgrf.cpp:140
bool GetGlobalVariable(uint8_t param, uint32_t *value, const GRFFile *grffile)
Reads a variable common to VarAction2 and Action7/9/D.
@ Reserve
Third step of NewGRF loading; reserve features and GRMs.
Definition newgrf.h:59
@ Init
Second step of NewGRF loading; load all actions into memory.
Definition newgrf.h:58
@ 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
void InitializePatchFlags()
Initialize the TTDPatch flags.
static bool IsSignalSideOnTrafficSide()
Checks whether the train signals are on the same side as the road vehicles are driving.
static std::array< uint32_t, 8 > _ttdpatch_flags
32 * 8 = 256 flags.
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.
@ NotFound
GRF file was not found in the local cache.
@ Initialised
GRF file has been initialised.
@ Disabled
GRF file is disabled.
@ Activated
GRF file has been activated.
@ 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
RailType GetRailTypeByLabel(RailTypeLabel label, bool allow_alternate_labels)
Get the rail type for a given label.
Definition rail.cpp:197
Rail specific functions.
@ INVALID_RAILTYPE
Flag for invalid railtype.
Definition rail_type.h:33
RoadType GetRoadTypeByLabel(RoadTypeLabel label, bool allow_alternate_labels)
Get the road type for a given label.
Definition road.cpp:265
Road specific functions.
RoadType
The different roadtypes we support.
Definition road_type.h:24
@ INVALID_ROADTYPE
flag for invalid roadtype
Definition road_type.h:29
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
Types related to global configuration settings.
@ RoadVehicleDrivingSide
Signals at the driving side of road vehicles.
@ Right
Signals at the right side.
@ Left
Signals at the left side.
@ Right
Drive on the right side.
@ Left
Drive on the left side.
Definition of base types and functions in a cross-platform compatible way.
std::string FormatArrayAsHex(std::span< const uint8_t > data)
Format a byte array into a continuous hex string.
Definition string.cpp:77
Functions related to low-level strings.
Information about GRF, used in the game and (part of it) in savegames.
GRFStatus status
NOSAVE: GRFStatus, enum.
GRFConfigFlags flags
NOSAVE: GCF_Flags, bitset.
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.