OpenTTD Source 20260129-master-g2bb01bd0e4
newgrf_act0_airports.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
10#include "../stdafx.h"
11#include "../debug.h"
12#include "../newgrf_airporttiles.h"
13#include "../newgrf_airport.h"
14#include "newgrf_bytereader.h"
15#include "newgrf_internal.h"
17
18#include "../safeguards.h"
19
28static ChangeInfoResult AirportChangeInfo(uint first, uint last, int prop, ByteReader &buf)
29{
31
32 if (last > NUM_AIRPORTS_PER_GRF) {
33 GrfMsg(1, "AirportChangeInfo: Too many airports, trying id ({}), max ({}). Ignoring.", last, NUM_AIRPORTS_PER_GRF);
34 return CIR_INVALID_ID;
35 }
36
37 /* Allocate industry specs if they haven't been allocated already. */
38 if (_cur_gps.grffile->airportspec.size() < last) _cur_gps.grffile->airportspec.resize(last);
39
40 for (uint id = first; id < last; ++id) {
41 auto &as = _cur_gps.grffile->airportspec[id];
42
43 if (as == nullptr && prop != 0x08 && prop != 0x09) {
44 GrfMsg(2, "AirportChangeInfo: Attempt to modify undefined airport {}, ignoring", id);
45 return CIR_INVALID_ID;
46 }
47
48 switch (prop) {
49 case 0x08: { // Modify original airport
50 uint8_t subs_id = buf.ReadByte();
51 if (subs_id == 0xFF) {
52 /* Instead of defining a new airport, an airport id
53 * of 0xFF disables the old airport with the current id. */
55 continue;
56 } else if (subs_id >= NEW_AIRPORT_OFFSET) {
57 /* The substitute id must be one of the original airports. */
58 GrfMsg(2, "AirportChangeInfo: Attempt to use new airport {} as substitute airport for {}. Ignoring.", subs_id, id);
59 continue;
60 }
61
62 /* Allocate space for this airport.
63 * Only need to do it once. If ever it is called again, it should not
64 * do anything */
65 if (as == nullptr) {
66 as = std::make_unique<AirportSpec>(*AirportSpec::GetWithoutOverride(subs_id));
67
68 as->enabled = true;
69 as->grf_prop.local_id = id;
70 as->grf_prop.subst_id = subs_id;
71 as->grf_prop.SetGRFFile(_cur_gps.grffile);
72 /* override the default airport */
73 _airport_mngr.Add(id, _cur_gps.grffile->grfid, subs_id);
74 }
75 break;
76 }
77
78 case 0x0A: { // Set airport layout
79 uint8_t num_layouts = buf.ReadByte();
80 buf.ReadDWord(); // Total size of definition, unneeded.
81 uint8_t size_x = 0;
82 uint8_t size_y = 0;
83
84 std::vector<AirportTileLayout> layouts;
85 layouts.reserve(num_layouts);
86
87 for (uint8_t j = 0; j != num_layouts; ++j) {
88 auto &layout = layouts.emplace_back();
89 layout.rotation = static_cast<Direction>(buf.ReadByte() & 6); // Rotation can only be DIR_NORTH, DIR_EAST, DIR_SOUTH or DIR_WEST.
90
91 for (;;) {
92 auto &tile = layout.tiles.emplace_back();
93 tile.ti.x = buf.ReadByte();
94 tile.ti.y = buf.ReadByte();
95 if (tile.ti.x == 0 && tile.ti.y == 0x80) {
96 /* Terminator, remove and finish up. */
97 layout.tiles.pop_back();
98 break;
99 }
100
101 tile.gfx = buf.ReadByte();
102
103 if (tile.gfx == 0xFE) {
104 /* Use a new tile from this GRF */
105 int local_tile_id = buf.ReadWord();
106
107 /* Read the ID from the _airporttile_mngr. */
108 uint16_t tempid = _airporttile_mngr.GetID(local_tile_id, _cur_gps.grffile->grfid);
109
110 if (tempid == INVALID_AIRPORTTILE) {
111 GrfMsg(2, "AirportChangeInfo: Attempt to use airport tile {} with airport id {}, not yet defined. Ignoring.", local_tile_id, id);
112 } else {
113 /* Declared as been valid, can be used */
114 tile.gfx = tempid;
115 }
116 } else if (tile.gfx == 0xFF) {
117 tile.ti.x = static_cast<int8_t>(GB(tile.ti.x, 0, 8));
118 tile.ti.y = static_cast<int8_t>(GB(tile.ti.y, 0, 8));
119 }
120
121 /* Determine largest size. */
122 if (layout.rotation == DIR_E || layout.rotation == DIR_W) {
123 size_x = std::max<uint8_t>(size_x, tile.ti.y + 1);
124 size_y = std::max<uint8_t>(size_y, tile.ti.x + 1);
125 } else {
126 size_x = std::max<uint8_t>(size_x, tile.ti.x + 1);
127 size_y = std::max<uint8_t>(size_y, tile.ti.y + 1);
128 }
129 }
130 }
131 as->layouts = std::move(layouts);
132 as->size_x = size_x;
133 as->size_y = size_y;
134 break;
135 }
136
137 case 0x0C:
138 as->min_year = TimerGameCalendar::Year{buf.ReadWord()};
139 as->max_year = TimerGameCalendar::Year{buf.ReadWord()};
140 if (as->max_year == 0xFFFF) as->max_year = CalendarTime::MAX_YEAR;
141 break;
142
143 case 0x0D:
144 as->ttd_airport_type = (TTDPAirportType)buf.ReadByte();
145 break;
146
147 case 0x0E:
148 as->catchment = Clamp(buf.ReadByte(), 1, MAX_CATCHMENT);
149 break;
150
151 case 0x0F:
152 as->noise_level = buf.ReadByte();
153 break;
154
155 case 0x10:
156 AddStringForMapping(GRFStringID{buf.ReadWord()}, &as->name);
157 break;
158
159 case 0x11: // Maintenance cost factor
160 as->maintenance_cost = buf.ReadWord();
161 break;
162
163 case 0x12: // Badge list
164 as->badges = ReadBadgeList(buf, GSF_AIRPORTS);
165 break;
166
167 default:
168 ret = CIR_UNKNOWN;
169 break;
170 }
171 }
172
173 return ret;
174}
175
176static ChangeInfoResult AirportTilesChangeInfo(uint first, uint last, int prop, ByteReader &buf)
177{
179
180 if (last > NUM_AIRPORTTILES_PER_GRF) {
181 GrfMsg(1, "AirportTileChangeInfo: Too many airport tiles loaded ({}), max ({}). Ignoring.", last, NUM_AIRPORTTILES_PER_GRF);
182 return CIR_INVALID_ID;
183 }
184
185 /* Allocate airport tile specs if they haven't been allocated already. */
186 if (_cur_gps.grffile->airtspec.size() < last) _cur_gps.grffile->airtspec.resize(last);
187
188 for (uint id = first; id < last; ++id) {
189 auto &tsp = _cur_gps.grffile->airtspec[id];
190
191 if (prop != 0x08 && tsp == nullptr) {
192 GrfMsg(2, "AirportTileChangeInfo: Attempt to modify undefined airport tile {}. Ignoring.", id);
193 return CIR_INVALID_ID;
194 }
195
196 switch (prop) {
197 case 0x08: { // Substitute airport tile type
198 uint8_t subs_id = buf.ReadByte();
199 if (subs_id >= NEW_AIRPORTTILE_OFFSET) {
200 /* The substitute id must be one of the original airport tiles. */
201 GrfMsg(2, "AirportTileChangeInfo: Attempt to use new airport tile {} as substitute airport tile for {}. Ignoring.", subs_id, id);
202 continue;
203 }
204
205 /* Allocate space for this airport tile. */
206 if (tsp == nullptr) {
207 tsp = std::make_unique<AirportTileSpec>(*AirportTileSpec::Get(subs_id));
208
209 tsp->enabled = true;
210
211 tsp->animation = {};
212
213 tsp->grf_prop.local_id = id;
214 tsp->grf_prop.subst_id = subs_id;
215 tsp->grf_prop.SetGRFFile(_cur_gps.grffile);
216 _airporttile_mngr.AddEntityID(id, _cur_gps.grffile->grfid, subs_id); // pre-reserve the tile slot
217 }
218 break;
219 }
220
221 case 0x09: { // Airport tile override
222 uint8_t override_id = buf.ReadByte();
223
224 /* The airport tile being overridden must be an original airport tile. */
225 if (override_id >= NEW_AIRPORTTILE_OFFSET) {
226 GrfMsg(2, "AirportTileChangeInfo: Attempt to override new airport tile {} with airport tile id {}. Ignoring.", override_id, id);
227 continue;
228 }
229
230 _airporttile_mngr.Add(id, _cur_gps.grffile->grfid, override_id);
231 break;
232 }
233
234 case 0x0E: // Callback mask
235 tsp->callback_mask = static_cast<AirportTileCallbackMasks>(buf.ReadByte());
236 break;
237
238 case 0x0F: // Animation information
239 tsp->animation.frames = buf.ReadByte();
240 tsp->animation.status = static_cast<AnimationStatus>(buf.ReadByte());
241 break;
242
243 case 0x10: // Animation speed
244 tsp->animation.speed = buf.ReadByte();
245 break;
246
247 case 0x11: // Animation triggers
248 tsp->animation.triggers = static_cast<AirportAnimationTriggers>(buf.ReadByte());
249 break;
250
251 case 0x12: // Badge list
252 tsp->badges = ReadBadgeList(buf, GSF_TRAMTYPES);
253 break;
254
255 default:
256 ret = CIR_UNKNOWN;
257 break;
258 }
259 }
260
261 return ret;
262}
263
265template <> ChangeInfoResult GrfChangeInfoHandler<GSF_AIRPORTS>::Activation(uint first, uint last, int prop, ByteReader &buf) { return AirportChangeInfo(first, last, prop, buf); }
266
268template <> ChangeInfoResult GrfChangeInfoHandler<GSF_AIRPORTTILES>::Activation(uint first, uint last, int prop, ByteReader &buf) { return AirportTilesChangeInfo(first, last, prop, buf); }
static const uint INVALID_AIRPORTTILE
id for an invalid airport tile
Definition airport.h:25
static const uint NEW_AIRPORTTILE_OFFSET
offset of first newgrf airport tile
Definition airport.h:24
static const uint NUM_AIRPORTTILES_PER_GRF
Number of airport tiles per NewGRF; limited to 255 to allow extending Action3 with an extended byte l...
Definition airport.h:21
@ NEW_AIRPORT_OFFSET
Number of the first newgrf airport.
Definition airport.h:39
@ NUM_AIRPORTS_PER_GRF
Maximal number of airports per NewGRF.
Definition airport.h:40
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
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).
virtual uint16_t GetID(uint16_t grf_local_id, uint32_t grfid) const
Return the ID (if ever available) of a previously inserted entity.
void Add(uint16_t local_id, uint32_t grfid, uint entity_type)
Since the entity IDs defined by the GRF file does not necessarily correlate to those used by the game...
virtual uint16_t AddEntityID(uint16_t grf_local_id, uint32_t grfid, uint16_t substitute_id)
Reserves a place in the mapping array for an entity to be installed.
static constexpr TimerGame< struct Calendar >::Year MAX_YEAR
MAX_YEAR, nicely rounded value of the number of years that can be encoded in a single 32 bits date,...
Direction
Defines the 8 directions on the map.
@ DIR_W
West.
@ DIR_E
East.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
std::vector< BadgeID > ReadBadgeList(ByteReader &buf, GrfSpecFeature feature)
Read a list of badges.
static ChangeInfoResult AirportChangeInfo(uint first, uint last, int prop, ByteReader &buf)
Define properties for airports.
TTDPAirportType
Allow incrementing of AirportClassID variables.
AnimationStatus
Statuses of animation within NewGRFs.
NewGRF buffer reader definition.
NewGRF internal processing state.
ChangeInfoResult
Possible return values for the GrfChangeInfoHandler functions.
@ CIR_INVALID_ID
Attempt to modify an invalid ID.
@ CIR_UNKNOWN
Variable is unknown.
@ CIR_UNHANDLED
Variable was parsed but unread.
@ CIR_SUCCESS
Variable was parsed and read.
void AddStringForMapping(GRFStringID source, std::function< void(StringID)> &&func)
Record a static StringID for getting translated later.
NewGRF string mapping definition.
static constexpr uint MAX_CATCHMENT
Maximum catchment for airports with "modified catchment" enabled.
static AirportSpec * GetWithoutOverride(uint8_t type)
Retrieve airport spec for the given airport.
bool enabled
Entity still available (by default true). Newgrf can disable it, though.
static const AirportTileSpec * Get(StationGfx gfx)
Retrieve airport tile spec for the given airport tile.
GRF feature handler.
GRFFile * grffile
Currently processed GRF file.
Templated helper to make a type-safe 'typedef' representing a single POD value.