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