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 
8 /** @file newgrf_debug_data.h Data 'tables' for NewGRF debugging. */
9 
10 #include "../newgrf_house.h"
11 #include "../newgrf_engine.h"
12 #include "../newgrf_roadtype.h"
13 
14 /* Helper for filling property tables */
15 #define NIP(prop, base, variable, type, name) { name, [] (const void *b) -> const void * { return std::addressof(static_cast<const base *>(b)->variable); }, cpp_sizeof(base, variable), prop, type }
16 #define NIP_END() { nullptr, 0, 0, 0, 0 }
17 
18 /* Helper for filling callback tables */
19 #define NIC(cb_id, base, variable, bit) { #cb_id, [] (const void *b) -> const void * { return std::addressof(static_cast<const base *>(b)->variable); }, cpp_sizeof(base, variable), bit, cb_id }
20 #define NIC_END() { nullptr, 0, 0, 0, 0 }
21 
22 /* Helper for filling variable tables */
23 #define NIV(var, name) { name, var }
24 #define NIV_END() { nullptr, 0 }
25 
26 
27 /*** NewGRF Vehicles ***/
28 
29 #define NICV(cb_id, bit) NIC(cb_id, Engine, info.callback_mask, bit)
30 static const NICallback _nic_vehicles[] = {
31 	NICV(CBID_VEHICLE_VISUAL_EFFECT,         CBM_VEHICLE_VISUAL_EFFECT),
32 	NICV(CBID_VEHICLE_LENGTH,                CBM_VEHICLE_LENGTH),
33 	NICV(CBID_VEHICLE_LOAD_AMOUNT,           CBM_VEHICLE_LOAD_AMOUNT),
34 	NICV(CBID_VEHICLE_REFIT_CAPACITY,        CBM_VEHICLE_REFIT_CAPACITY),
35 	NICV(CBID_VEHICLE_ARTIC_ENGINE,          CBM_VEHICLE_ARTIC_ENGINE),
36 	NICV(CBID_VEHICLE_CARGO_SUFFIX,          CBM_VEHICLE_CARGO_SUFFIX),
37 	NICV(CBID_TRAIN_ALLOW_WAGON_ATTACH,      CBM_NO_BIT),
38 	NICV(CBID_VEHICLE_ADDITIONAL_TEXT,       CBM_NO_BIT),
39 	NICV(CBID_VEHICLE_COLOUR_MAPPING,        CBM_VEHICLE_COLOUR_REMAP),
40 	NICV(CBID_VEHICLE_START_STOP_CHECK,      CBM_NO_BIT),
41 	NICV(CBID_VEHICLE_32DAY_CALLBACK,        CBM_NO_BIT),
42 	NICV(CBID_VEHICLE_SOUND_EFFECT,          CBM_VEHICLE_SOUND_EFFECT),
43 	NICV(CBID_VEHICLE_AUTOREPLACE_SELECTION, CBM_NO_BIT),
44 	NICV(CBID_VEHICLE_MODIFY_PROPERTY,       CBM_NO_BIT),
45 	NIC_END()
46 };
47 
48 
49 static const NIVariable _niv_vehicles[] = {
50 	NIV(0x40, "position in consist and length"),
51 	NIV(0x41, "position and length of chain of same vehicles"),
52 	NIV(0x42, "transported cargo types"),
53 	NIV(0x43, "player info"),
54 	NIV(0x44, "aircraft info"),
55 	NIV(0x45, "curvature info"),
56 	NIV(0x46, "motion counter"),
57 	NIV(0x47, "vehicle cargo info"),
58 	NIV(0x48, "vehicle type info"),
59 	NIV(0x49, "year of construction"),
60 	NIV(0x4A, "current rail/road type info"),
61 	NIV(0x4B, "long date of last service"),
62 	NIV(0x4C, "current max speed"),
63 	NIV(0x4D, "position in articulated vehicle"),
64 	NIV(0x60, "count vehicle id occurrences"),
65 	// 0x61 not useful, since it requires register 0x10F
66 	NIV(0x62, "curvature/position difference to other vehicle"),
67 	NIV(0x63, "tile compatibility wrt. track-type"),
68 	NIV_END()
69 };
70 
71 class NIHVehicle : public NIHelper {
IsInspectable(uint index)72 	bool IsInspectable(uint index) const override        { return Vehicle::Get(index)->GetGRF() != nullptr; }
GetParent(uint index)73 	uint GetParent(uint index) const override            { const Vehicle *first = Vehicle::Get(index)->First(); return GetInspectWindowNumber(GetGrfSpecFeature(first->type), first->index); }
GetInstance(uint index)74 	const void *GetInstance(uint index)const override    { return Vehicle::Get(index); }
GetSpec(uint index)75 	const void *GetSpec(uint index) const override       { return Vehicle::Get(index)->GetEngine(); }
SetStringParameters(uint index)76 	void SetStringParameters(uint index) const override  { this->SetSimpleStringParameters(STR_VEHICLE_NAME, index); }
GetGRFID(uint index)77 	uint32 GetGRFID(uint index) const override                   { return Vehicle::Get(index)->GetGRFID(); }
78 
Resolve(uint index,uint var,uint param,bool * avail)79 	uint Resolve(uint index, uint var, uint param, bool *avail) const override
80 	{
81 		Vehicle *v = Vehicle::Get(index);
82 		VehicleResolverObject ro(v->engine_type, v, VehicleResolverObject::WO_CACHED);
83 		return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
84 	}
85 };
86 
87 static const NIFeature _nif_vehicle = {
88 	nullptr,
89 	_nic_vehicles,
90 	_niv_vehicles,
91 	new NIHVehicle(),
92 };
93 
94 
95 /*** NewGRF station (tiles) ***/
96 
97 #define NICS(cb_id, bit) NIC(cb_id, StationSpec, callback_mask, bit)
98 static const NICallback _nic_stations[] = {
99 	NICS(CBID_STATION_AVAILABILITY,     CBM_STATION_AVAIL),
100 	NICS(CBID_STATION_SPRITE_LAYOUT,    CBM_STATION_SPRITE_LAYOUT),
101 	NICS(CBID_STATION_TILE_LAYOUT,      CBM_NO_BIT),
102 	NICS(CBID_STATION_ANIM_START_STOP,  CBM_NO_BIT),
103 	NICS(CBID_STATION_ANIM_NEXT_FRAME,  CBM_STATION_ANIMATION_NEXT_FRAME),
104 	NICS(CBID_STATION_ANIMATION_SPEED,  CBM_STATION_ANIMATION_SPEED),
105 	NICS(CBID_STATION_LAND_SLOPE_CHECK, CBM_STATION_SLOPE_CHECK),
106 	NIC_END()
107 };
108 
109 static const NIVariable _niv_stations[] = {
110 	NIV(0x40, "platform info and relative position"),
111 	NIV(0x41, "platform info and relative position for individually built sections"),
112 	NIV(0x42, "terrain and track type"),
113 	NIV(0x43, "player info"),
114 	NIV(0x44, "path signalling info"),
115 	NIV(0x45, "rail continuation info"),
116 	NIV(0x46, "platform info and relative position from middle"),
117 	NIV(0x47, "platform info and relative position from middle for individually built sections"),
118 	NIV(0x48, "bitmask of accepted cargoes"),
119 	NIV(0x49, "platform info and relative position of same-direction section"),
120 	NIV(0x4A, "current animation frame"),
121 	NIV(0x60, "amount of cargo waiting"),
122 	NIV(0x61, "time since last cargo pickup"),
123 	NIV(0x62, "rating of cargo"),
124 	NIV(0x63, "time spent on route"),
125 	NIV(0x64, "information about last vehicle picking cargo up"),
126 	NIV(0x65, "amount of cargo acceptance"),
127 	NIV(0x66, "animation frame of nearby tile"),
128 	NIV(0x67, "land info of nearby tiles"),
129 	NIV(0x68, "station info of nearby tiles"),
130 	NIV(0x69, "information about cargo accepted in the past"),
131 	NIV(0x6A, "GRFID of nearby station tiles"),
132 	NIV_END()
133 };
134 
135 class NIHStation : public NIHelper {
IsInspectable(uint index)136 	bool IsInspectable(uint index) const override        { return GetStationSpec(index) != nullptr; }
GetParent(uint index)137 	uint GetParent(uint index) const override            { return GetInspectWindowNumber(GSF_FAKE_TOWNS, Station::GetByTile(index)->town->index); }
GetInstance(uint index)138 	const void *GetInstance(uint index)const override    { return nullptr; }
GetSpec(uint index)139 	const void *GetSpec(uint index) const override       { return GetStationSpec(index); }
SetStringParameters(uint index)140 	void SetStringParameters(uint index) const override  { this->SetObjectAtStringParameters(STR_STATION_NAME, GetStationIndex(index), index); }
GetGRFID(uint index)141 	uint32 GetGRFID(uint index) const override           { return (this->IsInspectable(index)) ? GetStationSpec(index)->grf_prop.grffile->grfid : 0; }
142 
Resolve(uint index,uint var,uint param,bool * avail)143 	uint Resolve(uint index, uint var, uint param, bool *avail) const override
144 	{
145 		StationResolverObject ro(GetStationSpec(index), Station::GetByTile(index), index);
146 		return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
147 	}
148 };
149 
150 static const NIFeature _nif_station = {
151 	nullptr,
152 	_nic_stations,
153 	_niv_stations,
154 	new NIHStation(),
155 };
156 
157 
158 /*** NewGRF house tiles ***/
159 
160 #define NICH(cb_id, bit) NIC(cb_id, HouseSpec, callback_mask, bit)
161 static const NICallback _nic_house[] = {
162 	NICH(CBID_HOUSE_ALLOW_CONSTRUCTION,        CBM_HOUSE_ALLOW_CONSTRUCTION),
163 	NICH(CBID_HOUSE_ANIMATION_NEXT_FRAME,      CBM_HOUSE_ANIMATION_NEXT_FRAME),
164 	NICH(CBID_HOUSE_ANIMATION_START_STOP,      CBM_HOUSE_ANIMATION_START_STOP),
165 	NICH(CBID_HOUSE_CONSTRUCTION_STATE_CHANGE, CBM_HOUSE_CONSTRUCTION_STATE_CHANGE),
166 	NICH(CBID_HOUSE_COLOUR,                    CBM_HOUSE_COLOUR),
167 	NICH(CBID_HOUSE_CARGO_ACCEPTANCE,          CBM_HOUSE_CARGO_ACCEPTANCE),
168 	NICH(CBID_HOUSE_ANIMATION_SPEED,           CBM_HOUSE_ANIMATION_SPEED),
169 	NICH(CBID_HOUSE_DESTRUCTION,               CBM_HOUSE_DESTRUCTION),
170 	NICH(CBID_HOUSE_ACCEPT_CARGO,              CBM_HOUSE_ACCEPT_CARGO),
171 	NICH(CBID_HOUSE_PRODUCE_CARGO,             CBM_HOUSE_PRODUCE_CARGO),
172 	NICH(CBID_HOUSE_DENY_DESTRUCTION,          CBM_HOUSE_DENY_DESTRUCTION),
173 	NICH(CBID_HOUSE_WATCHED_CARGO_ACCEPTED,    CBM_NO_BIT),
174 	NICH(CBID_HOUSE_CUSTOM_NAME,               CBM_NO_BIT),
175 	NICH(CBID_HOUSE_DRAW_FOUNDATIONS,          CBM_HOUSE_DRAW_FOUNDATIONS),
176 	NICH(CBID_HOUSE_AUTOSLOPE,                 CBM_HOUSE_AUTOSLOPE),
177 	NIC_END()
178 };
179 
180 static const NIVariable _niv_house[] = {
181 	NIV(0x40, "construction state of tile and pseudo-random value"),
182 	NIV(0x41, "age of building in years"),
183 	NIV(0x42, "town zone"),
184 	NIV(0x43, "terrain type"),
185 	NIV(0x44, "building counts"),
186 	NIV(0x45, "town expansion bits"),
187 	NIV(0x46, "current animation frame"),
188 	NIV(0x47, "xy coordinate of the building"),
189 	NIV(0x60, "other building counts (old house type)"),
190 	NIV(0x61, "other building counts (new house type)"),
191 	NIV(0x62, "land info of nearby tiles"),
192 	NIV(0x63, "current animation frame of nearby house tile"),
193 	NIV(0x64, "cargo acceptance history of nearby stations"),
194 	NIV(0x65, "distance of nearest house matching a given criterion"),
195 	NIV(0x66, "class and ID of nearby house tile"),
196 	NIV(0x67, "GRFID of nearby house tile"),
197 	NIV_END()
198 };
199 
200 class NIHHouse : public NIHelper {
IsInspectable(uint index)201 	bool IsInspectable(uint index) const override        { return HouseSpec::Get(GetHouseType(index))->grf_prop.grffile != nullptr; }
GetParent(uint index)202 	uint GetParent(uint index) const override            { return GetInspectWindowNumber(GSF_FAKE_TOWNS, GetTownIndex(index)); }
GetInstance(uint index)203 	const void *GetInstance(uint index)const override    { return nullptr; }
GetSpec(uint index)204 	const void *GetSpec(uint index) const override       { return HouseSpec::Get(GetHouseType(index)); }
SetStringParameters(uint index)205 	void SetStringParameters(uint index) const override  { this->SetObjectAtStringParameters(STR_TOWN_NAME, GetTownIndex(index), index); }
GetGRFID(uint index)206 	uint32 GetGRFID(uint index) const override           { return (this->IsInspectable(index)) ? HouseSpec::Get(GetHouseType(index))->grf_prop.grffile->grfid : 0; }
207 
Resolve(uint index,uint var,uint param,bool * avail)208 	uint Resolve(uint index, uint var, uint param, bool *avail) const override
209 	{
210 		HouseResolverObject ro(GetHouseType(index), index, Town::GetByTile(index));
211 		return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
212 	}
213 };
214 
215 static const NIFeature _nif_house = {
216 	nullptr,
217 	_nic_house,
218 	_niv_house,
219 	new NIHHouse(),
220 };
221 
222 
223 /*** NewGRF industry tiles ***/
224 
225 #define NICIT(cb_id, bit) NIC(cb_id, IndustryTileSpec, callback_mask, bit)
226 static const NICallback _nic_industrytiles[] = {
227 	NICIT(CBID_INDTILE_ANIM_START_STOP,  CBM_NO_BIT),
228 	NICIT(CBID_INDTILE_ANIM_NEXT_FRAME,  CBM_INDT_ANIM_NEXT_FRAME),
229 	NICIT(CBID_INDTILE_ANIMATION_SPEED,  CBM_INDT_ANIM_SPEED),
230 	NICIT(CBID_INDTILE_CARGO_ACCEPTANCE, CBM_INDT_CARGO_ACCEPTANCE),
231 	NICIT(CBID_INDTILE_ACCEPT_CARGO,     CBM_INDT_ACCEPT_CARGO),
232 	NICIT(CBID_INDTILE_SHAPE_CHECK,      CBM_INDT_SHAPE_CHECK),
233 	NICIT(CBID_INDTILE_DRAW_FOUNDATIONS, CBM_INDT_DRAW_FOUNDATIONS),
234 	NICIT(CBID_INDTILE_AUTOSLOPE,        CBM_INDT_AUTOSLOPE),
235 	NIC_END()
236 };
237 
238 static const NIVariable _niv_industrytiles[] = {
239 	NIV(0x40, "construction state of tile"),
240 	NIV(0x41, "ground type"),
241 	NIV(0x42, "current town zone in nearest town"),
242 	NIV(0x43, "relative position"),
243 	NIV(0x44, "animation frame"),
244 	NIV(0x60, "land info of nearby tiles"),
245 	NIV(0x61, "animation stage of nearby tiles"),
246 	NIV(0x62, "get industry or airport tile ID at offset"),
247 	NIV_END()
248 };
249 
250 class NIHIndustryTile : public NIHelper {
IsInspectable(uint index)251 	bool IsInspectable(uint index) const override        { return GetIndustryTileSpec(GetIndustryGfx(index))->grf_prop.grffile != nullptr; }
GetParent(uint index)252 	uint GetParent(uint index) const override            { return GetInspectWindowNumber(GSF_INDUSTRIES, GetIndustryIndex(index)); }
GetInstance(uint index)253 	const void *GetInstance(uint index)const override    { return nullptr; }
GetSpec(uint index)254 	const void *GetSpec(uint index) const override       { return GetIndustryTileSpec(GetIndustryGfx(index)); }
SetStringParameters(uint index)255 	void SetStringParameters(uint index) const override  { this->SetObjectAtStringParameters(STR_INDUSTRY_NAME, GetIndustryIndex(index), index); }
GetGRFID(uint index)256 	uint32 GetGRFID(uint index) const override           { return (this->IsInspectable(index)) ? GetIndustryTileSpec(GetIndustryGfx(index))->grf_prop.grffile->grfid : 0; }
257 
Resolve(uint index,uint var,uint param,bool * avail)258 	uint Resolve(uint index, uint var, uint param, bool *avail) const override
259 	{
260 		IndustryTileResolverObject ro(GetIndustryGfx(index), index, Industry::GetByTile(index));
261 		return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
262 	}
263 };
264 
265 static const NIFeature _nif_industrytile = {
266 	nullptr,
267 	_nic_industrytiles,
268 	_niv_industrytiles,
269 	new NIHIndustryTile(),
270 };
271 
272 
273 /*** NewGRF industries ***/
274 
275 static const NIProperty _nip_industries[] = {
276 	NIP(0x25, Industry, produced_cargo[ 0], NIT_CARGO, "produced cargo 0"),
277 	NIP(0x25, Industry, produced_cargo[ 1], NIT_CARGO, "produced cargo 1"),
278 	NIP(0x25, Industry, produced_cargo[ 2], NIT_CARGO, "produced cargo 2"),
279 	NIP(0x25, Industry, produced_cargo[ 3], NIT_CARGO, "produced cargo 3"),
280 	NIP(0x25, Industry, produced_cargo[ 4], NIT_CARGO, "produced cargo 4"),
281 	NIP(0x25, Industry, produced_cargo[ 5], NIT_CARGO, "produced cargo 5"),
282 	NIP(0x25, Industry, produced_cargo[ 6], NIT_CARGO, "produced cargo 6"),
283 	NIP(0x25, Industry, produced_cargo[ 7], NIT_CARGO, "produced cargo 7"),
284 	NIP(0x25, Industry, produced_cargo[ 8], NIT_CARGO, "produced cargo 8"),
285 	NIP(0x25, Industry, produced_cargo[ 9], NIT_CARGO, "produced cargo 9"),
286 	NIP(0x25, Industry, produced_cargo[10], NIT_CARGO, "produced cargo 10"),
287 	NIP(0x25, Industry, produced_cargo[11], NIT_CARGO, "produced cargo 11"),
288 	NIP(0x25, Industry, produced_cargo[12], NIT_CARGO, "produced cargo 12"),
289 	NIP(0x25, Industry, produced_cargo[13], NIT_CARGO, "produced cargo 13"),
290 	NIP(0x25, Industry, produced_cargo[14], NIT_CARGO, "produced cargo 14"),
291 	NIP(0x25, Industry, produced_cargo[15], NIT_CARGO, "produced cargo 15"),
292 	NIP(0x26, Industry, accepts_cargo[ 0],  NIT_CARGO, "accepted cargo 0"),
293 	NIP(0x26, Industry, accepts_cargo[ 1],  NIT_CARGO, "accepted cargo 1"),
294 	NIP(0x26, Industry, accepts_cargo[ 2],  NIT_CARGO, "accepted cargo 2"),
295 	NIP(0x26, Industry, accepts_cargo[ 3],  NIT_CARGO, "accepted cargo 3"),
296 	NIP(0x26, Industry, accepts_cargo[ 4],  NIT_CARGO, "accepted cargo 4"),
297 	NIP(0x26, Industry, accepts_cargo[ 5],  NIT_CARGO, "accepted cargo 5"),
298 	NIP(0x26, Industry, accepts_cargo[ 6],  NIT_CARGO, "accepted cargo 6"),
299 	NIP(0x26, Industry, accepts_cargo[ 7],  NIT_CARGO, "accepted cargo 7"),
300 	NIP(0x26, Industry, accepts_cargo[ 8],  NIT_CARGO, "accepted cargo 8"),
301 	NIP(0x26, Industry, accepts_cargo[ 9],  NIT_CARGO, "accepted cargo 9"),
302 	NIP(0x26, Industry, accepts_cargo[10],  NIT_CARGO, "accepted cargo 10"),
303 	NIP(0x26, Industry, accepts_cargo[11],  NIT_CARGO, "accepted cargo 11"),
304 	NIP(0x26, Industry, accepts_cargo[12],  NIT_CARGO, "accepted cargo 12"),
305 	NIP(0x26, Industry, accepts_cargo[13],  NIT_CARGO, "accepted cargo 13"),
306 	NIP(0x26, Industry, accepts_cargo[14],  NIT_CARGO, "accepted cargo 14"),
307 	NIP(0x26, Industry, accepts_cargo[15],  NIT_CARGO, "accepted cargo 15"),
308 	NIP_END()
309 };
310 
311 #define NICI(cb_id, bit) NIC(cb_id, IndustrySpec, callback_mask, bit)
312 static const NICallback _nic_industries[] = {
313 	NICI(CBID_INDUSTRY_PROBABILITY,          CBM_IND_PROBABILITY),
314 	NICI(CBID_INDUSTRY_LOCATION,             CBM_IND_LOCATION),
315 	NICI(CBID_INDUSTRY_PRODUCTION_CHANGE,    CBM_IND_PRODUCTION_CHANGE),
316 	NICI(CBID_INDUSTRY_MONTHLYPROD_CHANGE,   CBM_IND_MONTHLYPROD_CHANGE),
317 	NICI(CBID_INDUSTRY_CARGO_SUFFIX,         CBM_IND_CARGO_SUFFIX),
318 	NICI(CBID_INDUSTRY_FUND_MORE_TEXT,       CBM_IND_FUND_MORE_TEXT),
319 	NICI(CBID_INDUSTRY_WINDOW_MORE_TEXT,     CBM_IND_WINDOW_MORE_TEXT),
320 	NICI(CBID_INDUSTRY_SPECIAL_EFFECT,       CBM_IND_SPECIAL_EFFECT),
321 	NICI(CBID_INDUSTRY_REFUSE_CARGO,         CBM_IND_REFUSE_CARGO),
322 	NICI(CBID_INDUSTRY_DECIDE_COLOUR,        CBM_IND_DECIDE_COLOUR),
323 	NICI(CBID_INDUSTRY_INPUT_CARGO_TYPES,    CBM_IND_INPUT_CARGO_TYPES),
324 	NICI(CBID_INDUSTRY_OUTPUT_CARGO_TYPES,   CBM_IND_OUTPUT_CARGO_TYPES),
325 	NICI(CBID_INDUSTRY_PROD_CHANGE_BUILD,    CBM_IND_PROD_CHANGE_BUILD),
326 	NIC_END()
327 };
328 
329 static const NIVariable _niv_industries[] = {
330 	NIV(0x40, "waiting cargo 0"),
331 	NIV(0x41, "waiting cargo 1"),
332 	NIV(0x42, "waiting cargo 2"),
333 	NIV(0x43, "distance to closest dry/land tile"),
334 	NIV(0x44, "layout number"),
335 	NIV(0x45, "player info"),
336 	NIV(0x46, "industry construction date"),
337 	NIV(0x60, "get industry tile ID at offset"),
338 	NIV(0x61, "get random tile bits at offset"),
339 	NIV(0x62, "land info of nearby tiles"),
340 	NIV(0x63, "animation stage of nearby tiles"),
341 	NIV(0x64, "distance on nearest industry with given type"),
342 	NIV(0x65, "get town zone and Manhattan distance of closest town"),
343 	NIV(0x66, "get square of Euclidean distance of closes town"),
344 	NIV(0x67, "count of industry and distance of closest instance"),
345 	NIV(0x68, "count of industry and distance of closest instance with layout filter"),
346 	NIV(0x69, "produced cargo waiting"),
347 	NIV(0x6A, "cargo produced this month"),
348 	NIV(0x6B, "cargo transported this month"),
349 	NIV(0x6C, "cargo produced last month"),
350 	NIV(0x6D, "cargo transported last month"),
351 	NIV(0x6E, "date since cargo was delivered"),
352 	NIV(0x6F, "waiting input cargo"),
353 	NIV(0x70, "production rate"),
354 	NIV(0x71, "percentage of cargo transported last month"),
355 	NIV_END()
356 };
357 
358 class NIHIndustry : public NIHelper {
IsInspectable(uint index)359 	bool IsInspectable(uint index) const override        { return GetIndustrySpec(Industry::Get(index)->type)->grf_prop.grffile != nullptr; }
GetParent(uint index)360 	uint GetParent(uint index) const override            { return GetInspectWindowNumber(GSF_FAKE_TOWNS, Industry::Get(index)->town->index); }
GetInstance(uint index)361 	const void *GetInstance(uint index)const override    { return Industry::Get(index); }
GetSpec(uint index)362 	const void *GetSpec(uint index) const override       { return GetIndustrySpec(Industry::Get(index)->type); }
SetStringParameters(uint index)363 	void SetStringParameters(uint index) const override  { this->SetSimpleStringParameters(STR_INDUSTRY_NAME, index); }
GetGRFID(uint index)364 	uint32 GetGRFID(uint index) const override           { return (this->IsInspectable(index)) ? GetIndustrySpec(Industry::Get(index)->type)->grf_prop.grffile->grfid : 0; }
365 
Resolve(uint index,uint var,uint param,bool * avail)366 	uint Resolve(uint index, uint var, uint param, bool *avail) const override
367 	{
368 		Industry *i = Industry::Get(index);
369 		IndustriesResolverObject ro(i->location.tile, i, i->type);
370 		return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
371 	}
372 
GetPSASize(uint index,uint32 grfid)373 	uint GetPSASize(uint index, uint32 grfid) const override { return cpp_lengthof(PersistentStorage, storage); }
374 
GetPSAFirstPosition(uint index,uint32 grfid)375 	const int32 *GetPSAFirstPosition(uint index, uint32 grfid) const override
376 	{
377 		const Industry *i = (const Industry *)this->GetInstance(index);
378 		if (i->psa == nullptr) return nullptr;
379 		return (int32 *)(&i->psa->storage);
380 	}
381 };
382 
383 static const NIFeature _nif_industry = {
384 	_nip_industries,
385 	_nic_industries,
386 	_niv_industries,
387 	new NIHIndustry(),
388 };
389 
390 
391 /*** NewGRF objects ***/
392 
393 #define NICO(cb_id, bit) NIC(cb_id, ObjectSpec, callback_mask, bit)
394 static const NICallback _nic_objects[] = {
395 	NICO(CBID_OBJECT_LAND_SLOPE_CHECK,     CBM_OBJ_SLOPE_CHECK),
396 	NICO(CBID_OBJECT_ANIMATION_NEXT_FRAME, CBM_OBJ_ANIMATION_NEXT_FRAME),
397 	NICO(CBID_OBJECT_ANIMATION_START_STOP, CBM_NO_BIT),
398 	NICO(CBID_OBJECT_ANIMATION_SPEED,      CBM_OBJ_ANIMATION_SPEED),
399 	NICO(CBID_OBJECT_COLOUR,               CBM_OBJ_COLOUR),
400 	NICO(CBID_OBJECT_FUND_MORE_TEXT,       CBM_OBJ_FUND_MORE_TEXT),
401 	NICO(CBID_OBJECT_AUTOSLOPE,            CBM_OBJ_AUTOSLOPE),
402 	NIC_END()
403 };
404 
405 static const NIVariable _niv_objects[] = {
406 	NIV(0x40, "relative position"),
407 	NIV(0x41, "tile information"),
408 	NIV(0x42, "construction date"),
409 	NIV(0x43, "animation counter"),
410 	NIV(0x44, "object founder"),
411 	NIV(0x45, "get town zone and Manhattan distance of closest town"),
412 	NIV(0x46, "get square of Euclidean distance of closes town"),
413 	NIV(0x47, "colour"),
414 	NIV(0x48, "view"),
415 	NIV(0x60, "get object ID at offset"),
416 	NIV(0x61, "get random tile bits at offset"),
417 	NIV(0x62, "land info of nearby tiles"),
418 	NIV(0x63, "animation stage of nearby tiles"),
419 	NIV(0x64, "distance on nearest object with given type"),
420 	NIV_END()
421 };
422 
423 class NIHObject : public NIHelper {
IsInspectable(uint index)424 	bool IsInspectable(uint index) const override        { return ObjectSpec::GetByTile(index)->grf_prop.grffile != nullptr; }
GetParent(uint index)425 	uint GetParent(uint index) const override            { return GetInspectWindowNumber(GSF_FAKE_TOWNS, Object::GetByTile(index)->town->index); }
GetInstance(uint index)426 	const void *GetInstance(uint index)const override    { return Object::GetByTile(index); }
GetSpec(uint index)427 	const void *GetSpec(uint index) const override       { return ObjectSpec::GetByTile(index); }
SetStringParameters(uint index)428 	void SetStringParameters(uint index) const override  { this->SetObjectAtStringParameters(STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_OBJECT, INVALID_STRING_ID, index); }
GetGRFID(uint index)429 	uint32 GetGRFID(uint index) const override           { return (this->IsInspectable(index)) ? ObjectSpec::GetByTile(index)->grf_prop.grffile->grfid : 0; }
430 
Resolve(uint index,uint var,uint param,bool * avail)431 	uint Resolve(uint index, uint var, uint param, bool *avail) const override
432 	{
433 		ObjectResolverObject ro(ObjectSpec::GetByTile(index), Object::GetByTile(index), index);
434 		return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
435 	}
436 };
437 
438 static const NIFeature _nif_object = {
439 	nullptr,
440 	_nic_objects,
441 	_niv_objects,
442 	new NIHObject(),
443 };
444 
445 
446 /*** NewGRF rail types ***/
447 
448 static const NIVariable _niv_railtypes[] = {
449 	NIV(0x40, "terrain type"),
450 	NIV(0x41, "enhanced tunnels"),
451 	NIV(0x42, "level crossing status"),
452 	NIV(0x43, "construction date"),
453 	NIV(0x44, "town zone"),
454 	NIV_END()
455 };
456 
457 class NIHRailType : public NIHelper {
IsInspectable(uint index)458 	bool IsInspectable(uint index) const override        { return true; }
GetParent(uint index)459 	uint GetParent(uint index) const override            { return UINT32_MAX; }
GetInstance(uint index)460 	const void *GetInstance(uint index)const override    { return nullptr; }
GetSpec(uint index)461 	const void *GetSpec(uint index) const override       { return nullptr; }
SetStringParameters(uint index)462 	void SetStringParameters(uint index) const override  { this->SetObjectAtStringParameters(STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE, INVALID_STRING_ID, index); }
GetGRFID(uint index)463 	uint32 GetGRFID(uint index) const override           { return 0; }
464 
Resolve(uint index,uint var,uint param,bool * avail)465 	uint Resolve(uint index, uint var, uint param, bool *avail) const override
466 	{
467 		/* There is no unique GRFFile for the tile. Multiple GRFs can define different parts of the railtype.
468 		 * However, currently the NewGRF Debug GUI does not display variables depending on the GRF (like 0x7F) anyway. */
469 		RailTypeResolverObject ro(nullptr, index, TCX_NORMAL, RTSG_END);
470 		return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
471 	}
472 };
473 
474 static const NIFeature _nif_railtype = {
475 	nullptr,
476 	nullptr,
477 	_niv_railtypes,
478 	new NIHRailType(),
479 };
480 
481 
482 /*** NewGRF airport tiles ***/
483 
484 #define NICAT(cb_id, bit) NIC(cb_id, AirportTileSpec, callback_mask, bit)
485 static const NICallback _nic_airporttiles[] = {
486 	NICAT(CBID_AIRPTILE_DRAW_FOUNDATIONS, CBM_AIRT_DRAW_FOUNDATIONS),
487 	NICAT(CBID_AIRPTILE_ANIM_START_STOP,  CBM_NO_BIT),
488 	NICAT(CBID_AIRPTILE_ANIM_NEXT_FRAME,  CBM_AIRT_ANIM_NEXT_FRAME),
489 	NICAT(CBID_AIRPTILE_ANIMATION_SPEED,  CBM_AIRT_ANIM_SPEED),
490 	NIC_END()
491 };
492 
493 class NIHAirportTile : public NIHelper {
IsInspectable(uint index)494 	bool IsInspectable(uint index) const override        { return AirportTileSpec::Get(GetAirportGfx(index))->grf_prop.grffile != nullptr; }
GetParent(uint index)495 	uint GetParent(uint index) const override            { return GetInspectWindowNumber(GSF_FAKE_TOWNS, Station::GetByTile(index)->town->index); }
GetInstance(uint index)496 	const void *GetInstance(uint index)const override    { return nullptr; }
GetSpec(uint index)497 	const void *GetSpec(uint index) const override       { return AirportTileSpec::Get(GetAirportGfx(index)); }
SetStringParameters(uint index)498 	void SetStringParameters(uint index) const override  { this->SetObjectAtStringParameters(STR_STATION_NAME, GetStationIndex(index), index); }
GetGRFID(uint index)499 	uint32 GetGRFID(uint index) const override           { return (this->IsInspectable(index)) ? AirportTileSpec::Get(GetAirportGfx(index))->grf_prop.grffile->grfid : 0; }
500 
Resolve(uint index,uint var,uint param,bool * avail)501 	uint Resolve(uint index, uint var, uint param, bool *avail) const override
502 	{
503 		AirportTileResolverObject ro(AirportTileSpec::GetByTile(index), index, Station::GetByTile(index));
504 		return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
505 	}
506 };
507 
508 static const NIFeature _nif_airporttile = {
509 	nullptr,
510 	_nic_airporttiles,
511 	_niv_industrytiles, // Yes, they share this (at least now)
512 	new NIHAirportTile(),
513 };
514 
515 
516 /*** NewGRF towns ***/
517 
518 static const NIVariable _niv_towns[] = {
519 	NIV(0x40, "larger town effect on this town"),
520 	NIV(0x41, "town index"),
521 	NIV(0x82, "population"),
522 	NIV(0x94, "zone radius 0"),
523 	NIV(0x96, "zone radius 1"),
524 	NIV(0x98, "zone radius 2"),
525 	NIV(0x9A, "zone radius 3"),
526 	NIV(0x9C, "zone radius 4"),
527 	NIV(0xB6, "number of buildings"),
528 	NIV_END()
529 };
530 
531 class NIHTown : public NIHelper {
IsInspectable(uint index)532 	bool IsInspectable(uint index) const override        { return Town::IsValidID(index); }
GetParent(uint index)533 	uint GetParent(uint index) const override            { return UINT32_MAX; }
GetInstance(uint index)534 	const void *GetInstance(uint index)const override    { return Town::Get(index); }
GetSpec(uint index)535 	const void *GetSpec(uint index) const override       { return nullptr; }
SetStringParameters(uint index)536 	void SetStringParameters(uint index) const override  { this->SetSimpleStringParameters(STR_TOWN_NAME, index); }
GetGRFID(uint index)537 	uint32 GetGRFID(uint index) const override           { return 0; }
PSAWithParameter()538 	bool PSAWithParameter() const override               { return true; }
GetPSASize(uint index,uint32 grfid)539 	uint GetPSASize(uint index, uint32 grfid) const override { return cpp_lengthof(PersistentStorage, storage); }
540 
Resolve(uint index,uint var,uint param,bool * avail)541 	uint Resolve(uint index, uint var, uint param, bool *avail) const override
542 	{
543 		TownResolverObject ro(nullptr, Town::Get(index), true);
544 		return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
545 	}
546 
GetPSAFirstPosition(uint index,uint32 grfid)547 	const int32 *GetPSAFirstPosition(uint index, uint32 grfid) const override
548 	{
549 		Town *t = Town::Get(index);
550 
551 		std::list<PersistentStorage *>::iterator iter;
552 		for (iter = t->psa_list.begin(); iter != t->psa_list.end(); iter++) {
553 			if ((*iter)->grfid == grfid) return (int32 *)(&(*iter)->storage[0]);
554 		}
555 
556 		return nullptr;
557 	}
558 };
559 
560 static const NIFeature _nif_town = {
561 	nullptr,
562 	nullptr,
563 	_niv_towns,
564 	new NIHTown(),
565 };
566 
567 /*** NewGRF road types ***/
568 
569 static const NIVariable _niv_roadtypes[] = {
570 	NIV(0x40, "terrain type"),
571 	NIV(0x41, "enhanced tunnels"),
572 	NIV(0x42, "level crossing status"),
573 	NIV(0x43, "construction date"),
574 	NIV(0x44, "town zone"),
575 	NIV_END()
576 };
577 
578 class NIHRoadType : public NIHelper {
IsInspectable(uint index)579 	bool IsInspectable(uint index) const override        { return true; }
GetParent(uint index)580 	uint GetParent(uint index) const override            { return UINT32_MAX; }
GetInstance(uint index)581 	const void *GetInstance(uint index) const override   { return nullptr; }
GetSpec(uint index)582 	const void *GetSpec(uint index) const override       { return nullptr; }
SetStringParameters(uint index)583 	void SetStringParameters(uint index) const override  { this->SetObjectAtStringParameters(STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE, INVALID_STRING_ID, index); }
GetGRFID(uint index)584 	uint32 GetGRFID(uint index) const override           { return 0; }
585 
Resolve(uint index,uint var,uint param,bool * avail)586 	uint Resolve(uint index, uint var, uint param, bool *avail) const override
587 	{
588 		/* There is no unique GRFFile for the tile. Multiple GRFs can define different parts of the railtype.
589 		 * However, currently the NewGRF Debug GUI does not display variables depending on the GRF (like 0x7F) anyway. */
590 		RoadTypeResolverObject ro(nullptr, index, TCX_NORMAL, ROTSG_END);
591 		return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
592 	}
593 };
594 
595 static const NIFeature _nif_roadtype = {
596 	nullptr,
597 	nullptr,
598 	_niv_roadtypes,
599 	new NIHRoadType(),
600 };
601 
602 static const NIFeature _nif_tramtype = {
603 	nullptr,
604 	nullptr,
605 	_niv_roadtypes,
606 	new NIHRoadType(),
607 };
608 
609 /** Table with all NIFeatures. */
610 static const NIFeature * const _nifeatures[] = {
611 	&_nif_vehicle,      // GSF_TRAINS
612 	&_nif_vehicle,      // GSF_ROADVEHICLES
613 	&_nif_vehicle,      // GSF_SHIPS
614 	&_nif_vehicle,      // GSF_AIRCRAFT
615 	&_nif_station,      // GSF_STATIONS
616 	nullptr,               // GSF_CANALS (no callbacks/action2 implemented)
617 	nullptr,               // GSF_BRIDGES (no callbacks/action2)
618 	&_nif_house,        // GSF_HOUSES
619 	nullptr,               // GSF_GLOBALVAR (has no "physical" objects)
620 	&_nif_industrytile, // GSF_INDUSTRYTILES
621 	&_nif_industry,     // GSF_INDUSTRIES
622 	nullptr,               // GSF_CARGOES (has no "physical" objects)
623 	nullptr,               // GSF_SOUNDFX (has no "physical" objects)
624 	nullptr,               // GSF_AIRPORTS (feature not implemented)
625 	nullptr,               // GSF_SIGNALS (feature not implemented)
626 	&_nif_object,       // GSF_OBJECTS
627 	&_nif_railtype,     // GSF_RAILTYPES
628 	&_nif_airporttile,  // GSF_AIRPORTTILES
629 	&_nif_roadtype,     // GSF_ROADTYPES
630 	&_nif_tramtype,     // GSF_TRAMTYPES
631 	&_nif_town,         // GSF_FAKE_TOWNS
632 };
633 static_assert(lengthof(_nifeatures) == GSF_FAKE_END);
634