OpenTTD Source 20260421-master-gc2fbc6fdeb
newgrf_act0.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_engine.h"
13#include "../newgrf_badge.h"
15#include "../newgrf_cargo.h"
17#include "../error.h"
18#include "../vehicle_base.h"
19#include "newgrf_bytereader.h"
20#include "newgrf_internal.h"
21
22#include "table/strings.h"
23
24#include "../safeguards.h"
25
34{
35 switch (prop) {
36 case 0x00: // Introduction date
38 break;
39
40 case 0x02: // Decay speed
41 ei->decay_speed = buf.ReadByte();
42 break;
43
44 case 0x03: // Vehicle life
46 break;
47
48 case 0x04: // Model life
50 break;
51
52 case 0x06: // Climates available
53 ei->climates = LandscapeTypes{buf.ReadByte()};
54 break;
55
56 case PROP_VEHICLE_LOAD_AMOUNT: // 0x07 Loading speed
57 /* Amount of cargo loaded during a vehicle's "loading tick" */
58 ei->load_amount = buf.ReadByte();
59 break;
60
61 default:
63 }
64
66}
67
73{
74 uint16_t count = buf.ReadWord();
75 while (count-- > 0) {
76 buf.ReadWord();
77 }
78}
79
86std::vector<BadgeID> ReadBadgeList(ByteReader &buf, GrfSpecFeature feature)
87{
88 uint16_t count = buf.ReadWord();
89
90 std::vector<BadgeID> badges;
91 badges.reserve(count);
92
93 while (count-- > 0) {
94 uint16_t local_index = buf.ReadWord();
95 if (local_index >= std::size(_cur_gps.grffile->badge_list)) {
96 GrfMsg(1, "ReadBadgeList: Badge label {} out of range (max {}), skipping.", local_index, std::size(_cur_gps.grffile->badge_list) - 1);
97 continue;
98 }
99
100 BadgeID index = _cur_gps.grffile->badge_list[local_index];
101
102 /* Is badge already present? */
103 if (std::ranges::find(badges, index) != std::end(badges)) continue;
104
105 badges.push_back(index);
106 MarkBadgeSeen(index, feature);
107 }
108
109 return badges;
110}
111
112bool HandleChangeInfoResult(std::string_view caller, ChangeInfoResult cir, GrfSpecFeature feature, uint8_t property)
113{
114 switch (cir) {
115 default: NOT_REACHED();
116
118 /* Error has already been printed; just stop parsing */
119 return true;
120
122 return false;
123
125 GrfMsg(1, "{}: Ignoring property 0x{:02X} of feature 0x{:02X} (not implemented)", caller, property, feature);
126 return false;
127
129 GrfMsg(0, "{}: Unknown property 0x{:02X} of feature 0x{:02X}, disabling", caller, property, feature);
130 [[fallthrough]];
131
133 /* No debug message for an invalid ID, as it has already been output */
134 GRFError *error = DisableGrf(cir == ChangeInfoResult::InvalidId ? STR_NEWGRF_ERROR_INVALID_ID : STR_NEWGRF_ERROR_UNKNOWN_PROPERTY);
135 if (cir != ChangeInfoResult::InvalidId) error->param_value[1] = property;
136 return true;
137 }
138 }
139}
140
153 template <GrfSpecFeature TFeature>
154 static ChangeInfoResult Invoke(uint first, uint last, int prop, ByteReader &buf, GrfLoadingStage stage)
155 {
156 switch (stage) {
157 case GrfLoadingStage::Reserve: return GrfChangeInfoHandler<TFeature>::Reserve(first, last, prop, buf);
159 default: NOT_REACHED();
160 }
161 }
162
164 using Invoker = ChangeInfoResult(*)(uint first, uint last, int prop, ByteReader &buf, GrfLoadingStage stage);
165
175
186 static ChangeInfoResult Invoke(GrfSpecFeature feature, uint first, uint last, int prop, ByteReader &buf, GrfLoadingStage stage)
187 {
188 Invoker func = to_underlying(feature) < std::size(funcs) ? funcs[feature] : nullptr;
189 if (func == nullptr) return ChangeInfoResult::Unknown;
190 return func(first, last, prop, buf, stage);
191 }
192};
193
194/* Action 0x00 */
195static void FeatureChangeInfo(ByteReader &buf)
196{
197 /* <00> <feature> <num-props> <num-info> <id> (<property <new-info>)...
198 *
199 * B feature
200 * B num-props how many properties to change per vehicle/station
201 * B num-info how many vehicles/stations to change
202 * E id ID of first vehicle/station to change, if num-info is
203 * greater than one, this one and the following
204 * vehicles/stations will be changed
205 * B property what property to change, depends on the feature
206 * V new-info new bytes of info (variable size; depends on properties) */
207
208 GrfSpecFeature feature{buf.ReadByte()};
209 uint8_t numprops = buf.ReadByte();
210 uint numinfo = buf.ReadByte();
211 uint engine = buf.ReadExtendedByte();
212
213 if (feature >= GrfSpecFeature::End) {
214 GrfMsg(1, "FeatureChangeInfo: Unsupported feature 0x{:02X}, skipping", feature);
215 return;
216 }
217
218 GrfMsg(6, "FeatureChangeInfo: Feature 0x{:02X}, {} properties, to apply to {}+{}",
219 feature, numprops, engine, numinfo);
220
221 /* Test if feature handles change. */
223 if (cir_test == ChangeInfoResult::Unhandled) return;
224 if (cir_test == ChangeInfoResult::Unknown) {
225 GrfMsg(1, "FeatureChangeInfo: Unsupported feature 0x{:02X}, skipping", feature);
226 return;
227 }
228
229 /* Mark the feature as used by the grf */
230 _cur_gps.grffile->grf_features.Set(feature);
231
232 while (numprops-- && buf.HasData()) {
233 uint8_t prop = buf.ReadByte();
234
235 ChangeInfoResult cir = InvokeGrfChangeInfoHandler::Invoke(feature, engine, engine + numinfo, prop, buf, GrfLoadingStage::Activation);
236 if (HandleChangeInfoResult("FeatureChangeInfo", cir, feature, prop)) return;
237 }
238}
239
240/* Action 0x00 (GrfLoadingStage::SafetyScan) */
241static void SafeChangeInfo(ByteReader &buf)
242{
243 GrfSpecFeature feature{buf.ReadByte()};
244 uint8_t numprops = buf.ReadByte();
245 uint numinfo = buf.ReadByte();
246 buf.ReadExtendedByte(); // id
247
248 if (feature == GrfSpecFeature::Bridges && numprops == 1) {
249 uint8_t prop = buf.ReadByte();
250 /* Bridge property 0x0D is redefinition of sprite layout tables, which
251 * is considered safe. */
252 if (prop == 0x0D) return;
253 } else if (feature == GrfSpecFeature::GlobalVar && numprops == 1) {
254 uint8_t prop = buf.ReadByte();
255 /* Engine ID Mappings are safe, if the source is static */
256 if (prop == 0x11) {
257 bool is_safe = true;
258 for (uint i = 0; i < numinfo; i++) {
259 uint32_t s = buf.ReadDWord();
260 buf.ReadDWord(); // dest
261 const GRFConfig *grfconfig = GetGRFConfig(s);
262 if (grfconfig != nullptr && !grfconfig->flags.Test(GRFConfigFlag::Static)) {
263 is_safe = false;
264 break;
265 }
266 }
267 if (is_safe) return;
268 }
269 }
270
271 GRFUnsafe(buf);
272}
273
274/* Action 0x00 (GrfLoadingStage::Reserve) */
275static void ReserveChangeInfo(ByteReader &buf)
276{
277 GrfSpecFeature feature{buf.ReadByte()};
278
279 /* Test if feature handles reservation. */
281 if (cir_test == ChangeInfoResult::Unhandled) return;
282 if (cir_test == ChangeInfoResult::Unknown) {
283 GrfMsg(1, "ReserveChangeInfo: Unsupported feature 0x{:02X}, skipping", feature);
284 return;
285 }
286
287 uint8_t numprops = buf.ReadByte();
288 uint8_t numinfo = buf.ReadByte();
289 uint16_t index = buf.ReadExtendedByte();
290
291 while (numprops-- && buf.HasData()) {
292 uint8_t prop = buf.ReadByte();
293
294 ChangeInfoResult cir = InvokeGrfChangeInfoHandler::Invoke(feature, index, index + numinfo, prop, buf, GrfLoadingStage::Reserve);
295 if (HandleChangeInfoResult("ReserveChangeInfo", cir, feature, prop)) return;
296 }
297}
298
302template <> void GrfActionHandler<0x00>::SafetyScan(ByteReader &buf) { SafeChangeInfo(buf); }
308template <> void GrfActionHandler<0x00>::Reserve(ByteReader &buf) { ReserveChangeInfo(buf); }
310template <> void GrfActionHandler<0x00>::Activation(ByteReader &buf) { FeatureChangeInfo(buf); }
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).
uint16_t ReadExtendedByte()
Read a single Extended Byte (8 or 16 bits).
uint8_t ReadByte()
Read a single byte (8 bits).
A sort-of mixin that implements 'at(pos)' and 'operator[](pos)' only for a specific enum class.
static constexpr TimerGame< struct Calendar >::Date DAYS_TILL_ORIGINAL_BASE_YEAR
StrongType::Typedef< int32_t, struct YearTag< struct Calendar >, StrongType::Compare, StrongType::Integer > Year
Functions related to debugging.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
Definition enum_type.hpp:21
Functions related to errors.
void GRFUnsafe(ByteReader &)
Set the current NewGRF as unsafe for static use.
Definition newgrf.cpp:379
GRFError * DisableGrf(StringID message, GRFConfig *config)
Disable a GRF.
Definition newgrf.cpp:139
GrfLoadingStage
Stages of loading all NewGRFs.
Definition newgrf.h:48
@ Reserve
Third step of NewGRF loading; reserve features and GRMs.
Definition newgrf.h:53
@ Activation
Forth step of NewGRF loading; activate the features.
Definition newgrf.h:54
GrfSpecFeature
Definition newgrf.h:72
@ End
End marker.
Definition newgrf.h:95
@ GlobalVar
Global variables feature.
Definition newgrf.h:81
@ Bridges
Bridges feature.
Definition newgrf.h:79
ChangeInfoResult CommonVehicleChangeInfo(EngineInfo *ei, int prop, ByteReader &buf)
Define properties common to all vehicles.
std::vector< BadgeID > ReadBadgeList(ByteReader &buf, GrfSpecFeature feature)
Read a list of badges.
void SkipBadgeList(ByteReader &buf)
Skip a list of badges.
void MarkBadgeSeen(BadgeID index, GrfSpecFeature feature)
Mark a badge a seen (used) by a feature.
Functions related to NewGRF badges.
Types related to NewGRF badges.
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.
@ Static
GRF file is used statically (can be used in any MP game).
Functions for NewGRF engines.
NewGRF internal processing state.
ChangeInfoResult
Possible return values for the GrfChangeInfoHandler functions.
@ Success
Variable was parsed and read.
@ Unhandled
Variable was parsed but unread.
@ Unknown
Variable is unknown.
@ Disabled
GRF was disabled due to error.
@ InvalidId
Attempt to modify an invalid ID.
@ PROP_VEHICLE_LOAD_AMOUNT
Loading speed.
A number of safeguards to prevent using unsafe methods.
Definition of base types and functions in a cross-platform compatible way.
Information about a vehicle.
TimerGameCalendar::Year base_life
Basic duration of engine availability (without random parts). 0xFF means infinite life.
LandscapeTypes climates
Climates supported by the engine.
TimerGameCalendar::Date base_intro
Basic date of engine introduction (without random parts).
TimerGameCalendar::Year lifelength
Lifetime of a single vehicle.
Information about GRF, used in the game and (part of it) in savegames.
GRFConfigFlags flags
NOSAVE: GCF_Flags, bitset.
Information about why GRF had problems during initialisation.
std::array< uint32_t, 2 > param_value
Values of GRF parameters to show for message and custom_message.
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 ChangeInfoResult Reserve(uint first, uint last, int prop, ByteReader &buf)
Implementation of the GrfLoadingStage::Reserve stage of this feature.
static ChangeInfoResult Activation(uint first, uint last, int prop, ByteReader &buf)
Implementation of the GrfLoadingStage::Activation stage of this feature.
Helper class to invoke a GrfChangeInfoHandler.
static constexpr EnumClassIndexContainer< std::array< Invoker, to_underlying(GrfSpecFeature::End)>, GrfSpecFeature > funcs
List of invoke handlers for each feature.
static ChangeInfoResult Invoke(uint first, uint last, int prop, ByteReader &buf, GrfLoadingStage stage)
Invoke the change info handler for a specific feature.
ChangeInfoResult(*)(uint first, uint last, int prop, ByteReader &buf, GrfLoadingStage stage) Invoker
The function prototype for a change info handler.
static ChangeInfoResult Invoke(GrfSpecFeature feature, uint first, uint last, int prop, ByteReader &buf, GrfLoadingStage stage)
Invoke the change info handler for a specific feature.
Definition of the game-calendar-timer.
Base class for all vehicles.