OpenTTD Source 20250331-master-g3c15e0c889
newgrf_act3.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 <http://www.gnu.org/licenses/>.
6 */
7
10#include "../stdafx.h"
11
12#include "../debug.h"
13#include "../house.h"
14#include "../newgrf_engine.h"
15#include "../newgrf_badge.h"
16#include "../newgrf_badge_type.h"
17#include "../newgrf_cargo.h"
18#include "../newgrf_house.h"
19#include "../newgrf_station.h"
20#include "../industrytype.h"
21#include "../newgrf_canal.h"
22#include "../newgrf_airporttiles.h"
23#include "../newgrf_airport.h"
24#include "../newgrf_object.h"
25#include "../error.h"
26#include "../vehicle_base.h"
27#include "../road.h"
28#include "../newgrf_roadstop.h"
29#include "newgrf_bytereader.h"
31#include "newgrf_internal.h"
32
33#include "../safeguards.h"
34
35
36static CargoType TranslateCargo(uint8_t feature, uint8_t ctype)
37{
38 /* Special cargo types for purchase list and stations */
39 if ((feature == GSF_STATIONS || feature == GSF_ROADSTOPS) && ctype == 0xFE) return SpriteGroupCargo::SG_DEFAULT_NA;
40 if (ctype == 0xFF) return SpriteGroupCargo::SG_PURCHASE;
41
42 auto cargo_list = GetCargoTranslationTable(*_cur.grffile);
43
44 /* Check if the cargo type is out of bounds of the cargo translation table */
45 if (ctype >= cargo_list.size()) {
46 GrfMsg(1, "TranslateCargo: Cargo type {} out of range (max {}), skipping.", ctype, (unsigned int)_cur.grffile->cargo_list.size() - 1);
47 return INVALID_CARGO;
48 }
49
50 /* Look up the cargo label from the translation table */
51 CargoLabel cl = cargo_list[ctype];
52 if (cl == CT_INVALID) {
53 GrfMsg(5, "TranslateCargo: Cargo type {} not available in this climate, skipping.", ctype);
54 return INVALID_CARGO;
55 }
56
57 CargoType cargo_type = GetCargoTypeByLabel(cl);
58 if (!IsValidCargoType(cargo_type)) {
59 GrfMsg(5, "TranslateCargo: Cargo '{:c}{:c}{:c}{:c}' unsupported, skipping.", GB(cl.base(), 24, 8), GB(cl.base(), 16, 8), GB(cl.base(), 8, 8), GB(cl.base(), 0, 8));
60 return INVALID_CARGO;
61 }
62
63 GrfMsg(6, "TranslateCargo: Cargo '{:c}{:c}{:c}{:c}' mapped to cargo type {}.", GB(cl.base(), 24, 8), GB(cl.base(), 16, 8), GB(cl.base(), 8, 8), GB(cl.base(), 0, 8), cargo_type);
64 return cargo_type;
65}
66
67
68static bool IsValidGroupID(uint16_t groupid, const char *function)
69{
70 if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == nullptr) {
71 GrfMsg(1, "{}: Spritegroup 0x{:04X} out of range or empty, skipping.", function, groupid);
72 return false;
73 }
74
75 return true;
76}
77
78static void VehicleMapSpriteGroup(ByteReader &buf, uint8_t feature, uint8_t idcount)
79{
80 static std::vector<EngineID> last_engines; // Engine IDs are remembered in case the next action is a wagon override.
81 bool wagover = false;
82
83 /* Test for 'wagon override' flag */
84 if (HasBit(idcount, 7)) {
85 wagover = true;
86 /* Strip off the flag */
87 idcount = GB(idcount, 0, 7);
88
89 if (last_engines.empty()) {
90 GrfMsg(0, "VehicleMapSpriteGroup: WagonOverride: No engine to do override with");
91 return;
92 }
93
94 GrfMsg(6, "VehicleMapSpriteGroup: WagonOverride: {} engines, {} wagons", last_engines.size(), idcount);
95 } else {
96 last_engines.resize(idcount);
97 }
98
99 std::vector<EngineID> engines;
100 engines.reserve(idcount);
101 for (uint i = 0; i < idcount; i++) {
102 Engine *e = GetNewEngine(_cur.grffile, (VehicleType)feature, buf.ReadExtendedByte());
103 if (e == nullptr) {
104 /* No engine could be allocated?!? Deal with it. Okay,
105 * this might look bad. Also make sure this NewGRF
106 * gets disabled, as a half loaded one is bad. */
107 HandleChangeInfoResult("VehicleMapSpriteGroup", CIR_INVALID_ID, 0, 0);
108 return;
109 }
110
111 engines.push_back(e->index);
112 if (!wagover) last_engines[i] = engines[i];
113 }
114
115 uint8_t cidcount = buf.ReadByte();
116 for (uint c = 0; c < cidcount; c++) {
117 uint8_t ctype = buf.ReadByte();
118 uint16_t groupid = buf.ReadWord();
119 if (!IsValidGroupID(groupid, "VehicleMapSpriteGroup")) continue;
120
121 GrfMsg(8, "VehicleMapSpriteGroup: * [{}] Cargo type 0x{:X}, group id 0x{:02X}", c, ctype, groupid);
122
123 CargoType cargo_type = TranslateCargo(feature, ctype);
124 if (!IsValidCargoType(cargo_type)) continue;
125
126 for (uint i = 0; i < idcount; i++) {
127 EngineID engine = engines[i];
128
129 GrfMsg(7, "VehicleMapSpriteGroup: [{}] Engine {}...", i, engine);
130
131 if (wagover) {
132 SetWagonOverrideSprites(engine, cargo_type, _cur.spritegroups[groupid], last_engines);
133 } else {
134 SetCustomEngineSprites(engine, cargo_type, _cur.spritegroups[groupid]);
135 }
136 }
137 }
138
139 uint16_t groupid = buf.ReadWord();
140 if (!IsValidGroupID(groupid, "VehicleMapSpriteGroup")) return;
141
142 GrfMsg(8, "-- Default group id 0x{:04X}", groupid);
143
144 for (uint i = 0; i < idcount; i++) {
145 EngineID engine = engines[i];
146
147 if (wagover) {
148 SetWagonOverrideSprites(engine, SpriteGroupCargo::SG_DEFAULT, _cur.spritegroups[groupid], last_engines);
149 } else {
150 SetCustomEngineSprites(engine, SpriteGroupCargo::SG_DEFAULT, _cur.spritegroups[groupid]);
151 SetEngineGRF(engine, _cur.grffile);
152 }
153 }
154}
155
156
157static void CanalMapSpriteGroup(ByteReader &buf, uint8_t idcount)
158{
159 std::vector<uint16_t> cfs;
160 cfs.reserve(idcount);
161 for (uint i = 0; i < idcount; i++) {
162 cfs.push_back(buf.ReadExtendedByte());
163 }
164
165 uint8_t cidcount = buf.ReadByte();
166 buf.Skip(cidcount * 3);
167
168 uint16_t groupid = buf.ReadWord();
169 if (!IsValidGroupID(groupid, "CanalMapSpriteGroup")) return;
170
171 for (auto &cf : cfs) {
172 if (cf >= CF_END) {
173 GrfMsg(1, "CanalMapSpriteGroup: Canal subset {} out of range, skipping", cf);
174 continue;
175 }
176
177 _water_feature[cf].grffile = _cur.grffile;
178 _water_feature[cf].group = _cur.spritegroups[groupid];
179 }
180}
181
182
183static void StationMapSpriteGroup(ByteReader &buf, uint8_t idcount)
184{
185 if (_cur.grffile->stations.empty()) {
186 GrfMsg(1, "StationMapSpriteGroup: No stations defined, skipping");
187 return;
188 }
189
190 std::vector<uint16_t> stations;
191 stations.reserve(idcount);
192 for (uint i = 0; i < idcount; i++) {
193 stations.push_back(buf.ReadExtendedByte());
194 }
195
196 uint8_t cidcount = buf.ReadByte();
197 for (uint c = 0; c < cidcount; c++) {
198 uint8_t ctype = buf.ReadByte();
199 uint16_t groupid = buf.ReadWord();
200 if (!IsValidGroupID(groupid, "StationMapSpriteGroup")) continue;
201
202 ctype = TranslateCargo(GSF_STATIONS, ctype);
203 if (!IsValidCargoType(ctype)) continue;
204
205 for (auto &station : stations) {
206 StationSpec *statspec = station >= _cur.grffile->stations.size() ? nullptr : _cur.grffile->stations[station].get();
207
208 if (statspec == nullptr) {
209 GrfMsg(1, "StationMapSpriteGroup: Station {} undefined, skipping", station);
210 continue;
211 }
212
213 statspec->grf_prop.SetSpriteGroup(ctype, _cur.spritegroups[groupid]);
214 }
215 }
216
217 uint16_t groupid = buf.ReadWord();
218 if (!IsValidGroupID(groupid, "StationMapSpriteGroup")) return;
219
220 for (auto &station : stations) {
221 StationSpec *statspec = station >= _cur.grffile->stations.size() ? nullptr : _cur.grffile->stations[station].get();
222
223 if (statspec == nullptr) {
224 GrfMsg(1, "StationMapSpriteGroup: Station {} undefined, skipping", station);
225 continue;
226 }
227
228 if (statspec->grf_prop.HasGrfFile()) {
229 GrfMsg(1, "StationMapSpriteGroup: Station {} mapped multiple times, skipping", station);
230 continue;
231 }
232
233 statspec->grf_prop.SetSpriteGroup(SpriteGroupCargo::SG_DEFAULT, _cur.spritegroups[groupid]);
234 statspec->grf_prop.SetGRFFile(_cur.grffile);
235 statspec->grf_prop.local_id = station;
236 StationClass::Assign(statspec);
237 }
238}
239
240
241static void TownHouseMapSpriteGroup(ByteReader &buf, uint8_t idcount)
242{
243 if (_cur.grffile->housespec.empty()) {
244 GrfMsg(1, "TownHouseMapSpriteGroup: No houses defined, skipping");
245 return;
246 }
247
248 std::vector<uint16_t> houses;
249 houses.reserve(idcount);
250 for (uint i = 0; i < idcount; i++) {
251 houses.push_back(buf.ReadExtendedByte());
252 }
253
254 /* Skip the cargo type section, we only care about the default group */
255 uint8_t cidcount = buf.ReadByte();
256 buf.Skip(cidcount * 3);
257
258 uint16_t groupid = buf.ReadWord();
259 if (!IsValidGroupID(groupid, "TownHouseMapSpriteGroup")) return;
260
261 for (auto &house : houses) {
262 HouseSpec *hs = house >= _cur.grffile->housespec.size() ? nullptr : _cur.grffile->housespec[house].get();
263
264 if (hs == nullptr) {
265 GrfMsg(1, "TownHouseMapSpriteGroup: House {} undefined, skipping.", house);
266 continue;
267 }
268
269 hs->grf_prop.SetSpriteGroup(0, _cur.spritegroups[groupid]);
270 }
271}
272
273static void IndustryMapSpriteGroup(ByteReader &buf, uint8_t idcount)
274{
275 if (_cur.grffile->industryspec.empty()) {
276 GrfMsg(1, "IndustryMapSpriteGroup: No industries defined, skipping");
277 return;
278 }
279
280 std::vector<uint16_t> industries;
281 industries.reserve(idcount);
282 for (uint i = 0; i < idcount; i++) {
283 industries.push_back(buf.ReadExtendedByte());
284 }
285
286 /* Skip the cargo type section, we only care about the default group */
287 uint8_t cidcount = buf.ReadByte();
288 buf.Skip(cidcount * 3);
289
290 uint16_t groupid = buf.ReadWord();
291 if (!IsValidGroupID(groupid, "IndustryMapSpriteGroup")) return;
292
293 for (auto &industry : industries) {
294 IndustrySpec *indsp = industry >= _cur.grffile->industryspec.size() ? nullptr : _cur.grffile->industryspec[industry].get();
295
296 if (indsp == nullptr) {
297 GrfMsg(1, "IndustryMapSpriteGroup: Industry {} undefined, skipping", industry);
298 continue;
299 }
300
301 indsp->grf_prop.SetSpriteGroup(0, _cur.spritegroups[groupid]);
302 }
303}
304
305static void IndustrytileMapSpriteGroup(ByteReader &buf, uint8_t idcount)
306{
307 if (_cur.grffile->indtspec.empty()) {
308 GrfMsg(1, "IndustrytileMapSpriteGroup: No industry tiles defined, skipping");
309 return;
310 }
311
312 std::vector<uint16_t> indtiles;
313 indtiles.reserve(idcount);
314 for (uint i = 0; i < idcount; i++) {
315 indtiles.push_back(buf.ReadExtendedByte());
316 }
317
318 /* Skip the cargo type section, we only care about the default group */
319 uint8_t cidcount = buf.ReadByte();
320 buf.Skip(cidcount * 3);
321
322 uint16_t groupid = buf.ReadWord();
323 if (!IsValidGroupID(groupid, "IndustrytileMapSpriteGroup")) return;
324
325 for (auto &indtile : indtiles) {
326 IndustryTileSpec *indtsp = indtile >= _cur.grffile->indtspec.size() ? nullptr : _cur.grffile->indtspec[indtile].get();
327
328 if (indtsp == nullptr) {
329 GrfMsg(1, "IndustrytileMapSpriteGroup: Industry tile {} undefined, skipping", indtile);
330 continue;
331 }
332
333 indtsp->grf_prop.SetSpriteGroup(0, _cur.spritegroups[groupid]);
334 }
335}
336
337static void CargoMapSpriteGroup(ByteReader &buf, uint8_t idcount)
338{
339 std::vector<uint16_t> cargoes;
340 cargoes.reserve(idcount);
341 for (uint i = 0; i < idcount; i++) {
342 cargoes.push_back(buf.ReadExtendedByte());
343 }
344
345 /* Skip the cargo type section, we only care about the default group */
346 uint8_t cidcount = buf.ReadByte();
347 buf.Skip(cidcount * 3);
348
349 uint16_t groupid = buf.ReadWord();
350 if (!IsValidGroupID(groupid, "CargoMapSpriteGroup")) return;
351
352 for (auto &cargo_type : cargoes) {
353 if (cargo_type >= NUM_CARGO) {
354 GrfMsg(1, "CargoMapSpriteGroup: Cargo type {} out of range, skipping", cargo_type);
355 continue;
356 }
357
358 CargoSpec *cs = CargoSpec::Get(cargo_type);
359 cs->grffile = _cur.grffile;
360 cs->group = _cur.spritegroups[groupid];
361 }
362}
363
364static void ObjectMapSpriteGroup(ByteReader &buf, uint8_t idcount)
365{
366 if (_cur.grffile->objectspec.empty()) {
367 GrfMsg(1, "ObjectMapSpriteGroup: No object tiles defined, skipping");
368 return;
369 }
370
371 std::vector<uint16_t> objects;
372 objects.reserve(idcount);
373 for (uint i = 0; i < idcount; i++) {
374 objects.push_back(buf.ReadExtendedByte());
375 }
376
377 uint8_t cidcount = buf.ReadByte();
378 for (uint c = 0; c < cidcount; c++) {
379 uint8_t ctype = buf.ReadByte();
380 uint16_t groupid = buf.ReadWord();
381 if (!IsValidGroupID(groupid, "ObjectMapSpriteGroup")) continue;
382
383 /* The only valid option here is purchase list sprite groups. */
384 if (ctype != 0xFF) {
385 GrfMsg(1, "ObjectMapSpriteGroup: Invalid cargo bitnum {} for objects, skipping.", ctype);
386 continue;
387 }
388
389 for (auto &object : objects) {
390 ObjectSpec *spec = object >= _cur.grffile->objectspec.size() ? nullptr : _cur.grffile->objectspec[object].get();
391
392 if (spec == nullptr) {
393 GrfMsg(1, "ObjectMapSpriteGroup: Object {} undefined, skipping", object);
394 continue;
395 }
396
397 spec->grf_prop.SetSpriteGroup(OBJECT_SPRITE_GROUP_PURCHASE, _cur.spritegroups[groupid]);
398 }
399 }
400
401 uint16_t groupid = buf.ReadWord();
402 if (!IsValidGroupID(groupid, "ObjectMapSpriteGroup")) return;
403
404 for (auto &object : objects) {
405 ObjectSpec *spec = object >= _cur.grffile->objectspec.size() ? nullptr : _cur.grffile->objectspec[object].get();
406
407 if (spec == nullptr) {
408 GrfMsg(1, "ObjectMapSpriteGroup: Object {} undefined, skipping", object);
409 continue;
410 }
411
412 if (spec->grf_prop.HasGrfFile()) {
413 GrfMsg(1, "ObjectMapSpriteGroup: Object {} mapped multiple times, skipping", object);
414 continue;
415 }
416
417 spec->grf_prop.SetSpriteGroup(OBJECT_SPRITE_GROUP_DEFAULT, _cur.spritegroups[groupid]);
418 spec->grf_prop.SetGRFFile(_cur.grffile);
419 spec->grf_prop.local_id = object;
420 }
421}
422
423static void RailTypeMapSpriteGroup(ByteReader &buf, uint8_t idcount)
424{
425 std::vector<uint8_t> railtypes;
426 railtypes.reserve(idcount);
427 for (uint i = 0; i < idcount; i++) {
428 uint16_t id = buf.ReadExtendedByte();
429 railtypes.push_back(id < RAILTYPE_END ? _cur.grffile->railtype_map[id] : INVALID_RAILTYPE);
430 }
431
432 uint8_t cidcount = buf.ReadByte();
433 for (uint c = 0; c < cidcount; c++) {
434 uint8_t ctype = buf.ReadByte();
435 uint16_t groupid = buf.ReadWord();
436 if (!IsValidGroupID(groupid, "RailTypeMapSpriteGroup")) continue;
437
438 if (ctype >= RTSG_END) continue;
439
440 extern RailTypeInfo _railtypes[RAILTYPE_END];
441 for (auto &railtype : railtypes) {
442 if (railtype != INVALID_RAILTYPE) {
443 RailTypeInfo *rti = &_railtypes[railtype];
444
445 rti->grffile[ctype] = _cur.grffile;
446 rti->group[ctype] = _cur.spritegroups[groupid];
447 }
448 }
449 }
450
451 /* Railtypes do not use the default group. */
452 buf.ReadWord();
453}
454
455static void RoadTypeMapSpriteGroup(ByteReader &buf, uint8_t idcount, RoadTramType rtt)
456{
457 std::array<RoadType, ROADTYPE_END> &type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map;
458
459 std::vector<uint8_t> roadtypes;
460 roadtypes.reserve(idcount);
461 for (uint i = 0; i < idcount; i++) {
462 uint16_t id = buf.ReadExtendedByte();
463 roadtypes.push_back(id < ROADTYPE_END ? type_map[id] : INVALID_ROADTYPE);
464 }
465
466 uint8_t cidcount = buf.ReadByte();
467 for (uint c = 0; c < cidcount; c++) {
468 uint8_t ctype = buf.ReadByte();
469 uint16_t groupid = buf.ReadWord();
470 if (!IsValidGroupID(groupid, "RoadTypeMapSpriteGroup")) continue;
471
472 if (ctype >= ROTSG_END) continue;
473
474 extern RoadTypeInfo _roadtypes[ROADTYPE_END];
475 for (auto &roadtype : roadtypes) {
476 if (roadtype != INVALID_ROADTYPE) {
477 RoadTypeInfo *rti = &_roadtypes[roadtype];
478
479 rti->grffile[ctype] = _cur.grffile;
480 rti->group[ctype] = _cur.spritegroups[groupid];
481 }
482 }
483 }
484
485 /* Roadtypes do not use the default group. */
486 buf.ReadWord();
487}
488
489static void AirportMapSpriteGroup(ByteReader &buf, uint8_t idcount)
490{
491 if (_cur.grffile->airportspec.empty()) {
492 GrfMsg(1, "AirportMapSpriteGroup: No airports defined, skipping");
493 return;
494 }
495
496 std::vector<uint16_t> airports;
497 airports.reserve(idcount);
498 for (uint i = 0; i < idcount; i++) {
499 airports.push_back(buf.ReadExtendedByte());
500 }
501
502 /* Skip the cargo type section, we only care about the default group */
503 uint8_t cidcount = buf.ReadByte();
504 buf.Skip(cidcount * 3);
505
506 uint16_t groupid = buf.ReadWord();
507 if (!IsValidGroupID(groupid, "AirportMapSpriteGroup")) return;
508
509 for (auto &airport : airports) {
510 AirportSpec *as = airport >= _cur.grffile->airportspec.size() ? nullptr : _cur.grffile->airportspec[airport].get();
511
512 if (as == nullptr) {
513 GrfMsg(1, "AirportMapSpriteGroup: Airport {} undefined, skipping", airport);
514 continue;
515 }
516
517 as->grf_prop.SetSpriteGroup(0, _cur.spritegroups[groupid]);
518 }
519}
520
521static void AirportTileMapSpriteGroup(ByteReader &buf, uint8_t idcount)
522{
523 if (_cur.grffile->airtspec.empty()) {
524 GrfMsg(1, "AirportTileMapSpriteGroup: No airport tiles defined, skipping");
525 return;
526 }
527
528 std::vector<uint16_t> airptiles;
529 airptiles.reserve(idcount);
530 for (uint i = 0; i < idcount; i++) {
531 airptiles.push_back(buf.ReadExtendedByte());
532 }
533
534 /* Skip the cargo type section, we only care about the default group */
535 uint8_t cidcount = buf.ReadByte();
536 buf.Skip(cidcount * 3);
537
538 uint16_t groupid = buf.ReadWord();
539 if (!IsValidGroupID(groupid, "AirportTileMapSpriteGroup")) return;
540
541 for (auto &airptile : airptiles) {
542 AirportTileSpec *airtsp = airptile >= _cur.grffile->airtspec.size() ? nullptr : _cur.grffile->airtspec[airptile].get();
543
544 if (airtsp == nullptr) {
545 GrfMsg(1, "AirportTileMapSpriteGroup: Airport tile {} undefined, skipping", airptile);
546 continue;
547 }
548
549 airtsp->grf_prop.SetSpriteGroup(0, _cur.spritegroups[groupid]);
550 }
551}
552
553static void RoadStopMapSpriteGroup(ByteReader &buf, uint8_t idcount)
554{
555 if (_cur.grffile->roadstops.empty()) {
556 GrfMsg(1, "RoadStopMapSpriteGroup: No roadstops defined, skipping");
557 return;
558 }
559
560 std::vector<uint16_t> roadstops;
561 roadstops.reserve(idcount);
562 for (uint i = 0; i < idcount; i++) {
563 roadstops.push_back(buf.ReadExtendedByte());
564 }
565
566 uint8_t cidcount = buf.ReadByte();
567 for (uint c = 0; c < cidcount; c++) {
568 uint8_t ctype = buf.ReadByte();
569 uint16_t groupid = buf.ReadWord();
570 if (!IsValidGroupID(groupid, "RoadStopMapSpriteGroup")) continue;
571
572 ctype = TranslateCargo(GSF_ROADSTOPS, ctype);
573 if (!IsValidCargoType(ctype)) continue;
574
575 for (auto &roadstop : roadstops) {
576 RoadStopSpec *roadstopspec = roadstop >= _cur.grffile->roadstops.size() ? nullptr : _cur.grffile->roadstops[roadstop].get();
577
578 if (roadstopspec == nullptr) {
579 GrfMsg(1, "RoadStopMapSpriteGroup: Road stop {} undefined, skipping", roadstop);
580 continue;
581 }
582
583 roadstopspec->grf_prop.SetSpriteGroup(ctype, _cur.spritegroups[groupid]);
584 }
585 }
586
587 uint16_t groupid = buf.ReadWord();
588 if (!IsValidGroupID(groupid, "RoadStopMapSpriteGroup")) return;
589
590 for (auto &roadstop : roadstops) {
591 RoadStopSpec *roadstopspec = roadstop >= _cur.grffile->roadstops.size() ? nullptr : _cur.grffile->roadstops[roadstop].get();
592
593 if (roadstopspec == nullptr) {
594 GrfMsg(1, "RoadStopMapSpriteGroup: Road stop {} undefined, skipping.", roadstop);
595 continue;
596 }
597
598 if (roadstopspec->grf_prop.HasGrfFile()) {
599 GrfMsg(1, "RoadStopMapSpriteGroup: Road stop {} mapped multiple times, skipping", roadstop);
600 continue;
601 }
602
603 roadstopspec->grf_prop.SetSpriteGroup(SpriteGroupCargo::SG_DEFAULT, _cur.spritegroups[groupid]);
604 roadstopspec->grf_prop.SetGRFFile(_cur.grffile);
605 roadstopspec->grf_prop.local_id = roadstop;
606 RoadStopClass::Assign(roadstopspec);
607 }
608}
609
610static void BadgeMapSpriteGroup(ByteReader &buf, uint8_t idcount)
611{
612 if (_cur.grffile->badge_map.empty()) {
613 GrfMsg(1, "BadgeMapSpriteGroup: No badges defined, skipping");
614 return;
615 }
616
617 std::vector<uint16_t> local_ids;
618 local_ids.reserve(idcount);
619 for (uint i = 0; i < idcount; i++) {
620 local_ids.push_back(buf.ReadExtendedByte());
621 }
622
623 uint8_t cidcount = buf.ReadByte();
624 for (uint c = 0; c < cidcount; c++) {
625 uint8_t ctype = buf.ReadByte();
626 uint16_t groupid = buf.ReadWord();
627 if (!IsValidGroupID(groupid, "BadgeMapSpriteGroup")) continue;
628
629 if (ctype >= GSF_END) continue;
630
631 for (const auto &local_id : local_ids) {
632 auto found = _cur.grffile->badge_map.find(local_id);
633 if (found == std::end(_cur.grffile->badge_map)) {
634 GrfMsg(1, "BadgeMapSpriteGroup: Badge {} undefined, skipping", local_id);
635 continue;
636 }
637
638 auto &badge = *GetBadge(found->second);
639 badge.grf_prop.SetSpriteGroup(ctype, _cur.spritegroups[groupid]);
640 }
641 }
642
643 uint16_t groupid = buf.ReadWord();
644 if (!IsValidGroupID(groupid, "BadgeMapSpriteGroup")) return;
645
646 for (auto &local_id : local_ids) {
647 auto found = _cur.grffile->badge_map.find(local_id);
648 if (found == std::end(_cur.grffile->badge_map)) {
649 GrfMsg(1, "BadgeMapSpriteGroup: Badge {} undefined, skipping", local_id);
650 continue;
651 }
652
653 auto &badge = *GetBadge(found->second);
654 badge.grf_prop.SetSpriteGroup(GSF_END, _cur.spritegroups[groupid]);
655 badge.grf_prop.SetGRFFile(_cur.grffile);
656 badge.grf_prop.local_id = local_id;
657 }
658}
659
660/* Action 0x03 */
661static void FeatureMapSpriteGroup(ByteReader &buf)
662{
663 /* <03> <feature> <n-id> <ids>... <num-cid> [<cargo-type> <cid>]... <def-cid>
664 * id-list := [<id>] [id-list]
665 * cargo-list := <cargo-type> <cid> [cargo-list]
666 *
667 * B feature see action 0
668 * B n-id bits 0-6: how many IDs this definition applies to
669 * bit 7: if set, this is a wagon override definition (see below)
670 * E ids the IDs for which this definition applies
671 * B num-cid number of cargo IDs (sprite group IDs) in this definition
672 * can be zero, in that case the def-cid is used always
673 * B cargo-type type of this cargo type (e.g. mail=2, wood=7, see below)
674 * W cid cargo ID (sprite group ID) for this type of cargo
675 * W def-cid default cargo ID (sprite group ID) */
676
677 uint8_t feature = buf.ReadByte();
678 uint8_t idcount = buf.ReadByte();
679
680 if (feature >= GSF_END) {
681 GrfMsg(1, "FeatureMapSpriteGroup: Unsupported feature 0x{:02X}, skipping", feature);
682 return;
683 }
684
685 /* If idcount is zero, this is a feature callback */
686 if (idcount == 0) {
687 /* Skip number of cargo ids? */
688 buf.ReadByte();
689 uint16_t groupid = buf.ReadWord();
690 if (!IsValidGroupID(groupid, "FeatureMapSpriteGroup")) return;
691
692 GrfMsg(6, "FeatureMapSpriteGroup: Adding generic feature callback for feature 0x{:02X}", feature);
693
694 AddGenericCallback(feature, _cur.grffile, _cur.spritegroups[groupid]);
695 return;
696 }
697
698 /* Mark the feature as used by the grf (generic callbacks do not count) */
699 SetBit(_cur.grffile->grf_features, feature);
700
701 GrfMsg(6, "FeatureMapSpriteGroup: Feature 0x{:02X}, {} ids", feature, idcount);
702
703 switch (feature) {
704 case GSF_TRAINS:
705 case GSF_ROADVEHICLES:
706 case GSF_SHIPS:
707 case GSF_AIRCRAFT:
708 VehicleMapSpriteGroup(buf, feature, idcount);
709 return;
710
711 case GSF_CANALS:
712 CanalMapSpriteGroup(buf, idcount);
713 return;
714
715 case GSF_STATIONS:
716 StationMapSpriteGroup(buf, idcount);
717 return;
718
719 case GSF_HOUSES:
720 TownHouseMapSpriteGroup(buf, idcount);
721 return;
722
723 case GSF_INDUSTRIES:
724 IndustryMapSpriteGroup(buf, idcount);
725 return;
726
727 case GSF_INDUSTRYTILES:
728 IndustrytileMapSpriteGroup(buf, idcount);
729 return;
730
731 case GSF_CARGOES:
732 CargoMapSpriteGroup(buf, idcount);
733 return;
734
735 case GSF_AIRPORTS:
736 AirportMapSpriteGroup(buf, idcount);
737 return;
738
739 case GSF_OBJECTS:
740 ObjectMapSpriteGroup(buf, idcount);
741 break;
742
743 case GSF_RAILTYPES:
744 RailTypeMapSpriteGroup(buf, idcount);
745 break;
746
747 case GSF_ROADTYPES:
748 RoadTypeMapSpriteGroup(buf, idcount, RTT_ROAD);
749 break;
750
751 case GSF_TRAMTYPES:
752 RoadTypeMapSpriteGroup(buf, idcount, RTT_TRAM);
753 break;
754
755 case GSF_AIRPORTTILES:
756 AirportTileMapSpriteGroup(buf, idcount);
757 return;
758
759 case GSF_ROADSTOPS:
760 RoadStopMapSpriteGroup(buf, idcount);
761 return;
762
763 case GSF_BADGES:
764 BadgeMapSpriteGroup(buf, idcount);
765 break;
766
767 default:
768 GrfMsg(1, "FeatureMapSpriteGroup: Unsupported feature 0x{:02X}, skipping", feature);
769 return;
770 }
771}
772
773template <> void GrfActionHandler<0x03>::FileScan(ByteReader &) { }
774template <> void GrfActionHandler<0x03>::SafetyScan(ByteReader &buf) { GRFUnsafe(buf); }
775template <> void GrfActionHandler<0x03>::LabelScan(ByteReader &) { }
776template <> void GrfActionHandler<0x03>::Init(ByteReader &) { }
777template <> void GrfActionHandler<0x03>::Reserve(ByteReader &) { }
778template <> void GrfActionHandler<0x03>::Activation(ByteReader &buf) { FeatureMapSpriteGroup(buf); }
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
static constexpr CargoLabel CT_INVALID
Invalid cargo type.
Definition cargo_type.h:72
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:23
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:106
static const CargoType NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:75
Class to read from a NewGRF file.
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).
static void Assign(Tspec *spec)
Assign a spec to one of the classes.
This struct contains all the info that is needed to draw and construct tracks.
Definition rail.h:118
const SpriteGroup * group[RTSG_END]
Sprite groups for resolving sprites.
Definition rail.h:272
const GRFFile * grffile[RTSG_END]
NewGRF providing the Action3 for the railtype.
Definition rail.h:267
const SpriteGroup * group[ROTSG_END]
Sprite groups for resolving sprites.
Definition road.h:183
const GRFFile * grffile[ROTSG_END]
NewGRF providing the Action3 for the roadtype.
Definition road.h:178
static constexpr CargoType SG_PURCHASE
Used in purchase lists before an item exists.
static constexpr CargoType SG_DEFAULT
Default type used when no more-specific cargo matches.
static constexpr CargoType SG_DEFAULT_NA
Used only by stations and roads when no more-specific cargo matches.
std::span< const CargoLabel > GetCargoTranslationTable(const GRFFile &grffile)
Get the cargo translation table to use for the given GRF file.
Definition newgrf.cpp:508
void GRFUnsafe(ByteReader &)
Set the current NewGRF as unsafe for static use.
Definition newgrf.cpp:365
Engine * GetNewEngine(const GRFFile *file, VehicleType type, uint16_t internal_id, bool static_access)
Returns the engine associated to a certain internal_id, resp.
Definition newgrf.cpp:207
Badge * GetBadge(BadgeID index)
Get a badge if it exists.
NewGRF buffer reader definition.
std::array< WaterFeature, CF_END > _water_feature
Table of canal 'feature' sprite groups.
void SetEngineGRF(EngineID engine, const GRFFile *file)
Tie a GRFFile entry to an engine, to allow us to retrieve GRF parameters etc during a game.
void AddGenericCallback(uint8_t feature, const GRFFile *file, const SpriteGroup *group)
Add a generic feature callback sprite group to the appropriate feature list.
NewGRF internal processing state.
@ CIR_INVALID_ID
Attempt to modify an invalid ID.
static constexpr uint MAX_SPRITEGROUP
Maximum GRF-local ID for a spritegroup.
NewGRF internal processing state for vehicles.
@ RAILTYPE_END
Used for iterations.
Definition rail_type.h:31
@ INVALID_RAILTYPE
Flag for invalid railtype.
Definition rail_type.h:32
@ INVALID_ROADTYPE
flag for invalid roadtype
Definition road_type.h:28
@ ROADTYPE_END
Used for iterations.
Definition road_type.h:27
Defines the data structure for an airport.
struct GRFFileProps grf_prop
Properties related to the grf file.
Defines the data structure of each individual tile of an airport.
GRFFileProps grf_prop
properties related the the grf file
Specification of a cargo type.
Definition cargotype.h:74
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:137
const struct GRFFile * grffile
NewGRF where group belongs to.
Definition cargotype.h:99
void SetSpriteGroup(size_t index, const struct SpriteGroup *spritegroup)
Set the SpriteGroup at the specified index.
uint16_t local_id
id defined by the grf file for this entity
void SetGRFFile(const struct GRFFile *grffile)
Set the NewGRF file, and its grfid, associated with grf props.
bool HasGrfFile() const
Test if this entity was introduced by NewGRF.
uint32_t grf_features
Bitset of GrfSpecFeature the grf uses.
Definition newgrf.h:156
std::vector< CargoLabel > cargo_list
Cargo translation table (local ID -> label)
Definition newgrf.h:134
GRF action handler.
GRFFile * grffile
Currently processed GRF file.
GRFFileProps grf_prop
Properties related the the grf file.
Definition house.h:109
Defines the data structure for constructing industry.
GRFFileProps grf_prop
properties related to the grf file
Defines the data structure of each individual tile of an industry.
GRFFileProps grf_prop
properties related to the grf file
Allow incrementing of ObjectClassID variables.
FixedGRFFileProps< 2 > grf_prop
Properties related the the grf file.
Tindex index
Index of this pool item.
Road stop specification.
VariableGRFFileProps grf_prop
Properties related the the grf file.
Station specification.
VariableGRFFileProps grf_prop
Properties related the the grf file.
void SetSpriteGroup(size_t index, const struct SpriteGroup *spritegroup)
Set the SpriteGroup at the specified index.
VehicleType
Available vehicle types.