OpenTTD Source 20241222-master-gc72542431a
newgrf.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 "core/backup_type.hpp"
14#include "debug.h"
15#include "fileio_func.h"
16#include "engine_func.h"
17#include "engine_base.h"
18#include "bridge.h"
19#include "town.h"
20#include "newgrf_engine.h"
21#include "newgrf_text.h"
22#include "fontcache.h"
23#include "currency.h"
24#include "landscape.h"
25#include "newgrf_cargo.h"
26#include "newgrf_house.h"
27#include "newgrf_sound.h"
28#include "newgrf_station.h"
29#include "industrytype.h"
30#include "industry_map.h"
31#include "newgrf_act5.h"
32#include "newgrf_canal.h"
33#include "newgrf_townname.h"
34#include "newgrf_industries.h"
35#include "newgrf_airporttiles.h"
36#include "newgrf_airport.h"
37#include "newgrf_object.h"
38#include "rev.h"
39#include "fios.h"
40#include "strings_func.h"
43#include "string_func.h"
44#include "network/core/config.h"
45#include "smallmap_gui.h"
46#include "genworld.h"
47#include "error.h"
48#include "error_func.h"
49#include "vehicle_func.h"
50#include "language.h"
51#include "vehicle_base.h"
52#include "road.h"
53#include "newgrf_roadstop.h"
54
55#include "table/strings.h"
57
58#include "safeguards.h"
59
60/* TTDPatch extended GRF format codec
61 * (c) Petr Baudis 2004 (GPL'd)
62 * Changes by Florian octo Forster are (c) by the OpenTTD development team.
63 *
64 * Contains portions of documentation by TTDPatch team.
65 * Thanks especially to Josef Drexler for the documentation as well as a lot
66 * of help at #tycoon. Also thanks to Michael Blunck for his GRF files which
67 * served as subject to the initial testing of this codec. */
68
70static std::vector<GRFFile *> _grf_files;
71
72const std::vector<GRFFile *> &GetAllGRFFiles()
73{
74 return _grf_files;
75}
76
79
81static uint32_t _ttdpatch_flags[8];
82
85
86static const uint MAX_SPRITEGROUP = UINT8_MAX;
87
90private:
96
98 std::map<uint, SpriteSet> spritesets[GSF_END];
99
100public:
101 /* Global state */
102 GrfLoadingStage stage;
104
105 /* Local state in the file */
109 uint32_t nfo_line;
110
111 /* Kind of return values when processing certain actions */
113
114 /* Currently referenceable spritegroups */
115 const SpriteGroup *spritegroups[MAX_SPRITEGROUP + 1];
116
119 {
120 this->nfo_line = 0;
121 this->skip_sprites = 0;
122
123 for (uint i = 0; i < GSF_END; i++) {
124 this->spritesets[i].clear();
125 }
126
127 memset(this->spritegroups, 0, sizeof(this->spritegroups));
128 }
129
138 void AddSpriteSets(uint8_t feature, SpriteID first_sprite, uint first_set, uint numsets, uint numents)
139 {
140 assert(feature < GSF_END);
141 for (uint i = 0; i < numsets; i++) {
142 SpriteSet &set = this->spritesets[feature][first_set + i];
143 set.sprite = first_sprite + i * numents;
144 set.num_sprites = numents;
145 }
146 }
147
154 bool HasValidSpriteSets(uint8_t feature) const
155 {
156 assert(feature < GSF_END);
157 return !this->spritesets[feature].empty();
158 }
159
167 bool IsValidSpriteSet(uint8_t feature, uint set) const
168 {
169 assert(feature < GSF_END);
170 return this->spritesets[feature].find(set) != this->spritesets[feature].end();
171 }
172
179 SpriteID GetSprite(uint8_t feature, uint set) const
180 {
181 assert(IsValidSpriteSet(feature, set));
182 return this->spritesets[feature].find(set)->second.sprite;
183 }
184
191 uint GetNumEnts(uint8_t feature, uint set) const
192 {
193 assert(IsValidSpriteSet(feature, set));
194 return this->spritesets[feature].find(set)->second.num_sprites;
195 }
196};
197
198static GrfProcessingState _cur;
199
200
207template <VehicleType T>
208static inline bool IsValidNewGRFImageIndex(uint8_t image_index)
209{
210 return image_index == 0xFD || IsValidImageIndex<T>(image_index);
211}
212
214
217protected:
218 uint8_t *data;
219 uint8_t *end;
220
221public:
222 ByteReader(uint8_t *data, uint8_t *end) : data(data), end(end) { }
223
224 inline uint8_t *ReadBytes(size_t size)
225 {
226 if (data + size >= end) {
227 /* Put data at the end, as would happen if every byte had been individually read. */
228 data = end;
229 throw OTTDByteReaderSignal();
230 }
231
232 uint8_t *ret = data;
233 data += size;
234 return ret;
235 }
236
237 inline uint8_t ReadByte()
238 {
239 if (data < end) return *(data)++;
240 throw OTTDByteReaderSignal();
241 }
242
243 uint16_t ReadWord()
244 {
245 uint16_t val = ReadByte();
246 return val | (ReadByte() << 8);
247 }
248
249 uint16_t ReadExtendedByte()
250 {
251 uint16_t val = ReadByte();
252 return val == 0xFF ? ReadWord() : val;
253 }
254
255 uint32_t ReadDWord()
256 {
257 uint32_t val = ReadWord();
258 return val | (ReadWord() << 16);
259 }
260
261 uint32_t PeekDWord()
262 {
263 AutoRestoreBackup backup(this->data, this->data);
264 return this->ReadDWord();
265 }
266
267 uint32_t ReadVarSize(uint8_t size)
268 {
269 switch (size) {
270 case 1: return ReadByte();
271 case 2: return ReadWord();
272 case 4: return ReadDWord();
273 default:
274 NOT_REACHED();
275 return 0;
276 }
277 }
278
279 std::string_view ReadString()
280 {
281 char *string = reinterpret_cast<char *>(data);
282 size_t string_length = ttd_strnlen(string, Remaining());
283
284 /* Skip past the terminating NUL byte if it is present, but not more than remaining. */
285 Skip(std::min(string_length + 1, Remaining()));
286
287 return std::string_view(string, string_length);
288 }
289
290 inline size_t Remaining() const
291 {
292 return end - data;
293 }
294
295 inline bool HasData(size_t count = 1) const
296 {
297 return data + count <= end;
298 }
299
300 inline void Skip(size_t len)
301 {
302 data += len;
303 /* It is valid to move the buffer to exactly the end of the data,
304 * as there may not be any more data read. */
305 if (data > end) throw OTTDByteReaderSignal();
306 }
307};
308
309typedef void (*SpecialSpriteHandler)(ByteReader &buf);
310
312static const uint NUM_STATIONS_PER_GRF = UINT16_MAX - 1;
313
322
326 RailTypeLabel railtypelabel;
327 uint8_t roadtramtype;
330 uint8_t rv_max_speed;
331 CargoTypes ctt_include_mask;
332 CargoTypes ctt_exclude_mask;
333
338 void UpdateRefittability(bool non_empty)
339 {
340 if (non_empty) {
341 this->refittability = NONEMPTY;
342 } else if (this->refittability == UNSET) {
343 this->refittability = EMPTY;
344 }
345 }
346};
347
348static std::vector<GRFTempEngineData> _gted;
349
354static uint32_t _grm_engines[256];
355
357static uint32_t _grm_cargoes[NUM_CARGO * 2];
358
360 uint32_t grfid;
361 uint32_t nfoline;
362
363 GRFLocation(uint32_t grfid, uint32_t nfoline) : grfid(grfid), nfoline(nfoline) { }
364
365 bool operator<(const GRFLocation &other) const
366 {
367 return this->grfid < other.grfid || (this->grfid == other.grfid && this->nfoline < other.nfoline);
368 }
369
370 bool operator == (const GRFLocation &other) const
371 {
372 return this->grfid == other.grfid && this->nfoline == other.nfoline;
373 }
374};
375
376static std::map<GRFLocation, std::pair<SpriteID, uint16_t>> _grm_sprites;
377typedef std::map<GRFLocation, std::vector<uint8_t>> GRFLineToSpriteOverride;
378static GRFLineToSpriteOverride _grf_line_to_action6_sprite_override;
379
390void GrfMsgI(int severity, const std::string &msg)
391{
392 Debug(grf, severity, "[{}:{}] {}", _cur.grfconfig->filename, _cur.nfo_line, msg);
393}
394
400static GRFFile *GetFileByGRFID(uint32_t grfid)
401{
402 for (GRFFile * const file : _grf_files) {
403 if (file->grfid == grfid) return file;
404 }
405 return nullptr;
406}
407
413static GRFFile *GetFileByFilename(const std::string &filename)
414{
415 for (GRFFile * const file : _grf_files) {
416 if (file->filename == filename) return file;
417 }
418 return nullptr;
419}
420
423{
424 gf->labels.clear();
425}
426
433static GRFError *DisableGrf(StringID message = STR_NULL, GRFConfig *config = nullptr)
434{
435 GRFFile *file;
436 if (config != nullptr) {
437 file = GetFileByGRFID(config->ident.grfid);
438 } else {
439 config = _cur.grfconfig;
440 file = _cur.grffile;
441 }
442
443 config->status = GCS_DISABLED;
444 if (file != nullptr) ClearTemporaryNewGRFData(file);
445 if (config == _cur.grfconfig) _cur.skip_sprites = -1;
446
447 if (message == STR_NULL) return nullptr;
448
449 config->error = {STR_NEWGRF_ERROR_MSG_FATAL, message};
450 if (config == _cur.grfconfig) config->error->param_value[0] = _cur.nfo_line;
451 return &config->error.value();
452}
453
458 uint32_t grfid;
460 std::function<void(StringID)> func;
461
462 StringIDMapping(uint32_t grfid, StringID source, std::function<void(StringID)> &&func) : grfid(grfid), source(source), func(std::move(func)) { }
463};
464
466static std::vector<StringIDMapping> _string_to_grf_mapping;
467
473static void AddStringForMapping(StringID source, std::function<void(StringID)> &&func)
474{
475 func(STR_UNDEFINED);
476 _string_to_grf_mapping.emplace_back(_cur.grffile->grfid, source, std::move(func));
477}
478
484static void AddStringForMapping(StringID source, StringID *target)
485{
486 AddStringForMapping(source, [target](StringID str) { *target = str; });
487}
488
497{
498 /* StringID table for TextIDs 0x4E->0x6D */
499 static const StringID units_volume[] = {
500 STR_ITEMS, STR_PASSENGERS, STR_TONS, STR_BAGS,
501 STR_LITERS, STR_ITEMS, STR_CRATES, STR_TONS,
502 STR_TONS, STR_TONS, STR_TONS, STR_BAGS,
503 STR_TONS, STR_TONS, STR_TONS, STR_BAGS,
504 STR_TONS, STR_TONS, STR_BAGS, STR_LITERS,
505 STR_TONS, STR_LITERS, STR_TONS, STR_ITEMS,
506 STR_BAGS, STR_LITERS, STR_TONS, STR_ITEMS,
507 STR_TONS, STR_ITEMS, STR_LITERS, STR_ITEMS
508 };
509
510 /* A string straight from a NewGRF; this was already translated by MapGRFStringID(). */
511 assert(!IsInsideMM(str, 0xD000, 0xD7FF));
512
513#define TEXTID_TO_STRINGID(begin, end, stringid, stringend) \
514 static_assert(stringend - stringid == end - begin); \
515 if (str >= begin && str <= end) return str + (stringid - begin)
516
517 /* We have some changes in our cargo strings, resulting in some missing. */
518 TEXTID_TO_STRINGID(0x000E, 0x002D, STR_CARGO_PLURAL_NOTHING, STR_CARGO_PLURAL_FIZZY_DRINKS);
519 TEXTID_TO_STRINGID(0x002E, 0x004D, STR_CARGO_SINGULAR_NOTHING, STR_CARGO_SINGULAR_FIZZY_DRINK);
520 if (str >= 0x004E && str <= 0x006D) return units_volume[str - 0x004E];
521 TEXTID_TO_STRINGID(0x006E, 0x008D, STR_QUANTITY_NOTHING, STR_QUANTITY_FIZZY_DRINKS);
522 TEXTID_TO_STRINGID(0x008E, 0x00AD, STR_ABBREV_NOTHING, STR_ABBREV_FIZZY_DRINKS);
523 TEXTID_TO_STRINGID(0x00D1, 0x00E0, STR_COLOUR_DARK_BLUE, STR_COLOUR_WHITE);
524
525 /* Map building names according to our lang file changes. There are several
526 * ranges of house ids, all of which need to be remapped to allow newgrfs
527 * to use original house names. */
528 TEXTID_TO_STRINGID(0x200F, 0x201F, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, STR_TOWN_BUILDING_NAME_OLD_HOUSES_1);
529 TEXTID_TO_STRINGID(0x2036, 0x2041, STR_TOWN_BUILDING_NAME_COTTAGES_1, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1);
530 TEXTID_TO_STRINGID(0x2059, 0x205C, STR_TOWN_BUILDING_NAME_IGLOO_1, STR_TOWN_BUILDING_NAME_PIGGY_BANK_1);
531
532 /* Same thing for industries */
533 TEXTID_TO_STRINGID(0x4802, 0x4826, STR_INDUSTRY_NAME_COAL_MINE, STR_INDUSTRY_NAME_SUGAR_MINE);
534 TEXTID_TO_STRINGID(0x482D, 0x482E, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_PLANTED);
535 TEXTID_TO_STRINGID(0x4832, 0x4834, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_CLOSURE_LACK_OF_TREES);
536 TEXTID_TO_STRINGID(0x4835, 0x4838, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM);
537 TEXTID_TO_STRINGID(0x4839, 0x483A, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM);
538
539 switch (str) {
540 case 0x4830: return STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY;
541 case 0x4831: return STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED;
542 case 0x483B: return STR_ERROR_CAN_ONLY_BE_POSITIONED;
543 }
544#undef TEXTID_TO_STRINGID
545
546 if (str == STR_NULL) return STR_EMPTY;
547
548 Debug(grf, 0, "Unknown StringID 0x{:04X} remapped to STR_EMPTY. Please open a Feature Request if you need it", str);
549
550 return STR_EMPTY;
551}
552
560StringID MapGRFStringID(uint32_t grfid, StringID str)
561{
562 if (IsInsideMM(str, 0xD800, 0x10000)) {
563 /* General text provided by NewGRF.
564 * In the specs this is called the 0xDCxx range (misc persistent texts),
565 * but we meanwhile extended the range to 0xD800-0xFFFF.
566 * Note: We are not involved in the "persistent" business, since we do not store
567 * any NewGRF strings in savegames. */
568 return GetGRFStringID(grfid, str);
569 } else if (IsInsideMM(str, 0xD000, 0xD800)) {
570 /* Callback text provided by NewGRF.
571 * In the specs this is called the 0xD0xx range (misc graphics texts).
572 * These texts can be returned by various callbacks.
573 *
574 * Due to how TTDP implements the GRF-local- to global-textid translation
575 * texts included via 0x80 or 0x81 control codes have to add 0x400 to the textid.
576 * We do not care about that difference and just mask out the 0x400 bit.
577 */
578 str &= ~0x400;
579 return GetGRFStringID(grfid, str);
580 } else {
581 /* The NewGRF wants to include/reference an original TTD string.
582 * Try our best to find an equivalent one. */
584 }
585}
586
587static std::map<uint32_t, uint32_t> _grf_id_overrides;
588
594static void SetNewGRFOverride(uint32_t source_grfid, uint32_t target_grfid)
595{
596 if (target_grfid == 0) {
597 _grf_id_overrides.erase(source_grfid);
598 GrfMsg(5, "SetNewGRFOverride: Removed override of 0x{:X}", BSWAP32(source_grfid));
599 } else {
600 _grf_id_overrides[source_grfid] = target_grfid;
601 GrfMsg(5, "SetNewGRFOverride: Added override of 0x{:X} to 0x{:X}", BSWAP32(source_grfid), BSWAP32(target_grfid));
602 }
603}
604
610{
611 auto found = _grf_id_overrides.find(_cur.grffile->grfid);
612 if (found != std::end(_grf_id_overrides)) {
613 GRFFile *grffile = GetFileByGRFID(found->second);
614 if (grffile != nullptr) return grffile;
615 }
616 return nullptr;
617}
618
627static Engine *GetNewEngine(const GRFFile *file, VehicleType type, uint16_t internal_id, bool static_access = false)
628{
629 /* Hack for add-on GRFs that need to modify another GRF's engines. This lets
630 * them use the same engine slots. */
631 uint32_t scope_grfid = INVALID_GRFID; // If not using dynamic_engines, all newgrfs share their ID range
633 /* If dynamic_engies is enabled, there can be multiple independent ID ranges. */
634 scope_grfid = file->grfid;
635 if (auto it = _grf_id_overrides.find(file->grfid); it != std::end(_grf_id_overrides)) {
636 scope_grfid = it->second;
637 const GRFFile *grf_match = GetFileByGRFID(scope_grfid);
638 if (grf_match == nullptr) {
639 GrfMsg(5, "Tried mapping from GRFID {:x} to {:x} but target is not loaded", BSWAP32(file->grfid), BSWAP32(scope_grfid));
640 } else {
641 GrfMsg(5, "Mapping from GRFID {:x} to {:x}", BSWAP32(file->grfid), BSWAP32(scope_grfid));
642 }
643 }
644
645 /* Check if the engine is registered in the override manager */
646 EngineID engine = _engine_mngr.GetID(type, internal_id, scope_grfid);
647 if (engine != INVALID_ENGINE) {
648 Engine *e = Engine::Get(engine);
649 if (!e->grf_prop.HasGrfFile()) {
650 e->grf_prop.grfid = file->grfid;
651 e->grf_prop.grffile = file;
652 }
653 return e;
654 }
655 }
656
657 /* Check if there is an unreserved slot */
658 EngineID engine = _engine_mngr.UseUnreservedID(type, internal_id, scope_grfid, static_access);
659 if (engine != INVALID_ENGINE) {
660 Engine *e = Engine::Get(engine);
661
662 if (!e->grf_prop.HasGrfFile()) {
663 e->grf_prop.grfid = file->grfid;
664 e->grf_prop.grffile = file;
665 GrfMsg(5, "Replaced engine at index {} for GRFID {:x}, type {}, index {}", e->index, BSWAP32(file->grfid), type, internal_id);
666 }
667
668 return e;
669 }
670
671 if (static_access) return nullptr;
672
674 GrfMsg(0, "Can't allocate any more engines");
675 return nullptr;
676 }
677
678 size_t engine_pool_size = Engine::GetPoolSize();
679
680 /* ... it's not, so create a new one based off an existing engine */
681 Engine *e = new Engine(type, internal_id);
682 e->grf_prop.grfid = file->grfid;
683 e->grf_prop.grffile = file;
684
685 /* Reserve the engine slot */
686 _engine_mngr.SetID(type, internal_id, scope_grfid, std::min<uint8_t>(internal_id, _engine_counts[type]), e->index);
687
688 if (engine_pool_size != Engine::GetPoolSize()) {
689 /* Resize temporary engine data ... */
690 _gted.resize(Engine::GetPoolSize());
691 }
692 if (type == VEH_TRAIN) {
693 _gted[e->index].railtypelabel = GetRailTypeInfo(e->u.rail.railtype)->label;
694 }
695
696 GrfMsg(5, "Created new engine at index {} for GRFID {:x}, type {}, index {}", e->index, BSWAP32(file->grfid), type, internal_id);
697
698 return e;
699}
700
711EngineID GetNewEngineID(const GRFFile *file, VehicleType type, uint16_t internal_id)
712{
713 uint32_t scope_grfid = INVALID_GRFID; // If not using dynamic_engines, all newgrfs share their ID range
715 scope_grfid = file->grfid;
716 if (auto it = _grf_id_overrides.find(file->grfid); it != std::end(_grf_id_overrides)) {
717 scope_grfid = it->second;
718 }
719 }
720
721 return _engine_mngr.GetID(type, internal_id, scope_grfid);
722}
723
728static void MapSpriteMappingRecolour(PalSpriteID *grf_sprite)
729{
730 if (HasBit(grf_sprite->pal, 14)) {
731 ClrBit(grf_sprite->pal, 14);
733 }
734
735 if (HasBit(grf_sprite->sprite, 14)) {
736 ClrBit(grf_sprite->sprite, 14);
738 }
739
740 if (HasBit(grf_sprite->sprite, 15)) {
741 ClrBit(grf_sprite->sprite, 15);
743 }
744}
745
759static TileLayoutFlags ReadSpriteLayoutSprite(ByteReader &buf, bool read_flags, bool invert_action1_flag, bool use_cur_spritesets, int feature, PalSpriteID *grf_sprite, uint16_t *max_sprite_offset = nullptr, uint16_t *max_palette_offset = nullptr)
760{
761 grf_sprite->sprite = buf.ReadWord();
762 grf_sprite->pal = buf.ReadWord();
763 TileLayoutFlags flags = read_flags ? (TileLayoutFlags)buf.ReadWord() : TLF_NOTHING;
764
765 MapSpriteMappingRecolour(grf_sprite);
766
767 bool custom_sprite = HasBit(grf_sprite->pal, 15) != invert_action1_flag;
768 ClrBit(grf_sprite->pal, 15);
769 if (custom_sprite) {
770 /* Use sprite from Action 1 */
771 uint index = GB(grf_sprite->sprite, 0, 14);
772 if (use_cur_spritesets && (!_cur.IsValidSpriteSet(feature, index) || _cur.GetNumEnts(feature, index) == 0)) {
773 GrfMsg(1, "ReadSpriteLayoutSprite: Spritelayout uses undefined custom spriteset {}", index);
774 grf_sprite->sprite = SPR_IMG_QUERY;
775 grf_sprite->pal = PAL_NONE;
776 } else {
777 SpriteID sprite = use_cur_spritesets ? _cur.GetSprite(feature, index) : index;
778 if (max_sprite_offset != nullptr) *max_sprite_offset = use_cur_spritesets ? _cur.GetNumEnts(feature, index) : UINT16_MAX;
779 SB(grf_sprite->sprite, 0, SPRITE_WIDTH, sprite);
781 }
782 } else if ((flags & TLF_SPRITE_VAR10) && !(flags & TLF_SPRITE_REG_FLAGS)) {
783 GrfMsg(1, "ReadSpriteLayoutSprite: Spritelayout specifies var10 value for non-action-1 sprite");
784 DisableGrf(STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT);
785 return flags;
786 }
787
788 if (flags & TLF_CUSTOM_PALETTE) {
789 /* Use palette from Action 1 */
790 uint index = GB(grf_sprite->pal, 0, 14);
791 if (use_cur_spritesets && (!_cur.IsValidSpriteSet(feature, index) || _cur.GetNumEnts(feature, index) == 0)) {
792 GrfMsg(1, "ReadSpriteLayoutSprite: Spritelayout uses undefined custom spriteset {} for 'palette'", index);
793 grf_sprite->pal = PAL_NONE;
794 } else {
795 SpriteID sprite = use_cur_spritesets ? _cur.GetSprite(feature, index) : index;
796 if (max_palette_offset != nullptr) *max_palette_offset = use_cur_spritesets ? _cur.GetNumEnts(feature, index) : UINT16_MAX;
797 SB(grf_sprite->pal, 0, SPRITE_WIDTH, sprite);
799 }
800 } else if ((flags & TLF_PALETTE_VAR10) && !(flags & TLF_PALETTE_REG_FLAGS)) {
801 GrfMsg(1, "ReadSpriteLayoutRegisters: Spritelayout specifies var10 value for non-action-1 palette");
802 DisableGrf(STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT);
803 return flags;
804 }
805
806 return flags;
807}
808
817static void ReadSpriteLayoutRegisters(ByteReader &buf, TileLayoutFlags flags, bool is_parent, NewGRFSpriteLayout *dts, uint index)
818{
819 if (!(flags & TLF_DRAWING_FLAGS)) return;
820
821 if (dts->registers == nullptr) dts->AllocateRegisters();
822 TileLayoutRegisters &regs = const_cast<TileLayoutRegisters&>(dts->registers[index]);
823 regs.flags = flags & TLF_DRAWING_FLAGS;
824
825 if (flags & TLF_DODRAW) regs.dodraw = buf.ReadByte();
826 if (flags & TLF_SPRITE) regs.sprite = buf.ReadByte();
827 if (flags & TLF_PALETTE) regs.palette = buf.ReadByte();
828
829 if (is_parent) {
830 if (flags & TLF_BB_XY_OFFSET) {
831 regs.delta.parent[0] = buf.ReadByte();
832 regs.delta.parent[1] = buf.ReadByte();
833 }
834 if (flags & TLF_BB_Z_OFFSET) regs.delta.parent[2] = buf.ReadByte();
835 } else {
836 if (flags & TLF_CHILD_X_OFFSET) regs.delta.child[0] = buf.ReadByte();
837 if (flags & TLF_CHILD_Y_OFFSET) regs.delta.child[1] = buf.ReadByte();
838 }
839
840 if (flags & TLF_SPRITE_VAR10) {
841 regs.sprite_var10 = buf.ReadByte();
842 if (regs.sprite_var10 > TLR_MAX_VAR10) {
843 GrfMsg(1, "ReadSpriteLayoutRegisters: Spritelayout specifies var10 ({}) exceeding the maximal allowed value {}", regs.sprite_var10, TLR_MAX_VAR10);
844 DisableGrf(STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT);
845 return;
846 }
847 }
848
849 if (flags & TLF_PALETTE_VAR10) {
850 regs.palette_var10 = buf.ReadByte();
851 if (regs.palette_var10 > TLR_MAX_VAR10) {
852 GrfMsg(1, "ReadSpriteLayoutRegisters: Spritelayout specifies var10 ({}) exceeding the maximal allowed value {}", regs.palette_var10, TLR_MAX_VAR10);
853 DisableGrf(STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT);
854 return;
855 }
856 }
857}
858
870static bool ReadSpriteLayout(ByteReader &buf, uint num_building_sprites, bool use_cur_spritesets, uint8_t feature, bool allow_var10, bool no_z_position, NewGRFSpriteLayout *dts)
871{
872 bool has_flags = HasBit(num_building_sprites, 6);
873 ClrBit(num_building_sprites, 6);
874 TileLayoutFlags valid_flags = TLF_KNOWN_FLAGS;
875 if (!allow_var10) valid_flags &= ~TLF_VAR10_FLAGS;
876 dts->Allocate(num_building_sprites); // allocate before reading groundsprite flags
877
878 std::vector<uint16_t> max_sprite_offset(num_building_sprites + 1, 0);
879 std::vector<uint16_t> max_palette_offset(num_building_sprites + 1, 0);
880
881 /* Groundsprite */
882 TileLayoutFlags flags = ReadSpriteLayoutSprite(buf, has_flags, false, use_cur_spritesets, feature, &dts->ground, max_sprite_offset.data(), max_palette_offset.data());
883 if (_cur.skip_sprites < 0) return true;
884
885 if (flags & ~(valid_flags & ~TLF_NON_GROUND_FLAGS)) {
886 GrfMsg(1, "ReadSpriteLayout: Spritelayout uses invalid flag 0x{:X} for ground sprite", flags & ~(valid_flags & ~TLF_NON_GROUND_FLAGS));
887 DisableGrf(STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT);
888 return true;
889 }
890
891 ReadSpriteLayoutRegisters(buf, flags, false, dts, 0);
892 if (_cur.skip_sprites < 0) return true;
893
894 for (uint i = 0; i < num_building_sprites; i++) {
895 DrawTileSeqStruct *seq = const_cast<DrawTileSeqStruct*>(&dts->seq[i]);
896
897 flags = ReadSpriteLayoutSprite(buf, has_flags, false, use_cur_spritesets, feature, &seq->image, max_sprite_offset.data() + i + 1, max_palette_offset.data() + i + 1);
898 if (_cur.skip_sprites < 0) return true;
899
900 if (flags & ~valid_flags) {
901 GrfMsg(1, "ReadSpriteLayout: Spritelayout uses unknown flag 0x{:X}", flags & ~valid_flags);
902 DisableGrf(STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT);
903 return true;
904 }
905
906 seq->delta_x = buf.ReadByte();
907 seq->delta_y = buf.ReadByte();
908
909 if (!no_z_position) seq->delta_z = buf.ReadByte();
910
911 if (seq->IsParentSprite()) {
912 seq->size_x = buf.ReadByte();
913 seq->size_y = buf.ReadByte();
914 seq->size_z = buf.ReadByte();
915 }
916
917 ReadSpriteLayoutRegisters(buf, flags, seq->IsParentSprite(), dts, i + 1);
918 if (_cur.skip_sprites < 0) return true;
919 }
920
921 /* Check if the number of sprites per spriteset is consistent */
922 bool is_consistent = true;
923 dts->consistent_max_offset = 0;
924 for (uint i = 0; i < num_building_sprites + 1; i++) {
925 if (max_sprite_offset[i] > 0) {
926 if (dts->consistent_max_offset == 0) {
927 dts->consistent_max_offset = max_sprite_offset[i];
928 } else if (dts->consistent_max_offset != max_sprite_offset[i]) {
929 is_consistent = false;
930 break;
931 }
932 }
933 if (max_palette_offset[i] > 0) {
934 if (dts->consistent_max_offset == 0) {
935 dts->consistent_max_offset = max_palette_offset[i];
936 } else if (dts->consistent_max_offset != max_palette_offset[i]) {
937 is_consistent = false;
938 break;
939 }
940 }
941 }
942
943 /* When the Action1 sets are unknown, everything should be 0 (no spriteset usage) or UINT16_MAX (some spriteset usage) */
944 assert(use_cur_spritesets || (is_consistent && (dts->consistent_max_offset == 0 || dts->consistent_max_offset == UINT16_MAX)));
945
946 if (!is_consistent || dts->registers != nullptr) {
947 dts->consistent_max_offset = 0;
948 if (dts->registers == nullptr) dts->AllocateRegisters();
949
950 for (uint i = 0; i < num_building_sprites + 1; i++) {
951 TileLayoutRegisters &regs = const_cast<TileLayoutRegisters&>(dts->registers[i]);
952 regs.max_sprite_offset = max_sprite_offset[i];
953 regs.max_palette_offset = max_palette_offset[i];
954 }
955 }
956
957 return false;
958}
959
963static CargoTypes TranslateRefitMask(uint32_t refit_mask)
964{
965 CargoTypes result = 0;
966 for (uint8_t bit : SetBitIterator(refit_mask)) {
967 CargoID cargo = GetCargoTranslation(bit, _cur.grffile, true);
968 if (IsValidCargoID(cargo)) SetBit(result, cargo);
969 }
970 return result;
971}
972
980static void ConvertTTDBasePrice(uint32_t base_pointer, const char *error_location, Price *index)
981{
982 /* Special value for 'none' */
983 if (base_pointer == 0) {
984 *index = INVALID_PRICE;
985 return;
986 }
987
988 static const uint32_t start = 0x4B34;
989 static const uint32_t size = 6;
990
991 if (base_pointer < start || (base_pointer - start) % size != 0 || (base_pointer - start) / size >= PR_END) {
992 GrfMsg(1, "{}: Unsupported running cost base 0x{:04X}, ignoring", error_location, base_pointer);
993 return;
994 }
995
996 *index = (Price)((base_pointer - start) / size);
997}
998
1007
1008typedef ChangeInfoResult (*VCI_Handler)(uint engine, int numinfo, int prop, ByteReader &buf);
1009
1018{
1019 switch (prop) {
1020 case 0x00: // Introduction date
1022 break;
1023
1024 case 0x02: // Decay speed
1025 ei->decay_speed = buf.ReadByte();
1026 break;
1027
1028 case 0x03: // Vehicle life
1029 ei->lifelength = buf.ReadByte();
1030 break;
1031
1032 case 0x04: // Model life
1033 ei->base_life = buf.ReadByte();
1034 break;
1035
1036 case 0x06: // Climates available
1037 ei->climates = buf.ReadByte();
1038 break;
1039
1040 case PROP_VEHICLE_LOAD_AMOUNT: // 0x07 Loading speed
1041 /* Amount of cargo loaded during a vehicle's "loading tick" */
1042 ei->load_amount = buf.ReadByte();
1043 break;
1044
1045 default:
1046 return CIR_UNKNOWN;
1047 }
1048
1049 return CIR_SUCCESS;
1050}
1051
1060static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader &buf)
1061{
1063
1064 for (int i = 0; i < numinfo; i++) {
1065 Engine *e = GetNewEngine(_cur.grffile, VEH_TRAIN, engine + i);
1066 if (e == nullptr) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles
1067
1068 EngineInfo *ei = &e->info;
1069 RailVehicleInfo *rvi = &e->u.rail;
1070
1071 switch (prop) {
1072 case 0x05: { // Track type
1073 uint8_t tracktype = buf.ReadByte();
1074
1075 if (tracktype < _cur.grffile->railtype_list.size()) {
1076 _gted[e->index].railtypelabel = _cur.grffile->railtype_list[tracktype];
1077 break;
1078 }
1079
1080 switch (tracktype) {
1081 case 0: _gted[e->index].railtypelabel = rvi->engclass >= 2 ? RAILTYPE_LABEL_ELECTRIC : RAILTYPE_LABEL_RAIL; break;
1082 case 1: _gted[e->index].railtypelabel = RAILTYPE_LABEL_MONO; break;
1083 case 2: _gted[e->index].railtypelabel = RAILTYPE_LABEL_MAGLEV; break;
1084 default:
1085 GrfMsg(1, "RailVehicleChangeInfo: Invalid track type {} specified, ignoring", tracktype);
1086 break;
1087 }
1088 break;
1089 }
1090
1091 case 0x08: // AI passenger service
1092 /* Tells the AI that this engine is designed for
1093 * passenger services and shouldn't be used for freight. */
1094 rvi->ai_passenger_only = buf.ReadByte();
1095 break;
1096
1097 case PROP_TRAIN_SPEED: { // 0x09 Speed (1 unit is 1 km-ish/h)
1098 uint16_t speed = buf.ReadWord();
1099 if (speed == 0xFFFF) speed = 0;
1100
1101 rvi->max_speed = speed;
1102 break;
1103 }
1104
1105 case PROP_TRAIN_POWER: // 0x0B Power
1106 rvi->power = buf.ReadWord();
1107
1108 /* Set engine / wagon state based on power */
1109 if (rvi->power != 0) {
1110 if (rvi->railveh_type == RAILVEH_WAGON) {
1111 rvi->railveh_type = RAILVEH_SINGLEHEAD;
1112 }
1113 } else {
1114 rvi->railveh_type = RAILVEH_WAGON;
1115 }
1116 break;
1117
1118 case PROP_TRAIN_RUNNING_COST_FACTOR: // 0x0D Running cost factor
1119 rvi->running_cost = buf.ReadByte();
1120 break;
1121
1122 case 0x0E: // Running cost base
1123 ConvertTTDBasePrice(buf.ReadDWord(), "RailVehicleChangeInfo", &rvi->running_cost_class);
1124 break;
1125
1126 case 0x12: { // Sprite ID
1127 uint8_t spriteid = buf.ReadByte();
1128 uint8_t orig_spriteid = spriteid;
1129
1130 /* TTD sprite IDs point to a location in a 16bit array, but we use it
1131 * as an array index, so we need it to be half the original value. */
1132 if (spriteid < 0xFD) spriteid >>= 1;
1133
1134 if (IsValidNewGRFImageIndex<VEH_TRAIN>(spriteid)) {
1135 rvi->image_index = spriteid;
1136 } else {
1137 GrfMsg(1, "RailVehicleChangeInfo: Invalid Sprite {} specified, ignoring", orig_spriteid);
1138 rvi->image_index = 0;
1139 }
1140 break;
1141 }
1142
1143 case 0x13: { // Dual-headed
1144 uint8_t dual = buf.ReadByte();
1145
1146 if (dual != 0) {
1147 rvi->railveh_type = RAILVEH_MULTIHEAD;
1148 } else {
1149 rvi->railveh_type = rvi->power == 0 ?
1151 }
1152 break;
1153 }
1154
1155 case PROP_TRAIN_CARGO_CAPACITY: // 0x14 Cargo capacity
1156 rvi->capacity = buf.ReadByte();
1157 break;
1158
1159 case 0x15: { // Cargo type
1160 _gted[e->index].defaultcargo_grf = _cur.grffile;
1161 uint8_t ctype = buf.ReadByte();
1162
1163 if (ctype == 0xFF) {
1164 /* 0xFF is specified as 'use first refittable' */
1165 ei->cargo_type = INVALID_CARGO;
1166 } else {
1167 /* Use translated cargo. Might result in INVALID_CARGO (first refittable), if cargo is not defined. */
1168 ei->cargo_type = GetCargoTranslation(ctype, _cur.grffile);
1169 if (ei->cargo_type == INVALID_CARGO) GrfMsg(2, "RailVehicleChangeInfo: Invalid cargo type {}, using first refittable", ctype);
1170 }
1171 ei->cargo_label = CT_INVALID;
1172 break;
1173 }
1174
1175 case PROP_TRAIN_WEIGHT: // 0x16 Weight
1176 SB(rvi->weight, 0, 8, buf.ReadByte());
1177 break;
1178
1179 case PROP_TRAIN_COST_FACTOR: // 0x17 Cost factor
1180 rvi->cost_factor = buf.ReadByte();
1181 break;
1182
1183 case 0x18: // AI rank
1184 GrfMsg(2, "RailVehicleChangeInfo: Property 0x18 'AI rank' not used by NoAI, ignored.");
1185 buf.ReadByte();
1186 break;
1187
1188 case 0x19: { // Engine traction type
1189 /* What do the individual numbers mean?
1190 * 0x00 .. 0x07: Steam
1191 * 0x08 .. 0x27: Diesel
1192 * 0x28 .. 0x31: Electric
1193 * 0x32 .. 0x37: Monorail
1194 * 0x38 .. 0x41: Maglev
1195 */
1196 uint8_t traction = buf.ReadByte();
1197 EngineClass engclass;
1198
1199 if (traction <= 0x07) {
1200 engclass = EC_STEAM;
1201 } else if (traction <= 0x27) {
1202 engclass = EC_DIESEL;
1203 } else if (traction <= 0x31) {
1204 engclass = EC_ELECTRIC;
1205 } else if (traction <= 0x37) {
1206 engclass = EC_MONORAIL;
1207 } else if (traction <= 0x41) {
1208 engclass = EC_MAGLEV;
1209 } else {
1210 break;
1211 }
1212
1213 if (_cur.grffile->railtype_list.empty()) {
1214 /* Use traction type to select between normal and electrified
1215 * rail only when no translation list is in place. */
1216 if (_gted[e->index].railtypelabel == RAILTYPE_LABEL_RAIL && engclass >= EC_ELECTRIC) _gted[e->index].railtypelabel = RAILTYPE_LABEL_ELECTRIC;
1217 if (_gted[e->index].railtypelabel == RAILTYPE_LABEL_ELECTRIC && engclass < EC_ELECTRIC) _gted[e->index].railtypelabel = RAILTYPE_LABEL_RAIL;
1218 }
1219
1220 rvi->engclass = engclass;
1221 break;
1222 }
1223
1224 case 0x1A: // Alter purchase list sort order
1225 AlterVehicleListOrder(e->index, buf.ReadExtendedByte());
1226 break;
1227
1228 case 0x1B: // Powered wagons power bonus
1229 rvi->pow_wag_power = buf.ReadWord();
1230 break;
1231
1232 case 0x1C: // Refit cost
1233 ei->refit_cost = buf.ReadByte();
1234 break;
1235
1236 case 0x1D: { // Refit cargo
1237 uint32_t mask = buf.ReadDWord();
1238 _gted[e->index].UpdateRefittability(mask != 0);
1239 ei->refit_mask = TranslateRefitMask(mask);
1240 _gted[e->index].defaultcargo_grf = _cur.grffile;
1241 break;
1242 }
1243
1244 case 0x1E: // Callback
1245 SB(ei->callback_mask, 0, 8, buf.ReadByte());
1246 break;
1247
1248 case PROP_TRAIN_TRACTIVE_EFFORT: // 0x1F Tractive effort coefficient
1249 rvi->tractive_effort = buf.ReadByte();
1250 break;
1251
1252 case 0x20: // Air drag
1253 rvi->air_drag = buf.ReadByte();
1254 break;
1255
1256 case PROP_TRAIN_SHORTEN_FACTOR: // 0x21 Shorter vehicle
1257 rvi->shorten_factor = buf.ReadByte();
1258 break;
1259
1260 case 0x22: // Visual effect
1261 rvi->visual_effect = buf.ReadByte();
1262 /* Avoid accidentally setting visual_effect to the default value
1263 * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
1264 if (rvi->visual_effect == VE_DEFAULT) {
1265 assert(HasBit(rvi->visual_effect, VE_DISABLE_EFFECT));
1267 }
1268 break;
1269
1270 case 0x23: // Powered wagons weight bonus
1271 rvi->pow_wag_weight = buf.ReadByte();
1272 break;
1273
1274 case 0x24: { // High byte of vehicle weight
1275 uint8_t weight = buf.ReadByte();
1276
1277 if (weight > 4) {
1278 GrfMsg(2, "RailVehicleChangeInfo: Nonsensical weight of {} tons, ignoring", weight << 8);
1279 } else {
1280 SB(rvi->weight, 8, 8, weight);
1281 }
1282 break;
1283 }
1284
1285 case PROP_TRAIN_USER_DATA: // 0x25 User-defined bit mask to set when checking veh. var. 42
1286 rvi->user_def_data = buf.ReadByte();
1287 break;
1288
1289 case 0x26: // Retire vehicle early
1290 ei->retire_early = buf.ReadByte();
1291 break;
1292
1293 case 0x27: // Miscellaneous flags
1294 ei->misc_flags = buf.ReadByte();
1296 break;
1297
1298 case 0x28: // Cargo classes allowed
1299 _gted[e->index].cargo_allowed = buf.ReadWord();
1300 _gted[e->index].UpdateRefittability(_gted[e->index].cargo_allowed != 0);
1301 _gted[e->index].defaultcargo_grf = _cur.grffile;
1302 break;
1303
1304 case 0x29: // Cargo classes disallowed
1305 _gted[e->index].cargo_disallowed = buf.ReadWord();
1306 _gted[e->index].UpdateRefittability(false);
1307 break;
1308
1309 case 0x2A: // Long format introduction date (days since year 0)
1310 ei->base_intro = buf.ReadDWord();
1311 break;
1312
1313 case PROP_TRAIN_CARGO_AGE_PERIOD: // 0x2B Cargo aging period
1314 ei->cargo_age_period = buf.ReadWord();
1315 break;
1316
1317 case 0x2C: // CTT refit include list
1318 case 0x2D: { // CTT refit exclude list
1319 uint8_t count = buf.ReadByte();
1320 _gted[e->index].UpdateRefittability(prop == 0x2C && count != 0);
1321 if (prop == 0x2C) _gted[e->index].defaultcargo_grf = _cur.grffile;
1322 CargoTypes &ctt = prop == 0x2C ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask;
1323 ctt = 0;
1324 while (count--) {
1325 CargoID ctype = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
1326 if (IsValidCargoID(ctype)) SetBit(ctt, ctype);
1327 }
1328 break;
1329 }
1330
1331 case PROP_TRAIN_CURVE_SPEED_MOD: // 0x2E Curve speed modifier
1332 rvi->curve_speed_mod = buf.ReadWord();
1333 break;
1334
1335 case 0x2F: // Engine variant
1336 ei->variant_id = buf.ReadWord();
1337 break;
1338
1339 case 0x30: // Extra miscellaneous flags
1340 ei->extra_flags = static_cast<ExtraEngineFlags>(buf.ReadDWord());
1341 break;
1342
1343 case 0x31: // Callback additional mask
1344 SB(ei->callback_mask, 8, 8, buf.ReadByte());
1345 break;
1346
1347 case 0x32: // Cargo classes required for a refit.
1348 _gted[e->index].cargo_allowed_required = buf.ReadWord();
1349 break;
1350
1351 default:
1352 ret = CommonVehicleChangeInfo(ei, prop, buf);
1353 break;
1354 }
1355 }
1356
1357 return ret;
1358}
1359
1368static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader &buf)
1369{
1371
1372 for (int i = 0; i < numinfo; i++) {
1373 Engine *e = GetNewEngine(_cur.grffile, VEH_ROAD, engine + i);
1374 if (e == nullptr) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles
1375
1376 EngineInfo *ei = &e->info;
1377 RoadVehicleInfo *rvi = &e->u.road;
1378
1379 switch (prop) {
1380 case 0x05: // Road/tram type
1381 /* RoadTypeLabel is looked up later after the engine's road/tram
1382 * flag is set, however 0 means the value has not been set. */
1383 _gted[e->index].roadtramtype = buf.ReadByte() + 1;
1384 break;
1385
1386 case 0x08: // Speed (1 unit is 0.5 kmh)
1387 rvi->max_speed = buf.ReadByte();
1388 break;
1389
1390 case PROP_ROADVEH_RUNNING_COST_FACTOR: // 0x09 Running cost factor
1391 rvi->running_cost = buf.ReadByte();
1392 break;
1393
1394 case 0x0A: // Running cost base
1395 ConvertTTDBasePrice(buf.ReadDWord(), "RoadVehicleChangeInfo", &rvi->running_cost_class);
1396 break;
1397
1398 case 0x0E: { // Sprite ID
1399 uint8_t spriteid = buf.ReadByte();
1400 uint8_t orig_spriteid = spriteid;
1401
1402 /* cars have different custom id in the GRF file */
1403 if (spriteid == 0xFF) spriteid = 0xFD;
1404
1405 if (spriteid < 0xFD) spriteid >>= 1;
1406
1407 if (IsValidNewGRFImageIndex<VEH_ROAD>(spriteid)) {
1408 rvi->image_index = spriteid;
1409 } else {
1410 GrfMsg(1, "RoadVehicleChangeInfo: Invalid Sprite {} specified, ignoring", orig_spriteid);
1411 rvi->image_index = 0;
1412 }
1413 break;
1414 }
1415
1416 case PROP_ROADVEH_CARGO_CAPACITY: // 0x0F Cargo capacity
1417 rvi->capacity = buf.ReadByte();
1418 break;
1419
1420 case 0x10: { // Cargo type
1421 _gted[e->index].defaultcargo_grf = _cur.grffile;
1422 uint8_t ctype = buf.ReadByte();
1423
1424 if (ctype == 0xFF) {
1425 /* 0xFF is specified as 'use first refittable' */
1426 ei->cargo_type = INVALID_CARGO;
1427 } else {
1428 /* Use translated cargo. Might result in INVALID_CARGO (first refittable), if cargo is not defined. */
1429 ei->cargo_type = GetCargoTranslation(ctype, _cur.grffile);
1430 if (ei->cargo_type == INVALID_CARGO) GrfMsg(2, "RoadVehicleChangeInfo: Invalid cargo type {}, using first refittable", ctype);
1431 }
1432 ei->cargo_label = CT_INVALID;
1433 break;
1434 }
1435
1436 case PROP_ROADVEH_COST_FACTOR: // 0x11 Cost factor
1437 rvi->cost_factor = buf.ReadByte();
1438 break;
1439
1440 case 0x12: // SFX
1441 rvi->sfx = GetNewGRFSoundID(_cur.grffile, buf.ReadByte());
1442 break;
1443
1444 case PROP_ROADVEH_POWER: // Power in units of 10 HP.
1445 rvi->power = buf.ReadByte();
1446 break;
1447
1448 case PROP_ROADVEH_WEIGHT: // Weight in units of 1/4 tons.
1449 rvi->weight = buf.ReadByte();
1450 break;
1451
1452 case PROP_ROADVEH_SPEED: // Speed in mph/0.8
1453 _gted[e->index].rv_max_speed = buf.ReadByte();
1454 break;
1455
1456 case 0x16: { // Cargoes available for refitting
1457 uint32_t mask = buf.ReadDWord();
1458 _gted[e->index].UpdateRefittability(mask != 0);
1459 ei->refit_mask = TranslateRefitMask(mask);
1460 _gted[e->index].defaultcargo_grf = _cur.grffile;
1461 break;
1462 }
1463
1464 case 0x17: // Callback mask
1465 SB(ei->callback_mask, 0, 8, buf.ReadByte());
1466 break;
1467
1468 case PROP_ROADVEH_TRACTIVE_EFFORT: // Tractive effort coefficient in 1/256.
1469 rvi->tractive_effort = buf.ReadByte();
1470 break;
1471
1472 case 0x19: // Air drag
1473 rvi->air_drag = buf.ReadByte();
1474 break;
1475
1476 case 0x1A: // Refit cost
1477 ei->refit_cost = buf.ReadByte();
1478 break;
1479
1480 case 0x1B: // Retire vehicle early
1481 ei->retire_early = buf.ReadByte();
1482 break;
1483
1484 case 0x1C: // Miscellaneous flags
1485 ei->misc_flags = buf.ReadByte();
1487 break;
1488
1489 case 0x1D: // Cargo classes allowed
1490 _gted[e->index].cargo_allowed = buf.ReadWord();
1491 _gted[e->index].UpdateRefittability(_gted[e->index].cargo_allowed != 0);
1492 _gted[e->index].defaultcargo_grf = _cur.grffile;
1493 break;
1494
1495 case 0x1E: // Cargo classes disallowed
1496 _gted[e->index].cargo_disallowed = buf.ReadWord();
1497 _gted[e->index].UpdateRefittability(false);
1498 break;
1499
1500 case 0x1F: // Long format introduction date (days since year 0)
1501 ei->base_intro = buf.ReadDWord();
1502 break;
1503
1504 case 0x20: // Alter purchase list sort order
1505 AlterVehicleListOrder(e->index, buf.ReadExtendedByte());
1506 break;
1507
1508 case 0x21: // Visual effect
1509 rvi->visual_effect = buf.ReadByte();
1510 /* Avoid accidentally setting visual_effect to the default value
1511 * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
1512 if (rvi->visual_effect == VE_DEFAULT) {
1513 assert(HasBit(rvi->visual_effect, VE_DISABLE_EFFECT));
1515 }
1516 break;
1517
1518 case PROP_ROADVEH_CARGO_AGE_PERIOD: // 0x22 Cargo aging period
1519 ei->cargo_age_period = buf.ReadWord();
1520 break;
1521
1522 case PROP_ROADVEH_SHORTEN_FACTOR: // 0x23 Shorter vehicle
1523 rvi->shorten_factor = buf.ReadByte();
1524 break;
1525
1526 case 0x24: // CTT refit include list
1527 case 0x25: { // CTT refit exclude list
1528 uint8_t count = buf.ReadByte();
1529 _gted[e->index].UpdateRefittability(prop == 0x24 && count != 0);
1530 if (prop == 0x24) _gted[e->index].defaultcargo_grf = _cur.grffile;
1531 CargoTypes &ctt = prop == 0x24 ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask;
1532 ctt = 0;
1533 while (count--) {
1534 CargoID ctype = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
1535 if (IsValidCargoID(ctype)) SetBit(ctt, ctype);
1536 }
1537 break;
1538 }
1539
1540 case 0x26: // Engine variant
1541 ei->variant_id = buf.ReadWord();
1542 break;
1543
1544 case 0x27: // Extra miscellaneous flags
1545 ei->extra_flags = static_cast<ExtraEngineFlags>(buf.ReadDWord());
1546 break;
1547
1548 case 0x28: // Callback additional mask
1549 SB(ei->callback_mask, 8, 8, buf.ReadByte());
1550 break;
1551
1552 case 0x29: // Cargo classes required for a refit.
1553 _gted[e->index].cargo_allowed_required = buf.ReadWord();
1554 break;
1555
1556 default:
1557 ret = CommonVehicleChangeInfo(ei, prop, buf);
1558 break;
1559 }
1560 }
1561
1562 return ret;
1563}
1564
1573static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader &buf)
1574{
1576
1577 for (int i = 0; i < numinfo; i++) {
1578 Engine *e = GetNewEngine(_cur.grffile, VEH_SHIP, engine + i);
1579 if (e == nullptr) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles
1580
1581 EngineInfo *ei = &e->info;
1582 ShipVehicleInfo *svi = &e->u.ship;
1583
1584 switch (prop) {
1585 case 0x08: { // Sprite ID
1586 uint8_t spriteid = buf.ReadByte();
1587 uint8_t orig_spriteid = spriteid;
1588
1589 /* ships have different custom id in the GRF file */
1590 if (spriteid == 0xFF) spriteid = 0xFD;
1591
1592 if (spriteid < 0xFD) spriteid >>= 1;
1593
1594 if (IsValidNewGRFImageIndex<VEH_SHIP>(spriteid)) {
1595 svi->image_index = spriteid;
1596 } else {
1597 GrfMsg(1, "ShipVehicleChangeInfo: Invalid Sprite {} specified, ignoring", orig_spriteid);
1598 svi->image_index = 0;
1599 }
1600 break;
1601 }
1602
1603 case 0x09: // Refittable
1604 svi->old_refittable = (buf.ReadByte() != 0);
1605 break;
1606
1607 case PROP_SHIP_COST_FACTOR: // 0x0A Cost factor
1608 svi->cost_factor = buf.ReadByte();
1609 break;
1610
1611 case PROP_SHIP_SPEED: // 0x0B Speed (1 unit is 0.5 km-ish/h). Use 0x23 to achieve higher speeds.
1612 svi->max_speed = buf.ReadByte();
1613 break;
1614
1615 case 0x0C: { // Cargo type
1616 _gted[e->index].defaultcargo_grf = _cur.grffile;
1617 uint8_t ctype = buf.ReadByte();
1618
1619 if (ctype == 0xFF) {
1620 /* 0xFF is specified as 'use first refittable' */
1621 ei->cargo_type = INVALID_CARGO;
1622 } else {
1623 /* Use translated cargo. Might result in INVALID_CARGO (first refittable), if cargo is not defined. */
1624 ei->cargo_type = GetCargoTranslation(ctype, _cur.grffile);
1625 if (ei->cargo_type == INVALID_CARGO) GrfMsg(2, "ShipVehicleChangeInfo: Invalid cargo type {}, using first refittable", ctype);
1626 }
1627 ei->cargo_label = CT_INVALID;
1628 break;
1629 }
1630
1631 case PROP_SHIP_CARGO_CAPACITY: // 0x0D Cargo capacity
1632 svi->capacity = buf.ReadWord();
1633 break;
1634
1635 case PROP_SHIP_RUNNING_COST_FACTOR: // 0x0F Running cost factor
1636 svi->running_cost = buf.ReadByte();
1637 break;
1638
1639 case 0x10: // SFX
1640 svi->sfx = GetNewGRFSoundID(_cur.grffile, buf.ReadByte());
1641 break;
1642
1643 case 0x11: { // Cargoes available for refitting
1644 uint32_t mask = buf.ReadDWord();
1645 _gted[e->index].UpdateRefittability(mask != 0);
1646 ei->refit_mask = TranslateRefitMask(mask);
1647 _gted[e->index].defaultcargo_grf = _cur.grffile;
1648 break;
1649 }
1650
1651 case 0x12: // Callback mask
1652 SB(ei->callback_mask, 0, 8, buf.ReadByte());
1653 break;
1654
1655 case 0x13: // Refit cost
1656 ei->refit_cost = buf.ReadByte();
1657 break;
1658
1659 case 0x14: // Ocean speed fraction
1660 svi->ocean_speed_frac = buf.ReadByte();
1661 break;
1662
1663 case 0x15: // Canal speed fraction
1664 svi->canal_speed_frac = buf.ReadByte();
1665 break;
1666
1667 case 0x16: // Retire vehicle early
1668 ei->retire_early = buf.ReadByte();
1669 break;
1670
1671 case 0x17: // Miscellaneous flags
1672 ei->misc_flags = buf.ReadByte();
1674 break;
1675
1676 case 0x18: // Cargo classes allowed
1677 _gted[e->index].cargo_allowed = buf.ReadWord();
1678 _gted[e->index].UpdateRefittability(_gted[e->index].cargo_allowed != 0);
1679 _gted[e->index].defaultcargo_grf = _cur.grffile;
1680 break;
1681
1682 case 0x19: // Cargo classes disallowed
1683 _gted[e->index].cargo_disallowed = buf.ReadWord();
1684 _gted[e->index].UpdateRefittability(false);
1685 break;
1686
1687 case 0x1A: // Long format introduction date (days since year 0)
1688 ei->base_intro = buf.ReadDWord();
1689 break;
1690
1691 case 0x1B: // Alter purchase list sort order
1692 AlterVehicleListOrder(e->index, buf.ReadExtendedByte());
1693 break;
1694
1695 case 0x1C: // Visual effect
1696 svi->visual_effect = buf.ReadByte();
1697 /* Avoid accidentally setting visual_effect to the default value
1698 * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
1699 if (svi->visual_effect == VE_DEFAULT) {
1700 assert(HasBit(svi->visual_effect, VE_DISABLE_EFFECT));
1702 }
1703 break;
1704
1705 case PROP_SHIP_CARGO_AGE_PERIOD: // 0x1D Cargo aging period
1706 ei->cargo_age_period = buf.ReadWord();
1707 break;
1708
1709 case 0x1E: // CTT refit include list
1710 case 0x1F: { // CTT refit exclude list
1711 uint8_t count = buf.ReadByte();
1712 _gted[e->index].UpdateRefittability(prop == 0x1E && count != 0);
1713 if (prop == 0x1E) _gted[e->index].defaultcargo_grf = _cur.grffile;
1714 CargoTypes &ctt = prop == 0x1E ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask;
1715 ctt = 0;
1716 while (count--) {
1717 CargoID ctype = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
1718 if (IsValidCargoID(ctype)) SetBit(ctt, ctype);
1719 }
1720 break;
1721 }
1722
1723 case 0x20: // Engine variant
1724 ei->variant_id = buf.ReadWord();
1725 break;
1726
1727 case 0x21: // Extra miscellaneous flags
1728 ei->extra_flags = static_cast<ExtraEngineFlags>(buf.ReadDWord());
1729 break;
1730
1731 case 0x22: // Callback additional mask
1732 SB(ei->callback_mask, 8, 8, buf.ReadByte());
1733 break;
1734
1735 case 0x23: // Speed (1 unit is 0.5 km-ish/h)
1736 svi->max_speed = buf.ReadWord();
1737 break;
1738
1739 case 0x24: // Acceleration (1 unit is 0.5 km-ish/h per tick)
1740 svi->acceleration = std::max<uint8_t>(1, buf.ReadByte());
1741 break;
1742
1743 case 0x25: // Cargo classes required for a refit.
1744 _gted[e->index].cargo_allowed_required = buf.ReadWord();
1745 break;
1746
1747 default:
1748 ret = CommonVehicleChangeInfo(ei, prop, buf);
1749 break;
1750 }
1751 }
1752
1753 return ret;
1754}
1755
1764static ChangeInfoResult AircraftVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader &buf)
1765{
1767
1768 for (int i = 0; i < numinfo; i++) {
1769 Engine *e = GetNewEngine(_cur.grffile, VEH_AIRCRAFT, engine + i);
1770 if (e == nullptr) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles
1771
1772 EngineInfo *ei = &e->info;
1773 AircraftVehicleInfo *avi = &e->u.air;
1774
1775 switch (prop) {
1776 case 0x08: { // Sprite ID
1777 uint8_t spriteid = buf.ReadByte();
1778 uint8_t orig_spriteid = spriteid;
1779
1780 /* aircraft have different custom id in the GRF file */
1781 if (spriteid == 0xFF) spriteid = 0xFD;
1782
1783 if (spriteid < 0xFD) spriteid >>= 1;
1784
1785 if (IsValidNewGRFImageIndex<VEH_AIRCRAFT>(spriteid)) {
1786 avi->image_index = spriteid;
1787 } else {
1788 GrfMsg(1, "AircraftVehicleChangeInfo: Invalid Sprite {} specified, ignoring", orig_spriteid);
1789 avi->image_index = 0;
1790 }
1791 break;
1792 }
1793
1794 case 0x09: // Helicopter
1795 if (buf.ReadByte() == 0) {
1796 avi->subtype = AIR_HELI;
1797 } else {
1798 SB(avi->subtype, 0, 1, 1); // AIR_CTOL
1799 }
1800 break;
1801
1802 case 0x0A: // Large
1803 AssignBit(avi->subtype, 1, buf.ReadByte() != 0); // AIR_FAST
1804 break;
1805
1806 case PROP_AIRCRAFT_COST_FACTOR: // 0x0B Cost factor
1807 avi->cost_factor = buf.ReadByte();
1808 break;
1809
1810 case PROP_AIRCRAFT_SPEED: // 0x0C Speed (1 unit is 8 mph, we translate to 1 unit is 1 km-ish/h)
1811 avi->max_speed = (buf.ReadByte() * 128) / 10;
1812 break;
1813
1814 case 0x0D: // Acceleration
1815 avi->acceleration = buf.ReadByte();
1816 break;
1817
1818 case PROP_AIRCRAFT_RUNNING_COST_FACTOR: // 0x0E Running cost factor
1819 avi->running_cost = buf.ReadByte();
1820 break;
1821
1822 case PROP_AIRCRAFT_PASSENGER_CAPACITY: // 0x0F Passenger capacity
1823 avi->passenger_capacity = buf.ReadWord();
1824 break;
1825
1826 case PROP_AIRCRAFT_MAIL_CAPACITY: // 0x11 Mail capacity
1827 avi->mail_capacity = buf.ReadByte();
1828 break;
1829
1830 case 0x12: // SFX
1831 avi->sfx = GetNewGRFSoundID(_cur.grffile, buf.ReadByte());
1832 break;
1833
1834 case 0x13: { // Cargoes available for refitting
1835 uint32_t mask = buf.ReadDWord();
1836 _gted[e->index].UpdateRefittability(mask != 0);
1837 ei->refit_mask = TranslateRefitMask(mask);
1838 _gted[e->index].defaultcargo_grf = _cur.grffile;
1839 break;
1840 }
1841
1842 case 0x14: // Callback mask
1843 SB(ei->callback_mask, 0, 8, buf.ReadByte());
1844 break;
1845
1846 case 0x15: // Refit cost
1847 ei->refit_cost = buf.ReadByte();
1848 break;
1849
1850 case 0x16: // Retire vehicle early
1851 ei->retire_early = buf.ReadByte();
1852 break;
1853
1854 case 0x17: // Miscellaneous flags
1855 ei->misc_flags = buf.ReadByte();
1857 break;
1858
1859 case 0x18: // Cargo classes allowed
1860 _gted[e->index].cargo_allowed = buf.ReadWord();
1861 _gted[e->index].UpdateRefittability(_gted[e->index].cargo_allowed != 0);
1862 _gted[e->index].defaultcargo_grf = _cur.grffile;
1863 break;
1864
1865 case 0x19: // Cargo classes disallowed
1866 _gted[e->index].cargo_disallowed = buf.ReadWord();
1867 _gted[e->index].UpdateRefittability(false);
1868 break;
1869
1870 case 0x1A: // Long format introduction date (days since year 0)
1871 ei->base_intro = buf.ReadDWord();
1872 break;
1873
1874 case 0x1B: // Alter purchase list sort order
1875 AlterVehicleListOrder(e->index, buf.ReadExtendedByte());
1876 break;
1877
1878 case PROP_AIRCRAFT_CARGO_AGE_PERIOD: // 0x1C Cargo aging period
1879 ei->cargo_age_period = buf.ReadWord();
1880 break;
1881
1882 case 0x1D: // CTT refit include list
1883 case 0x1E: { // CTT refit exclude list
1884 uint8_t count = buf.ReadByte();
1885 _gted[e->index].UpdateRefittability(prop == 0x1D && count != 0);
1886 if (prop == 0x1D) _gted[e->index].defaultcargo_grf = _cur.grffile;
1887 CargoTypes &ctt = prop == 0x1D ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask;
1888 ctt = 0;
1889 while (count--) {
1890 CargoID ctype = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
1891 if (IsValidCargoID(ctype)) SetBit(ctt, ctype);
1892 }
1893 break;
1894 }
1895
1896 case PROP_AIRCRAFT_RANGE: // 0x1F Max aircraft range
1897 avi->max_range = buf.ReadWord();
1898 break;
1899
1900 case 0x20: // Engine variant
1901 ei->variant_id = buf.ReadWord();
1902 break;
1903
1904 case 0x21: // Extra miscellaneous flags
1905 ei->extra_flags = static_cast<ExtraEngineFlags>(buf.ReadDWord());
1906 break;
1907
1908 case 0x22: // Callback additional mask
1909 SB(ei->callback_mask, 8, 8, buf.ReadByte());
1910 break;
1911
1912 case 0x23: // Cargo classes required for a refit.
1913 _gted[e->index].cargo_allowed_required = buf.ReadWord();
1914 break;
1915
1916 default:
1917 ret = CommonVehicleChangeInfo(ei, prop, buf);
1918 break;
1919 }
1920 }
1921
1922 return ret;
1923}
1924
1933static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, ByteReader &buf)
1934{
1936
1937 if (stid + numinfo > NUM_STATIONS_PER_GRF) {
1938 GrfMsg(1, "StationChangeInfo: Station {} is invalid, max {}, ignoring", stid + numinfo, NUM_STATIONS_PER_GRF);
1939 return CIR_INVALID_ID;
1940 }
1941
1942 /* Allocate station specs if necessary */
1943 if (_cur.grffile->stations.size() < stid + numinfo) _cur.grffile->stations.resize(stid + numinfo);
1944
1945 for (int i = 0; i < numinfo; i++) {
1946 auto &statspec = _cur.grffile->stations[stid + i];
1947
1948 /* Check that the station we are modifying is defined. */
1949 if (statspec == nullptr && prop != 0x08) {
1950 GrfMsg(2, "StationChangeInfo: Attempt to modify undefined station {}, ignoring", stid + i);
1951 return CIR_INVALID_ID;
1952 }
1953
1954 switch (prop) {
1955 case 0x08: { // Class ID
1956 /* Property 0x08 is special; it is where the station is allocated */
1957 if (statspec == nullptr) {
1958 statspec = std::make_unique<StationSpec>();
1959 }
1960
1961 /* Swap classid because we read it in BE meaning WAYP or DFLT */
1962 uint32_t classid = buf.ReadDWord();
1963 statspec->class_index = StationClass::Allocate(BSWAP32(classid));
1964 break;
1965 }
1966
1967 case 0x09: { // Define sprite layout
1968 uint16_t tiles = buf.ReadExtendedByte();
1969 statspec->renderdata.clear(); // delete earlier loaded stuff
1970 statspec->renderdata.reserve(tiles);
1971
1972 for (uint t = 0; t < tiles; t++) {
1973 NewGRFSpriteLayout *dts = &statspec->renderdata.emplace_back();
1974 dts->consistent_max_offset = UINT16_MAX; // Spritesets are unknown, so no limit.
1975
1976 if (buf.HasData(4) && buf.PeekDWord() == 0) {
1977 buf.Skip(4);
1978 extern const DrawTileSprites _station_display_datas_rail[8];
1979 dts->Clone(&_station_display_datas_rail[t % 8]);
1980 continue;
1981 }
1982
1983 ReadSpriteLayoutSprite(buf, false, false, false, GSF_STATIONS, &dts->ground);
1984 /* On error, bail out immediately. Temporary GRF data was already freed */
1985 if (_cur.skip_sprites < 0) return CIR_DISABLED;
1986
1987 static std::vector<DrawTileSeqStruct> tmp_layout;
1988 tmp_layout.clear();
1989 for (;;) {
1990 /* no relative bounding box support */
1991 DrawTileSeqStruct &dtss = tmp_layout.emplace_back();
1992 MemSetT(&dtss, 0);
1993
1994 dtss.delta_x = buf.ReadByte();
1995 if (dtss.IsTerminator()) break;
1996 dtss.delta_y = buf.ReadByte();
1997 dtss.delta_z = buf.ReadByte();
1998 dtss.size_x = buf.ReadByte();
1999 dtss.size_y = buf.ReadByte();
2000 dtss.size_z = buf.ReadByte();
2001
2002 ReadSpriteLayoutSprite(buf, false, true, false, GSF_STATIONS, &dtss.image);
2003 /* On error, bail out immediately. Temporary GRF data was already freed */
2004 if (_cur.skip_sprites < 0) return CIR_DISABLED;
2005 }
2006 dts->Clone(tmp_layout.data());
2007 }
2008
2009 /* Number of layouts must be even, alternating X and Y */
2010 if (statspec->renderdata.size() & 1) {
2011 GrfMsg(1, "StationChangeInfo: Station {} defines an odd number of sprite layouts, dropping the last item", stid + i);
2012 statspec->renderdata.pop_back();
2013 }
2014 break;
2015 }
2016
2017 case 0x0A: { // Copy sprite layout
2018 uint16_t srcid = buf.ReadExtendedByte();
2019 const StationSpec *srcstatspec = srcid >= _cur.grffile->stations.size() ? nullptr : _cur.grffile->stations[srcid].get();
2020
2021 if (srcstatspec == nullptr) {
2022 GrfMsg(1, "StationChangeInfo: Station {} is not defined, cannot copy sprite layout to {}.", srcid, stid + i);
2023 continue;
2024 }
2025
2026 statspec->renderdata.clear(); // delete earlier loaded stuff
2027 statspec->renderdata.reserve(srcstatspec->renderdata.size());
2028
2029 for (const auto &it : srcstatspec->renderdata) {
2030 NewGRFSpriteLayout *dts = &statspec->renderdata.emplace_back();
2031 dts->Clone(&it);
2032 }
2033 break;
2034 }
2035
2036 case 0x0B: // Callback mask
2037 statspec->callback_mask = buf.ReadByte();
2038 break;
2039
2040 case 0x0C: // Disallowed number of platforms
2041 statspec->disallowed_platforms = buf.ReadByte();
2042 break;
2043
2044 case 0x0D: // Disallowed platform lengths
2045 statspec->disallowed_lengths = buf.ReadByte();
2046 break;
2047
2048 case 0x0E: // Define custom layout
2049 while (buf.HasData()) {
2050 uint8_t length = buf.ReadByte();
2051 uint8_t number = buf.ReadByte();
2052
2053 if (length == 0 || number == 0) break;
2054
2055 const uint8_t *buf_layout = buf.ReadBytes(length * number);
2056
2057 /* Create entry in layouts and assign the layout to it. */
2058 auto &layout = statspec->layouts[GetStationLayoutKey(number, length)];
2059 layout.assign(buf_layout, buf_layout + length * number);
2060
2061 /* Ensure the first bit, axis, is zero. The rest of the value is validated during rendering, as we don't know the range yet. */
2062 for (auto &tile : layout) {
2063 if ((tile & ~1U) != tile) {
2064 GrfMsg(1, "StationChangeInfo: Invalid tile {} in layout {}x{}", tile, length, number);
2065 tile &= ~1U;
2066 }
2067 }
2068 }
2069 break;
2070
2071 case 0x0F: { // Copy custom layout
2072 uint16_t srcid = buf.ReadExtendedByte();
2073 const StationSpec *srcstatspec = srcid >= _cur.grffile->stations.size() ? nullptr : _cur.grffile->stations[srcid].get();
2074
2075 if (srcstatspec == nullptr) {
2076 GrfMsg(1, "StationChangeInfo: Station {} is not defined, cannot copy tile layout to {}.", srcid, stid + i);
2077 continue;
2078 }
2079
2080 statspec->layouts = srcstatspec->layouts;
2081 break;
2082 }
2083
2084 case 0x10: // Little/lots cargo threshold
2085 statspec->cargo_threshold = buf.ReadWord();
2086 break;
2087
2088 case 0x11: { // Pylon placement
2089 uint8_t pylons = buf.ReadByte();
2090 if (statspec->tileflags.size() < 8) statspec->tileflags.resize(8);
2091 for (int j = 0; j < 8; ++j) {
2092 if (HasBit(pylons, j)) {
2093 statspec->tileflags[j] |= StationSpec::TileFlags::Pylons;
2094 } else {
2095 statspec->tileflags[j] &= ~StationSpec::TileFlags::Pylons;
2096 }
2097 }
2098 break;
2099 }
2100
2101 case 0x12: // Cargo types for random triggers
2102 if (_cur.grffile->grf_version >= 7) {
2103 statspec->cargo_triggers = TranslateRefitMask(buf.ReadDWord());
2104 } else {
2105 statspec->cargo_triggers = (CargoTypes)buf.ReadDWord();
2106 }
2107 break;
2108
2109 case 0x13: // General flags
2110 statspec->flags = buf.ReadByte();
2111 break;
2112
2113 case 0x14: { // Overhead wire placement
2114 uint8_t wires = buf.ReadByte();
2115 if (statspec->tileflags.size() < 8) statspec->tileflags.resize(8);
2116 for (int j = 0; j < 8; ++j) {
2117 if (HasBit(wires, j)) {
2118 statspec->tileflags[j] |= StationSpec::TileFlags::NoWires;
2119 } else {
2120 statspec->tileflags[j] &= ~StationSpec::TileFlags::NoWires;
2121 }
2122 }
2123 break;
2124 }
2125
2126 case 0x15: { // Blocked tiles
2127 uint8_t blocked = buf.ReadByte();
2128 if (statspec->tileflags.size() < 8) statspec->tileflags.resize(8);
2129 for (int j = 0; j < 8; ++j) {
2130 if (HasBit(blocked, j)) {
2131 statspec->tileflags[j] |= StationSpec::TileFlags::Blocked;
2132 } else {
2133 statspec->tileflags[j] &= ~StationSpec::TileFlags::Blocked;
2134 }
2135 }
2136 break;
2137 }
2138
2139 case 0x16: // Animation info
2140 statspec->animation.frames = buf.ReadByte();
2141 statspec->animation.status = buf.ReadByte();
2142 break;
2143
2144 case 0x17: // Animation speed
2145 statspec->animation.speed = buf.ReadByte();
2146 break;
2147
2148 case 0x18: // Animation triggers
2149 statspec->animation.triggers = buf.ReadWord();
2150 break;
2151
2152 /* 0x19 road routing (not implemented) */
2153
2154 case 0x1A: { // Advanced sprite layout
2155 uint16_t tiles = buf.ReadExtendedByte();
2156 statspec->renderdata.clear(); // delete earlier loaded stuff
2157 statspec->renderdata.reserve(tiles);
2158
2159 for (uint t = 0; t < tiles; t++) {
2160 NewGRFSpriteLayout *dts = &statspec->renderdata.emplace_back();
2161 uint num_building_sprites = buf.ReadByte();
2162 /* On error, bail out immediately. Temporary GRF data was already freed */
2163 if (ReadSpriteLayout(buf, num_building_sprites, false, GSF_STATIONS, true, false, dts)) return CIR_DISABLED;
2164 }
2165
2166 /* Number of layouts must be even, alternating X and Y */
2167 if (statspec->renderdata.size() & 1) {
2168 GrfMsg(1, "StationChangeInfo: Station {} defines an odd number of sprite layouts, dropping the last item", stid + i);
2169 statspec->renderdata.pop_back();
2170 }
2171 break;
2172 }
2173
2174 case 0x1B: // Minimum bridge height (not implemented)
2175 buf.ReadWord();
2176 buf.ReadWord();
2177 buf.ReadWord();
2178 buf.ReadWord();
2179 break;
2180
2181 case 0x1C: // Station Name
2182 AddStringForMapping(buf.ReadWord(), &statspec->name);
2183 break;
2184
2185 case 0x1D: // Station Class name
2186 AddStringForMapping(buf.ReadWord(), [statspec = statspec.get()](StringID str) { StationClass::Get(statspec->class_index)->name = str; });
2187 break;
2188
2189 case 0x1E: { // Extended tile flags (replaces prop 11, 14 and 15)
2190 uint16_t tiles = buf.ReadExtendedByte();
2191 auto flags = reinterpret_cast<const StationSpec::TileFlags *>(buf.ReadBytes(tiles));
2192 statspec->tileflags.assign(flags, flags + tiles);
2193 break;
2194 }
2195
2196 default:
2197 ret = CIR_UNKNOWN;
2198 break;
2199 }
2200 }
2201
2202 return ret;
2203}
2204
2213static ChangeInfoResult CanalChangeInfo(uint id, int numinfo, int prop, ByteReader &buf)
2214{
2216
2217 if (id + numinfo > CF_END) {
2218 GrfMsg(1, "CanalChangeInfo: Canal feature 0x{:02X} is invalid, max {}, ignoring", id + numinfo, CF_END);
2219 return CIR_INVALID_ID;
2220 }
2221
2222 for (int i = 0; i < numinfo; i++) {
2223 CanalProperties *cp = &_cur.grffile->canal_local_properties[id + i];
2224
2225 switch (prop) {
2226 case 0x08:
2227 cp->callback_mask = buf.ReadByte();
2228 break;
2229
2230 case 0x09:
2231 cp->flags = buf.ReadByte();
2232 break;
2233
2234 default:
2235 ret = CIR_UNKNOWN;
2236 break;
2237 }
2238 }
2239
2240 return ret;
2241}
2242
2251static ChangeInfoResult BridgeChangeInfo(uint brid, int numinfo, int prop, ByteReader &buf)
2252{
2254
2255 if (brid + numinfo > MAX_BRIDGES) {
2256 GrfMsg(1, "BridgeChangeInfo: Bridge {} is invalid, max {}, ignoring", brid + numinfo, MAX_BRIDGES);
2257 return CIR_INVALID_ID;
2258 }
2259
2260 for (int i = 0; i < numinfo; i++) {
2261 BridgeSpec *bridge = &_bridge[brid + i];
2262
2263 switch (prop) {
2264 case 0x08: { // Year of availability
2265 /* We treat '0' as always available */
2266 uint8_t year = buf.ReadByte();
2267 bridge->avail_year = (year > 0 ? CalendarTime::ORIGINAL_BASE_YEAR + year : 0);
2268 break;
2269 }
2270
2271 case 0x09: // Minimum length
2272 bridge->min_length = buf.ReadByte();
2273 break;
2274
2275 case 0x0A: // Maximum length
2276 bridge->max_length = buf.ReadByte();
2277 if (bridge->max_length > 16) bridge->max_length = UINT16_MAX;
2278 break;
2279
2280 case 0x0B: // Cost factor
2281 bridge->price = buf.ReadByte();
2282 break;
2283
2284 case 0x0C: // Maximum speed
2285 bridge->speed = buf.ReadWord();
2286 if (bridge->speed == 0) bridge->speed = UINT16_MAX;
2287 break;
2288
2289 case 0x0D: { // Bridge sprite tables
2290 uint8_t tableid = buf.ReadByte();
2291 uint8_t numtables = buf.ReadByte();
2292
2293 if (bridge->sprite_table == nullptr) {
2294 /* Allocate memory for sprite table pointers and zero out */
2295 bridge->sprite_table = CallocT<PalSpriteID*>(NUM_BRIDGE_PIECES);
2296 }
2297
2298 for (; numtables-- != 0; tableid++) {
2299 if (tableid >= NUM_BRIDGE_PIECES) { // skip invalid data
2300 GrfMsg(1, "BridgeChangeInfo: Table {} >= {}, skipping", tableid, NUM_BRIDGE_PIECES);
2301 for (uint8_t sprite = 0; sprite < SPRITES_PER_BRIDGE_PIECE; sprite++) buf.ReadDWord();
2302 continue;
2303 }
2304
2305 if (bridge->sprite_table[tableid] == nullptr) {
2306 bridge->sprite_table[tableid] = MallocT<PalSpriteID>(SPRITES_PER_BRIDGE_PIECE);
2307 }
2308
2309 for (uint8_t sprite = 0; sprite < SPRITES_PER_BRIDGE_PIECE; sprite++) {
2310 SpriteID image = buf.ReadWord();
2311 PaletteID pal = buf.ReadWord();
2312
2313 bridge->sprite_table[tableid][sprite].sprite = image;
2314 bridge->sprite_table[tableid][sprite].pal = pal;
2315
2316 MapSpriteMappingRecolour(&bridge->sprite_table[tableid][sprite]);
2317 }
2318 }
2319 break;
2320 }
2321
2322 case 0x0E: // Flags; bit 0 - disable far pillars
2323 bridge->flags = buf.ReadByte();
2324 break;
2325
2326 case 0x0F: // Long format year of availability (year since year 0)
2328 break;
2329
2330 case 0x10: { // purchase string
2331 StringID newone = GetGRFStringID(_cur.grffile->grfid, buf.ReadWord());
2332 if (newone != STR_UNDEFINED) bridge->material = newone;
2333 break;
2334 }
2335
2336 case 0x11: // description of bridge with rails or roads
2337 case 0x12: {
2338 StringID newone = GetGRFStringID(_cur.grffile->grfid, buf.ReadWord());
2339 if (newone != STR_UNDEFINED) bridge->transport_name[prop - 0x11] = newone;
2340 break;
2341 }
2342
2343 case 0x13: // 16 bits cost multiplier
2344 bridge->price = buf.ReadWord();
2345 break;
2346
2347 default:
2348 ret = CIR_UNKNOWN;
2349 break;
2350 }
2351 }
2352
2353 return ret;
2354}
2355
2363{
2365
2366 switch (prop) {
2367 case 0x09:
2368 case 0x0B:
2369 case 0x0C:
2370 case 0x0D:
2371 case 0x0E:
2372 case 0x0F:
2373 case 0x11:
2374 case 0x14:
2375 case 0x15:
2376 case 0x16:
2377 case 0x18:
2378 case 0x19:
2379 case 0x1A:
2380 case 0x1B:
2381 case 0x1C:
2382 case 0x1D:
2383 case 0x1F:
2384 buf.ReadByte();
2385 break;
2386
2387 case 0x0A:
2388 case 0x10:
2389 case 0x12:
2390 case 0x13:
2391 case 0x21:
2392 case 0x22:
2393 buf.ReadWord();
2394 break;
2395
2396 case 0x1E:
2397 buf.ReadDWord();
2398 break;
2399
2400 case 0x17:
2401 for (uint j = 0; j < 4; j++) buf.ReadByte();
2402 break;
2403
2404 case 0x20: {
2405 uint8_t count = buf.ReadByte();
2406 for (uint8_t j = 0; j < count; j++) buf.ReadByte();
2407 break;
2408 }
2409
2410 case 0x23:
2411 buf.Skip(buf.ReadByte() * 2);
2412 break;
2413
2414 default:
2415 ret = CIR_UNKNOWN;
2416 break;
2417 }
2418 return ret;
2419}
2420
2429static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, ByteReader &buf)
2430{
2432
2433 if (hid + numinfo > NUM_HOUSES_PER_GRF) {
2434 GrfMsg(1, "TownHouseChangeInfo: Too many houses loaded ({}), max ({}). Ignoring.", hid + numinfo, NUM_HOUSES_PER_GRF);
2435 return CIR_INVALID_ID;
2436 }
2437
2438 /* Allocate house specs if they haven't been allocated already. */
2439 if (_cur.grffile->housespec.size() < hid + numinfo) _cur.grffile->housespec.resize(hid + numinfo);
2440
2441 for (int i = 0; i < numinfo; i++) {
2442 auto &housespec = _cur.grffile->housespec[hid + i];
2443
2444 if (prop != 0x08 && housespec == nullptr) {
2445 /* If the house property 08 is not yet set, ignore this property */
2447 if (cir > ret) ret = cir;
2448 continue;
2449 }
2450
2451 switch (prop) {
2452 case 0x08: { // Substitute building type, and definition of a new house
2453 uint8_t subs_id = buf.ReadByte();
2454 if (subs_id == 0xFF) {
2455 /* Instead of defining a new house, a substitute house id
2456 * of 0xFF disables the old house with the current id. */
2457 if (hid + i < NEW_HOUSE_OFFSET) HouseSpec::Get(hid + i)->enabled = false;
2458 continue;
2459 } else if (subs_id >= NEW_HOUSE_OFFSET) {
2460 /* The substitute id must be one of the original houses. */
2461 GrfMsg(2, "TownHouseChangeInfo: Attempt to use new house {} as substitute house for {}. Ignoring.", subs_id, hid + i);
2462 continue;
2463 }
2464
2465 /* Allocate space for this house. */
2466 if (housespec == nullptr) {
2467 /* Only the first property 08 setting copies properties; if you later change it, properties will stay. */
2468 housespec = std::make_unique<HouseSpec>(*HouseSpec::Get(subs_id));
2469
2470 housespec->enabled = true;
2471 housespec->grf_prop.local_id = hid + i;
2472 housespec->grf_prop.subst_id = subs_id;
2473 housespec->grf_prop.grfid = _cur.grffile->grfid;
2474 housespec->grf_prop.grffile = _cur.grffile;
2475 /* Set default colours for randomization, used if not overridden. */
2476 housespec->random_colour[0] = COLOUR_RED;
2477 housespec->random_colour[1] = COLOUR_BLUE;
2478 housespec->random_colour[2] = COLOUR_ORANGE;
2479 housespec->random_colour[3] = COLOUR_GREEN;
2480
2481 /* House flags 40 and 80 are exceptions; these flags are never set automatically. */
2482 housespec->building_flags &= ~(BUILDING_IS_CHURCH | BUILDING_IS_STADIUM);
2483
2484 /* Make sure that the third cargo type is valid in this
2485 * climate. This can cause problems when copying the properties
2486 * of a house that accepts food, where the new house is valid
2487 * in the temperate climate. */
2488 CargoID cid = housespec->accepts_cargo[2];
2489 if (!IsValidCargoID(cid)) cid = GetCargoIDByLabel(housespec->accepts_cargo_label[2]);
2490 if (!IsValidCargoID(cid)) {
2491 housespec->cargo_acceptance[2] = 0;
2492 }
2493 }
2494 break;
2495 }
2496
2497 case 0x09: // Building flags
2498 housespec->building_flags = (BuildingFlags)buf.ReadByte();
2499 break;
2500
2501 case 0x0A: { // Availability years
2502 uint16_t years = buf.ReadWord();
2503 housespec->min_year = GB(years, 0, 8) > 150 ? CalendarTime::MAX_YEAR : CalendarTime::ORIGINAL_BASE_YEAR + GB(years, 0, 8);
2504 housespec->max_year = GB(years, 8, 8) > 150 ? CalendarTime::MAX_YEAR : CalendarTime::ORIGINAL_BASE_YEAR + GB(years, 8, 8);
2505 break;
2506 }
2507
2508 case 0x0B: // Population
2509 housespec->population = buf.ReadByte();
2510 break;
2511
2512 case 0x0C: // Mail generation multiplier
2513 housespec->mail_generation = buf.ReadByte();
2514 break;
2515
2516 case 0x0D: // Passenger acceptance
2517 case 0x0E: // Mail acceptance
2518 housespec->cargo_acceptance[prop - 0x0D] = buf.ReadByte();
2519 break;
2520
2521 case 0x0F: { // Goods/candy, food/fizzy drinks acceptance
2522 int8_t goods = buf.ReadByte();
2523
2524 /* If value of goods is negative, it means in fact food or, if in toyland, fizzy_drink acceptance.
2525 * Else, we have "standard" 3rd cargo type, goods or candy, for toyland once more */
2526 CargoID cid = (goods >= 0) ? ((_settings_game.game_creation.landscape == LT_TOYLAND) ? GetCargoIDByLabel(CT_CANDY) : GetCargoIDByLabel(CT_GOODS)) :
2527 ((_settings_game.game_creation.landscape == LT_TOYLAND) ? GetCargoIDByLabel(CT_FIZZY_DRINKS) : GetCargoIDByLabel(CT_FOOD));
2528
2529 /* Make sure the cargo type is valid in this climate. */
2530 if (!IsValidCargoID(cid)) goods = 0;
2531
2532 housespec->accepts_cargo[2] = cid;
2533 housespec->accepts_cargo_label[2] = CT_INVALID;
2534 housespec->cargo_acceptance[2] = abs(goods); // but we do need positive value here
2535 break;
2536 }
2537
2538 case 0x10: // Local authority rating decrease on removal
2539 housespec->remove_rating_decrease = buf.ReadWord();
2540 break;
2541
2542 case 0x11: // Removal cost multiplier
2543 housespec->removal_cost = buf.ReadByte();
2544 break;
2545
2546 case 0x12: // Building name ID
2547 AddStringForMapping(buf.ReadWord(), &housespec->building_name);
2548 break;
2549
2550 case 0x13: // Building availability mask
2551 housespec->building_availability = (HouseZones)buf.ReadWord();
2552 break;
2553
2554 case 0x14: // House callback mask
2555 housespec->callback_mask |= buf.ReadByte();
2556 break;
2557
2558 case 0x15: { // House override byte
2559 uint8_t override = buf.ReadByte();
2560
2561 /* The house being overridden must be an original house. */
2562 if (override >= NEW_HOUSE_OFFSET) {
2563 GrfMsg(2, "TownHouseChangeInfo: Attempt to override new house {} with house id {}. Ignoring.", override, hid + i);
2564 continue;
2565 }
2566
2567 _house_mngr.Add(hid + i, _cur.grffile->grfid, override);
2568 break;
2569 }
2570
2571 case 0x16: // Periodic refresh multiplier
2572 housespec->processing_time = std::min<uint8_t>(buf.ReadByte(), 63u);
2573 break;
2574
2575 case 0x17: // Four random colours to use
2576 for (uint j = 0; j < 4; j++) housespec->random_colour[j] = static_cast<Colours>(GB(buf.ReadByte(), 0, 4));
2577 break;
2578
2579 case 0x18: // Relative probability of appearing
2580 housespec->probability = buf.ReadByte();
2581 break;
2582
2583 case 0x19: // Extra flags
2584 housespec->extra_flags = (HouseExtraFlags)buf.ReadByte();
2585 break;
2586
2587 case 0x1A: // Animation frames
2588 housespec->animation.frames = buf.ReadByte();
2589 housespec->animation.status = GB(housespec->animation.frames, 7, 1);
2590 SB(housespec->animation.frames, 7, 1, 0);
2591 break;
2592
2593 case 0x1B: // Animation speed
2594 housespec->animation.speed = Clamp(buf.ReadByte(), 2, 16);
2595 break;
2596
2597 case 0x1C: // Class of the building type
2598 housespec->class_id = AllocateHouseClassID(buf.ReadByte(), _cur.grffile->grfid);
2599 break;
2600
2601 case 0x1D: // Callback mask part 2
2602 housespec->callback_mask |= (buf.ReadByte() << 8);
2603 break;
2604
2605 case 0x1E: { // Accepted cargo types
2606 uint32_t cargotypes = buf.ReadDWord();
2607
2608 /* Check if the cargo types should not be changed */
2609 if (cargotypes == 0xFFFFFFFF) break;
2610
2611 for (uint j = 0; j < HOUSE_ORIGINAL_NUM_ACCEPTS; j++) {
2612 /* Get the cargo number from the 'list' */
2613 uint8_t cargo_part = GB(cargotypes, 8 * j, 8);
2614 CargoID cargo = GetCargoTranslation(cargo_part, _cur.grffile);
2615
2616 if (!IsValidCargoID(cargo)) {
2617 /* Disable acceptance of invalid cargo type */
2618 housespec->cargo_acceptance[j] = 0;
2619 } else {
2620 housespec->accepts_cargo[j] = cargo;
2621 }
2622 housespec->accepts_cargo_label[j] = CT_INVALID;
2623 }
2624 break;
2625 }
2626
2627 case 0x1F: // Minimum life span
2628 housespec->minimum_life = buf.ReadByte();
2629 break;
2630
2631 case 0x20: { // Cargo acceptance watch list
2632 uint8_t count = buf.ReadByte();
2633 for (uint8_t j = 0; j < count; j++) {
2634 CargoID cargo = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
2635 if (IsValidCargoID(cargo)) SetBit(housespec->watched_cargoes, cargo);
2636 }
2637 break;
2638 }
2639
2640 case 0x21: // long introduction year
2641 housespec->min_year = buf.ReadWord();
2642 break;
2643
2644 case 0x22: // long maximum year
2645 housespec->max_year = buf.ReadWord();
2646 if (housespec->max_year == UINT16_MAX) housespec->max_year = CalendarTime::MAX_YEAR;
2647 break;
2648
2649 case 0x23: { // variable length cargo types accepted
2650 uint count = buf.ReadByte();
2651 if (count > lengthof(housespec->accepts_cargo)) {
2652 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG);
2653 error->param_value[1] = prop;
2654 return CIR_DISABLED;
2655 }
2656 /* Always write the full accepts_cargo array, and check each index for being inside the
2657 * provided data. This ensures all values are properly initialized, and also avoids
2658 * any risks of array overrun. */
2659 for (uint i = 0; i < lengthof(housespec->accepts_cargo); i++) {
2660 if (i < count) {
2661 housespec->accepts_cargo[i] = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
2662 housespec->cargo_acceptance[i] = buf.ReadByte();
2663 } else {
2664 housespec->accepts_cargo[i] = INVALID_CARGO;
2665 housespec->cargo_acceptance[i] = 0;
2666 }
2667 if (i < std::size(housespec->accepts_cargo_label)) housespec->accepts_cargo_label[i] = CT_INVALID;
2668 }
2669 break;
2670 }
2671
2672 default:
2673 ret = CIR_UNKNOWN;
2674 break;
2675 }
2676 }
2677
2678 return ret;
2679}
2680
2687/* static */ const LanguageMap *LanguageMap::GetLanguageMap(uint32_t grfid, uint8_t language_id)
2688{
2689 /* LanguageID "MAX_LANG", i.e. 7F is any. This language can't have a gender/case mapping, but has to be handled gracefully. */
2690 const GRFFile *grffile = GetFileByGRFID(grfid);
2691 if (grffile == nullptr) return nullptr;
2692
2693 auto it = grffile->language_map.find(language_id);
2694 if (it == std::end(grffile->language_map)) return nullptr;
2695
2696 return &it->second;
2697}
2698
2708template <typename T, typename TGetTableFunc>
2709static ChangeInfoResult LoadTranslationTable(uint gvid, int numinfo, ByteReader &buf, TGetTableFunc gettable, std::string_view name)
2710{
2711 if (gvid != 0) {
2712 GrfMsg(1, "LoadTranslationTable: {} translation table must start at zero", name);
2713 return CIR_INVALID_ID;
2714 }
2715
2716 std::vector<T> &translation_table = gettable(*_cur.grffile);
2717 translation_table.clear();
2718 translation_table.reserve(numinfo);
2719 for (int i = 0; i < numinfo; i++) {
2720 translation_table.push_back(T(BSWAP32(buf.ReadDWord())));
2721 }
2722
2723 GRFFile *grf_override = GetCurrentGRFOverride();
2724 if (grf_override != nullptr) {
2725 /* GRF override is present, copy the translation table to the overridden GRF as well. */
2726 GrfMsg(1, "LoadTranslationTable: Copying {} translation table to override GRFID '{}'", name, BSWAP32(grf_override->grfid));
2727 std::vector<T> &override_table = gettable(*grf_override);
2728 override_table = translation_table;
2729 }
2730
2731 return CIR_SUCCESS;
2732}
2733
2740static std::string ReadDWordAsString(ByteReader &reader)
2741{
2742 std::string output;
2743 for (int i = 0; i < 4; i++) output.push_back(reader.ReadByte());
2744 return StrMakeValid(output);
2745}
2746
2755static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, ByteReader &buf)
2756{
2757 /* Properties which are handled as a whole */
2758 switch (prop) {
2759 case 0x09: // Cargo Translation Table; loading during both reservation and activation stage (in case it is selected depending on defined cargos)
2760 return LoadTranslationTable<CargoLabel>(gvid, numinfo, buf, [](GRFFile &grf) -> std::vector<CargoLabel> & { return grf.cargo_list; }, "Cargo");
2761
2762 case 0x12: // Rail type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes)
2763 return LoadTranslationTable<RailTypeLabel>(gvid, numinfo, buf, [](GRFFile &grf) -> std::vector<RailTypeLabel> & { return grf.railtype_list; }, "Rail type");
2764
2765 case 0x16: // Road type translation table; loading during both reservation and activation stage (in case it is selected depending on defined roadtypes)
2766 return LoadTranslationTable<RoadTypeLabel>(gvid, numinfo, buf, [](GRFFile &grf) -> std::vector<RoadTypeLabel> & { return grf.roadtype_list; }, "Road type");
2767
2768 case 0x17: // Tram type translation table; loading during both reservation and activation stage (in case it is selected depending on defined tramtypes)
2769 return LoadTranslationTable<RoadTypeLabel>(gvid, numinfo, buf, [](GRFFile &grf) -> std::vector<RoadTypeLabel> & { return grf.tramtype_list; }, "Tram type");
2770
2771 default:
2772 break;
2773 }
2774
2775 /* Properties which are handled per item */
2777 for (int i = 0; i < numinfo; i++) {
2778 switch (prop) {
2779 case 0x08: { // Cost base factor
2780 int factor = buf.ReadByte();
2781 uint price = gvid + i;
2782
2783 if (price < PR_END) {
2784 _cur.grffile->price_base_multipliers[price] = std::min<int>(factor - 8, MAX_PRICE_MODIFIER);
2785 } else {
2786 GrfMsg(1, "GlobalVarChangeInfo: Price {} out of range, ignoring", price);
2787 }
2788 break;
2789 }
2790
2791 case 0x0A: { // Currency display names
2792 uint curidx = GetNewgrfCurrencyIdConverted(gvid + i);
2793 StringID newone = GetGRFStringID(_cur.grffile->grfid, buf.ReadWord());
2794
2795 if ((newone != STR_UNDEFINED) && (curidx < CURRENCY_END)) {
2796 _currency_specs[curidx].name = newone;
2797 _currency_specs[curidx].code.clear();
2798 }
2799 break;
2800 }
2801
2802 case 0x0B: { // Currency multipliers
2803 uint curidx = GetNewgrfCurrencyIdConverted(gvid + i);
2804 uint32_t rate = buf.ReadDWord();
2805
2806 if (curidx < CURRENCY_END) {
2807 /* TTDPatch uses a multiple of 1000 for its conversion calculations,
2808 * which OTTD does not. For this reason, divide grf value by 1000,
2809 * to be compatible */
2810 _currency_specs[curidx].rate = rate / 1000;
2811 } else {
2812 GrfMsg(1, "GlobalVarChangeInfo: Currency multipliers {} out of range, ignoring", curidx);
2813 }
2814 break;
2815 }
2816
2817 case 0x0C: { // Currency options
2818 uint curidx = GetNewgrfCurrencyIdConverted(gvid + i);
2819 uint16_t options = buf.ReadWord();
2820
2821 if (curidx < CURRENCY_END) {
2822 _currency_specs[curidx].separator.clear();
2823 _currency_specs[curidx].separator.push_back(GB(options, 0, 8));
2824 /* By specifying only one bit, we prevent errors,
2825 * since newgrf specs said that only 0 and 1 can be set for symbol_pos */
2826 _currency_specs[curidx].symbol_pos = GB(options, 8, 1);
2827 } else {
2828 GrfMsg(1, "GlobalVarChangeInfo: Currency option {} out of range, ignoring", curidx);
2829 }
2830 break;
2831 }
2832
2833 case 0x0D: { // Currency prefix symbol
2834 uint curidx = GetNewgrfCurrencyIdConverted(gvid + i);
2835 std::string prefix = ReadDWordAsString(buf);
2836
2837 if (curidx < CURRENCY_END) {
2838 _currency_specs[curidx].prefix = prefix;
2839 } else {
2840 GrfMsg(1, "GlobalVarChangeInfo: Currency symbol {} out of range, ignoring", curidx);
2841 }
2842 break;
2843 }
2844
2845 case 0x0E: { // Currency suffix symbol
2846 uint curidx = GetNewgrfCurrencyIdConverted(gvid + i);
2847 std::string suffix = ReadDWordAsString(buf);
2848
2849 if (curidx < CURRENCY_END) {
2850 _currency_specs[curidx].suffix = suffix;
2851 } else {
2852 GrfMsg(1, "GlobalVarChangeInfo: Currency symbol {} out of range, ignoring", curidx);
2853 }
2854 break;
2855 }
2856
2857 case 0x0F: { // Euro introduction dates
2858 uint curidx = GetNewgrfCurrencyIdConverted(gvid + i);
2859 TimerGameCalendar::Year year_euro = buf.ReadWord();
2860
2861 if (curidx < CURRENCY_END) {
2862 _currency_specs[curidx].to_euro = year_euro;
2863 } else {
2864 GrfMsg(1, "GlobalVarChangeInfo: Euro intro date {} out of range, ignoring", curidx);
2865 }
2866 break;
2867 }
2868
2869 case 0x10: // Snow line height table
2870 if (numinfo > 1 || IsSnowLineSet()) {
2871 GrfMsg(1, "GlobalVarChangeInfo: The snowline can only be set once ({})", numinfo);
2872 } else if (buf.Remaining() < SNOW_LINE_MONTHS * SNOW_LINE_DAYS) {
2873 GrfMsg(1, "GlobalVarChangeInfo: Not enough entries set in the snowline table ({})", buf.Remaining());
2874 } else {
2875 uint8_t table[SNOW_LINE_MONTHS][SNOW_LINE_DAYS];
2876
2877 for (uint i = 0; i < SNOW_LINE_MONTHS; i++) {
2878 for (uint j = 0; j < SNOW_LINE_DAYS; j++) {
2879 table[i][j] = buf.ReadByte();
2880 if (_cur.grffile->grf_version >= 8) {
2881 if (table[i][j] != 0xFF) table[i][j] = table[i][j] * (1 + _settings_game.construction.map_height_limit) / 256;
2882 } else {
2883 if (table[i][j] >= 128) {
2884 /* no snow */
2885 table[i][j] = 0xFF;
2886 } else {
2887 table[i][j] = table[i][j] * (1 + _settings_game.construction.map_height_limit) / 128;
2888 }
2889 }
2890 }
2891 }
2892 SetSnowLine(table);
2893 }
2894 break;
2895
2896 case 0x11: // GRF match for engine allocation
2897 /* This is loaded during the reservation stage, so just skip it here. */
2898 /* Each entry is 8 bytes. */
2899 buf.Skip(8);
2900 break;
2901
2902 case 0x13: // Gender translation table
2903 case 0x14: // Case translation table
2904 case 0x15: { // Plural form translation
2905 uint curidx = gvid + i; // The current index, i.e. language.
2906 const LanguageMetadata *lang = curidx < MAX_LANG ? GetLanguage(curidx) : nullptr;
2907 if (lang == nullptr) {
2908 GrfMsg(1, "GlobalVarChangeInfo: Language {} is not known, ignoring", curidx);
2909 /* Skip over the data. */
2910 if (prop == 0x15) {
2911 buf.ReadByte();
2912 } else {
2913 while (buf.ReadByte() != 0) {
2914 buf.ReadString();
2915 }
2916 }
2917 break;
2918 }
2919
2920 if (prop == 0x15) {
2921 uint plural_form = buf.ReadByte();
2922 if (plural_form >= LANGUAGE_MAX_PLURAL) {
2923 GrfMsg(1, "GlobalVarChanceInfo: Plural form {} is out of range, ignoring", plural_form);
2924 } else {
2925 _cur.grffile->language_map[curidx].plural_form = plural_form;
2926 }
2927 break;
2928 }
2929
2930 uint8_t newgrf_id = buf.ReadByte(); // The NewGRF (custom) identifier.
2931 while (newgrf_id != 0) {
2932 std::string_view name = buf.ReadString(); // The name for the OpenTTD identifier.
2933
2934 /* We'll just ignore the UTF8 identifier character. This is (fairly)
2935 * safe as OpenTTD's strings gender/cases are usually in ASCII which
2936 * is just a subset of UTF8, or they need the bigger UTF8 characters
2937 * such as Cyrillic. Thus we will simply assume they're all UTF8. */
2938 char32_t c;
2939 size_t len = Utf8Decode(&c, name.data());
2940 if (c == NFO_UTF8_IDENTIFIER) name = name.substr(len);
2941
2943 map.newgrf_id = newgrf_id;
2944 if (prop == 0x13) {
2945 map.openttd_id = lang->GetGenderIndex(name.data());
2946 if (map.openttd_id >= MAX_NUM_GENDERS) {
2947 GrfMsg(1, "GlobalVarChangeInfo: Gender name {} is not known, ignoring", StrMakeValid(name));
2948 } else {
2949 _cur.grffile->language_map[curidx].gender_map.push_back(map);
2950 }
2951 } else {
2952 map.openttd_id = lang->GetCaseIndex(name.data());
2953 if (map.openttd_id >= MAX_NUM_CASES) {
2954 GrfMsg(1, "GlobalVarChangeInfo: Case name {} is not known, ignoring", StrMakeValid(name));
2955 } else {
2956 _cur.grffile->language_map[curidx].case_map.push_back(map);
2957 }
2958 }
2959 newgrf_id = buf.ReadByte();
2960 }
2961 break;
2962 }
2963
2964 default:
2965 ret = CIR_UNKNOWN;
2966 break;
2967 }
2968 }
2969
2970 return ret;
2971}
2972
2973static ChangeInfoResult GlobalVarReserveInfo(uint gvid, int numinfo, int prop, ByteReader &buf)
2974{
2975 /* Properties which are handled as a whole */
2976 switch (prop) {
2977 case 0x09: // Cargo Translation Table; loading during both reservation and activation stage (in case it is selected depending on defined cargos)
2978 return LoadTranslationTable<CargoLabel>(gvid, numinfo, buf, [](GRFFile &grf) -> std::vector<CargoLabel> & { return grf.cargo_list; }, "Cargo");
2979
2980 case 0x12: // Rail type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes)
2981 return LoadTranslationTable<RailTypeLabel>(gvid, numinfo, buf, [](GRFFile &grf) -> std::vector<RailTypeLabel> & { return grf.railtype_list; }, "Rail type");
2982
2983 case 0x16: // Road type translation table; loading during both reservation and activation stage (in case it is selected depending on defined roadtypes)
2984 return LoadTranslationTable<RoadTypeLabel>(gvid, numinfo, buf, [](GRFFile &grf) -> std::vector<RoadTypeLabel> & { return grf.roadtype_list; }, "Road type");
2985
2986 case 0x17: // Tram type translation table; loading during both reservation and activation stage (in case it is selected depending on defined tramtypes)
2987 return LoadTranslationTable<RoadTypeLabel>(gvid, numinfo, buf, [](GRFFile &grf) -> std::vector<RoadTypeLabel> & { return grf.tramtype_list; }, "Tram type");
2988
2989 default:
2990 break;
2991 }
2992
2993 /* Properties which are handled per item */
2995 for (int i = 0; i < numinfo; i++) {
2996 switch (prop) {
2997 case 0x08: // Cost base factor
2998 case 0x15: // Plural form translation
2999 buf.ReadByte();
3000 break;
3001
3002 case 0x0A: // Currency display names
3003 case 0x0C: // Currency options
3004 case 0x0F: // Euro introduction dates
3005 buf.ReadWord();
3006 break;
3007
3008 case 0x0B: // Currency multipliers
3009 case 0x0D: // Currency prefix symbol
3010 case 0x0E: // Currency suffix symbol
3011 buf.ReadDWord();
3012 break;
3013
3014 case 0x10: // Snow line height table
3015 buf.Skip(SNOW_LINE_MONTHS * SNOW_LINE_DAYS);
3016 break;
3017
3018 case 0x11: { // GRF match for engine allocation
3019 uint32_t s = buf.ReadDWord();
3020 uint32_t t = buf.ReadDWord();
3021 SetNewGRFOverride(s, t);
3022 break;
3023 }
3024
3025 case 0x13: // Gender translation table
3026 case 0x14: // Case translation table
3027 while (buf.ReadByte() != 0) {
3028 buf.ReadString();
3029 }
3030 break;
3031
3032 default:
3033 ret = CIR_UNKNOWN;
3034 break;
3035 }
3036 }
3037
3038 return ret;
3039}
3040
3041
3050static ChangeInfoResult CargoChangeInfo(uint cid, int numinfo, int prop, ByteReader &buf)
3051{
3053
3054 if (cid + numinfo > NUM_CARGO) {
3055 GrfMsg(2, "CargoChangeInfo: Cargo type {} out of range (max {})", cid + numinfo, NUM_CARGO - 1);
3056 return CIR_INVALID_ID;
3057 }
3058
3059 for (int i = 0; i < numinfo; i++) {
3060 CargoSpec *cs = CargoSpec::Get(cid + i);
3061
3062 switch (prop) {
3063 case 0x08: // Bit number of cargo
3064 cs->bitnum = buf.ReadByte();
3065 if (cs->IsValid()) {
3066 cs->grffile = _cur.grffile;
3067 SetBit(_cargo_mask, cid + i);
3068 } else {
3069 ClrBit(_cargo_mask, cid + i);
3070 }
3072 break;
3073
3074 case 0x09: // String ID for cargo type name
3075 AddStringForMapping(buf.ReadWord(), &cs->name);
3076 break;
3077
3078 case 0x0A: // String for 1 unit of cargo
3079 AddStringForMapping(buf.ReadWord(), &cs->name_single);
3080 break;
3081
3082 case 0x0B: // String for singular quantity of cargo (e.g. 1 tonne of coal)
3083 case 0x1B: // String for cargo units
3084 /* String for units of cargo. This is different in OpenTTD
3085 * (e.g. tonnes) to TTDPatch (e.g. {COMMA} tonne of coal).
3086 * Property 1B is used to set OpenTTD's behaviour. */
3087 AddStringForMapping(buf.ReadWord(), &cs->units_volume);
3088 break;
3089
3090 case 0x0C: // String for plural quantity of cargo (e.g. 10 tonnes of coal)
3091 case 0x1C: // String for any amount of cargo
3092 /* Strings for an amount of cargo. This is different in OpenTTD
3093 * (e.g. {WEIGHT} of coal) to TTDPatch (e.g. {COMMA} tonnes of coal).
3094 * Property 1C is used to set OpenTTD's behaviour. */
3095 AddStringForMapping(buf.ReadWord(), &cs->quantifier);
3096 break;
3097
3098 case 0x0D: // String for two letter cargo abbreviation
3099 AddStringForMapping(buf.ReadWord(), &cs->abbrev);
3100 break;
3101
3102 case 0x0E: // Sprite ID for cargo icon
3103 cs->sprite = buf.ReadWord();
3104 break;
3105
3106 case 0x0F: // Weight of one unit of cargo
3107 cs->weight = buf.ReadByte();
3108 break;
3109
3110 case 0x10: // Used for payment calculation
3111 cs->transit_periods[0] = buf.ReadByte();
3112 break;
3113
3114 case 0x11: // Used for payment calculation
3115 cs->transit_periods[1] = buf.ReadByte();
3116 break;
3117
3118 case 0x12: // Base cargo price
3119 cs->initial_payment = buf.ReadDWord();
3120 break;
3121
3122 case 0x13: // Colour for station rating bars
3123 cs->rating_colour = buf.ReadByte();
3124 break;
3125
3126 case 0x14: // Colour for cargo graph
3127 cs->legend_colour = buf.ReadByte();
3128 break;
3129
3130 case 0x15: // Freight status
3131 cs->is_freight = (buf.ReadByte() != 0);
3132 break;
3133
3134 case 0x16: // Cargo classes
3135 cs->classes = buf.ReadWord();
3136 break;
3137
3138 case 0x17: // Cargo label
3139 cs->label = CargoLabel{BSWAP32(buf.ReadDWord())};
3141 break;
3142
3143 case 0x18: { // Town growth substitute type
3144 uint8_t substitute_type = buf.ReadByte();
3145
3146 switch (substitute_type) {
3147 case 0x00: cs->town_acceptance_effect = TAE_PASSENGERS; break;
3148 case 0x02: cs->town_acceptance_effect = TAE_MAIL; break;
3149 case 0x05: cs->town_acceptance_effect = TAE_GOODS; break;
3150 case 0x09: cs->town_acceptance_effect = TAE_WATER; break;
3151 case 0x0B: cs->town_acceptance_effect = TAE_FOOD; break;
3152 default:
3153 GrfMsg(1, "CargoChangeInfo: Unknown town growth substitute value {}, setting to none.", substitute_type);
3154 [[fallthrough]];
3155 case 0xFF: cs->town_acceptance_effect = TAE_NONE; break;
3156 }
3157 break;
3158 }
3159
3160 case 0x19: // Town growth coefficient
3161 buf.ReadWord();
3162 break;
3163
3164 case 0x1A: // Bitmask of callbacks to use
3165 cs->callback_mask = buf.ReadByte();
3166 break;
3167
3168 case 0x1D: // Vehicle capacity muliplier
3169 cs->multiplier = std::max<uint16_t>(1u, buf.ReadWord());
3170 break;
3171
3172 case 0x1E: { // Town production substitute type
3173 uint8_t substitute_type = buf.ReadByte();
3174
3175 switch (substitute_type) {
3176 case 0x00: cs->town_production_effect = TPE_PASSENGERS; break;
3177 case 0x02: cs->town_production_effect = TPE_MAIL; break;
3178 default:
3179 GrfMsg(1, "CargoChangeInfo: Unknown town production substitute value {}, setting to none.", substitute_type);
3180 [[fallthrough]];
3181 case 0xFF: cs->town_production_effect = TPE_NONE; break;
3182 }
3183 break;
3184 }
3185
3186 case 0x1F: // Town production multiplier
3187 cs->town_production_multiplier = std::max<uint16_t>(1U, buf.ReadWord());
3188 break;
3189
3190 default:
3191 ret = CIR_UNKNOWN;
3192 break;
3193 }
3194 }
3195
3196 return ret;
3197}
3198
3199
3208static ChangeInfoResult SoundEffectChangeInfo(uint sid, int numinfo, int prop, ByteReader &buf)
3209{
3211
3212 if (_cur.grffile->sound_offset == 0) {
3213 GrfMsg(1, "SoundEffectChangeInfo: No effects defined, skipping");
3214 return CIR_INVALID_ID;
3215 }
3216
3217 if (sid + numinfo - ORIGINAL_SAMPLE_COUNT > _cur.grffile->num_sounds) {
3218 GrfMsg(1, "SoundEffectChangeInfo: Attempting to change undefined sound effect ({}), max ({}). Ignoring.", sid + numinfo, ORIGINAL_SAMPLE_COUNT + _cur.grffile->num_sounds);
3219 return CIR_INVALID_ID;
3220 }
3221
3222 for (int i = 0; i < numinfo; i++) {
3223 SoundEntry *sound = GetSound(sid + i + _cur.grffile->sound_offset - ORIGINAL_SAMPLE_COUNT);
3224
3225 switch (prop) {
3226 case 0x08: // Relative volume
3227 sound->volume = Clamp(buf.ReadByte(), 0, SOUND_EFFECT_MAX_VOLUME);
3228 break;
3229
3230 case 0x09: // Priority
3231 sound->priority = buf.ReadByte();
3232 break;
3233
3234 case 0x0A: { // Override old sound
3235 SoundID orig_sound = buf.ReadByte();
3236
3237 if (orig_sound >= ORIGINAL_SAMPLE_COUNT) {
3238 GrfMsg(1, "SoundEffectChangeInfo: Original sound {} not defined (max {})", orig_sound, ORIGINAL_SAMPLE_COUNT);
3239 } else {
3240 SoundEntry *old_sound = GetSound(orig_sound);
3241
3242 /* Literally copy the data of the new sound over the original */
3243 *old_sound = *sound;
3244 }
3245 break;
3246 }
3247
3248 default:
3249 ret = CIR_UNKNOWN;
3250 break;
3251 }
3252 }
3253
3254 return ret;
3255}
3256
3264{
3266
3267 switch (prop) {
3268 case 0x09:
3269 case 0x0D:
3270 case 0x0E:
3271 case 0x10:
3272 case 0x11:
3273 case 0x12:
3274 buf.ReadByte();
3275 break;
3276
3277 case 0x0A:
3278 case 0x0B:
3279 case 0x0C:
3280 case 0x0F:
3281 buf.ReadWord();
3282 break;
3283
3284 case 0x13:
3285 buf.Skip(buf.ReadByte() * 2);
3286 break;
3287
3288 default:
3289 ret = CIR_UNKNOWN;
3290 break;
3291 }
3292 return ret;
3293}
3294
3303static ChangeInfoResult IndustrytilesChangeInfo(uint indtid, int numinfo, int prop, ByteReader &buf)
3304{
3306
3307 if (indtid + numinfo > NUM_INDUSTRYTILES_PER_GRF) {
3308 GrfMsg(1, "IndustryTilesChangeInfo: Too many industry tiles loaded ({}), max ({}). Ignoring.", indtid + numinfo, NUM_INDUSTRYTILES_PER_GRF);
3309 return CIR_INVALID_ID;
3310 }
3311
3312 /* Allocate industry tile specs if they haven't been allocated already. */
3313 if (_cur.grffile->indtspec.size() < indtid + numinfo) _cur.grffile->indtspec.resize(indtid + numinfo);
3314
3315 for (int i = 0; i < numinfo; i++) {
3316 auto &tsp = _cur.grffile->indtspec[indtid + i];
3317
3318 if (prop != 0x08 && tsp == nullptr) {
3320 if (cir > ret) ret = cir;
3321 continue;
3322 }
3323
3324 switch (prop) {
3325 case 0x08: { // Substitute industry tile type
3326 uint8_t subs_id = buf.ReadByte();
3327 if (subs_id >= NEW_INDUSTRYTILEOFFSET) {
3328 /* The substitute id must be one of the original industry tile. */
3329 GrfMsg(2, "IndustryTilesChangeInfo: Attempt to use new industry tile {} as substitute industry tile for {}. Ignoring.", subs_id, indtid + i);
3330 continue;
3331 }
3332
3333 /* Allocate space for this industry. */
3334 if (tsp == nullptr) {
3335 tsp = std::make_unique<IndustryTileSpec>(_industry_tile_specs[subs_id]);
3336
3337 tsp->enabled = true;
3338
3339 /* A copied tile should not have the animation infos copied too.
3340 * The anim_state should be left untouched, though
3341 * It is up to the author to animate them */
3342 tsp->anim_production = INDUSTRYTILE_NOANIM;
3343 tsp->anim_next = INDUSTRYTILE_NOANIM;
3344
3345 tsp->grf_prop.local_id = indtid + i;
3346 tsp->grf_prop.subst_id = subs_id;
3347 tsp->grf_prop.grfid = _cur.grffile->grfid;
3348 tsp->grf_prop.grffile = _cur.grffile;
3349 _industile_mngr.AddEntityID(indtid + i, _cur.grffile->grfid, subs_id); // pre-reserve the tile slot
3350 }
3351 break;
3352 }
3353
3354 case 0x09: { // Industry tile override
3355 uint8_t ovrid = buf.ReadByte();
3356
3357 /* The industry being overridden must be an original industry. */
3358 if (ovrid >= NEW_INDUSTRYTILEOFFSET) {
3359 GrfMsg(2, "IndustryTilesChangeInfo: Attempt to override new industry tile {} with industry tile id {}. Ignoring.", ovrid, indtid + i);
3360 continue;
3361 }
3362
3363 _industile_mngr.Add(indtid + i, _cur.grffile->grfid, ovrid);
3364 break;
3365 }
3366
3367 case 0x0A: // Tile acceptance
3368 case 0x0B:
3369 case 0x0C: {
3370 uint16_t acctp = buf.ReadWord();
3371 tsp->accepts_cargo[prop - 0x0A] = GetCargoTranslation(GB(acctp, 0, 8), _cur.grffile);
3372 tsp->acceptance[prop - 0x0A] = Clamp(GB(acctp, 8, 8), 0, 16);
3373 tsp->accepts_cargo_label[prop - 0x0A] = CT_INVALID;
3374 break;
3375 }
3376
3377 case 0x0D: // Land shape flags
3378 tsp->slopes_refused = (Slope)buf.ReadByte();
3379 break;
3380
3381 case 0x0E: // Callback mask
3382 tsp->callback_mask = buf.ReadByte();
3383 break;
3384
3385 case 0x0F: // Animation information
3386 tsp->animation.frames = buf.ReadByte();
3387 tsp->animation.status = buf.ReadByte();
3388 break;
3389
3390 case 0x10: // Animation speed
3391 tsp->animation.speed = buf.ReadByte();
3392 break;
3393
3394 case 0x11: // Triggers for callback 25
3395 tsp->animation.triggers = buf.ReadByte();
3396 break;
3397
3398 case 0x12: // Special flags
3399 tsp->special_flags = (IndustryTileSpecialFlags)buf.ReadByte();
3400 break;
3401
3402 case 0x13: { // variable length cargo acceptance
3403 uint8_t num_cargoes = buf.ReadByte();
3404 if (num_cargoes > std::size(tsp->acceptance)) {
3405 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG);
3406 error->param_value[1] = prop;
3407 return CIR_DISABLED;
3408 }
3409 for (uint i = 0; i < std::size(tsp->acceptance); i++) {
3410 if (i < num_cargoes) {
3411 tsp->accepts_cargo[i] = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
3412 /* Tile acceptance can be negative to counteract the INDTILE_SPECIAL_ACCEPTS_ALL_CARGO flag */
3413 tsp->acceptance[i] = (int8_t)buf.ReadByte();
3414 } else {
3415 tsp->accepts_cargo[i] = INVALID_CARGO;
3416 tsp->acceptance[i] = 0;
3417 }
3418 if (i < std::size(tsp->accepts_cargo_label)) tsp->accepts_cargo_label[i] = CT_INVALID;
3419 }
3420 break;
3421 }
3422
3423 default:
3424 ret = CIR_UNKNOWN;
3425 break;
3426 }
3427 }
3428
3429 return ret;
3430}
3431
3439{
3441
3442 switch (prop) {
3443 case 0x09:
3444 case 0x0B:
3445 case 0x0F:
3446 case 0x12:
3447 case 0x13:
3448 case 0x14:
3449 case 0x17:
3450 case 0x18:
3451 case 0x19:
3452 case 0x21:
3453 case 0x22:
3454 buf.ReadByte();
3455 break;
3456
3457 case 0x0C:
3458 case 0x0D:
3459 case 0x0E:
3460 case 0x10: // INDUSTRY_ORIGINAL_NUM_OUTPUTS bytes
3461 case 0x1B:
3462 case 0x1F:
3463 case 0x24:
3464 buf.ReadWord();
3465 break;
3466
3467 case 0x11: // INDUSTRY_ORIGINAL_NUM_INPUTS bytes + 1
3468 case 0x1A:
3469 case 0x1C:
3470 case 0x1D:
3471 case 0x1E:
3472 case 0x20:
3473 case 0x23:
3474 buf.ReadDWord();
3475 break;
3476
3477 case 0x0A: {
3478 uint8_t num_table = buf.ReadByte();
3479 for (uint8_t j = 0; j < num_table; j++) {
3480 for (uint k = 0;; k++) {
3481 uint8_t x = buf.ReadByte();
3482 if (x == 0xFE && k == 0) {
3483 buf.ReadByte();
3484 buf.ReadByte();
3485 break;
3486 }
3487
3488 uint8_t y = buf.ReadByte();
3489 if (x == 0 && y == 0x80) break;
3490
3491 uint8_t gfx = buf.ReadByte();
3492 if (gfx == 0xFE) buf.ReadWord();
3493 }
3494 }
3495 break;
3496 }
3497
3498 case 0x16:
3499 for (uint8_t j = 0; j < INDUSTRY_ORIGINAL_NUM_INPUTS; j++) buf.ReadByte();
3500 break;
3501
3502 case 0x15:
3503 case 0x25:
3504 case 0x26:
3505 case 0x27:
3506 buf.Skip(buf.ReadByte());
3507 break;
3508
3509 case 0x28: {
3510 int num_inputs = buf.ReadByte();
3511 int num_outputs = buf.ReadByte();
3512 buf.Skip(num_inputs * num_outputs * 2);
3513 break;
3514 }
3515
3516 default:
3517 ret = CIR_UNKNOWN;
3518 break;
3519 }
3520 return ret;
3521}
3522
3529{
3530 const size_t size = layout.size();
3531 if (size == 0) return false;
3532
3533 for (size_t i = 0; i < size - 1; i++) {
3534 for (size_t j = i + 1; j < size; j++) {
3535 if (layout[i].ti.x == layout[j].ti.x &&
3536 layout[i].ti.y == layout[j].ti.y) {
3537 return false;
3538 }
3539 }
3540 }
3541
3542 bool have_regular_tile = false;
3543 for (const auto &tilelayout : layout) {
3544 if (tilelayout.gfx != GFX_WATERTILE_SPECIALCHECK) {
3545 have_regular_tile = true;
3546 break;
3547 }
3548 }
3549
3550 return have_regular_tile;
3551}
3552
3561static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, ByteReader &buf)
3562{
3564
3565 if (indid + numinfo > NUM_INDUSTRYTYPES_PER_GRF) {
3566 GrfMsg(1, "IndustriesChangeInfo: Too many industries loaded ({}), max ({}). Ignoring.", indid + numinfo, NUM_INDUSTRYTYPES_PER_GRF);
3567 return CIR_INVALID_ID;
3568 }
3569
3570 /* Allocate industry specs if they haven't been allocated already. */
3571 if (_cur.grffile->industryspec.size() < indid + numinfo) _cur.grffile->industryspec.resize(indid + numinfo);
3572
3573 for (int i = 0; i < numinfo; i++) {
3574 auto &indsp = _cur.grffile->industryspec[indid + i];
3575
3576 if (prop != 0x08 && indsp == nullptr) {
3578 if (cir > ret) ret = cir;
3579 continue;
3580 }
3581
3582 switch (prop) {
3583 case 0x08: { // Substitute industry type
3584 uint8_t subs_id = buf.ReadByte();
3585 if (subs_id == 0xFF) {
3586 /* Instead of defining a new industry, a substitute industry id
3587 * of 0xFF disables the old industry with the current id. */
3588 _industry_specs[indid + i].enabled = false;
3589 continue;
3590 } else if (subs_id >= NEW_INDUSTRYOFFSET) {
3591 /* The substitute id must be one of the original industry. */
3592 GrfMsg(2, "_industry_specs: Attempt to use new industry {} as substitute industry for {}. Ignoring.", subs_id, indid + i);
3593 continue;
3594 }
3595
3596 /* Allocate space for this industry.
3597 * Only need to do it once. If ever it is called again, it should not
3598 * do anything */
3599 if (indsp == nullptr) {
3600 indsp = std::make_unique<IndustrySpec>(_origin_industry_specs[subs_id]);
3601
3602 indsp->enabled = true;
3603 indsp->grf_prop.local_id = indid + i;
3604 indsp->grf_prop.subst_id = subs_id;
3605 indsp->grf_prop.grfid = _cur.grffile->grfid;
3606 indsp->grf_prop.grffile = _cur.grffile;
3607 /* If the grf industry needs to check its surrounding upon creation, it should
3608 * rely on callbacks, not on the original placement functions */
3609 indsp->check_proc = CHECK_NOTHING;
3610 }
3611 break;
3612 }
3613
3614 case 0x09: { // Industry type override
3615 uint8_t ovrid = buf.ReadByte();
3616
3617 /* The industry being overridden must be an original industry. */
3618 if (ovrid >= NEW_INDUSTRYOFFSET) {
3619 GrfMsg(2, "IndustriesChangeInfo: Attempt to override new industry {} with industry id {}. Ignoring.", ovrid, indid + i);
3620 continue;
3621 }
3622 indsp->grf_prop.override = ovrid;
3623 _industry_mngr.Add(indid + i, _cur.grffile->grfid, ovrid);
3624 break;
3625 }
3626
3627 case 0x0A: { // Set industry layout(s)
3628 uint8_t new_num_layouts = buf.ReadByte();
3629 uint32_t definition_size = buf.ReadDWord();
3630 uint32_t bytes_read = 0;
3631 std::vector<IndustryTileLayout> new_layouts;
3632 IndustryTileLayout layout;
3633
3634 for (uint8_t j = 0; j < new_num_layouts; j++) {
3635 layout.clear();
3636 layout.reserve(new_num_layouts);
3637
3638 for (uint k = 0;; k++) {
3639 if (bytes_read >= definition_size) {
3640 GrfMsg(3, "IndustriesChangeInfo: Incorrect size for industry tile layout definition for industry {}.", indid);
3641 /* Avoid warning twice */
3642 definition_size = UINT32_MAX;
3643 }
3644
3645 IndustryTileLayoutTile &it = layout.emplace_back();
3646
3647 it.ti.x = buf.ReadByte(); // Offsets from northermost tile
3648 ++bytes_read;
3649
3650 if (it.ti.x == 0xFE && k == 0) {
3651 /* This means we have to borrow the layout from an old industry */
3652 IndustryType type = buf.ReadByte();
3653 uint8_t laynbr = buf.ReadByte();
3654 bytes_read += 2;
3655
3656 if (type >= lengthof(_origin_industry_specs)) {
3657 GrfMsg(1, "IndustriesChangeInfo: Invalid original industry number for layout import, industry {}", indid);
3658 DisableGrf(STR_NEWGRF_ERROR_INVALID_ID);
3659 return CIR_DISABLED;
3660 }
3661 if (laynbr >= _origin_industry_specs[type].layouts.size()) {
3662 GrfMsg(1, "IndustriesChangeInfo: Invalid original industry layout index for layout import, industry {}", indid);
3663 DisableGrf(STR_NEWGRF_ERROR_INVALID_ID);
3664 return CIR_DISABLED;
3665 }
3666 layout = _origin_industry_specs[type].layouts[laynbr];
3667 break;
3668 }
3669
3670 it.ti.y = buf.ReadByte(); // Or table definition finalisation
3671 ++bytes_read;
3672
3673 if (it.ti.x == 0 && it.ti.y == 0x80) {
3674 /* Terminator, remove and finish up */
3675 layout.pop_back();
3676 break;
3677 }
3678
3679 it.gfx = buf.ReadByte();
3680 ++bytes_read;
3681
3682 if (it.gfx == 0xFE) {
3683 /* Use a new tile from this GRF */
3684 int local_tile_id = buf.ReadWord();
3685 bytes_read += 2;
3686
3687 /* Read the ID from the _industile_mngr. */
3688 int tempid = _industile_mngr.GetID(local_tile_id, _cur.grffile->grfid);
3689
3690 if (tempid == INVALID_INDUSTRYTILE) {
3691 GrfMsg(2, "IndustriesChangeInfo: Attempt to use industry tile {} with industry id {}, not yet defined. Ignoring.", local_tile_id, indid);
3692 } else {
3693 /* Declared as been valid, can be used */
3694 it.gfx = tempid;
3695 }
3696 } else if (it.gfx == GFX_WATERTILE_SPECIALCHECK) {
3697 it.ti.x = (int8_t)GB(it.ti.x, 0, 8);
3698 it.ti.y = (int8_t)GB(it.ti.y, 0, 8);
3699
3700 /* When there were only 256x256 maps, TileIndex was a uint16_t and
3701 * it.ti was just a TileIndexDiff that was added to it.
3702 * As such negative "x" values were shifted into the "y" position.
3703 * x = -1, y = 1 -> x = 255, y = 0
3704 * Since GRF version 8 the position is interpreted as pair of independent int8.
3705 * For GRF version < 8 we need to emulate the old shifting behaviour.
3706 */
3707 if (_cur.grffile->grf_version < 8 && it.ti.x < 0) it.ti.y += 1;
3708 }
3709 }
3710
3711 if (!ValidateIndustryLayout(layout)) {
3712 /* The industry layout was not valid, so skip this one. */
3713 GrfMsg(1, "IndustriesChangeInfo: Invalid industry layout for industry id {}. Ignoring", indid);
3714 new_num_layouts--;
3715 j--;
3716 } else {
3717 new_layouts.push_back(layout);
3718 }
3719 }
3720
3721 /* Install final layout construction in the industry spec */
3722 indsp->layouts = new_layouts;
3723 break;
3724 }
3725
3726 case 0x0B: // Industry production flags
3727 indsp->life_type = (IndustryLifeType)buf.ReadByte();
3728 break;
3729
3730 case 0x0C: // Industry closure message
3731 AddStringForMapping(buf.ReadWord(), &indsp->closure_text);
3732 break;
3733
3734 case 0x0D: // Production increase message
3735 AddStringForMapping(buf.ReadWord(), &indsp->production_up_text);
3736 break;
3737
3738 case 0x0E: // Production decrease message
3739 AddStringForMapping(buf.ReadWord(), &indsp->production_down_text);
3740 break;
3741
3742 case 0x0F: // Fund cost multiplier
3743 indsp->cost_multiplier = buf.ReadByte();
3744 break;
3745
3746 case 0x10: // Production cargo types
3747 for (uint8_t j = 0; j < INDUSTRY_ORIGINAL_NUM_OUTPUTS; j++) {
3748 indsp->produced_cargo[j] = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
3749 indsp->produced_cargo_label[j] = CT_INVALID;
3750 }
3751 break;
3752
3753 case 0x11: // Acceptance cargo types
3754 for (uint8_t j = 0; j < INDUSTRY_ORIGINAL_NUM_INPUTS; j++) {
3755 indsp->accepts_cargo[j] = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
3756 indsp->accepts_cargo_label[j] = CT_INVALID;
3757 }
3758 buf.ReadByte(); // Unnused, eat it up
3759 break;
3760
3761 case 0x12: // Production multipliers
3762 case 0x13:
3763 indsp->production_rate[prop - 0x12] = buf.ReadByte();
3764 break;
3765
3766 case 0x14: // Minimal amount of cargo distributed
3767 indsp->minimal_cargo = buf.ReadByte();
3768 break;
3769
3770 case 0x15: { // Random sound effects
3771 uint8_t num_sounds = buf.ReadByte();
3772
3773 std::vector<uint8_t> sounds;
3774 sounds.reserve(num_sounds);
3775 for (uint8_t j = 0; j < num_sounds; ++j) {
3776 sounds.push_back(buf.ReadByte());
3777 }
3778
3779 indsp->random_sounds = std::move(sounds);
3780 break;
3781 }
3782
3783 case 0x16: // Conflicting industry types
3784 for (uint8_t j = 0; j < 3; j++) indsp->conflicting[j] = buf.ReadByte();
3785 break;
3786
3787 case 0x17: // Probability in random game
3788 indsp->appear_creation[_settings_game.game_creation.landscape] = buf.ReadByte();
3789 break;
3790
3791 case 0x18: // Probability during gameplay
3792 indsp->appear_ingame[_settings_game.game_creation.landscape] = buf.ReadByte();
3793 break;
3794
3795 case 0x19: // Map colour
3796 indsp->map_colour = buf.ReadByte();
3797 break;
3798
3799 case 0x1A: // Special industry flags to define special behavior
3800 indsp->behaviour = (IndustryBehaviour)buf.ReadDWord();
3801 break;
3802
3803 case 0x1B: // New industry text ID
3804 AddStringForMapping(buf.ReadWord(), &indsp->new_industry_text);
3805 break;
3806
3807 case 0x1C: // Input cargo multipliers for the three input cargo types
3808 case 0x1D:
3809 case 0x1E: {
3810 uint32_t multiples = buf.ReadDWord();
3811 indsp->input_cargo_multiplier[prop - 0x1C][0] = GB(multiples, 0, 16);
3812 indsp->input_cargo_multiplier[prop - 0x1C][1] = GB(multiples, 16, 16);
3813 break;
3814 }
3815
3816 case 0x1F: // Industry name
3817 AddStringForMapping(buf.ReadWord(), &indsp->name);
3818 break;
3819
3820 case 0x20: // Prospecting success chance
3821 indsp->prospecting_chance = buf.ReadDWord();
3822 break;
3823
3824 case 0x21: // Callback mask
3825 case 0x22: { // Callback additional mask
3826 uint8_t aflag = buf.ReadByte();
3827 SB(indsp->callback_mask, (prop - 0x21) * 8, 8, aflag);
3828 break;
3829 }
3830
3831 case 0x23: // removal cost multiplier
3832 indsp->removal_cost_multiplier = buf.ReadDWord();
3833 break;
3834
3835 case 0x24: { // name for nearby station
3836 uint16_t str = buf.ReadWord();
3837 if (str == 0) {
3838 indsp->station_name = STR_NULL;
3839 } else {
3840 AddStringForMapping(str, &indsp->station_name);
3841 }
3842 break;
3843 }
3844
3845 case 0x25: { // variable length produced cargoes
3846 uint8_t num_cargoes = buf.ReadByte();
3847 if (num_cargoes > std::size(indsp->produced_cargo)) {
3848 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG);
3849 error->param_value[1] = prop;
3850 return CIR_DISABLED;
3851 }
3852 for (size_t i = 0; i < std::size(indsp->produced_cargo); i++) {
3853 if (i < num_cargoes) {
3854 CargoID cargo = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
3855 indsp->produced_cargo[i] = cargo;
3856 } else {
3857 indsp->produced_cargo[i] = INVALID_CARGO;
3858 }
3859 if (i < std::size(indsp->produced_cargo_label)) indsp->produced_cargo_label[i] = CT_INVALID;
3860 }
3861 break;
3862 }
3863
3864 case 0x26: { // variable length accepted cargoes
3865 uint8_t num_cargoes = buf.ReadByte();
3866 if (num_cargoes > std::size(indsp->accepts_cargo)) {
3867 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG);
3868 error->param_value[1] = prop;
3869 return CIR_DISABLED;
3870 }
3871 for (size_t i = 0; i < std::size(indsp->accepts_cargo); i++) {
3872 if (i < num_cargoes) {
3873 CargoID cargo = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
3874 indsp->accepts_cargo[i] = cargo;
3875 } else {
3876 indsp->accepts_cargo[i] = INVALID_CARGO;
3877 }
3878 if (i < std::size(indsp->accepts_cargo_label)) indsp->accepts_cargo_label[i] = CT_INVALID;
3879 }
3880 break;
3881 }
3882
3883 case 0x27: { // variable length production rates
3884 uint8_t num_cargoes = buf.ReadByte();
3885 if (num_cargoes > lengthof(indsp->production_rate)) {
3886 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG);
3887 error->param_value[1] = prop;
3888 return CIR_DISABLED;
3889 }
3890 for (uint i = 0; i < lengthof(indsp->production_rate); i++) {
3891 if (i < num_cargoes) {
3892 indsp->production_rate[i] = buf.ReadByte();
3893 } else {
3894 indsp->production_rate[i] = 0;
3895 }
3896 }
3897 break;
3898 }
3899
3900 case 0x28: { // variable size input/output production multiplier table
3901 uint8_t num_inputs = buf.ReadByte();
3902 uint8_t num_outputs = buf.ReadByte();
3903 if (num_inputs > std::size(indsp->accepts_cargo) || num_outputs > std::size(indsp->produced_cargo)) {
3904 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG);
3905 error->param_value[1] = prop;
3906 return CIR_DISABLED;
3907 }
3908 for (size_t i = 0; i < std::size(indsp->accepts_cargo); i++) {
3909 for (size_t j = 0; j < std::size(indsp->produced_cargo); j++) {
3910 uint16_t mult = 0;
3911 if (i < num_inputs && j < num_outputs) mult = buf.ReadWord();
3912 indsp->input_cargo_multiplier[i][j] = mult;
3913 }
3914 }
3915 break;
3916 }
3917
3918 default:
3919 ret = CIR_UNKNOWN;
3920 break;
3921 }
3922 }
3923
3924 return ret;
3925}
3926
3935static ChangeInfoResult AirportChangeInfo(uint airport, int numinfo, int prop, ByteReader &buf)
3936{
3938
3939 if (airport + numinfo > NUM_AIRPORTS_PER_GRF) {
3940 GrfMsg(1, "AirportChangeInfo: Too many airports, trying id ({}), max ({}). Ignoring.", airport + numinfo, NUM_AIRPORTS_PER_GRF);
3941 return CIR_INVALID_ID;
3942 }
3943
3944 /* Allocate industry specs if they haven't been allocated already. */
3945 if (_cur.grffile->airportspec.size() < airport + numinfo) _cur.grffile->airportspec.resize(airport + numinfo);
3946
3947 for (int i = 0; i < numinfo; i++) {
3948 auto &as = _cur.grffile->airportspec[airport + i];
3949
3950 if (as == nullptr && prop != 0x08 && prop != 0x09) {
3951 GrfMsg(2, "AirportChangeInfo: Attempt to modify undefined airport {}, ignoring", airport + i);
3952 return CIR_INVALID_ID;
3953 }
3954
3955 switch (prop) {
3956 case 0x08: { // Modify original airport
3957 uint8_t subs_id = buf.ReadByte();
3958 if (subs_id == 0xFF) {
3959 /* Instead of defining a new airport, an airport id
3960 * of 0xFF disables the old airport with the current id. */
3961 AirportSpec::GetWithoutOverride(airport + i)->enabled = false;
3962 continue;
3963 } else if (subs_id >= NEW_AIRPORT_OFFSET) {
3964 /* The substitute id must be one of the original airports. */
3965 GrfMsg(2, "AirportChangeInfo: Attempt to use new airport {} as substitute airport for {}. Ignoring.", subs_id, airport + i);
3966 continue;
3967 }
3968
3969 /* Allocate space for this airport.
3970 * Only need to do it once. If ever it is called again, it should not
3971 * do anything */
3972 if (as == nullptr) {
3973 as = std::make_unique<AirportSpec>(*AirportSpec::GetWithoutOverride(subs_id));
3974
3975 as->enabled = true;
3976 as->grf_prop.local_id = airport + i;
3977 as->grf_prop.subst_id = subs_id;
3978 as->grf_prop.grfid = _cur.grffile->grfid;
3979 as->grf_prop.grffile = _cur.grffile;
3980 /* override the default airport */
3981 _airport_mngr.Add(airport + i, _cur.grffile->grfid, subs_id);
3982 }
3983 break;
3984 }
3985
3986 case 0x0A: { // Set airport layout
3987 uint8_t num_layouts = buf.ReadByte();
3988 buf.ReadDWord(); // Total size of definition, unneeded.
3989 uint8_t size_x = 0;
3990 uint8_t size_y = 0;
3991
3992 std::vector<AirportTileLayout> layouts;
3993 layouts.reserve(num_layouts);
3994
3995 for (uint8_t j = 0; j != num_layouts; ++j) {
3996 auto &layout = layouts.emplace_back();
3997 layout.rotation = static_cast<Direction>(buf.ReadByte() & 6); // Rotation can only be DIR_NORTH, DIR_EAST, DIR_SOUTH or DIR_WEST.
3998
3999 for (;;) {
4000 auto &tile = layout.tiles.emplace_back();
4001 tile.ti.x = buf.ReadByte();
4002 tile.ti.y = buf.ReadByte();
4003 if (tile.ti.x == 0 && tile.ti.y == 0x80) {
4004 /* Convert terminator to our own. */
4005 tile.ti.x = -0x80;
4006 tile.ti.y = 0;
4007 tile.gfx = 0;
4008 break;
4009 }
4010
4011 tile.gfx = buf.ReadByte();
4012
4013 if (tile.gfx == 0xFE) {
4014 /* Use a new tile from this GRF */
4015 int local_tile_id = buf.ReadWord();
4016
4017 /* Read the ID from the _airporttile_mngr. */
4018 uint16_t tempid = _airporttile_mngr.GetID(local_tile_id, _cur.grffile->grfid);
4019
4020 if (tempid == INVALID_AIRPORTTILE) {
4021 GrfMsg(2, "AirportChangeInfo: Attempt to use airport tile {} with airport id {}, not yet defined. Ignoring.", local_tile_id, airport + i);
4022 } else {
4023 /* Declared as been valid, can be used */
4024 tile.gfx = tempid;
4025 }
4026 } else if (tile.gfx == 0xFF) {
4027 tile.ti.x = static_cast<int8_t>(GB(tile.ti.x, 0, 8));
4028 tile.ti.y = static_cast<int8_t>(GB(tile.ti.y, 0, 8));
4029 }
4030
4031 /* Determine largest size. */
4032 if (layout.rotation == DIR_E || layout.rotation == DIR_W) {
4033 size_x = std::max<uint8_t>(size_x, tile.ti.y + 1);
4034 size_y = std::max<uint8_t>(size_y, tile.ti.x + 1);
4035 } else {
4036 size_x = std::max<uint8_t>(size_x, tile.ti.x + 1);
4037 size_y = std::max<uint8_t>(size_y, tile.ti.y + 1);
4038 }
4039 }
4040 }
4041 as->layouts = std::move(layouts);
4042 as->size_x = size_x;
4043 as->size_y = size_y;
4044 break;
4045 }
4046
4047 case 0x0C:
4048 as->min_year = buf.ReadWord();
4049 as->max_year = buf.ReadWord();
4050 if (as->max_year == 0xFFFF) as->max_year = CalendarTime::MAX_YEAR;
4051 break;
4052
4053 case 0x0D:
4054 as->ttd_airport_type = (TTDPAirportType)buf.ReadByte();
4055 break;
4056
4057 case 0x0E:
4058 as->catchment = Clamp(buf.ReadByte(), 1, MAX_CATCHMENT);
4059 break;
4060
4061 case 0x0F:
4062 as->noise_level = buf.ReadByte();
4063 break;
4064
4065 case 0x10:
4066 AddStringForMapping(buf.ReadWord(), &as->name);
4067 break;
4068
4069 case 0x11: // Maintenance cost factor
4070 as->maintenance_cost = buf.ReadWord();
4071 break;
4072
4073 default:
4074 ret = CIR_UNKNOWN;
4075 break;
4076 }
4077 }
4078
4079 return ret;
4080}
4081
4089{
4091
4092 switch (prop) {
4093 case 0x0B:
4094 case 0x0C:
4095 case 0x0D:
4096 case 0x12:
4097 case 0x14:
4098 case 0x16:
4099 case 0x17:
4100 case 0x18:
4101 buf.ReadByte();
4102 break;
4103
4104 case 0x09:
4105 case 0x0A:
4106 case 0x10:
4107 case 0x11:
4108 case 0x13:
4109 case 0x15:
4110 buf.ReadWord();
4111 break;
4112
4113 case 0x08:
4114 case 0x0E:
4115 case 0x0F:
4116 buf.ReadDWord();
4117 break;
4118
4119 default:
4120 ret = CIR_UNKNOWN;
4121 break;
4122 }
4123
4124 return ret;
4125}
4126
4135static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, ByteReader &buf)
4136{
4138
4139 if (id + numinfo > NUM_OBJECTS_PER_GRF) {
4140 GrfMsg(1, "ObjectChangeInfo: Too many objects loaded ({}), max ({}). Ignoring.", id + numinfo, NUM_OBJECTS_PER_GRF);
4141 return CIR_INVALID_ID;
4142 }
4143
4144 /* Allocate object specs if they haven't been allocated already. */
4145 if (_cur.grffile->objectspec.size() < id + numinfo) _cur.grffile->objectspec.resize(id + numinfo);
4146
4147 for (int i = 0; i < numinfo; i++) {
4148 auto &spec = _cur.grffile->objectspec[id + i];
4149
4150 if (prop != 0x08 && spec == nullptr) {
4151 /* If the object property 08 is not yet set, ignore this property */
4152 ChangeInfoResult cir = IgnoreObjectProperty(prop, buf);
4153 if (cir > ret) ret = cir;
4154 continue;
4155 }
4156
4157 switch (prop) {
4158 case 0x08: { // Class ID
4159 /* Allocate space for this object. */
4160 if (spec == nullptr) {
4161 spec = std::make_unique<ObjectSpec>();
4162 spec->views = 1; // Default for NewGRFs that don't set it.
4163 spec->size = OBJECT_SIZE_1X1; // Default for NewGRFs that manage to not set it (1x1)
4164 }
4165
4166 /* Swap classid because we read it in BE. */
4167 uint32_t classid = buf.ReadDWord();
4168 spec->class_index = ObjectClass::Allocate(BSWAP32(classid));
4169 break;
4170 }
4171
4172 case 0x09: { // Class name
4173 AddStringForMapping(buf.ReadWord(), [spec = spec.get()](StringID str) { ObjectClass::Get(spec->class_index)->name = str; });
4174 break;
4175 }
4176
4177 case 0x0A: // Object name
4178 AddStringForMapping(buf.ReadWord(), &spec->name);
4179 break;
4180
4181 case 0x0B: // Climate mask
4182 spec->climate = buf.ReadByte();
4183 break;
4184
4185 case 0x0C: // Size
4186 spec->size = buf.ReadByte();
4187 if (GB(spec->size, 0, 4) == 0 || GB(spec->size, 4, 4) == 0) {
4188 GrfMsg(0, "ObjectChangeInfo: Invalid object size requested (0x{:X}) for object id {}. Ignoring.", spec->size, id + i);
4189 spec->size = OBJECT_SIZE_1X1;
4190 }
4191 break;
4192
4193 case 0x0D: // Build cost multipler
4194 spec->build_cost_multiplier = buf.ReadByte();
4195 spec->clear_cost_multiplier = spec->build_cost_multiplier;
4196 break;
4197
4198 case 0x0E: // Introduction date
4199 spec->introduction_date = buf.ReadDWord();
4200 break;
4201
4202 case 0x0F: // End of life
4203 spec->end_of_life_date = buf.ReadDWord();
4204 break;
4205
4206 case 0x10: // Flags
4207 spec->flags = (ObjectFlags)buf.ReadWord();
4209 break;
4210
4211 case 0x11: // Animation info
4212 spec->animation.frames = buf.ReadByte();
4213 spec->animation.status = buf.ReadByte();
4214 break;
4215
4216 case 0x12: // Animation speed
4217 spec->animation.speed = buf.ReadByte();
4218 break;
4219
4220 case 0x13: // Animation triggers
4221 spec->animation.triggers = buf.ReadWord();
4222 break;
4223
4224 case 0x14: // Removal cost multiplier
4225 spec->clear_cost_multiplier = buf.ReadByte();
4226 break;
4227
4228 case 0x15: // Callback mask
4229 spec->callback_mask = buf.ReadWord();
4230 break;
4231
4232 case 0x16: // Building height
4233 spec->height = buf.ReadByte();
4234 break;
4235
4236 case 0x17: // Views
4237 spec->views = buf.ReadByte();
4238 if (spec->views != 1 && spec->views != 2 && spec->views != 4) {
4239 GrfMsg(2, "ObjectChangeInfo: Invalid number of views ({}) for object id {}. Ignoring.", spec->views, id + i);
4240 spec->views = 1;
4241 }
4242 break;
4243
4244 case 0x18: // Amount placed on 256^2 map on map creation
4245 spec->generate_amount = buf.ReadByte();
4246 break;
4247
4248 default:
4249 ret = CIR_UNKNOWN;
4250 break;
4251 }
4252 }
4253
4254 return ret;
4255}
4256
4265static ChangeInfoResult RailTypeChangeInfo(uint id, int numinfo, int prop, ByteReader &buf)
4266{
4268
4269 extern RailTypeInfo _railtypes[RAILTYPE_END];
4270
4271 if (id + numinfo > RAILTYPE_END) {
4272 GrfMsg(1, "RailTypeChangeInfo: Rail type {} is invalid, max {}, ignoring", id + numinfo, RAILTYPE_END);
4273 return CIR_INVALID_ID;
4274 }
4275
4276 for (int i = 0; i < numinfo; i++) {
4277 RailType rt = _cur.grffile->railtype_map[id + i];
4278 if (rt == INVALID_RAILTYPE) return CIR_INVALID_ID;
4279
4280 RailTypeInfo *rti = &_railtypes[rt];
4281
4282 switch (prop) {
4283 case 0x08: // Label of rail type
4284 /* Skipped here as this is loaded during reservation stage. */
4285 buf.ReadDWord();
4286 break;
4287
4288 case 0x09: { // Toolbar caption of railtype (sets name as well for backwards compatibility for grf ver < 8)
4289 uint16_t str = buf.ReadWord();
4291 if (_cur.grffile->grf_version < 8) {
4292 AddStringForMapping(str, &rti->strings.name);
4293 }
4294 break;
4295 }
4296
4297 case 0x0A: // Menu text of railtype
4298 AddStringForMapping(buf.ReadWord(), &rti->strings.menu_text);
4299 break;
4300
4301 case 0x0B: // Build window caption
4302 AddStringForMapping(buf.ReadWord(), &rti->strings.build_caption);
4303 break;
4304
4305 case 0x0C: // Autoreplace text
4306 AddStringForMapping(buf.ReadWord(), &rti->strings.replace_text);
4307 break;
4308
4309 case 0x0D: // New locomotive text
4310 AddStringForMapping(buf.ReadWord(), &rti->strings.new_loco);
4311 break;
4312
4313 case 0x0E: // Compatible railtype list
4314 case 0x0F: // Powered railtype list
4315 case 0x18: // Railtype list required for date introduction
4316 case 0x19: // Introduced railtype list
4317 {
4318 /* Rail type compatibility bits are added to the existing bits
4319 * to allow multiple GRFs to modify compatibility with the
4320 * default rail types. */
4321 int n = buf.ReadByte();
4322 for (int j = 0; j != n; j++) {
4323 RailTypeLabel label = buf.ReadDWord();
4324 RailType resolved_rt = GetRailTypeByLabel(BSWAP32(label), false);
4325 if (resolved_rt != INVALID_RAILTYPE) {
4326 switch (prop) {
4327 case 0x0F: SetBit(rti->powered_railtypes, resolved_rt); [[fallthrough]]; // Powered implies compatible.
4328 case 0x0E: SetBit(rti->compatible_railtypes, resolved_rt); break;
4329 case 0x18: SetBit(rti->introduction_required_railtypes, resolved_rt); break;
4330 case 0x19: SetBit(rti->introduces_railtypes, resolved_rt); break;
4331 }
4332 }
4333 }
4334 break;
4335 }
4336
4337 case 0x10: // Rail Type flags
4338 rti->flags = (RailTypeFlags)buf.ReadByte();
4339 break;
4340
4341 case 0x11: // Curve speed advantage
4342 rti->curve_speed = buf.ReadByte();
4343 break;
4344
4345 case 0x12: // Station graphic
4346 rti->fallback_railtype = Clamp(buf.ReadByte(), 0, 2);
4347 break;
4348
4349 case 0x13: // Construction cost factor
4350 rti->cost_multiplier = buf.ReadWord();
4351 break;
4352
4353 case 0x14: // Speed limit
4354 rti->max_speed = buf.ReadWord();
4355 break;
4356
4357 case 0x15: // Acceleration model
4358 rti->acceleration_type = Clamp(buf.ReadByte(), 0, 2);
4359 break;
4360
4361 case 0x16: // Map colour
4362 rti->map_colour = buf.ReadByte();
4363 break;
4364
4365 case 0x17: // Introduction date
4366 rti->introduction_date = buf.ReadDWord();
4367 break;
4368
4369 case 0x1A: // Sort order
4370 rti->sorting_order = buf.ReadByte();
4371 break;
4372
4373 case 0x1B: // Name of railtype (overridden by prop 09 for grf ver < 8)
4374 AddStringForMapping(buf.ReadWord(), &rti->strings.name);
4375 break;
4376
4377 case 0x1C: // Maintenance cost factor
4378 rti->maintenance_multiplier = buf.ReadWord();
4379 break;
4380
4381 case 0x1D: // Alternate rail type label list
4382 /* Skipped here as this is loaded during reservation stage. */
4383 for (int j = buf.ReadByte(); j != 0; j--) buf.ReadDWord();
4384 break;
4385
4386 default:
4387 ret = CIR_UNKNOWN;
4388 break;
4389 }
4390 }
4391
4392 return ret;
4393}
4394
4395static ChangeInfoResult RailTypeReserveInfo(uint id, int numinfo, int prop, ByteReader &buf)
4396{
4398
4399 extern RailTypeInfo _railtypes[RAILTYPE_END];
4400
4401 if (id + numinfo > RAILTYPE_END) {
4402 GrfMsg(1, "RailTypeReserveInfo: Rail type {} is invalid, max {}, ignoring", id + numinfo, RAILTYPE_END);
4403 return CIR_INVALID_ID;
4404 }
4405
4406 for (int i = 0; i < numinfo; i++) {
4407 switch (prop) {
4408 case 0x08: // Label of rail type
4409 {
4410 RailTypeLabel rtl = buf.ReadDWord();
4411 rtl = BSWAP32(rtl);
4412
4413 RailType rt = GetRailTypeByLabel(rtl, false);
4414 if (rt == INVALID_RAILTYPE) {
4415 /* Set up new rail type */
4416 rt = AllocateRailType(rtl);
4417 }
4418
4419 _cur.grffile->railtype_map[id + i] = rt;
4420 break;
4421 }
4422
4423 case 0x09: // Toolbar caption of railtype
4424 case 0x0A: // Menu text
4425 case 0x0B: // Build window caption
4426 case 0x0C: // Autoreplace text
4427 case 0x0D: // New loco
4428 case 0x13: // Construction cost
4429 case 0x14: // Speed limit
4430 case 0x1B: // Name of railtype
4431 case 0x1C: // Maintenance cost factor
4432 buf.ReadWord();
4433 break;
4434
4435 case 0x1D: // Alternate rail type label list
4436 if (_cur.grffile->railtype_map[id + i] != INVALID_RAILTYPE) {
4437 int n = buf.ReadByte();
4438 for (int j = 0; j != n; j++) {
4439 _railtypes[_cur.grffile->railtype_map[id + i]].alternate_labels.push_back(BSWAP32(buf.ReadDWord()));
4440 }
4441 break;
4442 }
4443 GrfMsg(1, "RailTypeReserveInfo: Ignoring property 1D for rail type {} because no label was set", id + i);
4444 [[fallthrough]];
4445
4446 case 0x0E: // Compatible railtype list
4447 case 0x0F: // Powered railtype list
4448 case 0x18: // Railtype list required for date introduction
4449 case 0x19: // Introduced railtype list
4450 for (int j = buf.ReadByte(); j != 0; j--) buf.ReadDWord();
4451 break;
4452
4453 case 0x10: // Rail Type flags
4454 case 0x11: // Curve speed advantage
4455 case 0x12: // Station graphic
4456 case 0x15: // Acceleration model
4457 case 0x16: // Map colour
4458 case 0x1A: // Sort order
4459 buf.ReadByte();
4460 break;
4461
4462 case 0x17: // Introduction date
4463 buf.ReadDWord();
4464 break;
4465
4466 default:
4467 ret = CIR_UNKNOWN;
4468 break;
4469 }
4470 }
4471
4472 return ret;
4473}
4474
4483static ChangeInfoResult RoadTypeChangeInfo(uint id, int numinfo, int prop, ByteReader &buf, RoadTramType rtt)
4484{
4486
4487 extern RoadTypeInfo _roadtypes[ROADTYPE_END];
4488 std::array<RoadType, ROADTYPE_END> &type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map;
4489
4490 if (id + numinfo > ROADTYPE_END) {
4491 GrfMsg(1, "RoadTypeChangeInfo: Road type {} is invalid, max {}, ignoring", id + numinfo, ROADTYPE_END);
4492 return CIR_INVALID_ID;
4493 }
4494
4495 for (int i = 0; i < numinfo; i++) {
4496 RoadType rt = type_map[id + i];
4497 if (rt == INVALID_ROADTYPE) return CIR_INVALID_ID;
4498
4499 RoadTypeInfo *rti = &_roadtypes[rt];
4500
4501 switch (prop) {
4502 case 0x08: // Label of road type
4503 /* Skipped here as this is loaded during reservation stage. */
4504 buf.ReadDWord();
4505 break;
4506
4507 case 0x09: { // Toolbar caption of roadtype (sets name as well for backwards compatibility for grf ver < 8)
4508 uint16_t str = buf.ReadWord();
4510 break;
4511 }
4512
4513 case 0x0A: // Menu text of roadtype
4514 AddStringForMapping(buf.ReadWord(), &rti->strings.menu_text);
4515 break;
4516
4517 case 0x0B: // Build window caption
4518 AddStringForMapping(buf.ReadWord(), &rti->strings.build_caption);
4519 break;
4520
4521 case 0x0C: // Autoreplace text
4522 AddStringForMapping(buf.ReadWord(), &rti->strings.replace_text);
4523 break;
4524
4525 case 0x0D: // New engine text
4526 AddStringForMapping(buf.ReadWord(), &rti->strings.new_engine);
4527 break;
4528
4529 case 0x0F: // Powered roadtype list
4530 case 0x18: // Roadtype list required for date introduction
4531 case 0x19: { // Introduced roadtype list
4532 /* Road type compatibility bits are added to the existing bits
4533 * to allow multiple GRFs to modify compatibility with the
4534 * default road types. */
4535 int n = buf.ReadByte();
4536 for (int j = 0; j != n; j++) {
4537 RoadTypeLabel label = buf.ReadDWord();
4538 RoadType resolved_rt = GetRoadTypeByLabel(BSWAP32(label), false);
4539 if (resolved_rt != INVALID_ROADTYPE) {
4540 switch (prop) {
4541 case 0x0F:
4542 if (GetRoadTramType(resolved_rt) == rtt) {
4543 SetBit(rti->powered_roadtypes, resolved_rt);
4544 } else {
4545 GrfMsg(1, "RoadTypeChangeInfo: Powered road type list: Road type {} road/tram type does not match road type {}, ignoring", resolved_rt, rt);
4546 }
4547 break;
4548 case 0x18: SetBit(rti->introduction_required_roadtypes, resolved_rt); break;
4549 case 0x19: SetBit(rti->introduces_roadtypes, resolved_rt); break;
4550 }
4551 }
4552 }
4553 break;
4554 }
4555
4556 case 0x10: // Road Type flags
4557 rti->flags = (RoadTypeFlags)buf.ReadByte();
4558 break;
4559
4560 case 0x13: // Construction cost factor
4561 rti->cost_multiplier = buf.ReadWord();
4562 break;
4563
4564 case 0x14: // Speed limit
4565 rti->max_speed = buf.ReadWord();
4566 break;
4567
4568 case 0x16: // Map colour
4569 rti->map_colour = buf.ReadByte();
4570 break;
4571
4572 case 0x17: // Introduction date
4573 rti->introduction_date = buf.ReadDWord();
4574 break;
4575
4576 case 0x1A: // Sort order
4577 rti->sorting_order = buf.ReadByte();
4578 break;
4579
4580 case 0x1B: // Name of roadtype
4581 AddStringForMapping(buf.ReadWord(), &rti->strings.name);
4582 break;
4583
4584 case 0x1C: // Maintenance cost factor
4585 rti->maintenance_multiplier = buf.ReadWord();
4586 break;
4587
4588 case 0x1D: // Alternate road type label list
4589 /* Skipped here as this is loaded during reservation stage. */
4590 for (int j = buf.ReadByte(); j != 0; j--) buf.ReadDWord();
4591 break;
4592
4593 default:
4594 ret = CIR_UNKNOWN;
4595 break;
4596 }
4597 }
4598
4599 return ret;
4600}
4601
4602static ChangeInfoResult RoadTypeChangeInfo(uint id, int numinfo, int prop, ByteReader &buf)
4603{
4604 return RoadTypeChangeInfo(id, numinfo, prop, buf, RTT_ROAD);
4605}
4606
4607static ChangeInfoResult TramTypeChangeInfo(uint id, int numinfo, int prop, ByteReader &buf)
4608{
4609 return RoadTypeChangeInfo(id, numinfo, prop, buf, RTT_TRAM);
4610}
4611
4612
4613static ChangeInfoResult RoadTypeReserveInfo(uint id, int numinfo, int prop, ByteReader &buf, RoadTramType rtt)
4614{
4616
4617 extern RoadTypeInfo _roadtypes[ROADTYPE_END];
4618 std::array<RoadType, ROADTYPE_END> &type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map;
4619
4620 if (id + numinfo > ROADTYPE_END) {
4621 GrfMsg(1, "RoadTypeReserveInfo: Road type {} is invalid, max {}, ignoring", id + numinfo, ROADTYPE_END);
4622 return CIR_INVALID_ID;
4623 }
4624
4625 for (int i = 0; i < numinfo; i++) {
4626 switch (prop) {
4627 case 0x08: { // Label of road type
4628 RoadTypeLabel rtl = buf.ReadDWord();
4629 rtl = BSWAP32(rtl);
4630
4631 RoadType rt = GetRoadTypeByLabel(rtl, false);
4632 if (rt == INVALID_ROADTYPE) {
4633 /* Set up new road type */
4634 rt = AllocateRoadType(rtl, rtt);
4635 } else if (GetRoadTramType(rt) != rtt) {
4636 GrfMsg(1, "RoadTypeReserveInfo: Road type {} is invalid type (road/tram), ignoring", id + numinfo);
4637 return CIR_INVALID_ID;
4638 }
4639
4640 type_map[id + i] = rt;
4641 break;
4642 }
4643 case 0x09: // Toolbar caption of roadtype
4644 case 0x0A: // Menu text
4645 case 0x0B: // Build window caption
4646 case 0x0C: // Autoreplace text
4647 case 0x0D: // New loco
4648 case 0x13: // Construction cost
4649 case 0x14: // Speed limit
4650 case 0x1B: // Name of roadtype
4651 case 0x1C: // Maintenance cost factor
4652 buf.ReadWord();
4653 break;
4654
4655 case 0x1D: // Alternate road type label list
4656 if (type_map[id + i] != INVALID_ROADTYPE) {
4657 int n = buf.ReadByte();
4658 for (int j = 0; j != n; j++) {
4659 _roadtypes[type_map[id + i]].alternate_labels.push_back(BSWAP32(buf.ReadDWord()));
4660 }
4661 break;
4662 }
4663 GrfMsg(1, "RoadTypeReserveInfo: Ignoring property 1D for road type {} because no label was set", id + i);
4664 /* FALL THROUGH */
4665
4666 case 0x0F: // Powered roadtype list
4667 case 0x18: // Roadtype list required for date introduction
4668 case 0x19: // Introduced roadtype list
4669 for (int j = buf.ReadByte(); j != 0; j--) buf.ReadDWord();
4670 break;
4671
4672 case 0x10: // Road Type flags
4673 case 0x16: // Map colour
4674 case 0x1A: // Sort order
4675 buf.ReadByte();
4676 break;
4677
4678 case 0x17: // Introduction date
4679 buf.ReadDWord();
4680 break;
4681
4682 default:
4683 ret = CIR_UNKNOWN;
4684 break;
4685 }
4686 }
4687
4688 return ret;
4689}
4690
4691static ChangeInfoResult RoadTypeReserveInfo(uint id, int numinfo, int prop, ByteReader &buf)
4692{
4693 return RoadTypeReserveInfo(id, numinfo, prop, buf, RTT_ROAD);
4694}
4695
4696static ChangeInfoResult TramTypeReserveInfo(uint id, int numinfo, int prop, ByteReader &buf)
4697{
4698 return RoadTypeReserveInfo(id, numinfo, prop, buf, RTT_TRAM);
4699}
4700
4701static ChangeInfoResult AirportTilesChangeInfo(uint airtid, int numinfo, int prop, ByteReader &buf)
4702{
4704
4705 if (airtid + numinfo > NUM_AIRPORTTILES_PER_GRF) {
4706 GrfMsg(1, "AirportTileChangeInfo: Too many airport tiles loaded ({}), max ({}). Ignoring.", airtid + numinfo, NUM_AIRPORTTILES_PER_GRF);
4707 return CIR_INVALID_ID;
4708 }
4709
4710 /* Allocate airport tile specs if they haven't been allocated already. */
4711 if (_cur.grffile->airtspec.size() < airtid + numinfo) _cur.grffile->airtspec.resize(airtid + numinfo);
4712
4713 for (int i = 0; i < numinfo; i++) {
4714 auto &tsp = _cur.grffile->airtspec[airtid + i];
4715
4716 if (prop != 0x08 && tsp == nullptr) {
4717 GrfMsg(2, "AirportTileChangeInfo: Attempt to modify undefined airport tile {}. Ignoring.", airtid + i);
4718 return CIR_INVALID_ID;
4719 }
4720
4721 switch (prop) {
4722 case 0x08: { // Substitute airport tile type
4723 uint8_t subs_id = buf.ReadByte();
4724 if (subs_id >= NEW_AIRPORTTILE_OFFSET) {
4725 /* The substitute id must be one of the original airport tiles. */
4726 GrfMsg(2, "AirportTileChangeInfo: Attempt to use new airport tile {} as substitute airport tile for {}. Ignoring.", subs_id, airtid + i);
4727 continue;
4728 }
4729
4730 /* Allocate space for this airport tile. */
4731 if (tsp == nullptr) {
4732 tsp = std::make_unique<AirportTileSpec>(*AirportTileSpec::Get(subs_id));
4733
4734 tsp->enabled = true;
4735
4736 tsp->animation.status = ANIM_STATUS_NO_ANIMATION;
4737
4738 tsp->grf_prop.local_id = airtid + i;
4739 tsp->grf_prop.subst_id = subs_id;
4740 tsp->grf_prop.grfid = _cur.grffile->grfid;
4741 tsp->grf_prop.grffile = _cur.grffile;
4742 _airporttile_mngr.AddEntityID(airtid + i, _cur.grffile->grfid, subs_id); // pre-reserve the tile slot
4743 }
4744 break;
4745 }
4746
4747 case 0x09: { // Airport tile override
4748 uint8_t override = buf.ReadByte();
4749
4750 /* The airport tile being overridden must be an original airport tile. */
4751 if (override >= NEW_AIRPORTTILE_OFFSET) {
4752 GrfMsg(2, "AirportTileChangeInfo: Attempt to override new airport tile {} with airport tile id {}. Ignoring.", override, airtid + i);
4753 continue;
4754 }
4755
4756 _airporttile_mngr.Add(airtid + i, _cur.grffile->grfid, override);
4757 break;
4758 }
4759
4760 case 0x0E: // Callback mask
4761 tsp->callback_mask = buf.ReadByte();
4762 break;
4763
4764 case 0x0F: // Animation information
4765 tsp->animation.frames = buf.ReadByte();
4766 tsp->animation.status = buf.ReadByte();
4767 break;
4768
4769 case 0x10: // Animation speed
4770 tsp->animation.speed = buf.ReadByte();
4771 break;
4772
4773 case 0x11: // Animation triggers
4774 tsp->animation.triggers = buf.ReadByte();
4775 break;
4776
4777 default:
4778 ret = CIR_UNKNOWN;
4779 break;
4780 }
4781 }
4782
4783 return ret;
4784}
4785
4793{
4795
4796 switch (prop) {
4797 case 0x09:
4798 case 0x0C:
4799 case 0x0F:
4800 case 0x11:
4801 buf.ReadByte();
4802 break;
4803
4804 case 0x0A:
4805 case 0x0B:
4806 case 0x0E:
4807 case 0x10:
4808 case 0x15:
4809 buf.ReadWord();
4810 break;
4811
4812 case 0x08:
4813 case 0x0D:
4814 case 0x12:
4815 buf.ReadDWord();
4816 break;
4817
4818 default:
4819 ret = CIR_UNKNOWN;
4820 break;
4821 }
4822
4823 return ret;
4824}
4825
4826static ChangeInfoResult RoadStopChangeInfo(uint id, int numinfo, int prop, ByteReader &buf)
4827{
4829
4830 if (id + numinfo > NUM_ROADSTOPS_PER_GRF) {
4831 GrfMsg(1, "RoadStopChangeInfo: RoadStop {} is invalid, max {}, ignoring", id + numinfo, NUM_ROADSTOPS_PER_GRF);
4832 return CIR_INVALID_ID;
4833 }
4834
4835 if (_cur.grffile->roadstops.size() < id + numinfo) _cur.grffile->roadstops.resize(id + numinfo);
4836
4837 for (int i = 0; i < numinfo; i++) {
4838 auto &rs = _cur.grffile->roadstops[id + i];
4839
4840 if (rs == nullptr && prop != 0x08) {
4841 GrfMsg(1, "RoadStopChangeInfo: Attempt to modify undefined road stop {}, ignoring", id + i);
4843 if (cir > ret) ret = cir;
4844 continue;
4845 }
4846
4847 switch (prop) {
4848 case 0x08: { // Road Stop Class ID
4849 if (rs == nullptr) {
4850 rs = std::make_unique<RoadStopSpec>();
4851 }
4852
4853 uint32_t classid = buf.ReadDWord();
4854 rs->class_index = RoadStopClass::Allocate(BSWAP32(classid));
4855 break;
4856 }
4857
4858 case 0x09: // Road stop type
4859 rs->stop_type = (RoadStopAvailabilityType)buf.ReadByte();
4860 break;
4861
4862 case 0x0A: // Road Stop Name
4863 AddStringForMapping(buf.ReadWord(), &rs->name);
4864 break;
4865
4866 case 0x0B: // Road Stop Class name
4867 AddStringForMapping(buf.ReadWord(), [rs = rs.get()](StringID str) { RoadStopClass::Get(rs->class_index)->name = str; });
4868 break;
4869
4870 case 0x0C: // The draw mode
4871 rs->draw_mode = static_cast<RoadStopDrawMode>(buf.ReadByte());
4872 break;
4873
4874 case 0x0D: // Cargo types for random triggers
4875 rs->cargo_triggers = TranslateRefitMask(buf.ReadDWord());
4876 break;
4877
4878 case 0x0E: // Animation info
4879 rs->animation.frames = buf.ReadByte();
4880 rs->animation.status = buf.ReadByte();
4881 break;
4882
4883 case 0x0F: // Animation speed
4884 rs->animation.speed = buf.ReadByte();
4885 break;
4886
4887 case 0x10: // Animation triggers
4888 rs->animation.triggers = buf.ReadWord();
4889 break;
4890
4891 case 0x11: // Callback mask
4892 rs->callback_mask = buf.ReadByte();
4893 break;
4894
4895 case 0x12: // General flags
4896 rs->flags = (uint16_t)buf.ReadDWord(); // Future-proofing, size this as 4 bytes, but we only need two byte's worth of flags at present
4897 break;
4898
4899 case 0x15: // Cost multipliers
4900 rs->build_cost_multiplier = buf.ReadByte();
4901 rs->clear_cost_multiplier = buf.ReadByte();
4902 break;
4903
4904 default:
4905 ret = CIR_UNKNOWN;
4906 break;
4907 }
4908 }
4909
4910 return ret;
4911}
4912
4913static bool HandleChangeInfoResult(const char *caller, ChangeInfoResult cir, uint8_t feature, uint8_t property)
4914{
4915 switch (cir) {
4916 default: NOT_REACHED();
4917
4918 case CIR_DISABLED:
4919 /* Error has already been printed; just stop parsing */
4920 return true;
4921
4922 case CIR_SUCCESS:
4923 return false;
4924
4925 case CIR_UNHANDLED:
4926 GrfMsg(1, "{}: Ignoring property 0x{:02X} of feature 0x{:02X} (not implemented)", caller, property, feature);
4927 return false;
4928
4929 case CIR_UNKNOWN:
4930 GrfMsg(0, "{}: Unknown property 0x{:02X} of feature 0x{:02X}, disabling", caller, property, feature);
4931 [[fallthrough]];
4932
4933 case CIR_INVALID_ID: {
4934 /* No debug message for an invalid ID, as it has already been output */
4935 GRFError *error = DisableGrf(cir == CIR_INVALID_ID ? STR_NEWGRF_ERROR_INVALID_ID : STR_NEWGRF_ERROR_UNKNOWN_PROPERTY);
4936 if (cir != CIR_INVALID_ID) error->param_value[1] = property;
4937 return true;
4938 }
4939 }
4940}
4941
4942/* Action 0x00 */
4943static void FeatureChangeInfo(ByteReader &buf)
4944{
4945 /* <00> <feature> <num-props> <num-info> <id> (<property <new-info>)...
4946 *
4947 * B feature
4948 * B num-props how many properties to change per vehicle/station
4949 * B num-info how many vehicles/stations to change
4950 * E id ID of first vehicle/station to change, if num-info is
4951 * greater than one, this one and the following
4952 * vehicles/stations will be changed
4953 * B property what property to change, depends on the feature
4954 * V new-info new bytes of info (variable size; depends on properties) */
4955
4956 static const VCI_Handler handler[] = {
4957 /* GSF_TRAINS */ RailVehicleChangeInfo,
4958 /* GSF_ROADVEHICLES */ RoadVehicleChangeInfo,
4959 /* GSF_SHIPS */ ShipVehicleChangeInfo,
4960 /* GSF_AIRCRAFT */ AircraftVehicleChangeInfo,
4961 /* GSF_STATIONS */ StationChangeInfo,
4962 /* GSF_CANALS */ CanalChangeInfo,
4963 /* GSF_BRIDGES */ BridgeChangeInfo,
4964 /* GSF_HOUSES */ TownHouseChangeInfo,
4965 /* GSF_GLOBALVAR */ GlobalVarChangeInfo,
4966 /* GSF_INDUSTRYTILES */ IndustrytilesChangeInfo,
4967 /* GSF_INDUSTRIES */ IndustriesChangeInfo,
4968 /* GSF_CARGOES */ nullptr, // Cargo is handled during reservation
4969 /* GSF_SOUNDFX */ SoundEffectChangeInfo,
4970 /* GSF_AIRPORTS */ AirportChangeInfo,
4971 /* GSF_SIGNALS */ nullptr,
4972 /* GSF_OBJECTS */ ObjectChangeInfo,
4973 /* GSF_RAILTYPES */ RailTypeChangeInfo,
4974 /* GSF_AIRPORTTILES */ AirportTilesChangeInfo,
4975 /* GSF_ROADTYPES */ RoadTypeChangeInfo,
4976 /* GSF_TRAMTYPES */ TramTypeChangeInfo,
4977 /* GSF_ROADSTOPS */ RoadStopChangeInfo,
4978 };
4979 static_assert(GSF_END == lengthof(handler));
4980
4981 uint8_t feature = buf.ReadByte();
4982 uint8_t numprops = buf.ReadByte();
4983 uint numinfo = buf.ReadByte();
4984 uint engine = buf.ReadExtendedByte();
4985
4986 if (feature >= GSF_END) {
4987 GrfMsg(1, "FeatureChangeInfo: Unsupported feature 0x{:02X}, skipping", feature);
4988 return;
4989 }
4990
4991 GrfMsg(6, "FeatureChangeInfo: Feature 0x{:02X}, {} properties, to apply to {}+{}",
4992 feature, numprops, engine, numinfo);
4993
4994 if (handler[feature] == nullptr) {
4995 if (feature != GSF_CARGOES) GrfMsg(1, "FeatureChangeInfo: Unsupported feature 0x{:02X}, skipping", feature);
4996 return;
4997 }
4998
4999 /* Mark the feature as used by the grf */
5000 SetBit(_cur.grffile->grf_features, feature);
5001
5002 while (numprops-- && buf.HasData()) {
5003 uint8_t prop = buf.ReadByte();
5004
5005 ChangeInfoResult cir = handler[feature](engine, numinfo, prop, buf);
5006 if (HandleChangeInfoResult("FeatureChangeInfo", cir, feature, prop)) return;
5007 }
5008}
5009
5010/* Action 0x00 (GLS_SAFETYSCAN) */
5011static void SafeChangeInfo(ByteReader &buf)
5012{
5013 uint8_t feature = buf.ReadByte();
5014 uint8_t numprops = buf.ReadByte();
5015 uint numinfo = buf.ReadByte();
5016 buf.ReadExtendedByte(); // id
5017
5018 if (feature == GSF_BRIDGES && numprops == 1) {
5019 uint8_t prop = buf.ReadByte();
5020 /* Bridge property 0x0D is redefinition of sprite layout tables, which
5021 * is considered safe. */
5022 if (prop == 0x0D) return;
5023 } else if (feature == GSF_GLOBALVAR && numprops == 1) {
5024 uint8_t prop = buf.ReadByte();
5025 /* Engine ID Mappings are safe, if the source is static */
5026 if (prop == 0x11) {
5027 bool is_safe = true;
5028 for (uint i = 0; i < numinfo; i++) {
5029 uint32_t s = buf.ReadDWord();
5030 buf.ReadDWord(); // dest
5031 const GRFConfig *grfconfig = GetGRFConfig(s);
5032 if (grfconfig != nullptr && !HasBit(grfconfig->flags, GCF_STATIC)) {
5033 is_safe = false;
5034 break;
5035 }
5036 }
5037 if (is_safe) return;
5038 }
5039 }
5040
5042
5043 /* Skip remainder of GRF */
5044 _cur.skip_sprites = -1;
5045}
5046
5047/* Action 0x00 (GLS_RESERVE) */
5048static void ReserveChangeInfo(ByteReader &buf)
5049{
5050 uint8_t feature = buf.ReadByte();
5051
5052 if (feature != GSF_CARGOES && feature != GSF_GLOBALVAR && feature != GSF_RAILTYPES && feature != GSF_ROADTYPES && feature != GSF_TRAMTYPES) return;
5053
5054 uint8_t numprops = buf.ReadByte();
5055 uint8_t numinfo = buf.ReadByte();
5056 uint8_t index = buf.ReadExtendedByte();
5057
5058 while (numprops-- && buf.HasData()) {
5059 uint8_t prop = buf.ReadByte();
5061
5062 switch (feature) {
5063 default: NOT_REACHED();
5064 case GSF_CARGOES:
5065 cir = CargoChangeInfo(index, numinfo, prop, buf);
5066 break;
5067
5068 case GSF_GLOBALVAR:
5069 cir = GlobalVarReserveInfo(index, numinfo, prop, buf);
5070 break;
5071
5072 case GSF_RAILTYPES:
5073 cir = RailTypeReserveInfo(index, numinfo, prop, buf);
5074 break;
5075
5076 case GSF_ROADTYPES:
5077 cir = RoadTypeReserveInfo(index, numinfo, prop, buf);
5078 break;
5079
5080 case GSF_TRAMTYPES:
5081 cir = TramTypeReserveInfo(index, numinfo, prop, buf);
5082 break;
5083 }
5084
5085 if (HandleChangeInfoResult("ReserveChangeInfo", cir, feature, prop)) return;
5086 }
5087}
5088
5089/* Action 0x01 */
5090static void NewSpriteSet(ByteReader &buf)
5091{
5092 /* Basic format: <01> <feature> <num-sets> <num-ent>
5093 * Extended format: <01> <feature> 00 <first-set> <num-sets> <num-ent>
5094 *
5095 * B feature feature to define sprites for
5096 * 0, 1, 2, 3: veh-type, 4: train stations
5097 * E first-set first sprite set to define
5098 * B num-sets number of sprite sets (extended byte in extended format)
5099 * E num-ent how many entries per sprite set
5100 * For vehicles, this is the number of different
5101 * vehicle directions in each sprite set
5102 * Set num-dirs=8, unless your sprites are symmetric.
5103 * In that case, use num-dirs=4.
5104 */
5105
5106 uint8_t feature = buf.ReadByte();
5107 uint16_t num_sets = buf.ReadByte();
5108 uint16_t first_set = 0;
5109
5110 if (num_sets == 0 && buf.HasData(3)) {
5111 /* Extended Action1 format.
5112 * Some GRFs define zero sets of zero sprites, though there is actually no use in that. Ignore them. */
5113 first_set = buf.ReadExtendedByte();
5114 num_sets = buf.ReadExtendedByte();
5115 }
5116 uint16_t num_ents = buf.ReadExtendedByte();
5117
5118 if (feature >= GSF_END) {
5119 _cur.skip_sprites = num_sets * num_ents;
5120 GrfMsg(1, "NewSpriteSet: Unsupported feature 0x{:02X}, skipping {} sprites", feature, _cur.skip_sprites);
5121 return;
5122 }
5123
5124 _cur.AddSpriteSets(feature, _cur.spriteid, first_set, num_sets, num_ents);
5125
5126 GrfMsg(7, "New sprite set at {} of feature 0x{:02X}, consisting of {} sets with {} views each (total {})",
5127 _cur.spriteid, feature, num_sets, num_ents, num_sets * num_ents
5128 );
5129
5130 for (int i = 0; i < num_sets * num_ents; i++) {
5131 _cur.nfo_line++;
5132 LoadNextSprite(_cur.spriteid++, *_cur.file, _cur.nfo_line);
5133 }
5134}
5135
5136/* Action 0x01 (SKIP) */
5137static void SkipAct1(ByteReader &buf)
5138{
5139 buf.ReadByte();
5140 uint16_t num_sets = buf.ReadByte();
5141
5142 if (num_sets == 0 && buf.HasData(3)) {
5143 /* Extended Action1 format.
5144 * Some GRFs define zero sets of zero sprites, though there is actually no use in that. Ignore them. */
5145 buf.ReadExtendedByte(); // first_set
5146 num_sets = buf.ReadExtendedByte();
5147 }
5148 uint16_t num_ents = buf.ReadExtendedByte();
5149
5150 _cur.skip_sprites = num_sets * num_ents;
5151
5152 GrfMsg(3, "SkipAct1: Skipping {} sprites", _cur.skip_sprites);
5153}
5154
5155using CachedCallback = std::pair<uint16_t, SpriteGroupID>;
5156static std::vector<CachedCallback> _cached_callback_groups;
5157
5158static const SpriteGroup *GetCallbackResultGroup(uint16_t value)
5159{
5160 /* Old style callback results (only valid for version < 8) have the highest byte 0xFF to signify it is a callback result.
5161 * New style ones only have the highest bit set (allows 15-bit results, instead of just 8) */
5162 if (_cur.grffile->grf_version < 8 && GB(value, 8, 8) == 0xFF) {
5163 value &= ~0xFF00;
5164 } else {
5165 value &= ~0x8000;
5166 }
5167
5168 /* Find position for value within the cached callback list. */
5169 auto it = std::ranges::lower_bound(_cached_callback_groups, value, std::less{}, &CachedCallback::first);
5170 if (it != std::end(_cached_callback_groups) && it->first == value) return SpriteGroup::Get(it->second);
5171
5172 /* Result value is not present, so make it and add to cache. */
5174 const SpriteGroup *group = new CallbackResultSpriteGroup(value);
5175 it = _cached_callback_groups.emplace(it, value, group->index);
5176 return group;
5177}
5178
5179/* Helper function to either create a callback or link to a previously
5180 * defined spritegroup. */
5181static const SpriteGroup *GetGroupFromGroupID(uint8_t setid, uint8_t type, uint16_t groupid)
5182{
5183 if (HasBit(groupid, 15)) return GetCallbackResultGroup(groupid);
5184
5185 if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == nullptr) {
5186 GrfMsg(1, "GetGroupFromGroupID(0x{:02X}:0x{:02X}): Groupid 0x{:04X} does not exist, leaving empty", setid, type, groupid);
5187 return nullptr;
5188 }
5189
5190 return _cur.spritegroups[groupid];
5191}
5192
5201static const SpriteGroup *CreateGroupFromGroupID(uint8_t feature, uint8_t setid, uint8_t type, uint16_t spriteid)
5202{
5203 if (HasBit(spriteid, 15)) return GetCallbackResultGroup(spriteid);
5204
5205 if (!_cur.IsValidSpriteSet(feature, spriteid)) {
5206 GrfMsg(1, "CreateGroupFromGroupID(0x{:02X}:0x{:02X}): Sprite set {} invalid", setid, type, spriteid);
5207 return nullptr;
5208 }
5209
5210 SpriteID spriteset_start = _cur.GetSprite(feature, spriteid);
5211 uint num_sprites = _cur.GetNumEnts(feature, spriteid);
5212
5213 /* Ensure that the sprites are loeded */
5214 assert(spriteset_start + num_sprites <= _cur.spriteid);
5215
5217 return new ResultSpriteGroup(spriteset_start, num_sprites);
5218}
5219
5220/* Action 0x02 */
5221static void NewSpriteGroup(ByteReader &buf)
5222{
5223 /* <02> <feature> <set-id> <type/num-entries> <feature-specific-data...>
5224 *
5225 * B feature see action 1
5226 * B set-id ID of this particular definition
5227 * B type/num-entries
5228 * if 80 or greater, this is a randomized or variational
5229 * list definition, see below
5230 * otherwise it specifies a number of entries, the exact
5231 * meaning depends on the feature
5232 * V feature-specific-data (huge mess, don't even look it up --pasky) */
5233 const SpriteGroup *act_group = nullptr;
5234
5235 uint8_t feature = buf.ReadByte();
5236 if (feature >= GSF_END) {
5237 GrfMsg(1, "NewSpriteGroup: Unsupported feature 0x{:02X}, skipping", feature);
5238 return;
5239 }
5240
5241 uint8_t setid = buf.ReadByte();
5242 uint8_t type = buf.ReadByte();
5243
5244 /* Sprite Groups are created here but they are allocated from a pool, so
5245 * we do not need to delete anything if there is an exception from the
5246 * ByteReader. */
5247
5248 switch (type) {
5249 /* Deterministic Sprite Group */
5250 case 0x81: // Self scope, byte
5251 case 0x82: // Parent scope, byte
5252 case 0x85: // Self scope, word
5253 case 0x86: // Parent scope, word
5254 case 0x89: // Self scope, dword
5255 case 0x8A: // Parent scope, dword
5256 {
5257 uint8_t varadjust;
5258 uint8_t varsize;
5259
5262 group->nfo_line = _cur.nfo_line;
5263 act_group = group;
5264 group->var_scope = HasBit(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF;
5265
5266 switch (GB(type, 2, 2)) {
5267 default: NOT_REACHED();
5268 case 0: group->size = DSG_SIZE_BYTE; varsize = 1; break;
5269 case 1: group->size = DSG_SIZE_WORD; varsize = 2; break;
5270 case 2: group->size = DSG_SIZE_DWORD; varsize = 4; break;
5271 }
5272
5273 /* Loop through the var adjusts. Unfortunately we don't know how many we have
5274 * from the outset, so we shall have to keep reallocing. */
5275 do {
5276 DeterministicSpriteGroupAdjust &adjust = group->adjusts.emplace_back();
5277
5278 /* The first var adjust doesn't have an operation specified, so we set it to add. */
5279 adjust.operation = group->adjusts.size() == 1 ? DSGA_OP_ADD : (DeterministicSpriteGroupAdjustOperation)buf.ReadByte();
5280 adjust.variable = buf.ReadByte();
5281 if (adjust.variable == 0x7E) {
5282 /* Link subroutine group */
5283 adjust.subroutine = GetGroupFromGroupID(setid, type, buf.ReadByte());
5284 } else {
5285 adjust.parameter = IsInsideMM(adjust.variable, 0x60, 0x80) ? buf.ReadByte() : 0;
5286 }
5287
5288 varadjust = buf.ReadByte();
5289 adjust.shift_num = GB(varadjust, 0, 5);
5290 adjust.type = (DeterministicSpriteGroupAdjustType)GB(varadjust, 6, 2);
5291 adjust.and_mask = buf.ReadVarSize(varsize);
5292
5293 if (adjust.type != DSGA_TYPE_NONE) {
5294 adjust.add_val = buf.ReadVarSize(varsize);
5295 adjust.divmod_val = buf.ReadVarSize(varsize);
5296 if (adjust.divmod_val == 0) adjust.divmod_val = 1; // Ensure that divide by zero cannot occur
5297 } else {
5298 adjust.add_val = 0;
5299 adjust.divmod_val = 0;
5300 }
5301
5302 /* Continue reading var adjusts while bit 5 is set. */
5303 } while (HasBit(varadjust, 5));
5304
5305 std::vector<DeterministicSpriteGroupRange> ranges;
5306 ranges.resize(buf.ReadByte());
5307 for (auto &range : ranges) {
5308 range.group = GetGroupFromGroupID(setid, type, buf.ReadWord());
5309 range.low = buf.ReadVarSize(varsize);
5310 range.high = buf.ReadVarSize(varsize);
5311 }
5312
5313 group->default_group = GetGroupFromGroupID(setid, type, buf.ReadWord());
5314 group->error_group = ranges.empty() ? group->default_group : ranges[0].group;
5315 /* nvar == 0 is a special case -- we turn our value into a callback result */
5316 group->calculated_result = ranges.empty();
5317
5318 /* Sort ranges ascending. When ranges overlap, this may required clamping or splitting them */
5319 std::vector<uint32_t> bounds;
5320 bounds.reserve(ranges.size());
5321 for (const auto &range : ranges) {
5322 bounds.push_back(range.low);
5323 if (range.high != UINT32_MAX) bounds.push_back(range.high + 1);
5324 }
5325 std::sort(bounds.begin(), bounds.end());
5326 bounds.erase(std::unique(bounds.begin(), bounds.end()), bounds.end());
5327
5328 std::vector<const SpriteGroup *> target;
5329 target.reserve(bounds.size());
5330 for (const auto &bound : bounds) {
5331 const SpriteGroup *t = group->default_group;
5332 for (const auto &range : ranges) {
5333 if (range.low <= bound && bound <= range.high) {
5334 t = range.group;
5335 break;
5336 }
5337 }
5338 target.push_back(t);
5339 }
5340 assert(target.size() == bounds.size());
5341
5342 for (uint j = 0; j < bounds.size(); ) {
5343 if (target[j] != group->default_group) {
5344 DeterministicSpriteGroupRange &r = group->ranges.emplace_back();
5345 r.group = target[j];
5346 r.low = bounds[j];
5347 while (j < bounds.size() && target[j] == r.group) {
5348 j++;
5349 }
5350 r.high = j < bounds.size() ? bounds[j] - 1 : UINT32_MAX;
5351 } else {
5352 j++;
5353 }
5354 }
5355
5356 break;
5357 }
5358
5359 /* Randomized Sprite Group */
5360 case 0x80: // Self scope
5361 case 0x83: // Parent scope
5362 case 0x84: // Relative scope
5363 {
5366 group->nfo_line = _cur.nfo_line;
5367 act_group = group;
5368 group->var_scope = HasBit(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF;
5369
5370 if (HasBit(type, 2)) {
5371 if (feature <= GSF_AIRCRAFT) group->var_scope = VSG_SCOPE_RELATIVE;
5372 group->count = buf.ReadByte();
5373 }
5374
5375 uint8_t triggers = buf.ReadByte();
5376 group->triggers = GB(triggers, 0, 7);
5377 group->cmp_mode = HasBit(triggers, 7) ? RSG_CMP_ALL : RSG_CMP_ANY;
5378 group->lowest_randbit = buf.ReadByte();
5379
5380 uint8_t num_groups = buf.ReadByte();
5381 if (!HasExactlyOneBit(num_groups)) {
5382 GrfMsg(1, "NewSpriteGroup: Random Action 2 nrand should be power of 2");
5383 }
5384
5385 group->groups.reserve(num_groups);
5386 for (uint i = 0; i < num_groups; i++) {
5387 group->groups.push_back(GetGroupFromGroupID(setid, type, buf.ReadWord()));
5388 }
5389
5390 break;
5391 }
5392
5393 /* Neither a variable or randomized sprite group... must be a real group */
5394 default:
5395 {
5396 switch (feature) {
5397 case GSF_TRAINS:
5398 case GSF_ROADVEHICLES:
5399 case GSF_SHIPS:
5400 case GSF_AIRCRAFT:
5401 case GSF_STATIONS:
5402 case GSF_CANALS:
5403 case GSF_CARGOES:
5404 case GSF_AIRPORTS:
5405 case GSF_RAILTYPES:
5406 case GSF_ROADTYPES:
5407 case GSF_TRAMTYPES:
5408 {
5409 uint8_t num_loaded = type;
5410 uint8_t num_loading = buf.ReadByte();
5411
5412 if (!_cur.HasValidSpriteSets(feature)) {
5413 GrfMsg(0, "NewSpriteGroup: No sprite set to work on! Skipping");
5414 return;
5415 }
5416
5417 GrfMsg(6, "NewSpriteGroup: New SpriteGroup 0x{:02X}, {} loaded, {} loading",
5418 setid, num_loaded, num_loading);
5419
5420 if (num_loaded + num_loading == 0) {
5421 GrfMsg(1, "NewSpriteGroup: no result, skipping invalid RealSpriteGroup");
5422 break;
5423 }
5424
5425 if (num_loaded + num_loading == 1) {
5426 /* Avoid creating 'Real' sprite group if only one option. */
5427 uint16_t spriteid = buf.ReadWord();
5428 act_group = CreateGroupFromGroupID(feature, setid, type, spriteid);
5429 GrfMsg(8, "NewSpriteGroup: one result, skipping RealSpriteGroup = subset {}", spriteid);
5430 break;
5431 }
5432
5433 std::vector<uint16_t> loaded;
5434 std::vector<uint16_t> loading;
5435
5436 loaded.reserve(num_loaded);
5437 for (uint i = 0; i < num_loaded; i++) {
5438 loaded.push_back(buf.ReadWord());
5439 GrfMsg(8, "NewSpriteGroup: + rg->loaded[{}] = subset {}", i, loaded[i]);
5440 }
5441
5442 loading.reserve(num_loading);
5443 for (uint i = 0; i < num_loading; i++) {
5444 loading.push_back(buf.ReadWord());
5445 GrfMsg(8, "NewSpriteGroup: + rg->loading[{}] = subset {}", i, loading[i]);
5446 }
5447
5448 bool loaded_same = !loaded.empty() && std::adjacent_find(loaded.begin(), loaded.end(), std::not_equal_to<>()) == loaded.end();
5449 bool loading_same = !loading.empty() && std::adjacent_find(loading.begin(), loading.end(), std::not_equal_to<>()) == loading.end();
5450 if (loaded_same && loading_same && loaded[0] == loading[0]) {
5451 /* Both lists only contain the same value, so don't create 'Real' sprite group */
5452 act_group = CreateGroupFromGroupID(feature, setid, type, loaded[0]);
5453 GrfMsg(8, "NewSpriteGroup: same result, skipping RealSpriteGroup = subset {}", loaded[0]);
5454 break;
5455 }
5456
5458 RealSpriteGroup *group = new RealSpriteGroup();
5459 group->nfo_line = _cur.nfo_line;
5460 act_group = group;
5461
5462 if (loaded_same && loaded.size() > 1) loaded.resize(1);
5463 group->loaded.reserve(loaded.size());
5464 for (uint16_t spriteid : loaded) {
5465 const SpriteGroup *t = CreateGroupFromGroupID(feature, setid, type, spriteid);
5466 group->loaded.push_back(t);
5467 }
5468
5469 if (loading_same && loading.size() > 1) loading.resize(1);
5470 group->loading.reserve(loading.size());
5471 for (uint16_t spriteid : loading) {
5472 const SpriteGroup *t = CreateGroupFromGroupID(feature, setid, type, spriteid);
5473 group->loading.push_back(t);
5474 }
5475
5476 break;
5477 }
5478
5479 case GSF_HOUSES:
5480 case GSF_AIRPORTTILES:
5481 case GSF_OBJECTS:
5482 case GSF_INDUSTRYTILES:
5483 case GSF_ROADSTOPS: {
5484 uint8_t num_building_sprites = std::max((uint8_t)1, type);
5485
5488 group->nfo_line = _cur.nfo_line;
5489 act_group = group;
5490
5491 /* On error, bail out immediately. Temporary GRF data was already freed */
5492 if (ReadSpriteLayout(buf, num_building_sprites, true, feature, false, type == 0, &group->dts)) return;
5493 break;
5494 }
5495
5496 case GSF_INDUSTRIES: {
5497 if (type > 2) {
5498 GrfMsg(1, "NewSpriteGroup: Unsupported industry production version {}, skipping", type);
5499 break;
5500 }
5501
5504 group->nfo_line = _cur.nfo_line;
5505 act_group = group;
5506 group->version = type;
5507 if (type == 0) {
5509 for (uint i = 0; i < INDUSTRY_ORIGINAL_NUM_INPUTS; i++) {
5510 group->subtract_input[i] = (int16_t)buf.ReadWord(); // signed
5511 }
5513 for (uint i = 0; i < INDUSTRY_ORIGINAL_NUM_OUTPUTS; i++) {
5514 group->add_output[i] = buf.ReadWord(); // unsigned
5515 }
5516 group->again = buf.ReadByte();
5517 } else if (type == 1) {
5519 for (uint i = 0; i < INDUSTRY_ORIGINAL_NUM_INPUTS; i++) {
5520 group->subtract_input[i] = buf.ReadByte();
5521 }
5523 for (uint i = 0; i < INDUSTRY_ORIGINAL_NUM_OUTPUTS; i++) {
5524 group->add_output[i] = buf.ReadByte();
5525 }
5526 group->again = buf.ReadByte();
5527 } else if (type == 2) {
5528 group->num_input = buf.ReadByte();
5529 if (group->num_input > lengthof(group->subtract_input)) {
5530 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK);
5531 error->data = "too many inputs (max 16)";
5532 return;
5533 }
5534 for (uint i = 0; i < group->num_input; i++) {
5535 uint8_t rawcargo = buf.ReadByte();
5536 CargoID cargo = GetCargoTranslation(rawcargo, _cur.grffile);
5537 if (!IsValidCargoID(cargo)) {
5538 /* The mapped cargo is invalid. This is permitted at this point,
5539 * as long as the result is not used. Mark it invalid so this
5540 * can be tested later. */
5541 group->version = 0xFF;
5542 } else if (std::find(group->cargo_input, group->cargo_input + i, cargo) != group->cargo_input + i) {
5543 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK);
5544 error->data = "duplicate input cargo";
5545 return;
5546 }
5547 group->cargo_input[i] = cargo;
5548 group->subtract_input[i] = buf.ReadByte();
5549 }
5550 group->num_output = buf.ReadByte();
5551 if (group->num_output > lengthof(group->add_output)) {
5552 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK);
5553 error->data = "too many outputs (max 16)";
5554 return;
5555 }
5556 for (uint i = 0; i < group->num_output; i++) {
5557 uint8_t rawcargo = buf.ReadByte();
5558 CargoID cargo = GetCargoTranslation(rawcargo, _cur.grffile);
5559 if (!IsValidCargoID(cargo)) {
5560 /* Mark this result as invalid to use */
5561 group->version = 0xFF;
5562 } else if (std::find(group->cargo_output, group->cargo_output + i, cargo) != group->cargo_output + i) {
5563 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK);
5564 error->data = "duplicate output cargo";
5565 return;
5566 }
5567 group->cargo_output[i] = cargo;
5568 group->add_output[i] = buf.ReadByte();
5569 }
5570 group->again = buf.ReadByte();
5571 } else {
5572 NOT_REACHED();
5573 }
5574 break;
5575 }
5576
5577 /* Loading of Tile Layout and Production Callback groups would happen here */
5578 default: GrfMsg(1, "NewSpriteGroup: Unsupported feature 0x{:02X}, skipping", feature);
5579 }
5580 }
5581 }
5582
5583 _cur.spritegroups[setid] = act_group;
5584}
5585
5591std::span<const CargoLabel> GetCargoTranslationTable(const GRFFile &grffile)
5592{
5593 /* Always use the translation table if it's installed. */
5594 if (!grffile.cargo_list.empty()) return grffile.cargo_list;
5595
5596 /* Pre-v7 use climate-dependent "slot" table. */
5597 if (grffile.grf_version < 7) return GetClimateDependentCargoTranslationTable();
5598
5599 /* Otherwise use climate-independent "bitnum" table. */
5601}
5602
5603static CargoID TranslateCargo(uint8_t feature, uint8_t ctype)
5604{
5605 /* Special cargo types for purchase list and stations */
5606 if ((feature == GSF_STATIONS || feature == GSF_ROADSTOPS) && ctype == 0xFE) return SpriteGroupCargo::SG_DEFAULT_NA;
5607 if (ctype == 0xFF) return SpriteGroupCargo::SG_PURCHASE;
5608
5609 auto cargo_list = GetCargoTranslationTable(*_cur.grffile);
5610
5611 /* Check if the cargo type is out of bounds of the cargo translation table */
5612 if (ctype >= cargo_list.size()) {
5613 GrfMsg(1, "TranslateCargo: Cargo type {} out of range (max {}), skipping.", ctype, (unsigned int)_cur.grffile->cargo_list.size() - 1);
5614 return INVALID_CARGO;
5615 }
5616
5617 /* Look up the cargo label from the translation table */
5618 CargoLabel cl = cargo_list[ctype];
5619 if (cl == CT_INVALID) {
5620 GrfMsg(5, "TranslateCargo: Cargo type {} not available in this climate, skipping.", ctype);
5621 return INVALID_CARGO;
5622 }
5623
5624 CargoID cid = GetCargoIDByLabel(cl);
5625 if (!IsValidCargoID(cid)) {
5626 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));
5627 return INVALID_CARGO;
5628 }
5629
5630 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), cid);
5631 return cid;
5632}
5633
5634
5635static bool IsValidGroupID(uint16_t groupid, const char *function)
5636{
5637 if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == nullptr) {
5638 GrfMsg(1, "{}: Spritegroup 0x{:04X} out of range or empty, skipping.", function, groupid);
5639 return false;
5640 }
5641
5642 return true;
5643}
5644
5645static void VehicleMapSpriteGroup(ByteReader &buf, uint8_t feature, uint8_t idcount)
5646{
5647 static std::vector<EngineID> last_engines; // Engine IDs are remembered in case the next action is a wagon override.
5648 bool wagover = false;
5649
5650 /* Test for 'wagon override' flag */
5651 if (HasBit(idcount, 7)) {
5652 wagover = true;
5653 /* Strip off the flag */
5654 idcount = GB(idcount, 0, 7);
5655
5656 if (last_engines.empty()) {
5657 GrfMsg(0, "VehicleMapSpriteGroup: WagonOverride: No engine to do override with");
5658 return;
5659 }
5660
5661 GrfMsg(6, "VehicleMapSpriteGroup: WagonOverride: {} engines, {} wagons", last_engines.size(), idcount);
5662 } else {
5663 last_engines.resize(idcount);
5664 }
5665
5666 std::vector<EngineID> engines;
5667 engines.reserve(idcount);
5668 for (uint i = 0; i < idcount; i++) {
5669 Engine *e = GetNewEngine(_cur.grffile, (VehicleType)feature, buf.ReadExtendedByte());
5670 if (e == nullptr) {
5671 /* No engine could be allocated?!? Deal with it. Okay,
5672 * this might look bad. Also make sure this NewGRF
5673 * gets disabled, as a half loaded one is bad. */
5674 HandleChangeInfoResult("VehicleMapSpriteGroup", CIR_INVALID_ID, 0, 0);
5675 return;
5676 }
5677
5678 engines.push_back(e->index);
5679 if (!wagover) last_engines[i] = engines[i];
5680 }
5681
5682 uint8_t cidcount = buf.ReadByte();
5683 for (uint c = 0; c < cidcount; c++) {
5684 uint8_t ctype = buf.ReadByte();
5685 uint16_t groupid = buf.ReadWord();
5686 if (!IsValidGroupID(groupid, "VehicleMapSpriteGroup")) continue;
5687
5688 GrfMsg(8, "VehicleMapSpriteGroup: * [{}] Cargo type 0x{:X}, group id 0x{:02X}", c, ctype, groupid);
5689
5690 CargoID cid = TranslateCargo(feature, ctype);
5691 if (!IsValidCargoID(cid)) continue;
5692
5693 for (uint i = 0; i < idcount; i++) {
5694 EngineID engine = engines[i];
5695
5696 GrfMsg(7, "VehicleMapSpriteGroup: [{}] Engine {}...", i, engine);
5697
5698 if (wagover) {
5699 SetWagonOverrideSprites(engine, cid, _cur.spritegroups[groupid], last_engines);
5700 } else {
5701 SetCustomEngineSprites(engine, cid, _cur.spritegroups[groupid]);
5702 }
5703 }
5704 }
5705
5706 uint16_t groupid = buf.ReadWord();
5707 if (!IsValidGroupID(groupid, "VehicleMapSpriteGroup")) return;
5708
5709 GrfMsg(8, "-- Default group id 0x{:04X}", groupid);
5710
5711 for (uint i = 0; i < idcount; i++) {
5712 EngineID engine = engines[i];
5713
5714 if (wagover) {
5715 SetWagonOverrideSprites(engine, SpriteGroupCargo::SG_DEFAULT, _cur.spritegroups[groupid], last_engines);
5716 } else {
5717 SetCustomEngineSprites(engine, SpriteGroupCargo::SG_DEFAULT, _cur.spritegroups[groupid]);
5718 SetEngineGRF(engine, _cur.grffile);
5719 }
5720 }
5721}
5722
5723
5724static void CanalMapSpriteGroup(ByteReader &buf, uint8_t idcount)
5725{
5726 std::vector<uint16_t> cfs;
5727 cfs.reserve(idcount);
5728 for (uint i = 0; i < idcount; i++) {
5729 cfs.push_back(buf.ReadExtendedByte());
5730 }
5731
5732 uint8_t cidcount = buf.ReadByte();
5733 buf.Skip(cidcount * 3);
5734
5735 uint16_t groupid = buf.ReadWord();
5736 if (!IsValidGroupID(groupid, "CanalMapSpriteGroup")) return;
5737
5738 for (auto &cf : cfs) {
5739 if (cf >= CF_END) {
5740 GrfMsg(1, "CanalMapSpriteGroup: Canal subset {} out of range, skipping", cf);
5741 continue;
5742 }
5743
5744 _water_feature[cf].grffile = _cur.grffile;
5745 _water_feature[cf].group = _cur.spritegroups[groupid];
5746 }
5747}
5748
5749
5750static void StationMapSpriteGroup(ByteReader &buf, uint8_t idcount)
5751{
5752 if (_cur.grffile->stations.empty()) {
5753 GrfMsg(1, "StationMapSpriteGroup: No stations defined, skipping");
5754 return;
5755 }
5756
5757 std::vector<uint16_t> stations;
5758 stations.reserve(idcount);
5759 for (uint i = 0; i < idcount; i++) {
5760 stations.push_back(buf.ReadExtendedByte());
5761 }
5762
5763 uint8_t cidcount = buf.ReadByte();
5764 for (uint c = 0; c < cidcount; c++) {
5765 uint8_t ctype = buf.ReadByte();
5766 uint16_t groupid = buf.ReadWord();
5767 if (!IsValidGroupID(groupid, "StationMapSpriteGroup")) continue;
5768
5769 ctype = TranslateCargo(GSF_STATIONS, ctype);
5770 if (!IsValidCargoID(ctype)) continue;
5771
5772 for (auto &station : stations) {
5773 StationSpec *statspec = station >= _cur.grffile->stations.size() ? nullptr : _cur.grffile->stations[station].get();
5774
5775 if (statspec == nullptr) {
5776 GrfMsg(1, "StationMapSpriteGroup: Station {} undefined, skipping", station);
5777 continue;
5778 }
5779
5780 statspec->grf_prop.spritegroup[ctype] = _cur.spritegroups[groupid];
5781 }
5782 }
5783
5784 uint16_t groupid = buf.ReadWord();
5785 if (!IsValidGroupID(groupid, "StationMapSpriteGroup")) return;
5786
5787 for (auto &station : stations) {
5788 StationSpec *statspec = station >= _cur.grffile->stations.size() ? nullptr : _cur.grffile->stations[station].get();
5789
5790 if (statspec == nullptr) {
5791 GrfMsg(1, "StationMapSpriteGroup: Station {} undefined, skipping", station);
5792 continue;
5793 }
5794
5795 if (statspec->grf_prop.HasGrfFile()) {
5796 GrfMsg(1, "StationMapSpriteGroup: Station {} mapped multiple times, skipping", station);
5797 continue;
5798 }
5799
5800 statspec->grf_prop.spritegroup[SpriteGroupCargo::SG_DEFAULT] = _cur.spritegroups[groupid];
5801 statspec->grf_prop.grfid = _cur.grffile->grfid;
5802 statspec->grf_prop.grffile = _cur.grffile;
5803 statspec->grf_prop.local_id = station;
5804 StationClass::Assign(statspec);
5805 }
5806}
5807
5808
5809static void TownHouseMapSpriteGroup(ByteReader &buf, uint8_t idcount)
5810{
5811 if (_cur.grffile->housespec.empty()) {
5812 GrfMsg(1, "TownHouseMapSpriteGroup: No houses defined, skipping");
5813 return;
5814 }
5815
5816 std::vector<uint16_t> houses;
5817 houses.reserve(idcount);
5818 for (uint i = 0; i < idcount; i++) {
5819 houses.push_back(buf.ReadExtendedByte());
5820 }
5821
5822 /* Skip the cargo type section, we only care about the default group */
5823 uint8_t cidcount = buf.ReadByte();
5824 buf.Skip(cidcount * 3);
5825
5826 uint16_t groupid = buf.ReadWord();
5827 if (!IsValidGroupID(groupid, "TownHouseMapSpriteGroup")) return;
5828
5829 for (auto &house : houses) {
5830 HouseSpec *hs = house >= _cur.grffile->housespec.size() ? nullptr : _cur.grffile->housespec[house].get();
5831
5832 if (hs == nullptr) {
5833 GrfMsg(1, "TownHouseMapSpriteGroup: House {} undefined, skipping.", house);
5834 continue;
5835 }
5836
5837 hs->grf_prop.spritegroup[0] = _cur.spritegroups[groupid];
5838 }
5839}
5840
5841static void IndustryMapSpriteGroup(ByteReader &buf, uint8_t idcount)
5842{
5843 if (_cur.grffile->industryspec.empty()) {
5844 GrfMsg(1, "IndustryMapSpriteGroup: No industries defined, skipping");
5845 return;
5846 }
5847
5848 std::vector<uint16_t> industries;
5849 industries.reserve(idcount);
5850 for (uint i = 0; i < idcount; i++) {
5851 industries.push_back(buf.ReadExtendedByte());
5852 }
5853
5854 /* Skip the cargo type section, we only care about the default group */
5855 uint8_t cidcount = buf.ReadByte();
5856 buf.Skip(cidcount * 3);
5857
5858 uint16_t groupid = buf.ReadWord();
5859 if (!IsValidGroupID(groupid, "IndustryMapSpriteGroup")) return;
5860
5861 for (auto &industry : industries) {
5862 IndustrySpec *indsp = industry >= _cur.grffile->industryspec.size() ? nullptr : _cur.grffile->industryspec[industry].get();
5863
5864 if (indsp == nullptr) {
5865 GrfMsg(1, "IndustryMapSpriteGroup: Industry {} undefined, skipping", industry);
5866 continue;
5867 }
5868
5869 indsp->grf_prop.spritegroup[0] = _cur.spritegroups[groupid];
5870 }
5871}
5872
5873static void IndustrytileMapSpriteGroup(ByteReader &buf, uint8_t idcount)
5874{
5875 if (_cur.grffile->indtspec.empty()) {
5876 GrfMsg(1, "IndustrytileMapSpriteGroup: No industry tiles defined, skipping");
5877 return;
5878 }
5879
5880 std::vector<uint16_t> indtiles;
5881 indtiles.reserve(idcount);
5882 for (uint i = 0; i < idcount; i++) {
5883 indtiles.push_back(buf.ReadExtendedByte());
5884 }
5885
5886 /* Skip the cargo type section, we only care about the default group */
5887 uint8_t cidcount = buf.ReadByte();
5888 buf.Skip(cidcount * 3);
5889
5890 uint16_t groupid = buf.ReadWord();
5891 if (!IsValidGroupID(groupid, "IndustrytileMapSpriteGroup")) return;
5892
5893 for (auto &indtile : indtiles) {
5894 IndustryTileSpec *indtsp = indtile >= _cur.grffile->indtspec.size() ? nullptr : _cur.grffile->indtspec[indtile].get();
5895
5896 if (indtsp == nullptr) {
5897 GrfMsg(1, "IndustrytileMapSpriteGroup: Industry tile {} undefined, skipping", indtile);
5898 continue;
5899 }
5900
5901 indtsp->grf_prop.spritegroup[0] = _cur.spritegroups[groupid];
5902 }
5903}
5904
5905static void CargoMapSpriteGroup(ByteReader &buf, uint8_t idcount)
5906{
5907 std::vector<uint16_t> cargoes;
5908 cargoes.reserve(idcount);
5909 for (uint i = 0; i < idcount; i++) {
5910 cargoes.push_back(buf.ReadExtendedByte());
5911 }
5912
5913 /* Skip the cargo type section, we only care about the default group */
5914 uint8_t cidcount = buf.ReadByte();
5915 buf.Skip(cidcount * 3);
5916
5917 uint16_t groupid = buf.ReadWord();
5918 if (!IsValidGroupID(groupid, "CargoMapSpriteGroup")) return;
5919
5920 for (auto &cid : cargoes) {
5921 if (cid >= NUM_CARGO) {
5922 GrfMsg(1, "CargoMapSpriteGroup: Cargo ID {} out of range, skipping", cid);
5923 continue;
5924 }
5925
5926 CargoSpec *cs = CargoSpec::Get(cid);
5927 cs->grffile = _cur.grffile;
5928 cs->group = _cur.spritegroups[groupid];
5929 }
5930}
5931
5932static void ObjectMapSpriteGroup(ByteReader &buf, uint8_t idcount)
5933{
5934 if (_cur.grffile->objectspec.empty()) {
5935 GrfMsg(1, "ObjectMapSpriteGroup: No object tiles defined, skipping");
5936 return;
5937 }
5938
5939 std::vector<uint16_t> objects;
5940 objects.reserve(idcount);
5941 for (uint i = 0; i < idcount; i++) {
5942 objects.push_back(buf.ReadExtendedByte());
5943 }
5944
5945 uint8_t cidcount = buf.ReadByte();
5946 for (uint c = 0; c < cidcount; c++) {
5947 uint8_t ctype = buf.ReadByte();
5948 uint16_t groupid = buf.ReadWord();
5949 if (!IsValidGroupID(groupid, "ObjectMapSpriteGroup")) continue;
5950
5951 /* The only valid option here is purchase list sprite groups. */
5952 if (ctype != 0xFF) {
5953 GrfMsg(1, "ObjectMapSpriteGroup: Invalid cargo bitnum {} for objects, skipping.", ctype);
5954 continue;
5955 }
5956
5957 for (auto &object : objects) {
5958 ObjectSpec *spec = object >= _cur.grffile->objectspec.size() ? nullptr : _cur.grffile->objectspec[object].get();
5959
5960 if (spec == nullptr) {
5961 GrfMsg(1, "ObjectMapSpriteGroup: Object {} undefined, skipping", object);
5962 continue;
5963 }
5964
5965 spec->grf_prop.spritegroup[OBJECT_SPRITE_GROUP_PURCHASE] = _cur.spritegroups[groupid];
5966 }
5967 }
5968
5969 uint16_t groupid = buf.ReadWord();
5970 if (!IsValidGroupID(groupid, "ObjectMapSpriteGroup")) return;
5971
5972 for (auto &object : objects) {
5973 ObjectSpec *spec = object >= _cur.grffile->objectspec.size() ? nullptr : _cur.grffile->objectspec[object].get();
5974
5975 if (spec == nullptr) {
5976 GrfMsg(1, "ObjectMapSpriteGroup: Object {} undefined, skipping", object);
5977 continue;
5978 }
5979
5980 if (spec->grf_prop.HasGrfFile()) {
5981 GrfMsg(1, "ObjectMapSpriteGroup: Object {} mapped multiple times, skipping", object);
5982 continue;
5983 }
5984
5985 spec->grf_prop.spritegroup[OBJECT_SPRITE_GROUP_DEFAULT] = _cur.spritegroups[groupid];
5986 spec->grf_prop.grfid = _cur.grffile->grfid;
5987 spec->grf_prop.grffile = _cur.grffile;
5988 spec->grf_prop.local_id = object;
5989 }
5990}
5991
5992static void RailTypeMapSpriteGroup(ByteReader &buf, uint8_t idcount)
5993{
5994 std::vector<uint8_t> railtypes;
5995 railtypes.reserve(idcount);
5996 for (uint i = 0; i < idcount; i++) {
5997 uint16_t id = buf.ReadExtendedByte();
5998 railtypes.push_back(id < RAILTYPE_END ? _cur.grffile->railtype_map[id] : INVALID_RAILTYPE);
5999 }
6000
6001 uint8_t cidcount = buf.ReadByte();
6002 for (uint c = 0; c < cidcount; c++) {
6003 uint8_t ctype = buf.ReadByte();
6004 uint16_t groupid = buf.ReadWord();
6005 if (!IsValidGroupID(groupid, "RailTypeMapSpriteGroup")) continue;
6006
6007 if (ctype >= RTSG_END) continue;
6008
6009 extern RailTypeInfo _railtypes[RAILTYPE_END];
6010 for (auto &railtype : railtypes) {
6011 if (railtype != INVALID_RAILTYPE) {
6012 RailTypeInfo *rti = &_railtypes[railtype];
6013
6014 rti->grffile[ctype] = _cur.grffile;
6015 rti->group[ctype] = _cur.spritegroups[groupid];
6016 }
6017 }
6018 }
6019
6020 /* Railtypes do not use the default group. */
6021 buf.ReadWord();
6022}
6023
6024static void RoadTypeMapSpriteGroup(ByteReader &buf, uint8_t idcount, RoadTramType rtt)
6025{
6026 std::array<RoadType, ROADTYPE_END> &type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map;
6027
6028 std::vector<uint8_t> roadtypes;
6029 roadtypes.reserve(idcount);
6030 for (uint i = 0; i < idcount; i++) {
6031 uint16_t id = buf.ReadExtendedByte();
6032 roadtypes.push_back(id < ROADTYPE_END ? type_map[id] : INVALID_ROADTYPE);
6033 }
6034
6035 uint8_t cidcount = buf.ReadByte();
6036 for (uint c = 0; c < cidcount; c++) {
6037 uint8_t ctype = buf.ReadByte();
6038 uint16_t groupid = buf.ReadWord();
6039 if (!IsValidGroupID(groupid, "RoadTypeMapSpriteGroup")) continue;
6040
6041 if (ctype >= ROTSG_END) continue;
6042
6043 extern RoadTypeInfo _roadtypes[ROADTYPE_END];
6044 for (auto &roadtype : roadtypes) {
6045 if (roadtype != INVALID_ROADTYPE) {
6046 RoadTypeInfo *rti = &_roadtypes[roadtype];
6047
6048 rti->grffile[ctype] = _cur.grffile;
6049 rti->group[ctype] = _cur.spritegroups[groupid];
6050 }
6051 }
6052 }
6053
6054 /* Roadtypes do not use the default group. */
6055 buf.ReadWord();
6056}
6057
6058static void AirportMapSpriteGroup(ByteReader &buf, uint8_t idcount)
6059{
6060 if (_cur.grffile->airportspec.empty()) {
6061 GrfMsg(1, "AirportMapSpriteGroup: No airports defined, skipping");
6062 return;
6063 }
6064
6065 std::vector<uint16_t> airports;
6066 airports.reserve(idcount);
6067 for (uint i = 0; i < idcount; i++) {
6068 airports.push_back(buf.ReadExtendedByte());
6069 }
6070
6071 /* Skip the cargo type section, we only care about the default group */
6072 uint8_t cidcount = buf.ReadByte();
6073 buf.Skip(cidcount * 3);
6074
6075 uint16_t groupid = buf.ReadWord();
6076 if (!IsValidGroupID(groupid, "AirportMapSpriteGroup")) return;
6077
6078 for (auto &airport : airports) {
6079 AirportSpec *as = airport >= _cur.grffile->airportspec.size() ? nullptr : _cur.grffile->airportspec[airport].get();
6080
6081 if (as == nullptr) {
6082 GrfMsg(1, "AirportMapSpriteGroup: Airport {} undefined, skipping", airport);
6083 continue;
6084 }
6085
6086 as->grf_prop.spritegroup[0] = _cur.spritegroups[groupid];
6087 }
6088}
6089
6090static void AirportTileMapSpriteGroup(ByteReader &buf, uint8_t idcount)
6091{
6092 if (_cur.grffile->airtspec.empty()) {
6093 GrfMsg(1, "AirportTileMapSpriteGroup: No airport tiles defined, skipping");
6094 return;
6095 }
6096
6097 std::vector<uint16_t> airptiles;
6098 airptiles.reserve(idcount);
6099 for (uint i = 0; i < idcount; i++) {
6100 airptiles.push_back(buf.ReadExtendedByte());
6101 }
6102
6103 /* Skip the cargo type section, we only care about the default group */
6104 uint8_t cidcount = buf.ReadByte();
6105 buf.Skip(cidcount * 3);
6106
6107 uint16_t groupid = buf.ReadWord();
6108 if (!IsValidGroupID(groupid, "AirportTileMapSpriteGroup")) return;
6109
6110 for (auto &airptile : airptiles) {
6111 AirportTileSpec *airtsp = airptile >= _cur.grffile->airtspec.size() ? nullptr : _cur.grffile->airtspec[airptile].get();
6112
6113 if (airtsp == nullptr) {
6114 GrfMsg(1, "AirportTileMapSpriteGroup: Airport tile {} undefined, skipping", airptile);
6115 continue;
6116 }
6117
6118 airtsp->grf_prop.spritegroup[0] = _cur.spritegroups[groupid];
6119 }
6120}
6121
6122static void RoadStopMapSpriteGroup(ByteReader &buf, uint8_t idcount)
6123{
6124 if (_cur.grffile->roadstops.empty()) {
6125 GrfMsg(1, "RoadStopMapSpriteGroup: No roadstops defined, skipping");
6126 return;
6127 }
6128
6129 std::vector<uint16_t> roadstops;
6130 roadstops.reserve(idcount);
6131 for (uint i = 0; i < idcount; i++) {
6132 roadstops.push_back(buf.ReadExtendedByte());
6133 }
6134
6135 uint8_t cidcount = buf.ReadByte();
6136 for (uint c = 0; c < cidcount; c++) {
6137 uint8_t ctype = buf.ReadByte();
6138 uint16_t groupid = buf.ReadWord();
6139 if (!IsValidGroupID(groupid, "RoadStopMapSpriteGroup")) continue;
6140
6141 ctype = TranslateCargo(GSF_ROADSTOPS, ctype);
6142 if (!IsValidCargoID(ctype)) continue;
6143
6144 for (auto &roadstop : roadstops) {
6145 RoadStopSpec *roadstopspec = roadstop >= _cur.grffile->roadstops.size() ? nullptr : _cur.grffile->roadstops[roadstop].get();
6146
6147 if (roadstopspec == nullptr) {
6148 GrfMsg(1, "RoadStopMapSpriteGroup: Road stop {} undefined, skipping", roadstop);
6149 continue;
6150 }
6151
6152 roadstopspec->grf_prop.spritegroup[ctype] = _cur.spritegroups[groupid];
6153 }
6154 }
6155
6156 uint16_t groupid = buf.ReadWord();
6157 if (!IsValidGroupID(groupid, "RoadStopMapSpriteGroup")) return;
6158
6159 for (auto &roadstop : roadstops) {
6160 RoadStopSpec *roadstopspec = roadstop >= _cur.grffile->roadstops.size() ? nullptr : _cur.grffile->roadstops[roadstop].get();
6161
6162 if (roadstopspec == nullptr) {
6163 GrfMsg(1, "RoadStopMapSpriteGroup: Road stop {} undefined, skipping.", roadstop);
6164 continue;
6165 }
6166
6167 if (roadstopspec->grf_prop.HasGrfFile()) {
6168 GrfMsg(1, "RoadStopMapSpriteGroup: Road stop {} mapped multiple times, skipping", roadstop);
6169 continue;
6170 }
6171
6172 roadstopspec->grf_prop.spritegroup[SpriteGroupCargo::SG_DEFAULT] = _cur.spritegroups[groupid];
6173 roadstopspec->grf_prop.grfid = _cur.grffile->grfid;
6174 roadstopspec->grf_prop.grffile = _cur.grffile;
6175 roadstopspec->grf_prop.local_id = roadstop;
6176 RoadStopClass::Assign(roadstopspec);
6177 }
6178}
6179
6180/* Action 0x03 */
6181static void FeatureMapSpriteGroup(ByteReader &buf)
6182{
6183 /* <03> <feature> <n-id> <ids>... <num-cid> [<cargo-type> <cid>]... <def-cid>
6184 * id-list := [<id>] [id-list]
6185 * cargo-list := <cargo-type> <cid> [cargo-list]
6186 *
6187 * B feature see action 0
6188 * B n-id bits 0-6: how many IDs this definition applies to
6189 * bit 7: if set, this is a wagon override definition (see below)
6190 * E ids the IDs for which this definition applies
6191 * B num-cid number of cargo IDs (sprite group IDs) in this definition
6192 * can be zero, in that case the def-cid is used always
6193 * B cargo-type type of this cargo type (e.g. mail=2, wood=7, see below)
6194 * W cid cargo ID (sprite group ID) for this type of cargo
6195 * W def-cid default cargo ID (sprite group ID) */
6196
6197 uint8_t feature = buf.ReadByte();
6198 uint8_t idcount = buf.ReadByte();
6199
6200 if (feature >= GSF_END) {
6201 GrfMsg(1, "FeatureMapSpriteGroup: Unsupported feature 0x{:02X}, skipping", feature);
6202 return;
6203 }
6204
6205 /* If idcount is zero, this is a feature callback */
6206 if (idcount == 0) {
6207 /* Skip number of cargo ids? */
6208 buf.ReadByte();
6209 uint16_t groupid = buf.ReadWord();
6210 if (!IsValidGroupID(groupid, "FeatureMapSpriteGroup")) return;
6211
6212 GrfMsg(6, "FeatureMapSpriteGroup: Adding generic feature callback for feature 0x{:02X}", feature);
6213
6214 AddGenericCallback(feature, _cur.grffile, _cur.spritegroups[groupid]);
6215 return;
6216 }
6217
6218 /* Mark the feature as used by the grf (generic callbacks do not count) */
6219 SetBit(_cur.grffile->grf_features, feature);
6220
6221 GrfMsg(6, "FeatureMapSpriteGroup: Feature 0x{:02X}, {} ids", feature, idcount);
6222
6223 switch (feature) {
6224 case GSF_TRAINS:
6225 case GSF_ROADVEHICLES:
6226 case GSF_SHIPS:
6227 case GSF_AIRCRAFT:
6228 VehicleMapSpriteGroup(buf, feature, idcount);
6229 return;
6230
6231 case GSF_CANALS:
6232 CanalMapSpriteGroup(buf, idcount);
6233 return;
6234
6235 case GSF_STATIONS:
6236 StationMapSpriteGroup(buf, idcount);
6237 return;
6238
6239 case GSF_HOUSES:
6240 TownHouseMapSpriteGroup(buf, idcount);
6241 return;
6242
6243 case GSF_INDUSTRIES:
6244 IndustryMapSpriteGroup(buf, idcount);
6245 return;
6246
6247 case GSF_INDUSTRYTILES:
6248 IndustrytileMapSpriteGroup(buf, idcount);
6249 return;
6250
6251 case GSF_CARGOES:
6252 CargoMapSpriteGroup(buf, idcount);
6253 return;
6254
6255 case GSF_AIRPORTS:
6256 AirportMapSpriteGroup(buf, idcount);
6257 return;
6258
6259 case GSF_OBJECTS:
6260 ObjectMapSpriteGroup(buf, idcount);
6261 break;
6262
6263 case GSF_RAILTYPES:
6264 RailTypeMapSpriteGroup(buf, idcount);
6265 break;
6266
6267 case GSF_ROADTYPES:
6268 RoadTypeMapSpriteGroup(buf, idcount, RTT_ROAD);
6269 break;
6270
6271 case GSF_TRAMTYPES:
6272 RoadTypeMapSpriteGroup(buf, idcount, RTT_TRAM);
6273 break;
6274
6275 case GSF_AIRPORTTILES:
6276 AirportTileMapSpriteGroup(buf, idcount);
6277 return;
6278
6279 case GSF_ROADSTOPS:
6280 RoadStopMapSpriteGroup(buf, idcount);
6281 return;
6282
6283 default:
6284 GrfMsg(1, "FeatureMapSpriteGroup: Unsupported feature 0x{:02X}, skipping", feature);
6285 return;
6286 }
6287}
6288
6289/* Action 0x04 */
6290static void FeatureNewName(ByteReader &buf)
6291{
6292 /* <04> <veh-type> <language-id> <num-veh> <offset> <data...>
6293 *
6294 * B veh-type see action 0 (as 00..07, + 0A
6295 * But IF veh-type = 48, then generic text
6296 * B language-id If bit 6 is set, This is the extended language scheme,
6297 * with up to 64 language.
6298 * Otherwise, it is a mapping where set bits have meaning
6299 * 0 = american, 1 = english, 2 = german, 3 = french, 4 = spanish
6300 * Bit 7 set means this is a generic text, not a vehicle one (or else)
6301 * B num-veh number of vehicles which are getting a new name
6302 * B/W offset number of the first vehicle that gets a new name
6303 * Byte : ID of vehicle to change
6304 * Word : ID of string to change/add
6305 * S data new texts, each of them zero-terminated, after
6306 * which the next name begins. */
6307
6308 bool new_scheme = _cur.grffile->grf_version >= 7;
6309
6310 uint8_t feature = buf.ReadByte();
6311 if (feature >= GSF_END && feature != 0x48) {
6312 GrfMsg(1, "FeatureNewName: Unsupported feature 0x{:02X}, skipping", feature);
6313 return;
6314 }
6315
6316 uint8_t lang = buf.ReadByte();
6317 uint8_t num = buf.ReadByte();
6318 bool generic = HasBit(lang, 7);
6319 uint16_t id;
6320 if (generic) {
6321 id = buf.ReadWord();
6322 } else if (feature <= GSF_AIRCRAFT) {
6323 id = buf.ReadExtendedByte();
6324 } else {
6325 id = buf.ReadByte();
6326 }
6327
6328 ClrBit(lang, 7);
6329
6330 uint16_t endid = id + num;
6331
6332 GrfMsg(6, "FeatureNewName: About to rename engines {}..{} (feature 0x{:02X}) in language 0x{:02X}",
6333 id, endid, feature, lang);
6334
6335 for (; id < endid && buf.HasData(); id++) {
6336 const std::string_view name = buf.ReadString();
6337 GrfMsg(8, "FeatureNewName: 0x{:04X} <- {}", id, StrMakeValid(name));
6338
6339 switch (feature) {
6340 case GSF_TRAINS:
6341 case GSF_ROADVEHICLES:
6342 case GSF_SHIPS:
6343 case GSF_AIRCRAFT:
6344 if (!generic) {
6345 Engine *e = GetNewEngine(_cur.grffile, (VehicleType)feature, id, HasBit(_cur.grfconfig->flags, GCF_STATIC));
6346 if (e == nullptr) break;
6347 StringID string = AddGRFString(_cur.grffile->grfid, e->index, lang, new_scheme, false, name, e->info.string_id);
6348 e->info.string_id = string;
6349 } else {
6350 AddGRFString(_cur.grffile->grfid, id, lang, new_scheme, true, name, STR_UNDEFINED);
6351 }
6352 break;
6353
6354 default:
6355 if (IsInsideMM(id, 0xD000, 0xD400) || IsInsideMM(id, 0xD800, 0x10000)) {
6356 AddGRFString(_cur.grffile->grfid, id, lang, new_scheme, true, name, STR_UNDEFINED);
6357 break;
6358 }
6359
6360 switch (GB(id, 8, 8)) {
6361 case 0xC4: // Station class name
6362 if (GB(id, 0, 8) >= _cur.grffile->stations.size() || _cur.grffile->stations[GB(id, 0, 8)] == nullptr) {
6363 GrfMsg(1, "FeatureNewName: Attempt to name undefined station 0x{:X}, ignoring", GB(id, 0, 8));
6364 } else {
6365 StationClassID class_index = _cur.grffile->stations[GB(id, 0, 8)]->class_index;
6366 StationClass::Get(class_index)->name = AddGRFString(_cur.grffile->grfid, id, lang, new_scheme, false, name, STR_UNDEFINED);
6367 }
6368 break;
6369
6370 case 0xC5: // Station name
6371 if (GB(id, 0, 8) >= _cur.grffile->stations.size() || _cur.grffile->stations[GB(id, 0, 8)] == nullptr) {
6372 GrfMsg(1, "FeatureNewName: Attempt to name undefined station 0x{:X}, ignoring", GB(id, 0, 8));
6373 } else {
6374 _cur.grffile->stations[GB(id, 0, 8)]->name = AddGRFString(_cur.grffile->grfid, id, lang, new_scheme, false, name, STR_UNDEFINED);
6375 }
6376 break;
6377
6378 case 0xC7: // Airporttile name
6379 if (GB(id, 0, 8) >= _cur.grffile->airtspec.size() || _cur.grffile->airtspec[GB(id, 0, 8)] == nullptr) {
6380 GrfMsg(1, "FeatureNewName: Attempt to name undefined airport tile 0x{:X}, ignoring", GB(id, 0, 8));
6381 } else {
6382 _cur.grffile->airtspec[GB(id, 0, 8)]->name = AddGRFString(_cur.grffile->grfid, id, lang, new_scheme, false, name, STR_UNDEFINED);
6383 }
6384 break;
6385
6386 case 0xC9: // House name
6387 if (GB(id, 0, 8) >= _cur.grffile->housespec.size() || _cur.grffile->housespec[GB(id, 0, 8)] == nullptr) {
6388 GrfMsg(1, "FeatureNewName: Attempt to name undefined house 0x{:X}, ignoring.", GB(id, 0, 8));
6389 } else {
6390 _cur.grffile->housespec[GB(id, 0, 8)]->building_name = AddGRFString(_cur.grffile->grfid, id, lang, new_scheme, false, name, STR_UNDEFINED);
6391 }
6392 break;
6393
6394 default:
6395 GrfMsg(7, "FeatureNewName: Unsupported ID (0x{:04X})", id);
6396 break;
6397 }
6398 break;
6399 }
6400 }
6401}
6402
6411static uint16_t SanitizeSpriteOffset(uint16_t &num, uint16_t offset, int max_sprites, const std::string_view name)
6412{
6413
6414 if (offset >= max_sprites) {
6415 GrfMsg(1, "GraphicsNew: {} sprite offset must be less than {}, skipping", name, max_sprites);
6416 uint orig_num = num;
6417 num = 0;
6418 return orig_num;
6419 }
6420
6421 if (offset + num > max_sprites) {
6422 GrfMsg(4, "GraphicsNew: {} sprite overflow, truncating...", name);
6423 uint orig_num = num;
6424 num = std::max(max_sprites - offset, 0);
6425 return orig_num - num;
6426 }
6427
6428 return 0;
6429}
6430
6431
6433static constexpr auto _action5_types = std::to_array<Action5Type>({
6434 /* Note: min_sprites should not be changed. Therefore these constants are directly here and not in sprites.h */
6435 /* 0x00 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x00" },
6436 /* 0x01 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x01" },
6437 /* 0x02 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x02" },
6438 /* 0x03 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x03" },
6439 /* 0x04 */ { A5BLOCK_ALLOW_OFFSET, SPR_SIGNALS_BASE, 1, PRESIGNAL_SEMAPHORE_AND_PBS_SPRITE_COUNT, "Signal graphics" },
6440 /* 0x05 */ { A5BLOCK_ALLOW_OFFSET, SPR_ELRAIL_BASE, 1, ELRAIL_SPRITE_COUNT, "Rail catenary graphics" },
6441 /* 0x06 */ { A5BLOCK_ALLOW_OFFSET, SPR_SLOPES_BASE, 1, NORMAL_AND_HALFTILE_FOUNDATION_SPRITE_COUNT, "Foundation graphics" },
6442 /* 0x07 */ { A5BLOCK_INVALID, 0, 75, 0, "TTDP GUI graphics" }, // Not used by OTTD.
6443 /* 0x08 */ { A5BLOCK_ALLOW_OFFSET, SPR_CANALS_BASE, 1, CANALS_SPRITE_COUNT, "Canal graphics" },
6444 /* 0x09 */ { A5BLOCK_ALLOW_OFFSET, SPR_ONEWAY_BASE, 1, ONEWAY_SPRITE_COUNT, "One way road graphics" },
6445 /* 0x0A */ { A5BLOCK_ALLOW_OFFSET, SPR_2CCMAP_BASE, 1, TWOCCMAP_SPRITE_COUNT, "2CC colour maps" },
6446 /* 0x0B */ { A5BLOCK_ALLOW_OFFSET, SPR_TRAMWAY_BASE, 1, TRAMWAY_SPRITE_COUNT, "Tramway graphics" },
6447 /* 0x0C */ { A5BLOCK_INVALID, 0, 133, 0, "Snowy temperate tree" }, // Not yet used by OTTD.
6448 /* 0x0D */ { A5BLOCK_FIXED, SPR_SHORE_BASE, 16, SPR_SHORE_SPRITE_COUNT, "Shore graphics" },
6449 /* 0x0E */ { A5BLOCK_INVALID, 0, 0, 0, "New Signals graphics" }, // Not yet used by OTTD.
6450 /* 0x0F */ { A5BLOCK_ALLOW_OFFSET, SPR_TRACKS_FOR_SLOPES_BASE, 1, TRACKS_FOR_SLOPES_SPRITE_COUNT, "Sloped rail track" },
6451 /* 0x10 */ { A5BLOCK_ALLOW_OFFSET, SPR_AIRPORTX_BASE, 1, AIRPORTX_SPRITE_COUNT, "Airport graphics" },
6452 /* 0x11 */ { A5BLOCK_ALLOW_OFFSET, SPR_ROADSTOP_BASE, 1, ROADSTOP_SPRITE_COUNT, "Road stop graphics" },
6453 /* 0x12 */ { A5BLOCK_ALLOW_OFFSET, SPR_AQUEDUCT_BASE, 1, AQUEDUCT_SPRITE_COUNT, "Aqueduct graphics" },
6454 /* 0x13 */ { A5BLOCK_ALLOW_OFFSET, SPR_AUTORAIL_BASE, 1, AUTORAIL_SPRITE_COUNT, "Autorail graphics" },
6455 /* 0x14 */ { A5BLOCK_INVALID, 0, 1, 0, "Flag graphics" }, // deprecated, no longer used.
6456 /* 0x15 */ { A5BLOCK_ALLOW_OFFSET, SPR_OPENTTD_BASE, 1, OPENTTD_SPRITE_COUNT, "OpenTTD GUI graphics" },
6457 /* 0x16 */ { A5BLOCK_ALLOW_OFFSET, SPR_AIRPORT_PREVIEW_BASE, 1, SPR_AIRPORT_PREVIEW_COUNT, "Airport preview graphics" },
6458 /* 0x17 */ { A5BLOCK_ALLOW_OFFSET, SPR_RAILTYPE_TUNNEL_BASE, 1, RAILTYPE_TUNNEL_BASE_COUNT, "Railtype tunnel base" },
6459 /* 0x18 */ { A5BLOCK_ALLOW_OFFSET, SPR_PALETTE_BASE, 1, PALETTE_SPRITE_COUNT, "Palette" },
6460 /* 0x19 */ { A5BLOCK_ALLOW_OFFSET, SPR_ROAD_WAYPOINTS_BASE, 1, ROAD_WAYPOINTS_SPRITE_COUNT, "Road waypoints" },
6461});
6462
6467std::span<const Action5Type> GetAction5Types()
6468{
6469 return _action5_types;
6470}
6471
6472/* Action 0x05 */
6473static void GraphicsNew(ByteReader &buf)
6474{
6475 /* <05> <graphics-type> <num-sprites> <other data...>
6476 *
6477 * B graphics-type What set of graphics the sprites define.
6478 * E num-sprites How many sprites are in this set?
6479 * V other data Graphics type specific data. Currently unused. */
6480
6481 uint8_t type = buf.ReadByte();
6482 uint16_t num = buf.ReadExtendedByte();
6483 uint16_t offset = HasBit(type, 7) ? buf.ReadExtendedByte() : 0;
6484 ClrBit(type, 7); // Clear the high bit as that only indicates whether there is an offset.
6485
6486 if ((type == 0x0D) && (num == 10) && HasBit(_cur.grfconfig->flags, GCF_SYSTEM)) {
6487 /* Special not-TTDP-compatible case used in openttd.grf
6488 * Missing shore sprites and initialisation of SPR_SHORE_BASE */
6489 GrfMsg(2, "GraphicsNew: Loading 10 missing shore sprites from extra grf.");
6490 LoadNextSprite(SPR_SHORE_BASE + 0, *_cur.file, _cur.nfo_line++); // SLOPE_STEEP_S
6491 LoadNextSprite(SPR_SHORE_BASE + 5, *_cur.file, _cur.nfo_line++); // SLOPE_STEEP_W
6492 LoadNextSprite(SPR_SHORE_BASE + 7, *_cur.file, _cur.nfo_line++); // SLOPE_WSE
6493 LoadNextSprite(SPR_SHORE_BASE + 10, *_cur.file, _cur.nfo_line++); // SLOPE_STEEP_N
6494 LoadNextSprite(SPR_SHORE_BASE + 11, *_cur.file, _cur.nfo_line++); // SLOPE_NWS
6495 LoadNextSprite(SPR_SHORE_BASE + 13, *_cur.file, _cur.nfo_line++); // SLOPE_ENW
6496 LoadNextSprite(SPR_SHORE_BASE + 14, *_cur.file, _cur.nfo_line++); // SLOPE_SEN
6497 LoadNextSprite(SPR_SHORE_BASE + 15, *_cur.file, _cur.nfo_line++); // SLOPE_STEEP_E
6498 LoadNextSprite(SPR_SHORE_BASE + 16, *_cur.file, _cur.nfo_line++); // SLOPE_EW
6499 LoadNextSprite(SPR_SHORE_BASE + 17, *_cur.file, _cur.nfo_line++); // SLOPE_NS
6501 return;
6502 }
6503
6504 /* Supported type? */
6505 if ((type >= std::size(_action5_types)) || (_action5_types[type].block_type == A5BLOCK_INVALID)) {
6506 GrfMsg(2, "GraphicsNew: Custom graphics (type 0x{:02X}) sprite block of length {} (unimplemented, ignoring)", type, num);
6507 _cur.skip_sprites = num;
6508 return;
6509 }
6510
6511 const Action5Type *action5_type = &_action5_types[type];
6512
6513 /* Contrary to TTDP we allow always to specify too few sprites as we allow always an offset,
6514 * except for the long version of the shore type:
6515 * Ignore offset if not allowed */
6516 if ((action5_type->block_type != A5BLOCK_ALLOW_OFFSET) && (offset != 0)) {
6517 GrfMsg(1, "GraphicsNew: {} (type 0x{:02X}) do not allow an <offset> field. Ignoring offset.", action5_type->name, type);
6518 offset = 0;
6519 }
6520
6521 /* Ignore action5 if too few sprites are specified. (for TTDP compatibility)
6522 * This does not make sense, if <offset> is allowed */
6523 if ((action5_type->block_type == A5BLOCK_FIXED) && (num < action5_type->min_sprites)) {
6524 GrfMsg(1, "GraphicsNew: {} (type 0x{:02X}) count must be at least {}. Only {} were specified. Skipping.", action5_type->name, type, action5_type->min_sprites, num);
6525 _cur.skip_sprites = num;
6526 return;
6527 }
6528
6529 /* Load at most max_sprites sprites. Skip remaining sprites. (for compatibility with TTDP and future extensions) */
6530 uint16_t skip_num = SanitizeSpriteOffset(num, offset, action5_type->max_sprites, action5_type->name);
6531 SpriteID replace = action5_type->sprite_base + offset;
6532
6533 /* Load <num> sprites starting from <replace>, then skip <skip_num> sprites. */
6534 GrfMsg(2, "GraphicsNew: Replacing sprites {} to {} of {} (type 0x{:02X}) at SpriteID 0x{:04X}", offset, offset + num - 1, action5_type->name, type, replace);
6535
6537
6538 if (type == 0x0B) {
6539 static const SpriteID depot_with_track_offset = SPR_TRAMWAY_DEPOT_WITH_TRACK - SPR_TRAMWAY_BASE;
6540 static const SpriteID depot_no_track_offset = SPR_TRAMWAY_DEPOT_NO_TRACK - SPR_TRAMWAY_BASE;
6541 if (offset <= depot_with_track_offset && offset + num > depot_with_track_offset) _loaded_newgrf_features.tram = TRAMWAY_REPLACE_DEPOT_WITH_TRACK;
6542 if (offset <= depot_no_track_offset && offset + num > depot_no_track_offset) _loaded_newgrf_features.tram = TRAMWAY_REPLACE_DEPOT_NO_TRACK;
6543 }
6544
6545 /* If the baseset or grf only provides sprites for flat tiles (pre #10282), duplicate those for use on slopes. */
6546 bool dup_oneway_sprites = ((type == 0x09) && (offset + num <= SPR_ONEWAY_SLOPE_N_OFFSET));
6547
6548 for (; num > 0; num--) {
6549 _cur.nfo_line++;
6550 SpriteID load_index = (replace == 0 ? _cur.spriteid++ : replace++);
6551 LoadNextSprite(load_index, *_cur.file, _cur.nfo_line);
6552 if (dup_oneway_sprites) {
6553 DupSprite(load_index, load_index + SPR_ONEWAY_SLOPE_N_OFFSET);
6554 DupSprite(load_index, load_index + SPR_ONEWAY_SLOPE_S_OFFSET);
6555 }
6556 }
6557
6558 _cur.skip_sprites = skip_num;
6559}
6560
6561/* Action 0x05 (SKIP) */
6562static void SkipAct5(ByteReader &buf)
6563{
6564 /* Ignore type byte */
6565 buf.ReadByte();
6566
6567 /* Skip the sprites of this action */
6568 _cur.skip_sprites = buf.ReadExtendedByte();
6569
6570 GrfMsg(3, "SkipAct5: Skipping {} sprites", _cur.skip_sprites);
6571}
6572
6584bool GetGlobalVariable(uint8_t param, uint32_t *value, const GRFFile *grffile)
6585{
6586 switch (param) {
6587 case 0x00: // current date
6588 *value = std::max(TimerGameCalendar::date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR, TimerGameCalendar::Date(0)).base();
6589 return true;
6590
6591 case 0x01: // current year
6593 return true;
6594
6595 case 0x02: { // detailed date information: month of year (bit 0-7), day of month (bit 8-12), leap year (bit 15), day of year (bit 16-24)
6596 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date);
6597 TimerGameCalendar::Date start_of_year = TimerGameCalendar::ConvertYMDToDate(ymd.year, 0, 1);
6598 *value = ymd.month | (ymd.day - 1) << 8 | (TimerGameCalendar::IsLeapYear(ymd.year) ? 1 << 15 : 0) | (TimerGameCalendar::date - start_of_year).base() << 16;
6599 return true;
6600 }
6601
6602 case 0x03: // current climate, 0=temp, 1=arctic, 2=trop, 3=toyland
6604 return true;
6605
6606 case 0x06: // road traffic side, bit 4 clear=left, set=right
6607 *value = _settings_game.vehicle.road_side << 4;
6608 return true;
6609
6610 case 0x09: // date fraction
6611 *value = TimerGameCalendar::date_fract * 885;
6612 return true;
6613
6614 case 0x0A: // animation counter
6615 *value = GB(TimerGameTick::counter, 0, 16);
6616 return true;
6617
6618 case 0x0B: { // TTDPatch version
6619 uint major = 2;
6620 uint minor = 6;
6621 uint revision = 1; // special case: 2.0.1 is 2.0.10
6622 uint build = 1382;
6623 *value = (major << 24) | (minor << 20) | (revision << 16) | build;
6624 return true;
6625 }
6626
6627 case 0x0D: // TTD Version, 00=DOS, 01=Windows
6628 *value = _cur.grfconfig->palette & GRFP_USE_MASK;
6629 return true;
6630
6631 case 0x0E: // Y-offset for train sprites
6632 *value = _cur.grffile->traininfo_vehicle_pitch;
6633 return true;
6634
6635 case 0x0F: // Rail track type cost factors
6636 *value = 0;
6637 SB(*value, 0, 8, GetRailTypeInfo(RAILTYPE_RAIL)->cost_multiplier); // normal rail
6639 /* skip elrail multiplier - disabled */
6640 SB(*value, 8, 8, GetRailTypeInfo(RAILTYPE_MONO)->cost_multiplier); // monorail
6641 } else {
6642 SB(*value, 8, 8, GetRailTypeInfo(RAILTYPE_ELECTRIC)->cost_multiplier); // electified railway
6643 /* Skip monorail multiplier - no space in result */
6644 }
6645 SB(*value, 16, 8, GetRailTypeInfo(RAILTYPE_MAGLEV)->cost_multiplier); // maglev
6646 return true;
6647
6648 case 0x11: // current rail tool type
6649 *value = 0; // constant fake value to avoid desync
6650 return true;
6651
6652 case 0x12: // Game mode
6653 *value = _game_mode;
6654 return true;
6655
6656 /* case 0x13: // Tile refresh offset to left not implemented */
6657 /* case 0x14: // Tile refresh offset to right not implemented */
6658 /* case 0x15: // Tile refresh offset upwards not implemented */
6659 /* case 0x16: // Tile refresh offset downwards not implemented */
6660 /* case 0x17: // temperate snow line not implemented */
6661
6662 case 0x1A: // Always -1
6663 *value = UINT_MAX;
6664 return true;
6665
6666 case 0x1B: // Display options
6667 *value = 0x3F; // constant fake value to avoid desync
6668 return true;
6669
6670 case 0x1D: // TTD Platform, 00=TTDPatch, 01=OpenTTD
6671 *value = 1;
6672 return true;
6673
6674 case 0x1E: // Miscellaneous GRF features
6675 *value = _misc_grf_features;
6676
6677 /* Add the local flags */
6678 assert(!HasBit(*value, GMB_TRAIN_WIDTH_32_PIXELS));
6679 if (_cur.grffile->traininfo_vehicle_width == VEHICLEINFO_FULL_VEHICLE_WIDTH) SetBit(*value, GMB_TRAIN_WIDTH_32_PIXELS);
6680 return true;
6681
6682 /* case 0x1F: // locale dependent settings not implemented to avoid desync */
6683
6684 case 0x20: { // snow line height
6685 uint8_t snowline = GetSnowLine();
6687 *value = Clamp(snowline * (grffile->grf_version >= 8 ? 1 : TILE_HEIGHT), 0, 0xFE);
6688 } else {
6689 /* No snow */
6690 *value = 0xFF;
6691 }
6692 return true;
6693 }
6694
6695 case 0x21: // OpenTTD version
6696 *value = _openttd_newgrf_version;
6697 return true;
6698
6699 case 0x22: // difficulty level
6700 *value = SP_CUSTOM;
6701 return true;
6702
6703 case 0x23: // long format date
6704 *value = TimerGameCalendar::date.base();
6705 return true;
6706
6707 case 0x24: // long format year
6708 *value = TimerGameCalendar::year.base();
6709 return true;
6710
6711 default: return false;
6712 }
6713}
6714
6715static uint32_t GetParamVal(uint8_t param, uint32_t *cond_val)
6716{
6717 /* First handle variable common with VarAction2 */
6718 uint32_t value;
6719 if (GetGlobalVariable(param - 0x80, &value, _cur.grffile)) return value;
6720
6721
6722 /* Non-common variable */
6723 switch (param) {
6724 case 0x84: { // GRF loading stage
6725 uint32_t res = 0;
6726
6727 if (_cur.stage > GLS_INIT) SetBit(res, 0);
6728 if (_cur.stage == GLS_RESERVE) SetBit(res, 8);
6729 if (_cur.stage == GLS_ACTIVATION) SetBit(res, 9);
6730 return res;
6731 }
6732
6733 case 0x85: // TTDPatch flags, only for bit tests
6734 if (cond_val == nullptr) {
6735 /* Supported in Action 0x07 and 0x09, not 0x0D */
6736 return 0;
6737 } else {
6738 uint32_t index = *cond_val / 0x20;
6739 uint32_t param_val = index < lengthof(_ttdpatch_flags) ? _ttdpatch_flags[index] : 0;
6740 *cond_val %= 0x20;
6741 return param_val;
6742 }
6743
6744 case 0x88: // GRF ID check
6745 return 0;
6746
6747 /* case 0x99: Global ID offset not implemented */
6748
6749 default:
6750 /* GRF Parameter */
6751 if (param < 0x80) return _cur.grffile->GetParam(param);
6752
6753 /* In-game variable. */
6754 GrfMsg(1, "Unsupported in-game variable 0x{:02X}", param);
6755 return UINT_MAX;
6756 }
6757}
6758
6759/* Action 0x06 */
6760static void CfgApply(ByteReader &buf)
6761{
6762 /* <06> <param-num> <param-size> <offset> ... <FF>
6763 *
6764 * B param-num Number of parameter to substitute (First = "zero")
6765 * Ignored if that parameter was not specified in newgrf.cfg
6766 * B param-size How many bytes to replace. If larger than 4, the
6767 * bytes of the following parameter are used. In that
6768 * case, nothing is applied unless *all* parameters
6769 * were specified.
6770 * B offset Offset into data from beginning of next sprite
6771 * to place where parameter is to be stored. */
6772
6773 /* Preload the next sprite */
6774 SpriteFile &file = *_cur.file;
6775 size_t pos = file.GetPos();
6776 uint32_t num = file.GetContainerVersion() >= 2 ? file.ReadDword() : file.ReadWord();
6777 uint8_t type = file.ReadByte();
6778
6779 /* Check if the sprite is a pseudo sprite. We can't operate on real sprites. */
6780 if (type != 0xFF) {
6781 GrfMsg(2, "CfgApply: Ignoring (next sprite is real, unsupported)");
6782
6783 /* Reset the file position to the start of the next sprite */
6784 file.SeekTo(pos, SEEK_SET);
6785 return;
6786 }
6787
6788 /* Get (or create) the override for the next sprite. */
6789 GRFLocation location(_cur.grfconfig->ident.grfid, _cur.nfo_line + 1);
6790 std::vector<uint8_t> &preload_sprite = _grf_line_to_action6_sprite_override[location];
6791
6792 /* Load new sprite data if it hasn't already been loaded. */
6793 if (preload_sprite.empty()) {
6794 preload_sprite.resize(num);
6795 file.ReadBlock(preload_sprite.data(), num);
6796 }
6797
6798 /* Reset the file position to the start of the next sprite */
6799 file.SeekTo(pos, SEEK_SET);
6800
6801 /* Now perform the Action 0x06 on our data. */
6802 for (;;) {
6803 uint i;
6804 uint param_num;
6805 uint param_size;
6806 uint offset;
6807 bool add_value;
6808
6809 /* Read the parameter to apply. 0xFF indicates no more data to change. */
6810 param_num = buf.ReadByte();
6811 if (param_num == 0xFF) break;
6812
6813 /* Get the size of the parameter to use. If the size covers multiple
6814 * double words, sequential parameter values are used. */
6815 param_size = buf.ReadByte();
6816
6817 /* Bit 7 of param_size indicates we should add to the original value
6818 * instead of replacing it. */
6819 add_value = HasBit(param_size, 7);
6820 param_size = GB(param_size, 0, 7);
6821
6822 /* Where to apply the data to within the pseudo sprite data. */
6823 offset = buf.ReadExtendedByte();
6824
6825 /* If the parameter is a GRF parameter (not an internal variable) check
6826 * if it (and all further sequential parameters) has been defined. */
6827 if (param_num < 0x80 && (param_num + (param_size - 1) / 4) >= std::size(_cur.grffile->param)) {
6828 GrfMsg(2, "CfgApply: Ignoring (param {} not set)", (param_num + (param_size - 1) / 4));
6829 break;
6830 }
6831
6832 GrfMsg(8, "CfgApply: Applying {} bytes from parameter 0x{:02X} at offset 0x{:04X}", param_size, param_num, offset);
6833
6834 bool carry = false;
6835 for (i = 0; i < param_size && offset + i < num; i++) {
6836 uint32_t value = GetParamVal(param_num + i / 4, nullptr);
6837 /* Reset carry flag for each iteration of the variable (only really
6838 * matters if param_size is greater than 4) */
6839 if (i % 4 == 0) carry = false;
6840
6841 if (add_value) {
6842 uint new_value = preload_sprite[offset + i] + GB(value, (i % 4) * 8, 8) + (carry ? 1 : 0);
6843 preload_sprite[offset + i] = GB(new_value, 0, 8);
6844 /* Check if the addition overflowed */
6845 carry = new_value >= 256;
6846 } else {
6847 preload_sprite[offset + i] = GB(value, (i % 4) * 8, 8);
6848 }
6849 }
6850 }
6851}
6852
6863{
6864 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC, c);
6865 error->data = _cur.grfconfig->GetName();
6866}
6867
6868/* Action 0x07
6869 * Action 0x09 */
6870static void SkipIf(ByteReader &buf)
6871{
6872 /* <07/09> <param-num> <param-size> <condition-type> <value> <num-sprites>
6873 *
6874 * B param-num
6875 * B param-size
6876 * B condition-type
6877 * V value
6878 * B num-sprites */
6879 uint32_t cond_val = 0;
6880 uint32_t mask = 0;
6881 bool result;
6882
6883 uint8_t param = buf.ReadByte();
6884 uint8_t paramsize = buf.ReadByte();
6885 uint8_t condtype = buf.ReadByte();
6886
6887 if (condtype < 2) {
6888 /* Always 1 for bit tests, the given value should be ignored. */
6889 paramsize = 1;
6890 }
6891
6892 switch (paramsize) {
6893 case 8: cond_val = buf.ReadDWord(); mask = buf.ReadDWord(); break;
6894 case 4: cond_val = buf.ReadDWord(); mask = 0xFFFFFFFF; break;
6895 case 2: cond_val = buf.ReadWord(); mask = 0x0000FFFF; break;
6896 case 1: cond_val = buf.ReadByte(); mask = 0x000000FF; break;
6897 default: break;
6898 }
6899
6900 if (param < 0x80 && std::size(_cur.grffile->param) <= param) {
6901 GrfMsg(7, "SkipIf: Param {} undefined, skipping test", param);
6902 return;
6903 }
6904
6905 GrfMsg(7, "SkipIf: Test condtype {}, param 0x{:02X}, condval 0x{:08X}", condtype, param, cond_val);
6906
6907 /* condtypes that do not use 'param' are always valid.
6908 * condtypes that use 'param' are either not valid for param 0x88, or they are only valid for param 0x88.
6909 */
6910 if (condtype >= 0x0B) {
6911 /* Tests that ignore 'param' */
6912 switch (condtype) {
6913 case 0x0B: result = !IsValidCargoID(GetCargoIDByLabel(CargoLabel(BSWAP32(cond_val))));
6914 break;
6915 case 0x0C: result = IsValidCargoID(GetCargoIDByLabel(CargoLabel(BSWAP32(cond_val))));
6916 break;
6917 case 0x0D: result = GetRailTypeByLabel(BSWAP32(cond_val)) == INVALID_RAILTYPE;
6918 break;
6919 case 0x0E: result = GetRailTypeByLabel(BSWAP32(cond_val)) != INVALID_RAILTYPE;
6920 break;
6921 case 0x0F: {
6922 RoadType rt = GetRoadTypeByLabel(BSWAP32(cond_val));
6923 result = rt == INVALID_ROADTYPE || !RoadTypeIsRoad(rt);
6924 break;
6925 }
6926 case 0x10: {
6927 RoadType rt = GetRoadTypeByLabel(BSWAP32(cond_val));
6928 result = rt != INVALID_ROADTYPE && RoadTypeIsRoad(rt);
6929 break;
6930 }
6931 case 0x11: {
6932 RoadType rt = GetRoadTypeByLabel(BSWAP32(cond_val));
6933 result = rt == INVALID_ROADTYPE || !RoadTypeIsTram(rt);
6934 break;
6935 }
6936 case 0x12: {
6937 RoadType rt = GetRoadTypeByLabel(BSWAP32(cond_val));
6938 result = rt != INVALID_ROADTYPE && RoadTypeIsTram(rt);
6939 break;
6940 }
6941 default: GrfMsg(1, "SkipIf: Unsupported condition type {:02X}. Ignoring", condtype); return;
6942 }
6943 } else if (param == 0x88) {
6944 /* GRF ID checks */
6945
6946 GRFConfig *c = GetGRFConfig(cond_val, mask);
6947
6948 if (c != nullptr && HasBit(c->flags, GCF_STATIC) && !HasBit(_cur.grfconfig->flags, GCF_STATIC) && _networking) {
6950 c = nullptr;
6951 }
6952
6953 if (condtype != 10 && c == nullptr) {
6954 GrfMsg(7, "SkipIf: GRFID 0x{:08X} unknown, skipping test", BSWAP32(cond_val));
6955 return;
6956 }
6957
6958 switch (condtype) {
6959 /* Tests 0x06 to 0x0A are only for param 0x88, GRFID checks */
6960 case 0x06: // Is GRFID active?
6961 result = c->status == GCS_ACTIVATED;
6962 break;
6963
6964 case 0x07: // Is GRFID non-active?
6965 result = c->status != GCS_ACTIVATED;
6966 break;
6967
6968 case 0x08: // GRFID is not but will be active?
6969 result = c->status == GCS_INITIALISED;
6970 break;
6971
6972 case 0x09: // GRFID is or will be active?
6973 result = c->status == GCS_ACTIVATED || c->status == GCS_INITIALISED;
6974 break;
6975
6976 case 0x0A: // GRFID is not nor will be active
6977 /* This is the only condtype that doesn't get ignored if the GRFID is not found */
6978 result = c == nullptr || c->status == GCS_DISABLED || c->status == GCS_NOT_FOUND;
6979 break;
6980
6981 default: GrfMsg(1, "SkipIf: Unsupported GRF condition type {:02X}. Ignoring", condtype); return;
6982 }
6983 } else {
6984 /* Tests that use 'param' and are not GRF ID checks. */
6985 uint32_t param_val = GetParamVal(param, &cond_val); // cond_val is modified for param == 0x85
6986 switch (condtype) {
6987 case 0x00: result = !!(param_val & (1 << cond_val));
6988 break;
6989 case 0x01: result = !(param_val & (1 << cond_val));
6990 break;
6991 case 0x02: result = (param_val & mask) == cond_val;
6992 break;
6993 case 0x03: result = (param_val & mask) != cond_val;
6994 break;
6995 case 0x04: result = (param_val & mask) < cond_val;
6996 break;
6997 case 0x05: result = (param_val & mask) > cond_val;
6998 break;
6999 default: GrfMsg(1, "SkipIf: Unsupported condition type {:02X}. Ignoring", condtype); return;
7000 }
7001 }
7002
7003 if (!result) {
7004 GrfMsg(2, "SkipIf: Not skipping sprites, test was false");
7005 return;
7006 }
7007
7008 uint8_t numsprites = buf.ReadByte();
7009
7010 /* numsprites can be a GOTO label if it has been defined in the GRF
7011 * file. The jump will always be the first matching label that follows
7012 * the current nfo_line. If no matching label is found, the first matching
7013 * label in the file is used. */
7014 const GRFLabel *choice = nullptr;
7015 for (const auto &label : _cur.grffile->labels) {
7016 if (label.label != numsprites) continue;
7017
7018 /* Remember a goto before the current line */
7019 if (choice == nullptr) choice = &label;
7020 /* If we find a label here, this is definitely good */
7021 if (label.nfo_line > _cur.nfo_line) {
7022 choice = &label;
7023 break;
7024 }
7025 }
7026
7027 if (choice != nullptr) {
7028 GrfMsg(2, "SkipIf: Jumping to label 0x{:X} at line {}, test was true", choice->label, choice->nfo_line);
7029 _cur.file->SeekTo(choice->pos, SEEK_SET);
7030 _cur.nfo_line = choice->nfo_line;
7031 return;
7032 }
7033
7034 GrfMsg(2, "SkipIf: Skipping {} sprites, test was true", numsprites);
7035 _cur.skip_sprites = numsprites;
7036 if (_cur.skip_sprites == 0) {
7037 /* Zero means there are no sprites to skip, so
7038 * we use -1 to indicate that all further
7039 * sprites should be skipped. */
7040 _cur.skip_sprites = -1;
7041
7042 /* If an action 8 hasn't been encountered yet, disable the grf. */
7043 if (_cur.grfconfig->status != (_cur.stage < GLS_RESERVE ? GCS_INITIALISED : GCS_ACTIVATED)) {
7044 DisableGrf();
7045 }
7046 }
7047}
7048
7049
7050/* Action 0x08 (GLS_FILESCAN) */
7051static void ScanInfo(ByteReader &buf)
7052{
7053 uint8_t grf_version = buf.ReadByte();
7054 uint32_t grfid = buf.ReadDWord();
7055 std::string_view name = buf.ReadString();
7056
7057 _cur.grfconfig->ident.grfid = grfid;
7058
7059 if (grf_version < 2 || grf_version > 8) {
7061 Debug(grf, 0, "{}: NewGRF \"{}\" (GRFID {:08X}) uses GRF version {}, which is incompatible with this version of OpenTTD.", _cur.grfconfig->filename, StrMakeValid(name), BSWAP32(grfid), grf_version);
7062 }
7063
7064 /* GRF IDs starting with 0xFF are reserved for internal TTDPatch use */
7065 if (GB(grfid, 0, 8) == 0xFF) SetBit(_cur.grfconfig->flags, GCF_SYSTEM);
7066
7067 AddGRFTextToList(_cur.grfconfig->name, 0x7F, grfid, false, name);
7068
7069 if (buf.HasData()) {
7070 std::string_view info = buf.ReadString();
7071 AddGRFTextToList(_cur.grfconfig->info, 0x7F, grfid, true, info);
7072 }
7073
7074 /* GLS_INFOSCAN only looks for the action 8, so we can skip the rest of the file */
7075 _cur.skip_sprites = -1;
7076}
7077
7078/* Action 0x08 */
7079static void GRFInfo(ByteReader &buf)
7080{
7081 /* <08> <version> <grf-id> <name> <info>
7082 *
7083 * B version newgrf version, currently 06
7084 * 4*B grf-id globally unique ID of this .grf file
7085 * S name name of this .grf set
7086 * S info string describing the set, and e.g. author and copyright */
7087
7088 uint8_t version = buf.ReadByte();
7089 uint32_t grfid = buf.ReadDWord();
7090 std::string_view name = buf.ReadString();
7091
7092 if (_cur.stage < GLS_RESERVE && _cur.grfconfig->status != GCS_UNKNOWN) {
7093 DisableGrf(STR_NEWGRF_ERROR_MULTIPLE_ACTION_8);
7094 return;
7095 }
7096
7097 if (_cur.grffile->grfid != grfid) {
7098 Debug(grf, 0, "GRFInfo: GRFID {:08X} in FILESCAN stage does not match GRFID {:08X} in INIT/RESERVE/ACTIVATION stage", BSWAP32(_cur.grffile->grfid), BSWAP32(grfid));
7099 _cur.grffile->grfid = grfid;
7100 }
7101
7102 _cur.grffile->grf_version = version;
7103 _cur.grfconfig->status = _cur.stage < GLS_RESERVE ? GCS_INITIALISED : GCS_ACTIVATED;
7104
7105 /* Do swap the GRFID for displaying purposes since people expect that */
7106 Debug(grf, 1, "GRFInfo: Loaded GRFv{} set {:08X} - {} (palette: {}, version: {})", version, BSWAP32(grfid), StrMakeValid(name), (_cur.grfconfig->palette & GRFP_USE_MASK) ? "Windows" : "DOS", _cur.grfconfig->version);
7107}
7108
7115static bool IsGRMReservedSprite(SpriteID first_sprite, uint16_t num_sprites)
7116{
7117 for (const auto &grm_sprite : _grm_sprites) {
7118 if (grm_sprite.first.grfid != _cur.grffile->grfid) continue;
7119 if (grm_sprite.second.first <= first_sprite && grm_sprite.second.first + grm_sprite.second.second >= first_sprite + num_sprites) return true;
7120 }
7121 return false;
7122}
7123
7124/* Action 0x0A */
7125static void SpriteReplace(ByteReader &buf)
7126{
7127 /* <0A> <num-sets> <set1> [<set2> ...]
7128 * <set>: <num-sprites> <first-sprite>
7129 *
7130 * B num-sets How many sets of sprites to replace.
7131 * Each set:
7132 * B num-sprites How many sprites are in this set
7133 * W first-sprite First sprite number to replace */
7134
7135 uint8_t num_sets = buf.ReadByte();
7136
7137 for (uint i = 0; i < num_sets; i++) {
7138 uint8_t num_sprites = buf.ReadByte();
7139 uint16_t first_sprite = buf.ReadWord();
7140
7141 GrfMsg(2, "SpriteReplace: [Set {}] Changing {} sprites, beginning with {}",
7142 i, num_sprites, first_sprite
7143 );
7144
7145 if (first_sprite + num_sprites >= SPR_OPENTTD_BASE) {
7146 /* Outside allowed range, check for GRM sprite reservations. */
7147 if (!IsGRMReservedSprite(first_sprite, num_sprites)) {
7148 GrfMsg(0, "SpriteReplace: [Set {}] Changing {} sprites, beginning with {}, above limit of {} and not within reserved range, ignoring.",
7149 i, num_sprites, first_sprite, SPR_OPENTTD_BASE);
7150
7151 /* Load the sprites at the current location so they will do nothing instead of appearing to work. */
7152 first_sprite = _cur.spriteid;
7153 _cur.spriteid += num_sprites;
7154 }
7155 }
7156
7157 for (uint j = 0; j < num_sprites; j++) {
7158 SpriteID load_index = first_sprite + j;
7159 _cur.nfo_line++;
7160 LoadNextSprite(load_index, *_cur.file, _cur.nfo_line); // XXX
7161
7162 /* Shore sprites now located at different addresses.
7163 * So detect when the old ones get replaced. */
7164 if (IsInsideMM(load_index, SPR_ORIGINALSHORE_START, SPR_ORIGINALSHORE_END + 1)) {
7166 }
7167 }
7168 }
7169}
7170
7171/* Action 0x0A (SKIP) */
7172static void SkipActA(ByteReader &buf)
7173{
7174 uint8_t num_sets = buf.ReadByte();
7175
7176 for (uint i = 0; i < num_sets; i++) {
7177 /* Skip the sprites this replaces */
7178 _cur.skip_sprites += buf.ReadByte();
7179 /* But ignore where they go */
7180 buf.ReadWord();
7181 }
7182
7183 GrfMsg(3, "SkipActA: Skipping {} sprites", _cur.skip_sprites);
7184}
7185
7186/* Action 0x0B */
7187static void GRFLoadError(ByteReader &buf)
7188{
7189 /* <0B> <severity> <language-id> <message-id> [<message...> 00] [<data...>] 00 [<parnum>]
7190 *
7191 * B severity 00: notice, continue loading grf file
7192 * 01: warning, continue loading grf file
7193 * 02: error, but continue loading grf file, and attempt
7194 * loading grf again when loading or starting next game
7195 * 03: error, abort loading and prevent loading again in
7196 * the future (only when restarting the patch)
7197 * B language-id see action 4, use 1F for built-in error messages
7198 * B message-id message to show, see below
7199 * S message for custom messages (message-id FF), text of the message
7200 * not present for built-in messages.
7201 * V data additional data for built-in (or custom) messages
7202 * B parnum parameter numbers to be shown in the message (maximum of 2) */
7203
7204 static const StringID msgstr[] = {
7205 STR_NEWGRF_ERROR_VERSION_NUMBER,
7206 STR_NEWGRF_ERROR_DOS_OR_WINDOWS,
7207 STR_NEWGRF_ERROR_UNSET_SWITCH,
7208 STR_NEWGRF_ERROR_INVALID_PARAMETER,
7209 STR_NEWGRF_ERROR_LOAD_BEFORE,
7210 STR_NEWGRF_ERROR_LOAD_AFTER,
7211 STR_NEWGRF_ERROR_OTTD_VERSION_NUMBER,
7212 };
7213
7214 static const StringID sevstr[] = {
7215 STR_NEWGRF_ERROR_MSG_INFO,
7216 STR_NEWGRF_ERROR_MSG_WARNING,
7217 STR_NEWGRF_ERROR_MSG_ERROR,
7218 STR_NEWGRF_ERROR_MSG_FATAL
7219 };
7220
7221 uint8_t severity = buf.ReadByte();
7222 uint8_t lang = buf.ReadByte();
7223 uint8_t message_id = buf.ReadByte();
7224
7225 /* Skip the error if it isn't valid for the current language. */
7226 if (!CheckGrfLangID(lang, _cur.grffile->grf_version)) return;
7227
7228 /* Skip the error until the activation stage unless bit 7 of the severity
7229 * is set. */
7230 if (!HasBit(severity, 7) && _cur.stage == GLS_INIT) {
7231 GrfMsg(7, "GRFLoadError: Skipping non-fatal GRFLoadError in stage {}", _cur.stage);
7232 return;
7233 }
7234 ClrBit(severity, 7);
7235
7236 if (severity >= lengthof(sevstr)) {
7237 GrfMsg(7, "GRFLoadError: Invalid severity id {}. Setting to 2 (non-fatal error).", severity);
7238 severity = 2;
7239 } else if (severity == 3) {
7240 /* This is a fatal error, so make sure the GRF is deactivated and no
7241 * more of it gets loaded. */
7242 DisableGrf();
7243
7244 /* Make sure we show fatal errors, instead of silly infos from before */
7245 _cur.grfconfig->error.reset();
7246 }
7247
7248 if (message_id >= lengthof(msgstr) && message_id != 0xFF) {
7249 GrfMsg(7, "GRFLoadError: Invalid message id.");
7250 return;
7251 }
7252
7253 if (buf.Remaining() <= 1) {
7254 GrfMsg(7, "GRFLoadError: No message data supplied.");
7255 return;
7256 }
7257
7258 /* For now we can only show one message per newgrf file. */
7259 if (_cur.grfconfig->error.has_value()) return;
7260
7261 _cur.grfconfig->error = {sevstr[severity]};
7262 GRFError *error = &_cur.grfconfig->error.value();
7263
7264 if (message_id == 0xFF) {
7265 /* This is a custom error message. */
7266 if (buf.HasData()) {
7267 std::string_view message = buf.ReadString();
7268
7269 error->custom_message = TranslateTTDPatchCodes(_cur.grffile->grfid, lang, true, message, SCC_RAW_STRING_POINTER);
7270 } else {
7271 GrfMsg(7, "GRFLoadError: No custom message supplied.");
7272 error->custom_message.clear();
7273 }
7274 } else {
7275 error->message = msgstr[message_id];
7276 }
7277
7278 if (buf.HasData()) {
7279 std::string_view data = buf.ReadString();
7280
7281 error->data = TranslateTTDPatchCodes(_cur.grffile->grfid, lang, true, data);
7282 } else {
7283 GrfMsg(7, "GRFLoadError: No message data supplied.");
7284 error->data.clear();
7285 }
7286
7287 /* Only two parameter numbers can be used in the string. */
7288 for (uint i = 0; i < error->param_value.size() && buf.HasData(); i++) {
7289 uint param_number = buf.ReadByte();
7290 error->param_value[i] = _cur.grffile->GetParam(param_number);
7291 }
7292}
7293
7294/* Action 0x0C */
7295static void GRFComment(ByteReader &buf)
7296{
7297 /* <0C> [<ignored...>]
7298 *
7299 * V ignored Anything following the 0C is ignored */
7300
7301 if (!buf.HasData()) return;
7302
7303 std::string_view text = buf.ReadString();
7304 GrfMsg(2, "GRFComment: {}", StrMakeValid(text));
7305}
7306
7307/* Action 0x0D (GLS_SAFETYSCAN) */
7308static void SafeParamSet(ByteReader &buf)
7309{
7310 uint8_t target = buf.ReadByte();
7311
7312 /* Writing GRF parameters and some bits of 'misc GRF features' are safe. */
7313 if (target < 0x80 || target == 0x9E) return;
7314
7315 /* GRM could be unsafe, but as here it can only happen after other GRFs
7316 * are loaded, it should be okay. If the GRF tried to use the slots it
7317 * reserved, it would be marked unsafe anyway. GRM for (e.g. bridge)
7318 * sprites is considered safe. */
7319
7321
7322 /* Skip remainder of GRF */
7323 _cur.skip_sprites = -1;
7324}
7325
7326
7327static uint32_t GetPatchVariable(uint8_t param)
7328{
7329 switch (param) {
7330 /* start year - 1920 */
7332
7333 /* freight trains weight factor */
7334 case 0x0E: return _settings_game.vehicle.freight_trains;
7335
7336 /* empty wagon speed increase */
7337 case 0x0F: return 0;
7338
7339 /* plane speed factor; our patch option is reversed from TTDPatch's,
7340 * the following is good for 1x, 2x and 4x (most common?) and...
7341 * well not really for 3x. */
7342 case 0x10:
7344 default:
7345 case 4: return 1;
7346 case 3: return 2;
7347 case 2: return 2;
7348 case 1: return 4;
7349 }
7350
7351
7352 /* 2CC colourmap base sprite */
7353 case 0x11: return SPR_2CCMAP_BASE;
7354
7355 /* map size: format = -MABXYSS
7356 * M : the type of map
7357 * bit 0 : set : squared map. Bit 1 is now not relevant
7358 * clear : rectangle map. Bit 1 will indicate the bigger edge of the map
7359 * bit 1 : set : Y is the bigger edge. Bit 0 is clear
7360 * clear : X is the bigger edge.
7361 * A : minimum edge(log2) of the map
7362 * B : maximum edge(log2) of the map
7363 * XY : edges(log2) of each side of the map.
7364 * SS : combination of both X and Y, thus giving the size(log2) of the map
7365 */
7366 case 0x13: {
7367 uint8_t map_bits = 0;
7368 uint8_t log_X = Map::LogX() - 6; // subtraction is required to make the minimal size (64) zero based
7369 uint8_t log_Y = Map::LogY() - 6;
7370 uint8_t max_edge = std::max(log_X, log_Y);
7371
7372 if (log_X == log_Y) { // we have a squared map, since both edges are identical
7373 SetBit(map_bits, 0);
7374 } else {
7375 if (max_edge == log_Y) SetBit(map_bits, 1); // edge Y been the biggest, mark it
7376 }
7377
7378 return (map_bits << 24) | (std::min(log_X, log_Y) << 20) | (max_edge << 16) |
7379 (log_X << 12) | (log_Y << 8) | (log_X + log_Y);
7380 }
7381
7382 /* The maximum height of the map. */
7383 case 0x14:
7385
7386 /* Extra foundations base sprite */
7387 case 0x15:
7388 return SPR_SLOPES_BASE;
7389
7390 /* Shore base sprite */
7391 case 0x16:
7392 return SPR_SHORE_BASE;
7393
7394 /* Game map seed */
7395 case 0x17:
7397
7398 default:
7399 GrfMsg(2, "ParamSet: Unknown Patch variable 0x{:02X}.", param);
7400 return 0;
7401 }
7402}
7403
7404
7405static uint32_t PerformGRM(uint32_t *grm, uint16_t num_ids, uint16_t count, uint8_t op, uint8_t target, const char *type)
7406{
7407 uint start = 0;
7408 uint size = 0;
7409
7410 if (op == 6) {
7411 /* Return GRFID of set that reserved ID */
7412 return grm[_cur.grffile->GetParam(target)];
7413 }
7414
7415 /* With an operation of 2 or 3, we want to reserve a specific block of IDs */
7416 if (op == 2 || op == 3) start = _cur.grffile->GetParam(target);
7417
7418 for (uint i = start; i < num_ids; i++) {
7419 if (grm[i] == 0) {
7420 size++;
7421 } else {
7422 if (op == 2 || op == 3) break;
7423 start = i + 1;
7424 size = 0;
7425 }
7426
7427 if (size == count) break;
7428 }
7429
7430 if (size == count) {
7431 /* Got the slot... */
7432 if (op == 0 || op == 3) {
7433 GrfMsg(2, "ParamSet: GRM: Reserving {} {} at {}", count, type, start);
7434 for (uint i = 0; i < count; i++) grm[start + i] = _cur.grffile->grfid;
7435 }
7436 return start;
7437 }
7438
7439 /* Unable to allocate */
7440 if (op != 4 && op != 5) {
7441 /* Deactivate GRF */
7442 GrfMsg(0, "ParamSet: GRM: Unable to allocate {} {}, deactivating", count, type);
7443 DisableGrf(STR_NEWGRF_ERROR_GRM_FAILED);
7444 return UINT_MAX;
7445 }
7446
7447 GrfMsg(1, "ParamSet: GRM: Unable to allocate {} {}", count, type);
7448 return UINT_MAX;
7449}
7450
7451
7453static void ParamSet(ByteReader &buf)
7454{
7455 /* <0D> <target> <operation> <source1> <source2> [<data>]
7456 *
7457 * B target parameter number where result is stored
7458 * B operation operation to perform, see below
7459 * B source1 first source operand
7460 * B source2 second source operand
7461 * D data data to use in the calculation, not necessary
7462 * if both source1 and source2 refer to actual parameters
7463 *
7464 * Operations
7465 * 00 Set parameter equal to source1
7466 * 01 Addition, source1 + source2
7467 * 02 Subtraction, source1 - source2
7468 * 03 Unsigned multiplication, source1 * source2 (both unsigned)
7469 * 04 Signed multiplication, source1 * source2 (both signed)
7470 * 05 Unsigned bit shift, source1 by source2 (source2 taken to be a
7471 * signed quantity; left shift if positive and right shift if
7472 * negative, source1 is unsigned)
7473 * 06 Signed bit shift, source1 by source2
7474 * (source2 like in 05, and source1 as well)
7475 */
7476
7477 uint8_t target = buf.ReadByte();
7478 uint8_t oper = buf.ReadByte();
7479 uint32_t src1 = buf.ReadByte();
7480 uint32_t src2 = buf.ReadByte();
7481
7482 uint32_t data = 0;
7483 if (buf.Remaining() >= 4) data = buf.ReadDWord();
7484
7485 /* You can add 80 to the operation to make it apply only if the target
7486 * is not defined yet. In this respect, a parameter is taken to be
7487 * defined if any of the following applies:
7488 * - it has been set to any value in the newgrf(w).cfg parameter list
7489 * - it OR A PARAMETER WITH HIGHER NUMBER has been set to any value by
7490 * an earlier action D */
7491 if (HasBit(oper, 7)) {
7492 if (target < 0x80 && target < std::size(_cur.grffile->param)) {
7493 GrfMsg(7, "ParamSet: Param {} already defined, skipping", target);
7494 return;
7495 }
7496
7497 oper = GB(oper, 0, 7);
7498 }
7499
7500 if (src2 == 0xFE) {
7501 if (GB(data, 0, 8) == 0xFF) {
7502 if (data == 0x0000FFFF) {
7503 /* Patch variables */
7504 src1 = GetPatchVariable(src1);
7505 } else {
7506 /* GRF Resource Management */
7507 uint8_t op = src1;
7508 uint8_t feature = GB(data, 8, 8);
7509 uint16_t count = GB(data, 16, 16);
7510
7511 if (_cur.stage == GLS_RESERVE) {
7512 if (feature == 0x08) {
7513 /* General sprites */
7514 if (op == 0) {
7515 /* Check if the allocated sprites will fit below the original sprite limit */
7516 if (_cur.spriteid + count >= 16384) {
7517 GrfMsg(0, "ParamSet: GRM: Unable to allocate {} sprites; try changing NewGRF order", count);
7518 DisableGrf(STR_NEWGRF_ERROR_GRM_FAILED);
7519 return;
7520 }
7521
7522 /* Reserve space at the current sprite ID */
7523 GrfMsg(4, "ParamSet: GRM: Allocated {} sprites at {}", count, _cur.spriteid);
7524 _grm_sprites[GRFLocation(_cur.grffile->grfid, _cur.nfo_line)] = std::make_pair(_cur.spriteid, count);
7525 _cur.spriteid += count;
7526 }
7527 }
7528 /* Ignore GRM result during reservation */
7529 src1 = 0;
7530 } else if (_cur.stage == GLS_ACTIVATION) {
7531 switch (feature) {
7532 case 0x00: // Trains
7533 case 0x01: // Road Vehicles
7534 case 0x02: // Ships
7535 case 0x03: // Aircraft
7537 src1 = PerformGRM(&_grm_engines[_engine_offsets[feature]], _engine_counts[feature], count, op, target, "vehicles");
7538 if (_cur.skip_sprites == -1) return;
7539 } else {
7540 /* GRM does not apply for dynamic engine allocation. */
7541 switch (op) {
7542 case 2:
7543 case 3:
7544 src1 = _cur.grffile->GetParam(target);
7545 break;
7546
7547 default:
7548 src1 = 0;
7549 break;
7550 }
7551 }
7552 break;
7553
7554 case 0x08: // General sprites
7555 switch (op) {
7556 case 0:
7557 /* Return space reserved during reservation stage */
7558 src1 = _grm_sprites[GRFLocation(_cur.grffile->grfid, _cur.nfo_line)].first;
7559 GrfMsg(4, "ParamSet: GRM: Using pre-allocated sprites at {}", src1);
7560 break;
7561
7562 case 1:
7563 src1 = _cur.spriteid;
7564 break;
7565
7566 default:
7567 GrfMsg(1, "ParamSet: GRM: Unsupported operation {} for general sprites", op);
7568 return;
7569 }
7570 break;
7571
7572 case 0x0B: // Cargo
7573 /* There are two ranges: one for cargo IDs and one for cargo bitmasks */
7574 src1 = PerformGRM(_grm_cargoes, NUM_CARGO * 2, count, op, target, "cargoes");
7575 if (_cur.skip_sprites == -1) return;
7576 break;
7577
7578 default: GrfMsg(1, "ParamSet: GRM: Unsupported feature 0x{:X}", feature); return;
7579 }
7580 } else {
7581 /* Ignore GRM during initialization */
7582 src1 = 0;
7583 }
7584 }
7585 } else {
7586 /* Read another GRF File's parameter */
7587 const GRFFile *file = GetFileByGRFID(data);
7588 GRFConfig *c = GetGRFConfig(data);
7589 if (c != nullptr && HasBit(c->flags, GCF_STATIC) && !HasBit(_cur.grfconfig->flags, GCF_STATIC) && _networking) {
7590 /* Disable the read GRF if it is a static NewGRF. */
7592 src1 = 0;
7593 } else if (file == nullptr || c == nullptr || c->status == GCS_DISABLED) {
7594 src1 = 0;
7595 } else if (src1 == 0xFE) {
7596 src1 = c->version;
7597 } else {
7598 src1 = file->GetParam(src1);
7599 }
7600 }
7601 } else {
7602 /* The source1 and source2 operands refer to the grf parameter number
7603 * like in action 6 and 7. In addition, they can refer to the special
7604 * variables available in action 7, or they can be FF to use the value
7605 * of <data>. If referring to parameters that are undefined, a value
7606 * of 0 is used instead. */
7607 src1 = (src1 == 0xFF) ? data : GetParamVal(src1, nullptr);
7608 src2 = (src2 == 0xFF) ? data : GetParamVal(src2, nullptr);
7609 }
7610
7611 uint32_t res;
7612 switch (oper) {
7613 case 0x00:
7614 res = src1;
7615 break;
7616
7617 case 0x01:
7618 res = src1 + src2;
7619 break;
7620
7621 case 0x02:
7622 res = src1 - src2;
7623 break;
7624
7625 case 0x03:
7626 res = src1 * src2;
7627 break;
7628
7629 case 0x04:
7630 res = (int32_t)src1 * (int32_t)src2;
7631 break;
7632
7633 case 0x05:
7634 if ((int32_t)src2 < 0) {
7635 res = src1 >> -(int32_t)src2;
7636 } else {
7637 res = src1 << (src2 & 0x1F); // Same behaviour as in EvalAdjustT, mask 'value' to 5 bits, which should behave the same on all architectures.
7638 }
7639 break;
7640
7641 case 0x06:
7642 if ((int32_t)src2 < 0) {
7643 res = (int32_t)src1 >> -(int32_t)src2;
7644 } else {
7645 res = (int32_t)src1 << (src2 & 0x1F); // Same behaviour as in EvalAdjustT, mask 'value' to 5 bits, which should behave the same on all architectures.
7646 }
7647 break;
7648
7649 case 0x07: // Bitwise AND
7650 res = src1 & src2;
7651 break;
7652
7653 case 0x08: // Bitwise OR
7654 res = src1 | src2;
7655 break;
7656
7657 case 0x09: // Unsigned division
7658 if (src2 == 0) {
7659 res = src1;
7660 } else {
7661 res = src1 / src2;
7662 }
7663 break;
7664
7665 case 0x0A: // Signed division
7666 if (src2 == 0) {
7667 res = src1;
7668 } else {
7669 res = (int32_t)src1 / (int32_t)src2;
7670 }
7671 break;
7672
7673 case 0x0B: // Unsigned modulo
7674 if (src2 == 0) {
7675 res = src1;
7676 } else {
7677 res = src1 % src2;
7678 }
7679 break;
7680
7681 case 0x0C: // Signed modulo
7682 if (src2 == 0) {
7683 res = src1;
7684 } else {
7685 res = (int32_t)src1 % (int32_t)src2;
7686 }
7687 break;
7688
7689 default: GrfMsg(0, "ParamSet: Unknown operation {}, skipping", oper); return;
7690 }
7691
7692 switch (target) {
7693 case 0x8E: // Y-Offset for train sprites
7694 _cur.grffile->traininfo_vehicle_pitch = res;
7695 break;
7696
7697 case 0x8F: { // Rail track type cost factors
7698 extern RailTypeInfo _railtypes[RAILTYPE_END];
7699 _railtypes[RAILTYPE_RAIL].cost_multiplier = GB(res, 0, 8);
7701 _railtypes[RAILTYPE_ELECTRIC].cost_multiplier = GB(res, 0, 8);
7702 _railtypes[RAILTYPE_MONO].cost_multiplier = GB(res, 8, 8);
7703 } else {
7704 _railtypes[RAILTYPE_ELECTRIC].cost_multiplier = GB(res, 8, 8);
7705 _railtypes[RAILTYPE_MONO].cost_multiplier = GB(res, 16, 8);
7706 }
7707 _railtypes[RAILTYPE_MAGLEV].cost_multiplier = GB(res, 16, 8);
7708 break;
7709 }
7710
7711 /* not implemented */
7712 case 0x93: // Tile refresh offset to left -- Intended to allow support for larger sprites, not necessary for OTTD
7713 case 0x94: // Tile refresh offset to right
7714 case 0x95: // Tile refresh offset upwards
7715 case 0x96: // Tile refresh offset downwards
7716 case 0x97: // Snow line height -- Better supported by feature 8 property 10h (snow line table) TODO: implement by filling the entire snow line table with the given value
7717 case 0x99: // Global ID offset -- Not necessary since IDs are remapped automatically
7718 GrfMsg(7, "ParamSet: Skipping unimplemented target 0x{:02X}", target);
7719 break;
7720
7721 case 0x9E: // Miscellaneous GRF features
7722 /* Set train list engine width */
7723 _cur.grffile->traininfo_vehicle_width = HasBit(res, GMB_TRAIN_WIDTH_32_PIXELS) ? VEHICLEINFO_FULL_VEHICLE_WIDTH : TRAININFO_DEFAULT_VEHICLE_WIDTH;
7724 /* Remove the local flags from the global flags */
7726
7727 /* Only copy safe bits for static grfs */
7728 if (HasBit(_cur.grfconfig->flags, GCF_STATIC)) {
7729 uint32_t safe_bits = 0;
7730 SetBit(safe_bits, GMB_SECOND_ROCKY_TILE_SET);
7731
7732 _misc_grf_features = (_misc_grf_features & ~safe_bits) | (res & safe_bits);
7733 } else {
7734 _misc_grf_features = res;
7735 }
7736 break;
7737
7738 case 0x9F: // locale-dependent settings
7739 GrfMsg(7, "ParamSet: Skipping unimplemented target 0x{:02X}", target);
7740 break;
7741
7742 default:
7743 if (target < 0x80) {
7744 /* Resize (and fill with zeroes) if needed. */
7745 if (target >= std::size(_cur.grffile->param)) _cur.grffile->param.resize(target + 1);
7746 _cur.grffile->param[target] = res;
7747 } else {
7748 GrfMsg(7, "ParamSet: Skipping unknown target 0x{:02X}", target);
7749 }
7750 break;
7751 }
7752}
7753
7754/* Action 0x0E (GLS_SAFETYSCAN) */
7755static void SafeGRFInhibit(ByteReader &buf)
7756{
7757 /* <0E> <num> <grfids...>
7758 *
7759 * B num Number of GRFIDs that follow
7760 * D grfids GRFIDs of the files to deactivate */
7761
7762 uint8_t num = buf.ReadByte();
7763
7764 for (uint i = 0; i < num; i++) {
7765 uint32_t grfid = buf.ReadDWord();
7766
7767 /* GRF is unsafe it if tries to deactivate other GRFs */
7768 if (grfid != _cur.grfconfig->ident.grfid) {
7770
7771 /* Skip remainder of GRF */
7772 _cur.skip_sprites = -1;
7773
7774 return;
7775 }
7776 }
7777}
7778
7779/* Action 0x0E */
7780static void GRFInhibit(ByteReader &buf)
7781{
7782 /* <0E> <num> <grfids...>
7783 *
7784 * B num Number of GRFIDs that follow
7785 * D grfids GRFIDs of the files to deactivate */
7786
7787 uint8_t num = buf.ReadByte();
7788
7789 for (uint i = 0; i < num; i++) {
7790 uint32_t grfid = buf.ReadDWord();
7791 GRFConfig *file = GetGRFConfig(grfid);
7792
7793 /* Unset activation flag */
7794 if (file != nullptr && file != _cur.grfconfig) {
7795 GrfMsg(2, "GRFInhibit: Deactivating file '{}'", file->filename);
7796 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_FORCEFULLY_DISABLED, file);
7797 error->data = _cur.grfconfig->GetName();
7798 }
7799 }
7800}
7801
7804{
7805 /* <0F> <id> <style-name> <num-parts> <parts>
7806 *
7807 * B id ID of this definition in bottom 7 bits (final definition if bit 7 set)
7808 * V style-name Name of the style (only for final definition)
7809 * B num-parts Number of parts in this definition
7810 * V parts The parts */
7811
7812 uint32_t grfid = _cur.grffile->grfid;
7813
7814 GRFTownName *townname = AddGRFTownName(grfid);
7815
7816 uint8_t id = buf.ReadByte();
7817 GrfMsg(6, "FeatureTownName: definition 0x{:02X}", id & 0x7F);
7818
7819 if (HasBit(id, 7)) {
7820 /* Final definition */
7821 ClrBit(id, 7);
7822 bool new_scheme = _cur.grffile->grf_version >= 7;
7823
7824 uint8_t lang = buf.ReadByte();
7825 StringID style = STR_UNDEFINED;
7826
7827 do {
7828 ClrBit(lang, 7);
7829
7830 std::string_view name = buf.ReadString();
7831
7832 std::string lang_name = TranslateTTDPatchCodes(grfid, lang, false, name);
7833 GrfMsg(6, "FeatureTownName: lang 0x{:X} -> '{}'", lang, lang_name);
7834
7835 style = AddGRFString(grfid, id, lang, new_scheme, false, name, STR_UNDEFINED);
7836
7837 lang = buf.ReadByte();
7838 } while (lang != 0);
7839 townname->styles.emplace_back(style, id);
7840 }
7841
7842 uint8_t parts = buf.ReadByte();
7843 GrfMsg(6, "FeatureTownName: {} parts", parts);
7844
7845 townname->partlists[id].reserve(parts);
7846 for (uint partnum = 0; partnum < parts; partnum++) {
7847 NamePartList &partlist = townname->partlists[id].emplace_back();
7848 uint8_t texts = buf.ReadByte();
7849 partlist.bitstart = buf.ReadByte();
7850 partlist.bitcount = buf.ReadByte();
7851 partlist.maxprob = 0;
7852 GrfMsg(6, "FeatureTownName: part {} contains {} texts and will use GB(seed, {}, {})", partnum, texts, partlist.bitstart, partlist.bitcount);
7853
7854 partlist.parts.reserve(texts);
7855 for (uint textnum = 0; textnum < texts; textnum++) {
7856 NamePart &part = partlist.parts.emplace_back();
7857 part.prob = buf.ReadByte();
7858
7859 if (HasBit(part.prob, 7)) {
7860 uint8_t ref_id = buf.ReadByte();
7861 if (ref_id >= GRFTownName::MAX_LISTS || townname->partlists[ref_id].empty()) {
7862 GrfMsg(0, "FeatureTownName: definition 0x{:02X} doesn't exist, deactivating", ref_id);
7863 DelGRFTownName(grfid);
7864 DisableGrf(STR_NEWGRF_ERROR_INVALID_ID);
7865 return;
7866 }
7867 part.id = ref_id;
7868 GrfMsg(6, "FeatureTownName: part {}, text {}, uses intermediate definition 0x{:02X} (with probability {})", partnum, textnum, ref_id, part.prob & 0x7F);
7869 } else {
7870 std::string_view text = buf.ReadString();
7871 part.text = TranslateTTDPatchCodes(grfid, 0, false, text);
7872 GrfMsg(6, "FeatureTownName: part {}, text {}, '{}' (with probability {})", partnum, textnum, part.text, part.prob);
7873 }
7874 partlist.maxprob += GB(part.prob, 0, 7);
7875 }
7876 GrfMsg(6, "FeatureTownName: part {}, total probability {}", partnum, partlist.maxprob);
7877 }
7878}
7879
7882{
7883 /* <10> <label> [<comment>]
7884 *
7885 * B label The label to define
7886 * V comment Optional comment - ignored */
7887
7888 uint8_t nfo_label = buf.ReadByte();
7889
7890 _cur.grffile->labels.emplace_back(nfo_label, _cur.nfo_line, _cur.file->GetPos());
7891
7892 GrfMsg(2, "DefineGotoLabel: GOTO target with label 0x{:02X}", nfo_label);
7893}
7894
7899static void ImportGRFSound(SoundEntry *sound)
7900{
7901 const GRFFile *file;
7902 uint32_t grfid = _cur.file->ReadDword();
7903 SoundID sound_id = _cur.file->ReadWord();
7904
7905 file = GetFileByGRFID(grfid);
7906 if (file == nullptr || file->sound_offset == 0) {
7907 GrfMsg(1, "ImportGRFSound: Source file not available");
7908 return;
7909 }
7910
7911 if (sound_id >= file->num_sounds) {
7912 GrfMsg(1, "ImportGRFSound: Sound effect {} is invalid", sound_id);
7913 return;
7914 }
7915
7916 GrfMsg(2, "ImportGRFSound: Copying sound {} ({}) from file {:x}", sound_id, file->sound_offset + sound_id, grfid);
7917
7918 *sound = *GetSound(file->sound_offset + sound_id);
7919
7920 /* Reset volume and priority, which TTDPatch doesn't copy */
7921 sound->volume = SOUND_EFFECT_MAX_VOLUME;
7922 sound->priority = 0;
7923}
7924
7930static void LoadGRFSound(size_t offs, SoundEntry *sound)
7931{
7932 /* Set default volume and priority */
7933 sound->volume = SOUND_EFFECT_MAX_VOLUME;
7934 sound->priority = 0;
7935
7936 if (offs != SIZE_MAX) {
7937 /* Sound is present in the NewGRF. */
7938 sound->file = _cur.file;
7939 sound->file_offset = offs;
7940 sound->source = SoundSource::NewGRF;
7942 }
7943}
7944
7945/* Action 0x11 */
7946static void GRFSound(ByteReader &buf)
7947{
7948 /* <11> <num>
7949 *
7950 * W num Number of sound files that follow */
7951
7952 uint16_t num = buf.ReadWord();
7953 if (num == 0) return;
7954
7955 SoundEntry *sound;
7956 if (_cur.grffile->sound_offset == 0) {
7957 _cur.grffile->sound_offset = GetNumSounds();
7958 _cur.grffile->num_sounds = num;
7959 sound = AllocateSound(num);
7960 } else {
7961 sound = GetSound(_cur.grffile->sound_offset);
7962 }
7963
7964 SpriteFile &file = *_cur.file;
7965 uint8_t grf_container_version = file.GetContainerVersion();
7966 for (int i = 0; i < num; i++) {
7967 _cur.nfo_line++;
7968
7969 /* Check whether the index is in range. This might happen if multiple action 11 are present.
7970 * While this is invalid, we do not check for this. But we should prevent it from causing bigger trouble */
7971 bool invalid = i >= _cur.grffile->num_sounds;
7972
7973 size_t offs = file.GetPos();
7974
7975 uint32_t len = grf_container_version >= 2 ? file.ReadDword() : file.ReadWord();
7976 uint8_t type = file.ReadByte();
7977
7978 if (grf_container_version >= 2 && type == 0xFD) {
7979 /* Reference to sprite section. */
7980 if (invalid) {
7981 GrfMsg(1, "GRFSound: Sound index out of range (multiple Action 11?)");
7982 file.SkipBytes(len);
7983 } else if (len != 4) {
7984 GrfMsg(1, "GRFSound: Invalid sprite section import");
7985 file.SkipBytes(len);
7986 } else {
7987 uint32_t id = file.ReadDword();
7988 if (_cur.stage == GLS_INIT) LoadGRFSound(GetGRFSpriteOffset(id), sound + i);
7989 }
7990 continue;
7991 }
7992
7993 if (type != 0xFF) {
7994 GrfMsg(1, "GRFSound: Unexpected RealSprite found, skipping");
7995 file.SkipBytes(7);
7996 SkipSpriteData(*_cur.file, type, len - 8);
7997 continue;
7998 }
7999
8000 if (invalid) {
8001 GrfMsg(1, "GRFSound: Sound index out of range (multiple Action 11?)");
8002 file.SkipBytes(len);
8003 }
8004
8005 uint8_t action = file.ReadByte();
8006 switch (action) {
8007 case 0xFF:
8008 /* Allocate sound only in init stage. */
8009 if (_cur.stage == GLS_INIT) {
8010 if (grf_container_version >= 2) {
8011 GrfMsg(1, "GRFSound: Inline sounds are not supported for container version >= 2");
8012 } else {
8013 LoadGRFSound(offs, sound + i);
8014 }
8015 }
8016 file.SkipBytes(len - 1); // already read <action>
8017 break;
8018
8019 case 0xFE:
8020 if (_cur.stage == GLS_ACTIVATION) {
8021 /* XXX 'Action 0xFE' isn't really specified. It is only mentioned for
8022 * importing sounds, so this is probably all wrong... */
8023 if (file.ReadByte() != 0) GrfMsg(1, "GRFSound: Import type mismatch");
8024 ImportGRFSound(sound + i);
8025 } else {
8026 file.SkipBytes(len - 1); // already read <action>
8027 }
8028 break;
8029
8030 default:
8031 GrfMsg(1, "GRFSound: Unexpected Action {:x} found, skipping", action);
8032 file.SkipBytes(len - 1); // already read <action>
8033 break;
8034 }
8035 }
8036}
8037
8038/* Action 0x11 (SKIP) */
8039static void SkipAct11(ByteReader &buf)
8040{
8041 /* <11> <num>
8042 *
8043 * W num Number of sound files that follow */
8044
8045 _cur.skip_sprites = buf.ReadWord();
8046
8047 GrfMsg(3, "SkipAct11: Skipping {} sprites", _cur.skip_sprites);
8048}
8049
8051static void LoadFontGlyph(ByteReader &buf)
8052{
8053 /* <12> <num_def> <font_size> <num_char> <base_char>
8054 *
8055 * B num_def Number of definitions
8056 * B font_size Size of font (0 = normal, 1 = small, 2 = large, 3 = mono)
8057 * B num_char Number of consecutive glyphs
8058 * W base_char First character index */
8059
8060 uint8_t num_def = buf.ReadByte();
8061
8062 for (uint i = 0; i < num_def; i++) {
8063 FontSize size = (FontSize)buf.ReadByte();
8064 uint8_t num_char = buf.ReadByte();
8065 uint16_t base_char = buf.ReadWord();
8066
8067 if (size >= FS_END) {
8068 GrfMsg(1, "LoadFontGlyph: Size {} is not supported, ignoring", size);
8069 }
8070
8071 GrfMsg(7, "LoadFontGlyph: Loading {} glyph(s) at 0x{:04X} for size {}", num_char, base_char, size);
8072
8073 for (uint c = 0; c < num_char; c++) {
8074 if (size < FS_END) SetUnicodeGlyph(size, base_char + c, _cur.spriteid);
8075 _cur.nfo_line++;
8076 LoadNextSprite(_cur.spriteid++, *_cur.file, _cur.nfo_line);
8077 }
8078 }
8079}
8080
8082static void SkipAct12(ByteReader &buf)
8083{
8084 /* <12> <num_def> <font_size> <num_char> <base_char>
8085 *
8086 * B num_def Number of definitions
8087 * B font_size Size of font (0 = normal, 1 = small, 2 = large)
8088 * B num_char Number of consecutive glyphs
8089 * W base_char First character index */
8090
8091 uint8_t num_def = buf.ReadByte();
8092
8093 for (uint i = 0; i < num_def; i++) {
8094 /* Ignore 'size' byte */
8095 buf.ReadByte();
8096
8097 /* Sum up number of characters */
8098 _cur.skip_sprites += buf.ReadByte();
8099
8100 /* Ignore 'base_char' word */
8101 buf.ReadWord();
8102 }
8103
8104 GrfMsg(3, "SkipAct12: Skipping {} sprites", _cur.skip_sprites);
8105}
8106
8109{
8110 /* <13> <grfid> <num-ent> <offset> <text...>
8111 *
8112 * 4*B grfid The GRFID of the file whose texts are to be translated
8113 * B num-ent Number of strings
8114 * W offset First text ID
8115 * S text... Zero-terminated strings */
8116
8117 uint32_t grfid = buf.ReadDWord();
8118 const GRFConfig *c = GetGRFConfig(grfid);
8119 if (c == nullptr || (c->status != GCS_INITIALISED && c->status != GCS_ACTIVATED)) {
8120 GrfMsg(7, "TranslateGRFStrings: GRFID 0x{:08X} unknown, skipping action 13", BSWAP32(grfid));
8121 return;
8122 }
8123
8124 if (c->status == GCS_INITIALISED) {
8125 /* If the file is not active but will be activated later, give an error
8126 * and disable this file. */
8127 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LOAD_AFTER);
8128
8129 error->data = GetString(STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE);
8130
8131 return;
8132 }
8133
8134 /* Since no language id is supplied for with version 7 and lower NewGRFs, this string has
8135 * to be added as a generic string, thus the language id of 0x7F. For this to work
8136 * new_scheme has to be true as well, which will also be implicitly the case for version 8
8137 * and higher. A language id of 0x7F will be overridden by a non-generic id, so this will
8138 * not change anything if a string has been provided specifically for this language. */
8139 uint8_t language = _cur.grffile->grf_version >= 8 ? buf.ReadByte() : 0x7F;
8140 uint8_t num_strings = buf.ReadByte();
8141 uint16_t first_id = buf.ReadWord();
8142
8143 if (!((first_id >= 0xD000 && first_id + num_strings <= 0xD400) || (first_id >= 0xD800 && first_id + num_strings <= 0xE000))) {
8144 GrfMsg(7, "TranslateGRFStrings: Attempting to set out-of-range string IDs in action 13 (first: 0x{:04X}, number: 0x{:02X})", first_id, num_strings);
8145 return;
8146 }
8147
8148 for (uint i = 0; i < num_strings && buf.HasData(); i++) {
8149 std::string_view string = buf.ReadString();
8150
8151 if (string.empty()) {
8152 GrfMsg(7, "TranslateGRFString: Ignoring empty string.");
8153 continue;
8154 }
8155
8156 AddGRFString(grfid, first_id + i, language, true, true, string, STR_UNDEFINED);
8157 }
8158}
8159
8161static bool ChangeGRFName(uint8_t langid, std::string_view str)
8162{
8163 AddGRFTextToList(_cur.grfconfig->name, langid, _cur.grfconfig->ident.grfid, false, str);
8164 return true;
8165}
8166
8168static bool ChangeGRFDescription(uint8_t langid, std::string_view str)
8169{
8170 AddGRFTextToList(_cur.grfconfig->info, langid, _cur.grfconfig->ident.grfid, true, str);
8171 return true;
8172}
8173
8175static bool ChangeGRFURL(uint8_t langid, std::string_view str)
8176{
8177 AddGRFTextToList(_cur.grfconfig->url, langid, _cur.grfconfig->ident.grfid, false, str);
8178 return true;
8179}
8180
8182static bool ChangeGRFNumUsedParams(size_t len, ByteReader &buf)
8183{
8184 if (len != 1) {
8185 GrfMsg(2, "StaticGRFInfo: expected only 1 byte for 'INFO'->'NPAR' but got {}, ignoring this field", len);
8186 buf.Skip(len);
8187 } else {
8188 _cur.grfconfig->num_valid_params = std::min(buf.ReadByte(), GRFConfig::MAX_NUM_PARAMS);
8189 }
8190 return true;
8191}
8192
8194static bool ChangeGRFPalette(size_t len, ByteReader &buf)
8195{
8196 if (len != 1) {
8197 GrfMsg(2, "StaticGRFInfo: expected only 1 byte for 'INFO'->'PALS' but got {}, ignoring this field", len);
8198 buf.Skip(len);
8199 } else {
8200 char data = buf.ReadByte();
8202 switch (data) {
8203 case '*':
8204 case 'A': pal = GRFP_GRF_ANY; break;
8205 case 'W': pal = GRFP_GRF_WINDOWS; break;
8206 case 'D': pal = GRFP_GRF_DOS; break;
8207 default:
8208 GrfMsg(2, "StaticGRFInfo: unexpected value '{:02X}' for 'INFO'->'PALS', ignoring this field", data);
8209 break;
8210 }
8211 if (pal != GRFP_GRF_UNSET) {
8212 _cur.grfconfig->palette &= ~GRFP_GRF_MASK;
8213 _cur.grfconfig->palette |= pal;
8214 }
8215 }
8216 return true;
8217}
8218
8220static bool ChangeGRFBlitter(size_t len, ByteReader &buf)
8221{
8222 if (len != 1) {
8223 GrfMsg(2, "StaticGRFInfo: expected only 1 byte for 'INFO'->'BLTR' but got {}, ignoring this field", len);
8224 buf.Skip(len);
8225 } else {
8226 char data = buf.ReadByte();
8228 switch (data) {
8229 case '8': pal = GRFP_BLT_UNSET; break;
8230 case '3': pal = GRFP_BLT_32BPP; break;
8231 default:
8232 GrfMsg(2, "StaticGRFInfo: unexpected value '{:02X}' for 'INFO'->'BLTR', ignoring this field", data);
8233 return true;
8234 }
8235 _cur.grfconfig->palette &= ~GRFP_BLT_MASK;
8236 _cur.grfconfig->palette |= pal;
8237 }
8238 return true;
8239}
8240
8242static bool ChangeGRFVersion(size_t len, ByteReader &buf)
8243{
8244 if (len != 4) {
8245 GrfMsg(2, "StaticGRFInfo: expected 4 bytes for 'INFO'->'VRSN' but got {}, ignoring this field", len);
8246 buf.Skip(len);
8247 } else {
8248 /* Set min_loadable_version as well (default to minimal compatibility) */
8249 _cur.grfconfig->version = _cur.grfconfig->min_loadable_version = buf.ReadDWord();
8250 }
8251 return true;
8252}
8253
8255static bool ChangeGRFMinVersion(size_t len, ByteReader &buf)
8256{
8257 if (len != 4) {
8258 GrfMsg(2, "StaticGRFInfo: expected 4 bytes for 'INFO'->'MINV' but got {}, ignoring this field", len);
8259 buf.Skip(len);
8260 } else {
8261 _cur.grfconfig->min_loadable_version = buf.ReadDWord();
8262 if (_cur.grfconfig->version == 0) {
8263 GrfMsg(2, "StaticGRFInfo: 'MINV' defined before 'VRSN' or 'VRSN' set to 0, ignoring this field");
8265 }
8266 if (_cur.grfconfig->version < _cur.grfconfig->min_loadable_version) {
8267 GrfMsg(2, "StaticGRFInfo: 'MINV' defined as {}, limiting it to 'VRSN'", _cur.grfconfig->min_loadable_version);
8269 }
8270 }
8271 return true;
8272}
8273
8275
8277static bool ChangeGRFParamName(uint8_t langid, std::string_view str)
8278{
8279 AddGRFTextToList(_cur_parameter->name, langid, _cur.grfconfig->ident.grfid, false, str);
8280 return true;
8281}
8282
8284static bool ChangeGRFParamDescription(uint8_t langid, std::string_view str)
8285{
8286 AddGRFTextToList(_cur_parameter->desc, langid, _cur.grfconfig->ident.grfid, true, str);
8287 return true;
8288}
8289
8291static bool ChangeGRFParamType(size_t len, ByteReader &buf)
8292{
8293 if (len != 1) {
8294 GrfMsg(2, "StaticGRFInfo: expected 1 byte for 'INFO'->'PARA'->'TYPE' but got {}, ignoring this field", len);
8295 buf.Skip(len);
8296 } else {
8297 GRFParameterType type = (GRFParameterType)buf.ReadByte();
8298 if (type < PTYPE_END) {
8299 _cur_parameter->type = type;
8300 } else {
8301 GrfMsg(3, "StaticGRFInfo: unknown parameter type {}, ignoring this field", type);
8302 }
8303 }
8304 return true;
8305}
8306
8308static bool ChangeGRFParamLimits(size_t len, ByteReader &buf)
8309{
8311 GrfMsg(2, "StaticGRFInfo: 'INFO'->'PARA'->'LIMI' is only valid for parameters with type uint/enum, ignoring this field");
8312 buf.Skip(len);
8313 } else if (len != 8) {
8314 GrfMsg(2, "StaticGRFInfo: expected 8 bytes for 'INFO'->'PARA'->'LIMI' but got {}, ignoring this field", len);
8315 buf.Skip(len);
8316 } else {
8317 uint32_t min_value = buf.ReadDWord();
8318 uint32_t max_value = buf.ReadDWord();
8319 if (min_value <= max_value) {
8320 _cur_parameter->min_value = min_value;
8321 _cur_parameter->max_value = max_value;
8322 } else {
8323 GrfMsg(2, "StaticGRFInfo: 'INFO'->'PARA'->'LIMI' values are incoherent, ignoring this field");
8324 }
8325 }
8326 return true;
8327}
8328
8330static bool ChangeGRFParamMask(size_t len, ByteReader &buf)
8331{
8332 if (len < 1 || len > 3) {
8333 GrfMsg(2, "StaticGRFInfo: expected 1 to 3 bytes for 'INFO'->'PARA'->'MASK' but got {}, ignoring this field", len);
8334 buf.Skip(len);
8335 } else {
8336 uint8_t param_nr = buf.ReadByte();
8337 if (param_nr >= GRFConfig::MAX_NUM_PARAMS) {
8338 GrfMsg(2, "StaticGRFInfo: invalid parameter number in 'INFO'->'PARA'->'MASK', param {}, ignoring this field", param_nr);
8339 buf.Skip(len - 1);
8340 } else {
8341 _cur_parameter->param_nr = param_nr;
8342 if (len >= 2) _cur_parameter->first_bit = std::min<uint8_t>(buf.ReadByte(), 31);
8343 if (len >= 3) _cur_parameter->num_bit = std::min<uint8_t>(buf.ReadByte(), 32 - _cur_parameter->first_bit);
8344 }
8345 }
8346
8347 return true;
8348}
8349
8351static bool ChangeGRFParamDefault(size_t len, ByteReader &buf)
8352{
8353 if (len != 4) {
8354 GrfMsg(2, "StaticGRFInfo: expected 4 bytes for 'INFO'->'PARA'->'DEFA' but got {}, ignoring this field", len);
8355 buf.Skip(len);
8356 } else {
8357 _cur_parameter->def_value = buf.ReadDWord();
8358 }
8359 _cur.grfconfig->has_param_defaults = true;
8360 return true;
8361}
8362
8363typedef bool (*DataHandler)(size_t, ByteReader &);
8364typedef bool (*TextHandler)(uint8_t, std::string_view str);
8365typedef bool (*BranchHandler)(ByteReader &);
8366
8377 id(0),
8378 type(0)
8379 {}
8380
8386 AllowedSubtags(uint32_t id, DataHandler handler) :
8387 id(id),
8388 type('B')
8389 {
8390 this->handler.data = handler;
8391 }
8392
8398 AllowedSubtags(uint32_t id, TextHandler handler) :
8399 id(id),
8400 type('T')
8401 {
8402 this->handler.text = handler;
8403 }
8404
8410 AllowedSubtags(uint32_t id, BranchHandler handler) :
8411 id(id),
8412 type('C')
8413 {
8414 this->handler.call_handler = true;
8415 this->handler.u.branch = handler;
8416 }
8417
8424 id(id),
8425 type('C')
8426 {
8427 this->handler.call_handler = false;
8428 this->handler.u.subtags = subtags;
8429 }
8430
8431 uint32_t id;
8432 uint8_t type;
8433 union {
8436 struct {
8437 union {
8440 } u;
8442 };
8443 } handler;
8444};
8445
8446static bool SkipUnknownInfo(ByteReader &buf, uint8_t type);
8447static bool HandleNodes(ByteReader &buf, AllowedSubtags *tags);
8448
8456{
8457 uint8_t type = buf.ReadByte();
8458 while (type != 0) {
8459 uint32_t id = buf.ReadDWord();
8460 if (type != 'T' || id > _cur_parameter->max_value) {
8461 GrfMsg(2, "StaticGRFInfo: all child nodes of 'INFO'->'PARA'->param_num->'VALU' should have type 't' and the value/bit number as id");
8462 if (!SkipUnknownInfo(buf, type)) return false;
8463 type = buf.ReadByte();
8464 continue;
8465 }
8466
8467 uint8_t langid = buf.ReadByte();
8468 std::string_view name_string = buf.ReadString();
8469
8470 auto val_name = _cur_parameter->value_names.find(id);
8471 if (val_name != _cur_parameter->value_names.end()) {
8472 AddGRFTextToList(val_name->second, langid, _cur.grfconfig->ident.grfid, false, name_string);
8473 } else {
8474 GRFTextList list;
8475 AddGRFTextToList(list, langid, _cur.grfconfig->ident.grfid, false, name_string);
8476 _cur_parameter->value_names[id] = list;
8477 }
8478
8479 type = buf.ReadByte();
8480 }
8481 return true;
8482}
8483
8495
8503{
8504 uint8_t type = buf.ReadByte();
8505 while (type != 0) {
8506 uint32_t id = buf.ReadDWord();
8507 if (type != 'C' || id >= _cur.grfconfig->num_valid_params) {
8508 GrfMsg(2, "StaticGRFInfo: all child nodes of 'INFO'->'PARA' should have type 'C' and their parameter number as id");
8509 if (!SkipUnknownInfo(buf, type)) return false;
8510 type = buf.ReadByte();
8511 continue;
8512 }
8513
8514 if (id >= _cur.grfconfig->param_info.size()) {
8515 _cur.grfconfig->param_info.resize(id + 1);
8516 }
8517 if (!_cur.grfconfig->param_info[id].has_value()) {
8518 _cur.grfconfig->param_info[id] = GRFParameterInfo(id);
8519 }
8520 _cur_parameter = &_cur.grfconfig->param_info[id].value();
8521 /* Read all parameter-data and process each node. */
8522 if (!HandleNodes(buf, _tags_parameters)) return false;
8523 type = buf.ReadByte();
8524 }
8525 return true;
8526}
8527
8541
8547
8548
8555static bool SkipUnknownInfo(ByteReader &buf, uint8_t type)
8556{
8557 /* type and id are already read */
8558 switch (type) {
8559 case 'C': {
8560 uint8_t new_type = buf.ReadByte();
8561 while (new_type != 0) {
8562 buf.ReadDWord(); // skip the id
8563 if (!SkipUnknownInfo(buf, new_type)) return false;
8564 new_type = buf.ReadByte();
8565 }
8566 break;
8567 }
8568
8569 case 'T':
8570 buf.ReadByte(); // lang
8571 buf.ReadString(); // actual text
8572 break;
8573
8574 case 'B': {
8575 uint16_t size = buf.ReadWord();
8576 buf.Skip(size);
8577 break;
8578 }
8579
8580 default:
8581 return false;
8582 }
8583
8584 return true;
8585}
8586
8595static bool HandleNode(uint8_t type, uint32_t id, ByteReader &buf, AllowedSubtags subtags[])
8596{
8597 uint i = 0;
8598 AllowedSubtags *tag;
8599 while ((tag = &subtags[i++])->type != 0) {
8600 if (tag->id != BSWAP32(id) || tag->type != type) continue;
8601 switch (type) {
8602 default: NOT_REACHED();
8603
8604 case 'T': {
8605 uint8_t langid = buf.ReadByte();
8606 return tag->handler.text(langid, buf.ReadString());
8607 }
8608
8609 case 'B': {
8610 size_t len = buf.ReadWord();
8611 if (buf.Remaining() < len) return false;
8612 return tag->handler.data(len, buf);
8613 }
8614
8615 case 'C': {
8616 if (tag->handler.call_handler) {
8617 return tag->handler.u.branch(buf);
8618 }
8619 return HandleNodes(buf, tag->handler.u.subtags);
8620 }
8621 }
8622 }
8623 GrfMsg(2, "StaticGRFInfo: unknown type/id combination found, type={:c}, id={:x}", type, id);
8624 return SkipUnknownInfo(buf, type);
8625}
8626
8633static bool HandleNodes(ByteReader &buf, AllowedSubtags subtags[])
8634{
8635 uint8_t type = buf.ReadByte();
8636 while (type != 0) {
8637 uint32_t id = buf.ReadDWord();
8638 if (!HandleNode(type, id, buf, subtags)) return false;
8639 type = buf.ReadByte();
8640 }
8641 return true;
8642}
8643
8648static void StaticGRFInfo(ByteReader &buf)
8649{
8650 /* <14> <type> <id> <text/data...> */
8651 HandleNodes(buf, _tags_root);
8652}
8653
8658static void GRFUnsafe(ByteReader &)
8659{
8661
8662 /* Skip remainder of GRF */
8663 _cur.skip_sprites = -1;
8664}
8665
8666
8669{
8670 _ttdpatch_flags[0] = ((_settings_game.station.never_expire_airports ? 1U : 0U) << 0x0C) // keepsmallairport
8671 | (1U << 0x0D) // newairports
8672 | (1U << 0x0E) // largestations
8673 | ((_settings_game.construction.max_bridge_length > 16 ? 1U : 0U) << 0x0F) // longbridges
8674 | (0U << 0x10) // loadtime
8675 | (1U << 0x12) // presignals
8676 | (1U << 0x13) // extpresignals
8677 | ((_settings_game.vehicle.never_expire_vehicles ? 1U : 0U) << 0x16) // enginespersist
8678 | (1U << 0x1B) // multihead
8679 | (1U << 0x1D) // lowmemory
8680 | (1U << 0x1E); // generalfixes
8681
8682 _ttdpatch_flags[1] = ((_settings_game.economy.station_noise_level ? 1U : 0U) << 0x07) // moreairports - based on units of noise
8683 | (1U << 0x08) // mammothtrains
8684 | (1U << 0x09) // trainrefit
8685 | (0U << 0x0B) // subsidiaries
8686 | ((_settings_game.order.gradual_loading ? 1U : 0U) << 0x0C) // gradualloading
8687 | (1U << 0x12) // unifiedmaglevmode - set bit 0 mode. Not revelant to OTTD
8688 | (1U << 0x13) // unifiedmaglevmode - set bit 1 mode
8689 | (1U << 0x14) // bridgespeedlimits
8690 | (1U << 0x16) // eternalgame
8691 | (1U << 0x17) // newtrains
8692 | (1U << 0x18) // newrvs
8693 | (1U << 0x19) // newships
8694 | (1U << 0x1A) // newplanes
8695 | ((_settings_game.construction.train_signal_side == 1 ? 1U : 0U) << 0x1B) // signalsontrafficside
8696 | ((_settings_game.vehicle.disable_elrails ? 0U : 1U) << 0x1C); // electrifiedrailway
8697
8698 _ttdpatch_flags[2] = (1U << 0x01) // loadallgraphics - obsolote
8699 | (1U << 0x03) // semaphores
8700 | (1U << 0x0A) // newobjects
8701 | (0U << 0x0B) // enhancedgui
8702 | (0U << 0x0C) // newagerating
8703 | ((_settings_game.construction.build_on_slopes ? 1U : 0U) << 0x0D) // buildonslopes
8704 | (1U << 0x0E) // fullloadany
8705 | (1U << 0x0F) // planespeed
8706 | (0U << 0x10) // moreindustriesperclimate - obsolete
8707 | (0U << 0x11) // moretoylandfeatures
8708 | (1U << 0x12) // newstations
8709 | (1U << 0x13) // tracktypecostdiff
8710 | (1U << 0x14) // manualconvert
8711 | ((_settings_game.construction.build_on_slopes ? 1U : 0U) << 0x15) // buildoncoasts
8712 | (1U << 0x16) // canals
8713 | (1U << 0x17) // newstartyear
8714 | ((_settings_game.vehicle.freight_trains > 1 ? 1U : 0U) << 0x18) // freighttrains
8715 | (1U << 0x19) // newhouses
8716 | (1U << 0x1A) // newbridges
8717 | (1U << 0x1B) // newtownnames
8718 | (1U << 0x1C) // moreanimation
8719 | ((_settings_game.vehicle.wagon_speed_limits ? 1U : 0U) << 0x1D) // wagonspeedlimits
8720 | (1U << 0x1E) // newshistory
8721 | (0U << 0x1F); // custombridgeheads
8722
8723 _ttdpatch_flags[3] = (0U << 0x00) // newcargodistribution
8724 | (1U << 0x01) // windowsnap
8725 | ((_settings_game.economy.allow_town_roads || _generating_world ? 0U : 1U) << 0x02) // townbuildnoroad
8726 | (1U << 0x03) // pathbasedsignalling
8727 | (0U << 0x04) // aichoosechance
8728 | (1U << 0x05) // resolutionwidth
8729 | (1U << 0x06) // resolutionheight
8730 | (1U << 0x07) // newindustries
8731 | ((_settings_game.order.improved_load ? 1U : 0U) << 0x08) // fifoloading
8732 | (0U << 0x09) // townroadbranchprob
8733 | (0U << 0x0A) // tempsnowline
8734 | (1U << 0x0B) // newcargo
8735 | (1U << 0x0C) // enhancemultiplayer
8736 | (1U << 0x0D) // onewayroads
8737 | (1U << 0x0E) // irregularstations
8738 | (1U << 0x0F) // statistics
8739 | (1U << 0x10) // newsounds
8740 | (1U << 0x11) // autoreplace
8741 | (1U << 0x12) // autoslope
8742 | (0U << 0x13) // followvehicle
8743 | (1U << 0x14) // trams
8744 | (0U << 0x15) // enhancetunnels
8745 | (1U << 0x16) // shortrvs
8746 | (1U << 0x17) // articulatedrvs
8747 | ((_settings_game.vehicle.dynamic_engines ? 1U : 0U) << 0x18) // dynamic engines
8748 | (1U << 0x1E) // variablerunningcosts
8749 | (1U << 0x1F); // any switch is on
8750
8751 _ttdpatch_flags[4] = (1U << 0x00) // larger persistent storage
8752 | ((_settings_game.economy.inflation ? 1U : 0U) << 0x01) // inflation is on
8753 | (1U << 0x02); // extended string range
8754}
8755
8758{
8759 for (GRFFile * const file : _grf_files) {
8760 file->stations.clear();
8761 }
8762}
8763
8766{
8767 for (GRFFile * const file : _grf_files) {
8768 file->housespec.clear();
8769 }
8770}
8771
8774{
8775 for (GRFFile * const file : _grf_files) {
8776 file->airportspec.clear();
8777 file->airtspec.clear();
8778 }
8779}
8780
8783{
8784 for (GRFFile * const file : _grf_files) {
8785 file->industryspec.clear();
8786 file->indtspec.clear();
8787 }
8788}
8789
8792{
8793 for (GRFFile * const file : _grf_files) {
8794 file->objectspec.clear();
8795 }
8796}
8797
8798static void ResetCustomRoadStops()
8799{
8800 for (auto file : _grf_files) {
8801 file->roadstops.clear();
8802 }
8803}
8804
8806static void ResetNewGRF()
8807{
8808 for (GRFFile * const file : _grf_files) {
8809 delete file;
8810 }
8811
8812 _grf_files.clear();
8813 _cur.grffile = nullptr;
8814}
8815
8818{
8819 for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) {
8820 c->error.reset();
8821 }
8822}
8823
8828{
8830 CleanUpGRFTownNames();
8831
8832 /* Copy/reset original engine info data */
8833 SetupEngines();
8834
8835 /* Copy/reset original bridge info data */
8836 ResetBridges();
8837
8838 /* Reset rail type information */
8840
8841 /* Copy/reset original road type info data */
8843
8844 /* Allocate temporary refit/cargo class data */
8845 _gted.resize(Engine::GetPoolSize());
8846
8847 /* Fill rail type label temporary data for default trains */
8848 for (const Engine *e : Engine::IterateType(VEH_TRAIN)) {
8849 _gted[e->index].railtypelabel = GetRailTypeInfo(e->u.rail.railtype)->label;
8850 }
8851
8852 /* Reset GRM reservations */
8853 memset(&_grm_engines, 0, sizeof(_grm_engines));
8854 memset(&_grm_cargoes, 0, sizeof(_grm_cargoes));
8855
8856 /* Reset generic feature callback lists */
8858
8859 /* Reset price base data */
8861
8862 /* Reset the curencies array */
8864
8865 /* Reset the house array */
8867 ResetHouses();
8868
8869 /* Reset the industries structures*/
8872
8873 /* Reset the objects. */
8876 ResetObjects();
8877
8878 /* Reset station classes */
8881
8882 /* Reset airport-related structures */
8887
8888 /* Reset road stop classes */
8890 ResetCustomRoadStops();
8891
8892 /* Reset canal sprite groups and flags */
8893 memset(_water_feature, 0, sizeof(_water_feature));
8894
8895 /* Reset the snowline table. */
8896 ClearSnowLine();
8897
8898 /* Reset NewGRF files */
8899 ResetNewGRF();
8900
8901 /* Reset NewGRF errors. */
8903
8904 /* Set up the default cargo types */
8906
8907 /* Reset misc GRF features and train list display variables */
8909
8911 _loaded_newgrf_features.used_liveries = 1 << LS_DEFAULT;
8914
8915 /* Clear all GRF overrides */
8916 _grf_id_overrides.clear();
8917
8918 InitializeSoundPool();
8919 _spritegroup_pool.CleanPool();
8921}
8922
8927{
8928 /* Reset override managers */
8929 _engine_mngr.ResetToDefaultMapping();
8930 _house_mngr.ResetMapping();
8931 _industry_mngr.ResetMapping();
8932 _industile_mngr.ResetMapping();
8933 _airport_mngr.ResetMapping();
8934 _airporttile_mngr.ResetMapping();
8935}
8936
8942{
8943 _cur.grffile->cargo_map.fill(UINT8_MAX);
8944
8945 auto cargo_list = GetCargoTranslationTable(*_cur.grffile);
8946
8947 for (const CargoSpec *cs : CargoSpec::Iterate()) {
8948 if (!cs->IsValid()) continue;
8949
8950 /* Check the translation table for this cargo's label */
8951 int idx = find_index(cargo_list, cs->label);
8952 if (idx >= 0) _cur.grffile->cargo_map[cs->Index()] = idx;
8953 }
8954}
8955
8960static void InitNewGRFFile(const GRFConfig *config)
8961{
8962 GRFFile *newfile = GetFileByFilename(config->filename);
8963 if (newfile != nullptr) {
8964 /* We already loaded it once. */
8965 _cur.grffile = newfile;
8966 return;
8967 }
8968
8969 newfile = new GRFFile(config);
8970 _grf_files.push_back(_cur.grffile = newfile);
8971}
8972
8978{
8979 this->filename = config->filename;
8980 this->grfid = config->ident.grfid;
8981
8982 /* Initialise local settings to defaults */
8983 this->traininfo_vehicle_pitch = 0;
8984 this->traininfo_vehicle_width = TRAININFO_DEFAULT_VEHICLE_WIDTH;
8985
8986 /* Mark price_base_multipliers as 'not set' */
8987 for (Price i = PR_BEGIN; i < PR_END; i++) {
8988 this->price_base_multipliers[i] = INVALID_PRICE_MODIFIER;
8989 }
8990
8991 /* Initialise rail type map with default rail types */
8992 this->railtype_map.fill(INVALID_RAILTYPE);
8993 this->railtype_map[0] = RAILTYPE_RAIL;
8994 this->railtype_map[1] = RAILTYPE_ELECTRIC;
8995 this->railtype_map[2] = RAILTYPE_MONO;
8996 this->railtype_map[3] = RAILTYPE_MAGLEV;
8997
8998 /* Initialise road type map with default road types */
8999 this->roadtype_map.fill(INVALID_ROADTYPE);
9000 this->roadtype_map[0] = ROADTYPE_ROAD;
9001
9002 /* Initialise tram type map with default tram types */
9003 this->tramtype_map.fill(INVALID_ROADTYPE);
9004 this->tramtype_map[0] = ROADTYPE_TRAM;
9005
9006 /* Copy the initial parameter list */
9007 this->param = config->param;
9008}
9009
9015static CargoLabel GetActiveCargoLabel(const std::initializer_list<CargoLabel> &labels)
9016{
9017 for (const CargoLabel &label : labels) {
9018 CargoID cid = GetCargoIDByLabel(label);
9019 if (cid != INVALID_CARGO) return label;
9020 }
9021 return CT_INVALID;
9022}
9023
9029static CargoLabel GetActiveCargoLabel(const std::variant<CargoLabel, MixedCargoType> &label)
9030{
9031 struct visitor {
9032 CargoLabel operator()(const CargoLabel &label) { return label; }
9033 CargoLabel operator()(const MixedCargoType &mixed)
9034 {
9035 switch (mixed) {
9036 case MCT_LIVESTOCK_FRUIT: return GetActiveCargoLabel({CT_LIVESTOCK, CT_FRUIT});
9037 case MCT_GRAIN_WHEAT_MAIZE: return GetActiveCargoLabel({CT_GRAIN, CT_WHEAT, CT_MAIZE});
9038 case MCT_VALUABLES_GOLD_DIAMONDS: return GetActiveCargoLabel({CT_VALUABLES, CT_GOLD, CT_DIAMONDS});
9039 default: NOT_REACHED();
9040 }
9041 }
9042 };
9043
9044 return std::visit(visitor{}, label);
9045}
9046
9051{
9052 CargoTypes original_known_cargoes = 0;
9053 for (CargoID cid = 0; cid != NUM_CARGO; ++cid) {
9054 if (IsDefaultCargo(cid)) SetBit(original_known_cargoes, cid);
9055 }
9056
9057 for (Engine *e : Engine::Iterate()) {
9058 EngineID engine = e->index;
9059 EngineInfo *ei = &e->info;
9060 bool only_defaultcargo;
9061
9062 /* Apply default cargo translation map if cargo type hasn't been set, either explicitly or by aircraft cargo handling. */
9063 if (!IsValidCargoID(e->info.cargo_type)) {
9064 e->info.cargo_type = GetCargoIDByLabel(GetActiveCargoLabel(e->info.cargo_label));
9065 }
9066
9067 /* If the NewGRF did not set any cargo properties, we apply default values. */
9068 if (_gted[engine].defaultcargo_grf == nullptr) {
9069 /* If the vehicle has any capacity, apply the default refit masks */
9070 if (e->type != VEH_TRAIN || e->u.rail.capacity != 0) {
9071 static constexpr uint8_t T = 1 << LT_TEMPERATE;
9072 static constexpr uint8_t A = 1 << LT_ARCTIC;
9073 static constexpr uint8_t S = 1 << LT_TROPIC;
9074 static constexpr uint8_t Y = 1 << LT_TOYLAND;
9075 static const struct DefaultRefitMasks {
9076 uint8_t climate;
9077 CargoLabel cargo_label;
9078 CargoClasses cargo_allowed;
9079 CargoClasses cargo_disallowed;
9080 } _default_refit_masks[] = {
9081 {T | A | S | Y, CT_PASSENGERS, CC_PASSENGERS, 0},
9082 {T | A | S , CT_MAIL, CC_MAIL, 0},
9083 {T | A | S , CT_VALUABLES, CC_ARMOURED, CC_LIQUID},
9084 { Y, CT_MAIL, CC_MAIL | CC_ARMOURED, CC_LIQUID},
9085 {T | A , CT_COAL, CC_BULK, 0},
9086 { S , CT_COPPER_ORE, CC_BULK, 0},
9087 { Y, CT_SUGAR, CC_BULK, 0},
9088 {T | A | S , CT_OIL, CC_LIQUID, 0},
9089 { Y, CT_COLA, CC_LIQUID, 0},
9090 {T , CT_GOODS, CC_PIECE_GOODS | CC_EXPRESS, CC_LIQUID | CC_PASSENGERS},
9092 { A | S , CT_FOOD, CC_REFRIGERATED, 0},
9093 { Y, CT_CANDY, CC_PIECE_GOODS | CC_EXPRESS, CC_LIQUID | CC_PASSENGERS},
9094 };
9095
9096 if (e->type == VEH_AIRCRAFT) {
9097 /* Aircraft default to "light" cargoes */
9098 _gted[engine].cargo_allowed = CC_PASSENGERS | CC_MAIL | CC_ARMOURED | CC_EXPRESS;
9099 _gted[engine].cargo_disallowed = CC_LIQUID;
9100 } else if (e->type == VEH_SHIP) {
9101 CargoLabel label = GetActiveCargoLabel(ei->cargo_label);
9102 switch (label.base()) {
9103 case CT_PASSENGERS.base():
9104 /* Ferries */
9105 _gted[engine].cargo_allowed = CC_PASSENGERS;
9106 _gted[engine].cargo_disallowed = 0;
9107 break;
9108 case CT_OIL.base():
9109 /* Tankers */
9110 _gted[engine].cargo_allowed = CC_LIQUID;
9111 _gted[engine].cargo_disallowed = 0;
9112 break;
9113 default:
9114 /* Cargo ships */
9115 if (_settings_game.game_creation.landscape == LT_TOYLAND) {
9116 /* No tanker in toyland :( */
9117 _gted[engine].cargo_allowed = CC_MAIL | CC_ARMOURED | CC_EXPRESS | CC_BULK | CC_PIECE_GOODS | CC_LIQUID;
9118 _gted[engine].cargo_disallowed = CC_PASSENGERS;
9119 } else {
9120 _gted[engine].cargo_allowed = CC_MAIL | CC_ARMOURED | CC_EXPRESS | CC_BULK | CC_PIECE_GOODS;
9121 _gted[engine].cargo_disallowed = CC_LIQUID | CC_PASSENGERS;
9122 }
9123 break;
9124 }
9125 e->u.ship.old_refittable = true;
9126 } else if (e->type == VEH_TRAIN && e->u.rail.railveh_type != RAILVEH_WAGON) {
9127 /* Train engines default to all cargoes, so you can build single-cargo consists with fast engines.
9128 * Trains loading multiple cargoes may start stations accepting unwanted cargoes. */
9130 _gted[engine].cargo_disallowed = 0;
9131 } else {
9132 /* Train wagons and road vehicles are classified by their default cargo type */
9133 CargoLabel label = GetActiveCargoLabel(ei->cargo_label);
9134 for (const auto &drm : _default_refit_masks) {
9135 if (!HasBit(drm.climate, _settings_game.game_creation.landscape)) continue;
9136 if (drm.cargo_label != label) continue;
9137
9138 _gted[engine].cargo_allowed = drm.cargo_allowed;
9139 _gted[engine].cargo_disallowed = drm.cargo_disallowed;
9140 break;
9141 }
9142
9143 /* All original cargoes have specialised vehicles, so exclude them */
9144 _gted[engine].ctt_exclude_mask = original_known_cargoes;
9145 }
9146 }
9147 _gted[engine].UpdateRefittability(_gted[engine].cargo_allowed != 0);
9148
9149 if (IsValidCargoID(ei->cargo_type)) ClrBit(_gted[engine].ctt_exclude_mask, ei->cargo_type);
9150 }
9151
9152 /* Compute refittability */
9153 {
9154 CargoTypes mask = 0;
9155 CargoTypes not_mask = 0;
9156 CargoTypes xor_mask = ei->refit_mask;
9157
9158 /* If the original masks set by the grf are zero, the vehicle shall only carry the default cargo.
9159 * Note: After applying the translations, the vehicle may end up carrying no defined cargo. It becomes unavailable in that case. */
9160 only_defaultcargo = _gted[engine].refittability != GRFTempEngineData::NONEMPTY;
9161
9162 if (_gted[engine].cargo_allowed != 0) {
9163 /* Build up the list of cargo types from the set cargo classes. */
9164 for (const CargoSpec *cs : CargoSpec::Iterate()) {
9165 if ((_gted[engine].cargo_allowed & cs->classes) != 0 && (_gted[engine].cargo_allowed_required & cs->classes) == _gted[engine].cargo_allowed_required) SetBit(mask, cs->Index());
9166 if (_gted[engine].cargo_disallowed & cs->classes) SetBit(not_mask, cs->Index());
9167 }
9168 }
9169
9170 ei->refit_mask = ((mask & ~not_mask) ^ xor_mask) & _cargo_mask;
9171
9172 /* Apply explicit refit includes/excludes. */
9173 ei->refit_mask |= _gted[engine].ctt_include_mask;
9174 ei->refit_mask &= ~_gted[engine].ctt_exclude_mask;
9175
9176 /* Custom refit mask callback. */
9177 const GRFFile *file = _gted[e->index].defaultcargo_grf;
9178 if (file == nullptr) file = e->GetGRF();
9179 if (file != nullptr && HasBit(e->info.callback_mask, CBM_VEHICLE_CUSTOM_REFIT)) {
9180 for (const CargoSpec *cs : CargoSpec::Iterate()) {
9181 uint8_t local_slot = file->cargo_map[cs->Index()];
9182 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_CUSTOM_REFIT, cs->classes, local_slot, engine, nullptr);
9183 switch (callback) {
9184 case CALLBACK_FAILED:
9185 case 0:
9186 break; // Do nothing.
9187 case 1: SetBit(ei->refit_mask, cs->Index()); break;
9188 case 2: ClrBit(ei->refit_mask, cs->Index()); break;
9189
9190 default: ErrorUnknownCallbackResult(file->grfid, CBID_VEHICLE_CUSTOM_REFIT, callback);
9191 }
9192 }
9193 }
9194 }
9195
9196 /* Clear invalid cargoslots (from default vehicles or pre-NewCargo GRFs) */
9197 if (IsValidCargoID(ei->cargo_type) && !HasBit(_cargo_mask, ei->cargo_type)) ei->cargo_type = INVALID_CARGO;
9198
9199 /* Ensure that the vehicle is either not refittable, or that the default cargo is one of the refittable cargoes.
9200 * Note: Vehicles refittable to no cargo are handle differently to vehicle refittable to a single cargo. The latter might have subtypes. */
9201 if (!only_defaultcargo && (e->type != VEH_SHIP || e->u.ship.old_refittable) && IsValidCargoID(ei->cargo_type) && !HasBit(ei->refit_mask, ei->cargo_type)) {
9202 ei->cargo_type = INVALID_CARGO;
9203 }
9204
9205 /* Check if this engine's cargo type is valid. If not, set to the first refittable
9206 * cargo type. Finally disable the vehicle, if there is still no cargo. */
9207 if (!IsValidCargoID(ei->cargo_type) && ei->refit_mask != 0) {
9208 /* Figure out which CTT to use for the default cargo, if it is 'first refittable'. */
9209 const GRFFile *file = _gted[engine].defaultcargo_grf;
9210 if (file == nullptr) file = e->GetGRF();
9211 if (file != nullptr && file->grf_version >= 8 && !file->cargo_list.empty()) {
9212 /* Use first refittable cargo from cargo translation table */
9213 uint8_t best_local_slot = UINT8_MAX;
9214 for (CargoID cargo_type : SetCargoBitIterator(ei->refit_mask)) {
9215 uint8_t local_slot = file->cargo_map[cargo_type];
9216 if (local_slot < best_local_slot) {
9217 best_local_slot = local_slot;
9218 ei->cargo_type = cargo_type;
9219 }
9220 }
9221 }
9222
9223 if (!IsValidCargoID(ei->cargo_type)) {
9224 /* Use first refittable cargo slot */
9225 ei->cargo_type = (CargoID)FindFirstBit(ei->refit_mask);
9226 }
9227 }
9228 if (!IsValidCargoID(ei->cargo_type) && e->type == VEH_TRAIN && e->u.rail.railveh_type != RAILVEH_WAGON && e->u.rail.capacity == 0) {
9229 /* For train engines which do not carry cargo it does not matter if their cargo type is invalid.
9230 * Fallback to the first available instead, if the cargo type has not been changed (as indicated by
9231 * cargo_label not being CT_INVALID). */
9232 if (GetActiveCargoLabel(ei->cargo_label) != CT_INVALID) {
9233 ei->cargo_type = static_cast<CargoID>(FindFirstBit(_standard_cargo_mask));
9234 }
9235 }
9236 if (!IsValidCargoID(ei->cargo_type)) ei->climates = 0;
9237
9238 /* Clear refit_mask for not refittable ships */
9239 if (e->type == VEH_SHIP && !e->u.ship.old_refittable) {
9240 ei->refit_mask = 0;
9241 }
9242 }
9243}
9244
9246static void FinaliseCanals()
9247{
9248 for (uint i = 0; i < CF_END; i++) {
9249 if (_water_feature[i].grffile != nullptr) {
9252 }
9253 }
9254}
9255
9258{
9259 for (Engine *e : Engine::Iterate()) {
9260 if (e->GetGRF() == nullptr) {
9261 auto found = std::ranges::find(_engine_mngr.mappings[e->type], e->index, &EngineIDMapping::engine);
9262 if (found == std::end(_engine_mngr.mappings[e->type]) || found->grfid != INVALID_GRFID || found->internal_id != found->substitute_id) {
9263 e->info.string_id = STR_NEWGRF_INVALID_ENGINE;
9264 }
9265 }
9266
9267 /* Do final mapping on variant engine ID. */
9268 if (e->info.variant_id != INVALID_ENGINE) {
9269 e->info.variant_id = GetNewEngineID(e->grf_prop.grffile, e->type, e->info.variant_id);
9270 }
9271
9272 if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue;
9273
9274 /* Skip wagons, there livery is defined via the engine */
9275 if (e->type != VEH_TRAIN || e->u.rail.railveh_type != RAILVEH_WAGON) {
9278 /* Note: For ships and roadvehicles we assume that they cannot be refitted between passenger and freight */
9279
9280 if (e->type == VEH_TRAIN) {
9281 SetBit(_loaded_newgrf_features.used_liveries, LS_FREIGHT_WAGON);
9282 switch (ls) {
9283 case LS_STEAM:
9284 case LS_DIESEL:
9285 case LS_ELECTRIC:
9286 case LS_MONORAIL:
9287 case LS_MAGLEV:
9288 SetBit(_loaded_newgrf_features.used_liveries, LS_PASSENGER_WAGON_STEAM + ls - LS_STEAM);
9289 break;
9290
9291 case LS_DMU:
9292 case LS_EMU:
9293 SetBit(_loaded_newgrf_features.used_liveries, LS_PASSENGER_WAGON_DIESEL + ls - LS_DMU);
9294 break;
9295
9296 default: NOT_REACHED();
9297 }
9298 }
9299 }
9300 }
9301
9302 /* Check engine variants don't point back on themselves (either directly or via a loop) then set appropriate flags
9303 * on variant engine. This is performed separately as all variant engines need to have been resolved. */
9304 for (Engine *e : Engine::Iterate()) {
9305 EngineID parent = e->info.variant_id;
9306 while (parent != INVALID_ENGINE) {
9307 parent = Engine::Get(parent)->info.variant_id;
9308 if (parent != e->index) continue;
9309
9310 /* Engine looped back on itself, so clear the variant. */
9311 e->info.variant_id = INVALID_ENGINE;
9312
9313 GrfMsg(1, "FinaliseEngineArray: Variant of engine {:x} in '{}' loops back on itself", e->grf_prop.local_id, e->GetGRF()->filename);
9314 break;
9315 }
9316
9317 if (e->info.variant_id != INVALID_ENGINE) {
9319 }
9320 }
9321}
9322
9325{
9326 for (CargoSpec &cs : CargoSpec::array) {
9327 if (cs.town_production_effect == INVALID_TPE) {
9328 /* Set default town production effect by cargo label. */
9329 switch (cs.label.base()) {
9330 case CT_PASSENGERS.base(): cs.town_production_effect = TPE_PASSENGERS; break;
9331 case CT_MAIL.base(): cs.town_production_effect = TPE_MAIL; break;
9332 default: cs.town_production_effect = TPE_NONE; break;
9333 }
9334 }
9335 if (!cs.IsValid()) {
9336 cs.name = cs.name_single = cs.units_volume = STR_NEWGRF_INVALID_CARGO;
9337 cs.quantifier = STR_NEWGRF_INVALID_CARGO_QUANTITY;
9338 cs.abbrev = STR_NEWGRF_INVALID_CARGO_ABBREV;
9339 }
9340 }
9341}
9342
9354static bool IsHouseSpecValid(HouseSpec *hs, const HouseSpec *next1, const HouseSpec *next2, const HouseSpec *next3, const std::string &filename)
9355{
9356 if (((hs->building_flags & BUILDING_HAS_2_TILES) != 0 &&
9357 (next1 == nullptr || !next1->enabled || (next1->building_flags & BUILDING_HAS_1_TILE) != 0)) ||
9358 ((hs->building_flags & BUILDING_HAS_4_TILES) != 0 &&
9359 (next2 == nullptr || !next2->enabled || (next2->building_flags & BUILDING_HAS_1_TILE) != 0 ||
9360 next3 == nullptr || !next3->enabled || (next3->building_flags & BUILDING_HAS_1_TILE) != 0))) {
9361 hs->enabled = false;
9362 if (!filename.empty()) Debug(grf, 1, "FinaliseHouseArray: {} defines house {} as multitile, but no suitable tiles follow. Disabling house.", filename, hs->grf_prop.local_id);
9363 return false;
9364 }
9365
9366 /* Some places sum population by only counting north tiles. Other places use all tiles causing desyncs.
9367 * As the newgrf specs define population to be zero for non-north tiles, we just disable the offending house.
9368 * If you want to allow non-zero populations somewhen, make sure to sum the population of all tiles in all places. */
9369 if (((hs->building_flags & BUILDING_HAS_2_TILES) != 0 && next1->population != 0) ||
9370 ((hs->building_flags & BUILDING_HAS_4_TILES) != 0 && (next2->population != 0 || next3->population != 0))) {
9371 hs->enabled = false;
9372 if (!filename.empty()) Debug(grf, 1, "FinaliseHouseArray: {} defines multitile house {} with non-zero population on additional tiles. Disabling house.", filename, hs->grf_prop.local_id);
9373 return false;
9374 }
9375
9376 /* Substitute type is also used for override, and having an override with a different size causes crashes.
9377 * This check should only be done for NewGRF houses because grf_prop.subst_id is not set for original houses.*/
9378 if (!filename.empty() && (hs->building_flags & BUILDING_HAS_1_TILE) != (HouseSpec::Get(hs->grf_prop.subst_id)->building_flags & BUILDING_HAS_1_TILE)) {
9379 hs->enabled = false;
9380 Debug(grf, 1, "FinaliseHouseArray: {} defines house {} with different house size then it's substitute type. Disabling house.", filename, hs->grf_prop.local_id);
9381 return false;
9382 }
9383
9384 /* Make sure that additional parts of multitile houses are not available. */
9385 if ((hs->building_flags & BUILDING_HAS_1_TILE) == 0 && (hs->building_availability & HZ_ZONALL) != 0 && (hs->building_availability & HZ_CLIMALL) != 0) {
9386 hs->enabled = false;
9387 if (!filename.empty()) Debug(grf, 1, "FinaliseHouseArray: {} defines house {} without a size but marked it as available. Disabling house.", filename, hs->grf_prop.local_id);
9388 return false;
9389 }
9390
9391 return true;
9392}
9393
9400static void EnsureEarlyHouse(HouseZones bitmask)
9401{
9403
9404 for (const auto &hs : HouseSpec::Specs()) {
9405 if (!hs.enabled) continue;
9406 if ((hs.building_availability & bitmask) != bitmask) continue;
9407 if (hs.min_year < min_year) min_year = hs.min_year;
9408 }
9409
9410 if (min_year == 0) return;
9411
9412 for (auto &hs : HouseSpec::Specs()) {
9413 if (!hs.enabled) continue;
9414 if ((hs.building_availability & bitmask) != bitmask) continue;
9415 if (hs.min_year == min_year) hs.min_year = 0;
9416 }
9417}
9418
9426{
9427 /* If there are no houses with start dates before 1930, then all houses
9428 * with start dates of 1930 have them reset to 0. This is in order to be
9429 * compatible with TTDPatch, where if no houses have start dates before
9430 * 1930 and the date is before 1930, the game pretends that this is 1930.
9431 * If there have been any houses defined with start dates before 1930 then
9432 * the dates are left alone.
9433 * On the other hand, why 1930? Just 'fix' the houses with the lowest
9434 * minimum introduction date to 0.
9435 */
9436 for (GRFFile * const file : _grf_files) {
9437 if (file->housespec.empty()) continue;
9438
9439 size_t num_houses = file->housespec.size();
9440 for (size_t i = 0; i < num_houses; i++) {
9441 HouseSpec *hs = file->housespec[i].get();
9442
9443 if (hs == nullptr) continue;
9444
9445 const HouseSpec *next1 = (i + 1 < num_houses ? file->housespec[i + 1].get() : nullptr);
9446 const HouseSpec *next2 = (i + 2 < num_houses ? file->housespec[i + 2].get() : nullptr);
9447 const HouseSpec *next3 = (i + 3 < num_houses ? file->housespec[i + 3].get() : nullptr);
9448
9449 if (!IsHouseSpecValid(hs, next1, next2, next3, file->filename)) continue;
9450
9451 _house_mngr.SetEntitySpec(hs);
9452 }
9453 }
9454
9455 for (size_t i = 0; i < HouseSpec::Specs().size(); i++) {
9456 HouseSpec *hs = HouseSpec::Get(i);
9457 const HouseSpec *next1 = (i + 1 < NUM_HOUSES ? HouseSpec::Get(i + 1) : nullptr);
9458 const HouseSpec *next2 = (i + 2 < NUM_HOUSES ? HouseSpec::Get(i + 2) : nullptr);
9459 const HouseSpec *next3 = (i + 3 < NUM_HOUSES ? HouseSpec::Get(i + 3) : nullptr);
9460
9461 /* We need to check all houses again to we are sure that multitile houses
9462 * did get consecutive IDs and none of the parts are missing. */
9463 if (!IsHouseSpecValid(hs, next1, next2, next3, std::string{})) {
9464 /* GetHouseNorthPart checks 3 houses that are directly before
9465 * it in the house pool. If any of those houses have multi-tile
9466 * flags set it assumes it's part of a multitile house. Since
9467 * we can have invalid houses in the pool marked as disabled, we
9468 * don't want to have them influencing valid tiles. As such set
9469 * building_flags to zero here to make sure any house following
9470 * this one in the pool is properly handled as 1x1 house. */
9471 hs->building_flags = TILE_NO_FLAG;
9472 }
9473
9474 /* Apply default cargo translation map for unset cargo slots */
9475 for (uint i = 0; i < lengthof(hs->accepts_cargo_label); ++i) {
9476 if (!IsValidCargoID(hs->accepts_cargo[i])) hs->accepts_cargo[i] = GetCargoIDByLabel(hs->accepts_cargo_label[i]);
9477 /* Disable acceptance if cargo type is invalid. */
9478 if (!IsValidCargoID(hs->accepts_cargo[i])) hs->cargo_acceptance[i] = 0;
9479 }
9480 }
9481
9482 HouseZones climate_mask = (HouseZones)(1 << (_settings_game.game_creation.landscape + 12));
9483 EnsureEarlyHouse(HZ_ZON1 | climate_mask);
9484 EnsureEarlyHouse(HZ_ZON2 | climate_mask);
9485 EnsureEarlyHouse(HZ_ZON3 | climate_mask);
9486 EnsureEarlyHouse(HZ_ZON4 | climate_mask);
9487 EnsureEarlyHouse(HZ_ZON5 | climate_mask);
9488
9489 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
9495 }
9496}
9497
9504{
9505 for (GRFFile * const file : _grf_files) {
9506 for (const auto &indsp : file->industryspec) {
9507 if (indsp == nullptr || !indsp->enabled) continue;
9508
9509 StringID strid;
9510 /* process the conversion of text at the end, so to be sure everything will be fine
9511 * and available. Check if it does not return undefind marker, which is a very good sign of a
9512 * substitute industry who has not changed the string been examined, thus using it as such */
9513 strid = GetGRFStringID(indsp->grf_prop.grfid, indsp->name);
9514 if (strid != STR_UNDEFINED) indsp->name = strid;
9515
9516 strid = GetGRFStringID(indsp->grf_prop.grfid, indsp->closure_text);
9517 if (strid != STR_UNDEFINED) indsp->closure_text = strid;
9518
9519 strid = GetGRFStringID(indsp->grf_prop.grfid, indsp->production_up_text);
9520 if (strid != STR_UNDEFINED) indsp->production_up_text = strid;
9521
9522 strid = GetGRFStringID(indsp->grf_prop.grfid, indsp->production_down_text);
9523 if (strid != STR_UNDEFINED) indsp->production_down_text = strid;
9524
9525 strid = GetGRFStringID(indsp->grf_prop.grfid, indsp->new_industry_text);
9526 if (strid != STR_UNDEFINED) indsp->new_industry_text = strid;
9527
9528 if (indsp->station_name != STR_NULL) {
9529 /* STR_NULL (0) can be set by grf. It has a meaning regarding assignation of the
9530 * station's name. Don't want to lose the value, therefore, do not process. */
9531 strid = GetGRFStringID(indsp->grf_prop.grfid, indsp->station_name);
9532 if (strid != STR_UNDEFINED) indsp->station_name = strid;
9533 }
9534
9535 _industry_mngr.SetEntitySpec(indsp.get());
9536 }
9537
9538 for (const auto &indtsp : file->indtspec) {
9539 if (indtsp != nullptr) {
9540 _industile_mngr.SetEntitySpec(indtsp.get());
9541 }
9542 }
9543 }
9544
9545 for (auto &indsp : _industry_specs) {
9546 if (indsp.enabled && indsp.grf_prop.HasGrfFile()) {
9547 for (auto &conflicting : indsp.conflicting) {
9548 conflicting = MapNewGRFIndustryType(conflicting, indsp.grf_prop.grfid);
9549 }
9550 }
9551 if (!indsp.enabled) {
9552 indsp.name = STR_NEWGRF_INVALID_INDUSTRYTYPE;
9553 }
9554
9555 /* Apply default cargo translation map for unset cargo slots */
9556 for (size_t i = 0; i < std::size(indsp.produced_cargo_label); ++i) {
9557 if (!IsValidCargoID(indsp.produced_cargo[i])) indsp.produced_cargo[i] = GetCargoIDByLabel(GetActiveCargoLabel(indsp.produced_cargo_label[i]));
9558 }
9559 for (size_t i = 0; i < std::size(indsp.accepts_cargo_label); ++i) {
9560 if (!IsValidCargoID(indsp.accepts_cargo[i])) indsp.accepts_cargo[i] = GetCargoIDByLabel(GetActiveCargoLabel(indsp.accepts_cargo_label[i]));
9561 }
9562 }
9563
9564 for (auto &indtsp : _industry_tile_specs) {
9565 /* Apply default cargo translation map for unset cargo slots */
9566 for (size_t i = 0; i < std::size(indtsp.accepts_cargo_label); ++i) {
9567 if (!IsValidCargoID(indtsp.accepts_cargo[i])) indtsp.accepts_cargo[i] = GetCargoIDByLabel(GetActiveCargoLabel(indtsp.accepts_cargo_label[i]));
9568 }
9569 }
9570}
9571
9578{
9579 for (GRFFile * const file : _grf_files) {
9580 for (auto &objectspec : file->objectspec) {
9581 if (objectspec != nullptr && objectspec->grf_prop.HasGrfFile() && objectspec->IsEnabled()) {
9582 _object_mngr.SetEntitySpec(objectspec.get());
9583 }
9584 }
9585 }
9586
9588}
9589
9596{
9597 for (GRFFile * const file : _grf_files) {
9598 for (auto &as : file->airportspec) {
9599 if (as != nullptr && as->enabled) {
9600 _airport_mngr.SetEntitySpec(as.get());
9601 }
9602 }
9603
9604 for (auto &ats : file->airtspec) {
9605 if (ats != nullptr && ats->enabled) {
9606 _airporttile_mngr.SetEntitySpec(ats.get());
9607 }
9608 }
9609 }
9610}
9611
9612/* Here we perform initial decoding of some special sprites (as are they
9613 * described at http://www.ttdpatch.net/src/newgrf.txt, but this is only a very
9614 * partial implementation yet).
9615 * XXX: We consider GRF files trusted. It would be trivial to exploit OTTD by
9616 * a crafted invalid GRF file. We should tell that to the user somehow, or
9617 * better make this more robust in the future. */
9618static void DecodeSpecialSprite(uint8_t *buf, uint num, GrfLoadingStage stage)
9619{
9620 /* XXX: There is a difference between staged loading in TTDPatch and
9621 * here. In TTDPatch, for some reason actions 1 and 2 are carried out
9622 * during stage 1, whilst action 3 is carried out during stage 2 (to
9623 * "resolve" cargo IDs... wtf). This is a little problem, because cargo
9624 * IDs are valid only within a given set (action 1) block, and may be
9625 * overwritten after action 3 associates them. But overwriting happens
9626 * in an earlier stage than associating, so... We just process actions
9627 * 1 and 2 in stage 2 now, let's hope that won't get us into problems.
9628 * --pasky
9629 * We need a pre-stage to set up GOTO labels of Action 0x10 because the grf
9630 * is not in memory and scanning the file every time would be too expensive.
9631 * In other stages we skip action 0x10 since it's already dealt with. */
9632 static const SpecialSpriteHandler handlers[][GLS_END] = {
9633 /* 0x00 */ { nullptr, SafeChangeInfo, nullptr, nullptr, ReserveChangeInfo, FeatureChangeInfo, },
9634 /* 0x01 */ { SkipAct1, SkipAct1, SkipAct1, SkipAct1, SkipAct1, NewSpriteSet, },
9635 /* 0x02 */ { nullptr, nullptr, nullptr, nullptr, nullptr, NewSpriteGroup, },
9636 /* 0x03 */ { nullptr, GRFUnsafe, nullptr, nullptr, nullptr, FeatureMapSpriteGroup, },
9637 /* 0x04 */ { nullptr, nullptr, nullptr, nullptr, nullptr, FeatureNewName, },
9638 /* 0x05 */ { SkipAct5, SkipAct5, SkipAct5, SkipAct5, SkipAct5, GraphicsNew, },
9639 /* 0x06 */ { nullptr, nullptr, nullptr, CfgApply, CfgApply, CfgApply, },
9640 /* 0x07 */ { nullptr, nullptr, nullptr, nullptr, SkipIf, SkipIf, },
9641 /* 0x08 */ { ScanInfo, nullptr, nullptr, GRFInfo, GRFInfo, GRFInfo, },
9642 /* 0x09 */ { nullptr, nullptr, nullptr, SkipIf, SkipIf, SkipIf, },
9643 /* 0x0A */ { SkipActA, SkipActA, SkipActA, SkipActA, SkipActA, SpriteReplace, },
9644 /* 0x0B */ { nullptr, nullptr, nullptr, GRFLoadError, GRFLoadError, GRFLoadError, },
9645 /* 0x0C */ { nullptr, nullptr, nullptr, GRFComment, nullptr, GRFComment, },
9646 /* 0x0D */ { nullptr, SafeParamSet, nullptr, ParamSet, ParamSet, ParamSet, },
9647 /* 0x0E */ { nullptr, SafeGRFInhibit, nullptr, GRFInhibit, GRFInhibit, GRFInhibit, },
9648 /* 0x0F */ { nullptr, GRFUnsafe, nullptr, FeatureTownName, nullptr, nullptr, },
9649 /* 0x10 */ { nullptr, nullptr, DefineGotoLabel, nullptr, nullptr, nullptr, },
9650 /* 0x11 */ { SkipAct11, GRFUnsafe, SkipAct11, GRFSound, SkipAct11, GRFSound, },
9652 /* 0x13 */ { nullptr, nullptr, nullptr, nullptr, nullptr, TranslateGRFStrings, },
9653 /* 0x14 */ { StaticGRFInfo, nullptr, nullptr, nullptr, nullptr, nullptr, },
9654 };
9655
9656 GRFLocation location(_cur.grfconfig->ident.grfid, _cur.nfo_line);
9657
9658 GRFLineToSpriteOverride::iterator it = _grf_line_to_action6_sprite_override.find(location);
9659 if (it == _grf_line_to_action6_sprite_override.end()) {
9660 /* No preloaded sprite to work with; read the
9661 * pseudo sprite content. */
9662 _cur.file->ReadBlock(buf, num);
9663 } else {
9664 /* Use the preloaded sprite data. */
9665 buf = _grf_line_to_action6_sprite_override[location].data();
9666 GrfMsg(7, "DecodeSpecialSprite: Using preloaded pseudo sprite data");
9667
9668 /* Skip the real (original) content of this action. */
9669 _cur.file->SeekTo(num, SEEK_CUR);
9670 }
9671
9672 ByteReader br(buf, buf + num);
9673
9674 try {
9675 uint8_t action = br.ReadByte();
9676
9677 if (action == 0xFF) {
9678 GrfMsg(2, "DecodeSpecialSprite: Unexpected data block, skipping");
9679 } else if (action == 0xFE) {
9680 GrfMsg(2, "DecodeSpecialSprite: Unexpected import block, skipping");
9681 } else if (action >= lengthof(handlers)) {
9682 GrfMsg(7, "DecodeSpecialSprite: Skipping unknown action 0x{:02X}", action);
9683 } else if (handlers[action][stage] == nullptr) {
9684 GrfMsg(7, "DecodeSpecialSprite: Skipping action 0x{:02X} in stage {}", action, stage);
9685 } else {
9686 GrfMsg(7, "DecodeSpecialSprite: Handling action 0x{:02X} in stage {}", action, stage);
9687 handlers[action][stage](br);
9688 }
9689 } catch (...) {
9690 GrfMsg(1, "DecodeSpecialSprite: Tried to read past end of pseudo-sprite data");
9691 DisableGrf(STR_NEWGRF_ERROR_READ_BOUNDS);
9692 }
9693}
9694
9701static void LoadNewGRFFileFromFile(GRFConfig *config, GrfLoadingStage stage, SpriteFile &file)
9702{
9703 _cur.file = &file;
9704 _cur.grfconfig = config;
9705
9706 Debug(grf, 2, "LoadNewGRFFile: Reading NewGRF-file '{}'", config->filename);
9707
9708 uint8_t grf_container_version = file.GetContainerVersion();
9709 if (grf_container_version == 0) {
9710 Debug(grf, 7, "LoadNewGRFFile: Custom .grf has invalid format");
9711 return;
9712 }
9713
9714 if (stage == GLS_INIT || stage == GLS_ACTIVATION) {
9715 /* We need the sprite offsets in the init stage for NewGRF sounds
9716 * and in the activation stage for real sprites. */
9718 } else {
9719 /* Skip sprite section offset if present. */
9720 if (grf_container_version >= 2) file.ReadDword();
9721 }
9722
9723 if (grf_container_version >= 2) {
9724 /* Read compression value. */
9725 uint8_t compression = file.ReadByte();
9726 if (compression != 0) {
9727 Debug(grf, 7, "LoadNewGRFFile: Unsupported compression format");
9728 return;
9729 }
9730 }
9731
9732 /* Skip the first sprite; we don't care about how many sprites this
9733 * does contain; newest TTDPatches and George's longvehicles don't
9734 * neither, apparently. */
9735 uint32_t num = grf_container_version >= 2 ? file.ReadDword() : file.ReadWord();
9736 if (num == 4 && file.ReadByte() == 0xFF) {
9737 file.ReadDword();
9738 } else {
9739 Debug(grf, 7, "LoadNewGRFFile: Custom .grf has invalid format");
9740 return;
9741 }
9742
9743 _cur.ClearDataForNextFile();
9744
9746
9747 while ((num = (grf_container_version >= 2 ? file.ReadDword() : file.ReadWord())) != 0) {
9748 uint8_t type = file.ReadByte();
9749 _cur.nfo_line++;
9750
9751 if (type == 0xFF) {
9752 if (_cur.skip_sprites == 0) {
9753 DecodeSpecialSprite(buf.Allocate(num), num, stage);
9754
9755 /* Stop all processing if we are to skip the remaining sprites */
9756 if (_cur.skip_sprites == -1) break;
9757
9758 continue;
9759 } else {
9760 file.SkipBytes(num);
9761 }
9762 } else {
9763 if (_cur.skip_sprites == 0) {
9764 GrfMsg(0, "LoadNewGRFFile: Unexpected sprite, disabling");
9765 DisableGrf(STR_NEWGRF_ERROR_UNEXPECTED_SPRITE);
9766 break;
9767 }
9768
9769 if (grf_container_version >= 2 && type == 0xFD) {
9770 /* Reference to data section. Container version >= 2 only. */
9771 file.SkipBytes(num);
9772 } else {
9773 file.SkipBytes(7);
9774 SkipSpriteData(file, type, num - 8);
9775 }
9776 }
9777
9778 if (_cur.skip_sprites > 0) _cur.skip_sprites--;
9779 }
9780}
9781
9790void LoadNewGRFFile(GRFConfig *config, GrfLoadingStage stage, Subdirectory subdir, bool temporary)
9791{
9792 const std::string &filename = config->filename;
9793
9794 /* A .grf file is activated only if it was active when the game was
9795 * started. If a game is loaded, only its active .grfs will be
9796 * reactivated, unless "loadallgraphics on" is used. A .grf file is
9797 * considered active if its action 8 has been processed, i.e. its
9798 * action 8 hasn't been skipped using an action 7.
9799 *
9800 * During activation, only actions 0, 1, 2, 3, 4, 5, 7, 8, 9, 0A and 0B are
9801 * carried out. All others are ignored, because they only need to be
9802 * processed once at initialization. */
9803 if (stage != GLS_FILESCAN && stage != GLS_SAFETYSCAN && stage != GLS_LABELSCAN) {
9804 _cur.grffile = GetFileByFilename(filename);
9805 if (_cur.grffile == nullptr) UserError("File '{}' lost in cache.\n", filename);
9806 if (stage == GLS_RESERVE && config->status != GCS_INITIALISED) return;
9807 if (stage == GLS_ACTIVATION && !HasBit(config->flags, GCF_RESERVED)) return;
9808 }
9809
9810 bool needs_palette_remap = config->palette & GRFP_USE_MASK;
9811 if (temporary) {
9812 SpriteFile temporarySpriteFile(filename, subdir, needs_palette_remap);
9813 LoadNewGRFFileFromFile(config, stage, temporarySpriteFile);
9814 } else {
9815 LoadNewGRFFileFromFile(config, stage, OpenCachedSpriteFile(filename, subdir, needs_palette_remap));
9816 }
9817}
9818
9826static void ActivateOldShore()
9827{
9828 /* Use default graphics, if no shore sprites were loaded.
9829 * Should not happen, as the base set's extra grf should include some. */
9831
9833 DupSprite(SPR_ORIGINALSHORE_START + 1, SPR_SHORE_BASE + 1); // SLOPE_W
9834 DupSprite(SPR_ORIGINALSHORE_START + 2, SPR_SHORE_BASE + 2); // SLOPE_S
9835 DupSprite(SPR_ORIGINALSHORE_START + 6, SPR_SHORE_BASE + 3); // SLOPE_SW
9836 DupSprite(SPR_ORIGINALSHORE_START + 0, SPR_SHORE_BASE + 4); // SLOPE_E
9837 DupSprite(SPR_ORIGINALSHORE_START + 4, SPR_SHORE_BASE + 6); // SLOPE_SE
9838 DupSprite(SPR_ORIGINALSHORE_START + 3, SPR_SHORE_BASE + 8); // SLOPE_N
9839 DupSprite(SPR_ORIGINALSHORE_START + 7, SPR_SHORE_BASE + 9); // SLOPE_NW
9840 DupSprite(SPR_ORIGINALSHORE_START + 5, SPR_SHORE_BASE + 12); // SLOPE_NE
9841 }
9842
9844 DupSprite(SPR_FLAT_GRASS_TILE + 16, SPR_SHORE_BASE + 0); // SLOPE_STEEP_S
9845 DupSprite(SPR_FLAT_GRASS_TILE + 17, SPR_SHORE_BASE + 5); // SLOPE_STEEP_W
9846 DupSprite(SPR_FLAT_GRASS_TILE + 7, SPR_SHORE_BASE + 7); // SLOPE_WSE
9847 DupSprite(SPR_FLAT_GRASS_TILE + 15, SPR_SHORE_BASE + 10); // SLOPE_STEEP_N
9848 DupSprite(SPR_FLAT_GRASS_TILE + 11, SPR_SHORE_BASE + 11); // SLOPE_NWS
9849 DupSprite(SPR_FLAT_GRASS_TILE + 13, SPR_SHORE_BASE + 13); // SLOPE_ENW
9850 DupSprite(SPR_FLAT_GRASS_TILE + 14, SPR_SHORE_BASE + 14); // SLOPE_SEN
9851 DupSprite(SPR_FLAT_GRASS_TILE + 18, SPR_SHORE_BASE + 15); // SLOPE_STEEP_E
9852
9853 /* XXX - SLOPE_EW, SLOPE_NS are currently not used.
9854 * If they would be used somewhen, then these grass tiles will most like not look as needed */
9855 DupSprite(SPR_FLAT_GRASS_TILE + 5, SPR_SHORE_BASE + 16); // SLOPE_EW
9856 DupSprite(SPR_FLAT_GRASS_TILE + 10, SPR_SHORE_BASE + 17); // SLOPE_NS
9857 }
9858}
9859
9864{
9866 DupSprite(SPR_ROAD_DEPOT + 0, SPR_TRAMWAY_DEPOT_NO_TRACK + 0); // use road depot graphics for "no tracks"
9867 DupSprite(SPR_TRAMWAY_DEPOT_WITH_TRACK + 1, SPR_TRAMWAY_DEPOT_NO_TRACK + 1);
9868 DupSprite(SPR_ROAD_DEPOT + 2, SPR_TRAMWAY_DEPOT_NO_TRACK + 2); // use road depot graphics for "no tracks"
9869 DupSprite(SPR_TRAMWAY_DEPOT_WITH_TRACK + 3, SPR_TRAMWAY_DEPOT_NO_TRACK + 3);
9870 DupSprite(SPR_TRAMWAY_DEPOT_WITH_TRACK + 4, SPR_TRAMWAY_DEPOT_NO_TRACK + 4);
9871 DupSprite(SPR_TRAMWAY_DEPOT_WITH_TRACK + 5, SPR_TRAMWAY_DEPOT_NO_TRACK + 5);
9872 }
9873}
9874
9879{
9880 extern const PriceBaseSpec _price_base_specs[];
9882 static const uint32_t override_features = (1 << GSF_TRAINS) | (1 << GSF_ROADVEHICLES) | (1 << GSF_SHIPS) | (1 << GSF_AIRCRAFT);
9883
9884 /* Evaluate grf overrides */
9885 int num_grfs = (uint)_grf_files.size();
9886 std::vector<int> grf_overrides(num_grfs, -1);
9887 for (int i = 0; i < num_grfs; i++) {
9888 GRFFile *source = _grf_files[i];
9889 auto it = _grf_id_overrides.find(source->grfid);
9890 if (it == std::end(_grf_id_overrides)) continue;
9891 uint32_t override = it->second;
9892
9893 GRFFile *dest = GetFileByGRFID(override);
9894 if (dest == nullptr) continue;
9895
9896 grf_overrides[i] = find_index(_grf_files, dest);
9897 assert(grf_overrides[i] >= 0);
9898 }
9899
9900 /* Override features and price base multipliers of earlier loaded grfs */
9901 for (int i = 0; i < num_grfs; i++) {
9902 if (grf_overrides[i] < 0 || grf_overrides[i] >= i) continue;
9903 GRFFile *source = _grf_files[i];
9904 GRFFile *dest = _grf_files[grf_overrides[i]];
9905
9906 uint32_t features = (source->grf_features | dest->grf_features) & override_features;
9907 source->grf_features |= features;
9908 dest->grf_features |= features;
9909
9910 for (Price p = PR_BEGIN; p < PR_END; p++) {
9911 /* No price defined -> nothing to do */
9912 if (!HasBit(features, _price_base_specs[p].grf_feature) || source->price_base_multipliers[p] == INVALID_PRICE_MODIFIER) continue;
9913 Debug(grf, 3, "'{}' overrides price base multiplier {} of '{}'", source->filename, p, dest->filename);
9914 dest->price_base_multipliers[p] = source->price_base_multipliers[p];
9915 }
9916 }
9917
9918 /* Propagate features and price base multipliers of afterwards loaded grfs, if none is present yet */
9919 for (int i = num_grfs - 1; i >= 0; i--) {
9920 if (grf_overrides[i] < 0 || grf_overrides[i] <= i) continue;
9921 GRFFile *source = _grf_files[i];
9922 GRFFile *dest = _grf_files[grf_overrides[i]];
9923
9924 uint32_t features = (source->grf_features | dest->grf_features) & override_features;
9925 source->grf_features |= features;
9926 dest->grf_features |= features;
9927
9928 for (Price p = PR_BEGIN; p < PR_END; p++) {
9929 /* Already a price defined -> nothing to do */
9930 if (!HasBit(features, _price_base_specs[p].grf_feature) || dest->price_base_multipliers[p] != INVALID_PRICE_MODIFIER) continue;
9931 Debug(grf, 3, "Price base multiplier {} from '{}' propagated to '{}'", p, source->filename, dest->filename);
9932 dest->price_base_multipliers[p] = source->price_base_multipliers[p];
9933 }
9934 }
9935
9936 /* The 'master grf' now have the correct multipliers. Assign them to the 'addon grfs' to make everything consistent. */
9937 for (int i = 0; i < num_grfs; i++) {
9938 if (grf_overrides[i] < 0) continue;
9939 GRFFile *source = _grf_files[i];
9940 GRFFile *dest = _grf_files[grf_overrides[i]];
9941
9942 uint32_t features = (source->grf_features | dest->grf_features) & override_features;
9943 source->grf_features |= features;
9944 dest->grf_features |= features;
9945
9946 for (Price p = PR_BEGIN; p < PR_END; p++) {
9947 if (!HasBit(features, _price_base_specs[p].grf_feature)) continue;
9948 if (source->price_base_multipliers[p] != dest->price_base_multipliers[p]) {
9949 Debug(grf, 3, "Price base multiplier {} from '{}' propagated to '{}'", p, dest->filename, source->filename);
9950 }
9951 source->price_base_multipliers[p] = dest->price_base_multipliers[p];
9952 }
9953 }
9954
9955 /* Apply fallback prices for grf version < 8 */
9956 for (GRFFile * const file : _grf_files) {
9957 if (file->grf_version >= 8) continue;
9958 PriceMultipliers &price_base_multipliers = file->price_base_multipliers;
9959 for (Price p = PR_BEGIN; p < PR_END; p++) {
9960 Price fallback_price = _price_base_specs[p].fallback_price;
9961 if (fallback_price != INVALID_PRICE && price_base_multipliers[p] == INVALID_PRICE_MODIFIER) {
9962 /* No price multiplier has been set.
9963 * So copy the multiplier from the fallback price, maybe a multiplier was set there. */
9964 price_base_multipliers[p] = price_base_multipliers[fallback_price];
9965 }
9966 }
9967 }
9968
9969 /* Decide local/global scope of price base multipliers */
9970 for (GRFFile * const file : _grf_files) {
9971 PriceMultipliers &price_base_multipliers = file->price_base_multipliers;
9972 for (Price p = PR_BEGIN; p < PR_END; p++) {
9973 if (price_base_multipliers[p] == INVALID_PRICE_MODIFIER) {
9974 /* No multiplier was set; set it to a neutral value */
9975 price_base_multipliers[p] = 0;
9976 } else {
9977 if (!HasBit(file->grf_features, _price_base_specs[p].grf_feature)) {
9978 /* The grf does not define any objects of the feature,
9979 * so it must be a difficulty setting. Apply it globally */
9980 Debug(grf, 3, "'{}' sets global price base multiplier {}", file->filename, p);
9981 SetPriceBaseMultiplier(p, price_base_multipliers[p]);
9982 price_base_multipliers[p] = 0;
9983 } else {
9984 Debug(grf, 3, "'{}' sets local price base multiplier {}", file->filename, p);
9985 }
9986 }
9987 }
9988 }
9989}
9990
9991extern void InitGRFTownGeneratorNames();
9992
9994static void AfterLoadGRFs()
9995{
9996 /* Cached callback groups are no longer needed. */
9998 _cached_callback_groups.shrink_to_fit();
9999
10001 it.func(MapGRFStringID(it.grfid, it.source));
10002 }
10003 _string_to_grf_mapping.clear();
10004
10005 /* Clear the action 6 override sprites. */
10006 _grf_line_to_action6_sprite_override.clear();
10007
10008 /* Polish cargoes */
10010
10011 /* Pre-calculate all refit masks after loading GRF files. */
10013
10014 /* Polish engines */
10016
10017 /* Set the actually used Canal properties */
10019
10020 /* Add all new houses to the house array. */
10022
10023 /* Add all new industries to the industry array. */
10025
10026 /* Add all new objects to the object array. */
10028
10030
10031 /* Sort the list of industry types. */
10033
10034 /* Create dynamic list of industry legends for smallmap_gui.cpp */
10036
10037 /* Build the routemap legend, based on the available cargos */
10039
10040 /* Add all new airports to the airports array. */
10043
10044 /* Update the townname generators list */
10046
10047 /* Run all queued vehicle list order changes */
10049
10050 /* Load old shore sprites in new position, if they were replaced by ActionA */
10052
10053 /* Load old tram depot sprites in new position, if no new ones are present */
10055
10056 /* Set up custom rail types */
10057 InitRailTypes();
10058 InitRoadTypes();
10059
10060 for (Engine *e : Engine::IterateType(VEH_ROAD)) {
10061 if (_gted[e->index].rv_max_speed != 0) {
10062 /* Set RV maximum speed from the mph/0.8 unit value */
10063 e->u.road.max_speed = _gted[e->index].rv_max_speed * 4;
10064 }
10065
10066 RoadTramType rtt = HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? RTT_TRAM : RTT_ROAD;
10067
10068 const GRFFile *file = e->GetGRF();
10069 if (file == nullptr || _gted[e->index].roadtramtype == 0) {
10070 e->u.road.roadtype = (rtt == RTT_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD;
10071 continue;
10072 }
10073
10074 /* Remove +1 offset. */
10075 _gted[e->index].roadtramtype--;
10076
10077 const std::vector<RoadTypeLabel> *list = (rtt == RTT_TRAM) ? &file->tramtype_list : &file->roadtype_list;
10078 if (_gted[e->index].roadtramtype < list->size())
10079 {
10080 RoadTypeLabel rtl = (*list)[_gted[e->index].roadtramtype];
10081 RoadType rt = GetRoadTypeByLabel(rtl);
10082 if (rt != INVALID_ROADTYPE && GetRoadTramType(rt) == rtt) {
10083 e->u.road.roadtype = rt;
10084 continue;
10085 }
10086 }
10087
10088 /* Road type is not available, so disable this engine */
10089 e->info.climates = 0;
10090 }
10091
10093 RailType railtype = GetRailTypeByLabel(_gted[e->index].railtypelabel);
10094 if (railtype == INVALID_RAILTYPE) {
10095 /* Rail type is not available, so disable this engine */
10096 e->info.climates = 0;
10097 } else {
10098 e->u.rail.railtype = railtype;
10099 e->u.rail.intended_railtype = railtype;
10100 }
10101 }
10102
10104
10106
10107 /* Deallocate temporary loading data */
10108 _gted.clear();
10109 _grm_sprites.clear();
10110}
10111
10117void LoadNewGRF(SpriteID load_index, uint num_baseset)
10118{
10119 /* In case of networking we need to "sync" the start values
10120 * so all NewGRFs are loaded equally. For this we use the
10121 * start date of the game and we set the counters, etc. to
10122 * 0 so they're the same too. */
10123 TimerGameCalendar::Date date = TimerGameCalendar::date;
10126
10127 TimerGameEconomy::Date economy_date = TimerGameEconomy::date;
10128 TimerGameEconomy::Year economy_year = TimerGameEconomy::year;
10130
10131 uint64_t tick_counter = TimerGameTick::counter;
10132 uint8_t display_opt = _display_opt;
10133
10134 if (_networking) {
10138
10142
10144 _display_opt = 0;
10145 }
10146
10148
10150
10151 /*
10152 * Reset the status of all files, so we can 'retry' to load them.
10153 * This is needed when one for example rearranges the NewGRFs in-game
10154 * and a previously disabled NewGRF becomes usable. If it would not
10155 * be reset, the NewGRF would remain disabled even though it should
10156 * have been enabled.
10157 */
10158 for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) {
10159 if (c->status != GCS_NOT_FOUND) c->status = GCS_UNKNOWN;
10160 }
10161
10162 _cur.spriteid = load_index;
10163
10164 /* Load newgrf sprites
10165 * in each loading stage, (try to) open each file specified in the config
10166 * and load information from it. */
10167 for (GrfLoadingStage stage = GLS_LABELSCAN; stage <= GLS_ACTIVATION; stage++) {
10168 /* Set activated grfs back to will-be-activated between reservation- and activation-stage.
10169 * This ensures that action7/9 conditions 0x06 - 0x0A work correctly. */
10170 for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) {
10172 }
10173
10174 if (stage == GLS_RESERVE) {
10175 static const std::pair<uint32_t, uint32_t> default_grf_overrides[] = {
10176 { BSWAP32(0x44442202), BSWAP32(0x44440111) }, // UKRS addons modifies UKRS
10177 { BSWAP32(0x6D620402), BSWAP32(0x6D620401) }, // DBSetXL ECS extension modifies DBSetXL
10178 { BSWAP32(0x4D656f20), BSWAP32(0x4D656F17) }, // LV4cut modifies LV4
10179 };
10180 for (const auto &grf_override : default_grf_overrides) {
10181 SetNewGRFOverride(grf_override.first, grf_override.second);
10182 }
10183 }
10184
10185 uint num_grfs = 0;
10186 uint num_non_static = 0;
10187
10188 _cur.stage = stage;
10189 for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) {
10190 if (c->status == GCS_DISABLED || c->status == GCS_NOT_FOUND) continue;
10191 if (stage > GLS_INIT && HasBit(c->flags, GCF_INIT_ONLY)) continue;
10192
10193 Subdirectory subdir = num_grfs < num_baseset ? BASESET_DIR : NEWGRF_DIR;
10194 if (!FioCheckFileExists(c->filename, subdir)) {
10195 Debug(grf, 0, "NewGRF file is missing '{}'; disabling", c->filename);
10196 c->status = GCS_NOT_FOUND;
10197 continue;
10198 }
10199
10200 if (stage == GLS_LABELSCAN) InitNewGRFFile(c);
10201
10202 if (!HasBit(c->flags, GCF_STATIC) && !HasBit(c->flags, GCF_SYSTEM)) {
10203 if (num_non_static == NETWORK_MAX_GRF_COUNT) {
10204 Debug(grf, 0, "'{}' is not loaded as the maximum number of non-static GRFs has been reached", c->filename);
10205 c->status = GCS_DISABLED;
10206 c->error = {STR_NEWGRF_ERROR_MSG_FATAL, STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED};
10207 continue;
10208 }
10209 num_non_static++;
10210 }
10211
10212 num_grfs++;
10213
10214 LoadNewGRFFile(c, stage, subdir, false);
10215 if (stage == GLS_RESERVE) {
10217 } else if (stage == GLS_ACTIVATION) {
10219 assert(GetFileByGRFID(c->ident.grfid) == _cur.grffile);
10222 Debug(sprite, 2, "LoadNewGRF: Currently {} sprites are loaded", _cur.spriteid);
10223 } else if (stage == GLS_INIT && HasBit(c->flags, GCF_INIT_ONLY)) {
10224 /* We're not going to activate this, so free whatever data we allocated */
10226 }
10227 }
10228 }
10229
10230 /* Pseudo sprite processing is finished; free temporary stuff */
10231 _cur.ClearDataForNextFile();
10232
10233 /* Call any functions that should be run after GRFs have been loaded. */
10234 AfterLoadGRFs();
10235
10236 /* Now revert back to the original situation */
10239 TimerGameCalendar::date_fract = date_fract;
10240
10241 TimerGameEconomy::year = economy_year;
10242 TimerGameEconomy::date = economy_date;
10243 TimerGameEconomy::date_fract = economy_date_fract;
10244
10245 TimerGameTick::counter = tick_counter;
10246 _display_opt = display_opt;
10247}
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
@ 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 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
Class for backupping variables and making sure they are restored later.
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr bool HasExactlyOneBit(T value)
Test whether value has exactly 1 bit set.
constexpr T AssignBit(T &x, const uint8_t y, bool value)
Assigns a bit in a variable.
constexpr T SB(T &x, const uint8_t s, const uint8_t n, const U d)
Set n bits in x starting at bit s to d.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
static uint32_t BSWAP32(uint32_t x)
Perform a 32 bits endianness bitswap on x.
constexpr uint8_t FindFirstBit(T x)
Search the first set bit in a value.
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.
constexpr T ClrBit(T &x, const uint8_t y)
Clears a bit in a variable.
Header file for bridges.
constexpr uint SPRITES_PER_BRIDGE_PIECE
Number of sprites there are per bridge piece.
Definition bridge.h:36
static const uint MAX_BRIDGES
Maximal number of available bridge specs.
Definition bridge.h:35
BridgeSpec _bridge[MAX_BRIDGES]
The specification of all bridges.
void ResetBridges()
Reset the data been eventually changed by the grf loaded.
Tables with default industry layouts and behaviours.
static constexpr CargoLabel CT_INVALID
Invalid cargo type.
Definition cargo_type.h:71
uint8_t CargoID
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:22
bool IsValidCargoID(CargoID t)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:107
static constexpr CargoLabel CT_PASSENGERS
Available types of cargo Labels may be re-used between different climates.
Definition cargo_type.h:30
StrongType::Typedef< uint32_t, struct CargoLabelTag, StrongType::Compare > CargoLabel
Globally unique label of a cargo type.
Definition cargo_type.h:17
MixedCargoType
Mixed cargo types for definitions with cargo that can vary depending on climate.
Definition cargo_type.h:83
@ MCT_GRAIN_WHEAT_MAIZE
Cargo can be grain, wheat or maize.
Definition cargo_type.h:85
@ MCT_LIVESTOCK_FRUIT
Cargo can be livestock or fruit.
Definition cargo_type.h:84
@ MCT_VALUABLES_GOLD_DIAMONDS
Cargo can be valuables, gold or diamonds.
Definition cargo_type.h:86
static const CargoID NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:74
bool IsDefaultCargo(CargoID cid)
Test if a cargo is a default cargo type.
std::span< const CargoLabel > GetClimateDependentCargoTranslationTable()
Get default climate-dependent cargo translation table for a NewGRF, used if the NewGRF does not provi...
CargoTypes _standard_cargo_mask
Bitmask of real cargo types available.
Definition cargotype.cpp:38
std::span< const CargoLabel > GetClimateIndependentCargoTranslationTable()
Get default climate-independent cargo translation table for a NewGRF, used if the NewGRF does not pro...
void BuildCargoLabelMap()
Build cargo label map.
void InitializeSortedCargoSpecs()
Initialize the list of sorted cargo specifications.
void SetupCargoForClimate(LandscapeID l)
Set up the default cargo types for the given landscape type.
Definition cargotype.cpp:64
CargoTypes _cargo_mask
Bitmask of cargo types available.
Definition cargotype.cpp:33
@ CC_MAIL
Mail.
Definition cargotype.h:51
@ CC_REFRIGERATED
Refrigerated cargo (Food, Fruit)
Definition cargotype.h:57
@ CC_ARMOURED
Armoured cargo (Valuables, Gold, Diamonds)
Definition cargotype.h:53
@ CC_BULK
Bulk cargo (Coal, Grain etc., Ores, Fruit)
Definition cargotype.h:54
@ CC_EXPRESS
Express cargo (Goods, Food, Candy, but also possible for passengers)
Definition cargotype.h:52
@ CC_LIQUID
Liquids (Oil, Water, Rubber)
Definition cargotype.h:56
@ CC_PIECE_GOODS
Piece goods (Livestock, Wood, Steel, Paper)
Definition cargotype.h:55
@ CC_PASSENGERS
Passengers.
Definition cargotype.h:50
@ INVALID_TPE
Invalid town production effect.
Definition cargotype.h:44
@ TPE_NONE
Town will not produce this cargo type.
Definition cargotype.h:35
@ TPE_PASSENGERS
Cargo behaves passenger-like for production.
Definition cargotype.h:36
@ TPE_MAIL
Cargo behaves mail-like for production.
Definition cargotype.h:37
uint16_t CargoClasses
Bitmask of cargo classes.
Definition cargotype.h:69
@ TAE_GOODS
Cargo behaves goods/candy-like.
Definition cargotype.h:26
@ TAE_NONE
Cargo has no effect.
Definition cargotype.h:23
@ TAE_PASSENGERS
Cargo behaves passenger-like.
Definition cargotype.h:24
@ TAE_MAIL
Cargo behaves mail-like.
Definition cargotype.h:25
@ TAE_FOOD
Cargo behaves food/fizzy-drinks-like.
Definition cargotype.h:28
@ TAE_WATER
Cargo behaves water-like.
Definition cargotype.h:27
Class to read from a NewGRF file.
Definition newgrf.cpp:216
void SetEntitySpec(const HouseSpec *hs)
Install the specs into the HouseSpecs array It will find itself the proper slot on which it will go.
void SetEntitySpec(IndustrySpec *inds)
Method to install the new industry data in its proper slot The slot assignment is internal of this me...
static void Assign(Tspec *spec)
Assign a spec to one of the classes.
StringID name
Name of this class.
static NewGRFClass * Get(Tindex class_index)
Get a particular class.
static Tindex Allocate(uint32_t global_id)
Allocate a class with a given global class ID.
static void Reset()
Reset the classes, i.e.
void SetEntitySpec(ObjectSpec *spec)
Method to install the new object data in its proper slot The slot assignment is internal of this meth...
void ResetMapping()
Resets the mapping, which is used while initializing game.
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.
This struct contains all the info that is needed to draw and construct tracks.
Definition rail.h:127
uint16_t max_speed
Maximum speed for vehicles travelling on this rail type.
Definition rail.h:231
TimerGameCalendar::Date introduction_date
Introduction date.
Definition rail.h:255
struct RailTypeInfo::@26 strings
Strings associated with the rail type.
RailTypes powered_railtypes
bitmask to the OTHER railtypes on which an engine of THIS railtype generates power
Definition rail.h:188
RailTypes introduces_railtypes
Bitmask of which other railtypes are introduced when this railtype is introduced.
Definition rail.h:266
RailTypes introduction_required_railtypes
Bitmask of railtypes that are required for this railtype to be introduced at a given introduction_dat...
Definition rail.h:261
uint8_t sorting_order
The sorting order of this railtype for the toolbar dropdown.
Definition rail.h:271
RailTypeLabel label
Unique 32 bit rail type identifier.
Definition rail.h:236
uint16_t maintenance_multiplier
Cost multiplier for maintenance of this rail type.
Definition rail.h:221
const SpriteGroup * group[RTSG_END]
Sprite groups for resolving sprites.
Definition rail.h:281
uint8_t map_colour
Colour on mini-map.
Definition rail.h:246
StringID menu_text
Name of this rail type in the main toolbar dropdown.
Definition rail.h:178
StringID name
Name of this rail type.
Definition rail.h:176
RailTypes compatible_railtypes
bitmask to the OTHER railtypes on which an engine of THIS railtype can physically travel
Definition rail.h:191
uint8_t fallback_railtype
Original railtype number to use when drawing non-newgrf railtypes, or when drawing stations.
Definition rail.h:201
StringID toolbar_caption
Caption in the construction toolbar GUI for this rail type.
Definition rail.h:177
RailTypeFlags flags
Bit mask of rail type flags.
Definition rail.h:211
uint8_t curve_speed
Multiplier for curve maximum speed advantage.
Definition rail.h:206
uint16_t cost_multiplier
Cost multiplier for building this rail type.
Definition rail.h:216
StringID replace_text
Text used in the autoreplace GUI.
Definition rail.h:180
RailTypeLabelList alternate_labels
Rail type labels this type provides in addition to the main label.
Definition rail.h:241
StringID build_caption
Caption of the build vehicle GUI for this rail type.
Definition rail.h:179
StringID new_loco
Name of an engine for this type of rail in the engine preview GUI.
Definition rail.h:181
const GRFFile * grffile[RTSG_END]
NewGRF providing the Action3 for the railtype.
Definition rail.h:276
uint8_t acceleration_type
Acceleration type of this rail type.
Definition rail.h:226
void ReadBlock(void *ptr, size_t size)
Read a block.
size_t GetPos() const
Get position in the file.
void SeekTo(size_t pos, int mode)
Seek in the current file.
std::string filename
Full name of the file; relative path to subdir plus the extension of the file.
uint8_t ReadByte()
Read a byte from the file.
uint32_t ReadDword()
Read a double word (32 bits) from the file (in low endian format).
void SkipBytes(size_t n)
Skip n bytes ahead in the file.
uint16_t ReadWord()
Read a word (16 bits) from the file (in low endian format).
A reusable buffer that can be used for places that temporary allocate a bit of memory and do that ver...
T * Allocate(size_t count)
Get buffer of at least count times T.
StringID menu_text
Name of this rail type in the main toolbar dropdown.
Definition road.h:105
StringID replace_text
Text used in the autoreplace GUI.
Definition road.h:107
RoadTypeLabelList alternate_labels
Road type labels this type provides in addition to the main label.
Definition road.h:152
RoadTypes powered_roadtypes
bitmask to the OTHER roadtypes on which a vehicle of THIS roadtype generates power
Definition road.h:122
RoadTypes introduces_roadtypes
Bitmask of which other roadtypes are introduced when this roadtype is introduced.
Definition road.h:177
TimerGameCalendar::Date introduction_date
Introduction date.
Definition road.h:166
const SpriteGroup * group[ROTSG_END]
Sprite groups for resolving sprites.
Definition road.h:192
uint8_t sorting_order
The sorting order of this roadtype for the toolbar dropdown.
Definition road.h:182
uint16_t maintenance_multiplier
Cost multiplier for maintenance of this road type.
Definition road.h:137
RoadTypeFlags flags
Bit mask of road type flags.
Definition road.h:127
struct RoadTypeInfo::@29 strings
Strings associated with the rail type.
uint8_t map_colour
Colour on mini-map.
Definition road.h:157
const GRFFile * grffile[ROTSG_END]
NewGRF providing the Action3 for the roadtype.
Definition road.h:187
uint16_t max_speed
Maximum speed for vehicles travelling on this road type.
Definition road.h:142
StringID name
Name of this rail type.
Definition road.h:103
StringID toolbar_caption
Caption in the construction toolbar GUI for this rail type.
Definition road.h:104
StringID new_engine
Name of an engine for this type of road in the engine preview GUI.
Definition road.h:108
RoadTypes introduction_required_roadtypes
Bitmask of roadtypes that are required for this roadtype to be introduced at a given introduction_dat...
Definition road.h:172
uint16_t cost_multiplier
Cost multiplier for building this road type.
Definition road.h:132
StringID build_caption
Caption of the build vehicle GUI for this rail type.
Definition road.h:106
RandomAccessFile with some extra information specific for sprite files.
uint8_t GetContainerVersion() const
Get the version number of container type used by the file.
static Date ConvertYMDToDate(Year year, Month month, Day day)
Converts a tuple of Year, Month and Day to a Date.
static YearMonthDay ConvertDateToYMD(Date date)
Converts a Date to a Year, Month & Day.
static Date date
Current date in days (day counter).
static Year year
Current year, starting at 0.
static DateFract date_fract
Fractional part of the day.
static constexpr TimerGame< struct Calendar >::Year ORIGINAL_MAX_YEAR
The maximum year of the original TTD.
static constexpr TimerGame< struct Calendar >::Year MIN_YEAR
The absolute minimum year in OTTD.
static constexpr TimerGame< struct Calendar >::Year ORIGINAL_BASE_YEAR
The minimum starting year/base year of the original TTD.
static constexpr TimerGame< struct Calendar >::Date DAYS_TILL_ORIGINAL_BASE_YEAR
The date of the first day of the original base year.
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,...
static Date date
Current date in days (day counter).
static Year year
Current year, starting at 0.
static DateFract date_fract
Fractional part of the day.
static Date ConvertYMDToDate(Year year, Month month, Day day)
Converts a tuple of Year, Month and Day to a Date.
static TickCounter counter
Monotonic counter, in ticks, since start of game.
uint16_t DateFract
The fraction of a date we're in, i.e.
static constexpr bool IsLeapYear(Year year)
Checks whether the given year is a leap year or not.
Configuration options of the network stuff.
static const uint NETWORK_MAX_GRF_COUNT
Maximum number of GRFs that can be sent.
Definition config.h:90
Some simple functions to help with accessing containers.
int find_index(Container const &container, typename Container::const_reference item)
Helper function to get the index of an item Consider using std::set, std::unordered_set or std::flat_...
void ResetCurrencies(bool preserve_custom)
Will fill _currency_specs array with default values from origin_currency_specs Called only from newgr...
Definition currency.cpp:160
uint8_t GetNewgrfCurrencyIdConverted(uint8_t grfcurr_id)
Will return the ottd's index correspondence to the ttdpatch's id.
Definition currency.cpp:116
std::array< CurrencySpec, CURRENCY_END > _currency_specs
Array of currencies used by the system.
Definition currency.cpp:77
Functions to handle different currencies.
@ CURRENCY_END
always the last item
Definition currency.h:71
Functions related to debugging.
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition debug.h:37
Direction
Defines the 8 directions on the map.
@ DIR_W
West.
@ DIR_E
East.
void SetPriceBaseMultiplier(Price price, int factor)
Change a price base by the given factor.
Definition economy.cpp:899
void ResetPriceBaseMultipliers()
Reset changes to the price base multipliers.
Definition economy.cpp:887
Price
Enumeration of all base prices for use with Prices.
void SetYearEngineAgingStops()
Compute the value for _year_engine_aging_stops.
Definition engine.cpp:693
const uint8_t _engine_counts[4]
Number of engines of each vehicle type in original engine data.
Definition engine.cpp:54
void SetupEngines()
Initialise the engine pool with the data from the original vehicles.
Definition engine.cpp:601
const uint8_t _engine_offsets[4]
Offset of the first engine of each vehicle type in original engine data.
Definition engine.cpp:62
Base class for engines.
@ HasVariants
Set if engine has variants.
@ IsFolded
Set if display of variants should be folded (hidden).
Functions related to engines.
ExtraEngineFlags
Extra engine flags for NewGRF features.
static const EngineID INVALID_ENGINE
Constant denoting an invalid engine.
uint16_t EngineID
Unique identification number of an engine.
Definition engine_type.h:21
EngineClass
Type of rail engine.
Definition engine_type.h:33
@ EC_DIESEL
Diesel rail engine.
Definition engine_type.h:35
@ EC_STEAM
Steam rail engine.
Definition engine_type.h:34
@ EC_MAGLEV
Maglev engine.
Definition engine_type.h:38
@ EC_ELECTRIC
Electric rail engine.
Definition engine_type.h:36
@ EC_MONORAIL
Mono rail engine.
Definition engine_type.h:37
@ EF_USES_2CC
Vehicle uses two company colours.
@ EF_ROAD_TRAM
Road vehicle is a tram/light rail vehicle.
@ RAILVEH_SINGLEHEAD
indicates a "standalone" locomotive
Definition engine_type.h:27
@ RAILVEH_WAGON
simple wagon, not motorized
Definition engine_type.h:29
@ RAILVEH_MULTIHEAD
indicates a combination of two locomotives
Definition engine_type.h:28
Functions related to errors.
Error reporting related functions.
bool FioCheckFileExists(const std::string &filename, Subdirectory subdir)
Check whether the given file exists.
Definition fileio.cpp:121
Functions for Standard In/Out file operations.
Subdirectory
The different kinds of subdirectories OpenTTD uses.
@ NEWGRF_DIR
Subdirectory for all NewGRFs.
@ BASESET_DIR
Subdirectory for all base data (base sets, intro game)
Declarations for savegames operations.
Functions to read fonts from files and cache them.
void SetUnicodeGlyph(FontSize size, char32_t key, SpriteID sprite)
Map a SpriteID to the font size and key.
Definition fontcache.h:152
bool _generating_world
Whether we are generating the map or not.
Definition genworld.cpp:67
Functions related to world/map generation.
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:18
FontSize
Available font sizes.
Definition gfx_type.h:208
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:19
void SetSnowLine(uint8_t table[SNOW_LINE_MONTHS][SNOW_LINE_DAYS])
Set a variable snow line, as loaded from a newgrf file.
uint8_t GetSnowLine()
Get the current snow line, either variable or static.
bool IsSnowLineSet()
Has a snow line table already been loaded.
void ClearSnowLine()
Clear the variable snow line table and free the memory.
static const HouseID NUM_HOUSES
Total number of houses.
Definition house.h:27
static const HouseID NEW_HOUSE_OFFSET
Offset for new houses.
Definition house.h:26
static const HouseID NUM_HOUSES_PER_GRF
Number of supported houses per NewGRF.
Definition house.h:30
static const uint HOUSE_ORIGINAL_NUM_ACCEPTS
Original number of accepted cargo types.
Definition house.h:33
HouseZones
Definition house.h:66
@ HZ_ZONALL
1F This is just to englobe all above types at once
Definition house.h:73
@ HZ_CLIMALL
Bitmask of all climate bits.
Definition house.h:79
@ HZ_ZON5
center of town
Definition house.h:72
@ HZ_SUBARTC_ABOVE
11 800 can appear in sub-arctic climate above the snow line
Definition house.h:74
@ HZ_ZON1
0..4 1,2,4,8,10 which town zones the building can be built in, Zone1 been the further suburb
Definition house.h:68
HouseExtraFlags
Definition house.h:83
void ResetIndustries()
This function initialize the spec arrays of both industry and industry tiles.
void SortIndustryTypes()
Initialize the list of sorted industry types.
Accessors for industries.
@ GFX_WATERTILE_SPECIALCHECK
not really a tile, but rather a very special check
static const IndustryGfx NEW_INDUSTRYTILEOFFSET
original number of tiles
static const IndustryGfx INDUSTRYTILE_NOANIM
flag to mark industry tiles as having no animation
static const IndustryType NEW_INDUSTRYOFFSET
original number of industry types
static const int INDUSTRY_ORIGINAL_NUM_INPUTS
Original number of accepted cargo types.
static const IndustryGfx NUM_INDUSTRYTILES_PER_GRF
Maximum number of industry tiles per NewGRF; limited to 255 to allow extending Action3 with an extend...
static const IndustryGfx INVALID_INDUSTRYTILE
one above amount is considered invalid
static const int INDUSTRY_ORIGINAL_NUM_OUTPUTS
Original number of produced cargo types.
static const IndustryType NUM_INDUSTRYTYPES_PER_GRF
maximum number of industry types per NewGRF; limited to 128 because bit 7 has a special meaning in so...
Industry type specs.
IndustryLifeType
Available types of industry lifetimes.
@ CHECK_NOTHING
Always succeeds.
std::vector< IndustryTileLayoutTile > IndustryTileLayout
A complete tile layout for an industry is a list of tiles.
IndustryBehaviour
Various industry behaviours mostly to represent original TTD specialities.
IndustryTileSpecialFlags
Flags for miscellaneous industry tile specialities.
Functions related to OTTD's landscape.
static const uint SNOW_LINE_DAYS
Number of days in each month in the snow line table.
Definition landscape.h:17
static const uint SNOW_LINE_MONTHS
Number of months in the snow line table.
Definition landscape.h:16
Information about languages and their files.
static const uint8_t MAX_NUM_GENDERS
Maximum number of supported genders.
Definition language.h:20
const LanguageMetadata * GetLanguage(uint8_t newgrflangid)
Get the language with the given NewGRF language ID.
Definition strings.cpp:2072
static const uint8_t MAX_NUM_CASES
Maximum number of supported cases.
Definition language.h:21
LiveryScheme
List of different livery schemes.
Definition livery.h:21
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition math_func.hpp:23
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
constexpr bool IsInsideMM(const T x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
void MemSetT(T *ptr, uint8_t value, size_t num=1)
Type-safe version of memset().
Definition mem_func.hpp:49
static constexpr CargoID SG_DEFAULT
Default type used when no more-specific cargo matches.
static constexpr CargoID SG_PURCHASE
Used in purchase lists before an item exists.
static constexpr CargoID SG_DEFAULT_NA
Used only by stations and roads when no more-specific cargo matches.
bool _networking
are we in networking mode?
Definition network.cpp:65
static void FinaliseObjectsArray()
Add all new objects to the object array.
Definition newgrf.cpp:9577
static void FinalisePriceBaseMultipliers()
Decide whether price base multipliers of grfs shall apply globally or only to the grf specifying them...
Definition newgrf.cpp:9878
std::span< const Action5Type > GetAction5Types()
Get list of all action 5 types.
Definition newgrf.cpp:6467
static void ResetCustomStations()
Reset and clear all NewGRF stations.
Definition newgrf.cpp:8757
static void SkipAct12(ByteReader &buf)
Action 0x12 (SKIP)
Definition newgrf.cpp:8082
static std::vector< GRFTempEngineData > _gted
Temporary engine data used during NewGRF loading.
Definition newgrf.cpp:348
static CargoLabel GetActiveCargoLabel(const std::initializer_list< CargoLabel > &labels)
Find first cargo label that exists and is active from a list of cargo labels.
Definition newgrf.cpp:9015
bool GetGlobalVariable(uint8_t param, uint32_t *value, const GRFFile *grffile)
Reads a variable common to VarAction2 and Action7/9/D.
Definition newgrf.cpp:6584
static bool ChangeGRFParamType(size_t len, ByteReader &buf)
Callback function for 'INFO'->'PARAM'->param_num->'TYPE' to set the typeof a parameter.
Definition newgrf.cpp:8291
bool(* BranchHandler)(ByteReader &)
Type of callback function for branch nodes.
Definition newgrf.cpp:8365
StringID MapGRFStringID(uint32_t grfid, StringID str)
Used when setting an object's property to map to the GRF's strings while taking in consideration the ...
Definition newgrf.cpp:560
static uint16_t SanitizeSpriteOffset(uint16_t &num, uint16_t offset, int max_sprites, const std::string_view name)
Sanitize incoming sprite offsets for Action 5 graphics replacements.
Definition newgrf.cpp:6411
static void FinaliseIndustriesArray()
Add all new industries to the industry array.
Definition newgrf.cpp:9503
static bool ChangeGRFParamLimits(size_t len, ByteReader &buf)
Callback function for 'INFO'->'PARAM'->param_num->'LIMI' to set the min/max value of a parameter.
Definition newgrf.cpp:8308
static void AddStringForMapping(StringID source, std::function< void(StringID)> &&func)
Record a static StringID for getting translated later.
Definition newgrf.cpp:473
std::span< const CargoLabel > GetCargoTranslationTable(const GRFFile &grffile)
Get the cargo translation table to use for the given GRF file.
Definition newgrf.cpp:5591
static bool ChangeGRFNumUsedParams(size_t len, ByteReader &buf)
Callback function for 'INFO'->'NPAR' to set the number of valid parameters.
Definition newgrf.cpp:8182
void ResetPersistentNewGRFData()
Reset NewGRF data which is stored persistently in savegames.
Definition newgrf.cpp:8926
static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, ByteReader &buf)
Define properties for stations.
Definition newgrf.cpp:1933
static uint32_t _grm_cargoes[NUM_CARGO *2]
Contains the GRF ID of the owner of a cargo if it has been reserved.
Definition newgrf.cpp:357
static bool ChangeGRFURL(uint8_t langid, std::string_view str)
Callback function for 'INFO'->'URL_' to set the newgrf url.
Definition newgrf.cpp:8175
static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader &buf)
Define properties for road vehicles.
Definition newgrf.cpp:1368
bool(* DataHandler)(size_t, ByteReader &)
Type of callback function for binary nodes.
Definition newgrf.cpp:8363
static ChangeInfoResult CommonVehicleChangeInfo(EngineInfo *ei, int prop, ByteReader &buf)
Define properties common to all vehicles.
Definition newgrf.cpp:1017
static void FinaliseAirportsArray()
Add all new airports to the airport array.
Definition newgrf.cpp:9595
static ChangeInfoResult AirportChangeInfo(uint airport, int numinfo, int prop, ByteReader &buf)
Define properties for airports.
Definition newgrf.cpp:3935
static GRFFile * GetFileByFilename(const std::string &filename)
Obtain a NewGRF file by its filename.
Definition newgrf.cpp:413
static bool ChangeGRFParamDescription(uint8_t langid, std::string_view str)
Callback function for 'INFO'->'PARAM'->param_num->'DESC' to set the description of a parameter.
Definition newgrf.cpp:8284
static ChangeInfoResult CanalChangeInfo(uint id, int numinfo, int prop, ByteReader &buf)
Define properties for water features.
Definition newgrf.cpp:2213
static void InitNewGRFFile(const GRFConfig *config)
Prepare loading a NewGRF file with its config.
Definition newgrf.cpp:8960
static bool ChangeGRFMinVersion(size_t len, ByteReader &buf)
Callback function for 'INFO'->'MINV' to the minimum compatible version of the NewGRF.
Definition newgrf.cpp:8255
static bool IsHouseSpecValid(HouseSpec *hs, const HouseSpec *next1, const HouseSpec *next2, const HouseSpec *next3, const std::string &filename)
Check if a given housespec is valid and disable it if it's not.
Definition newgrf.cpp:9354
static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, ByteReader &buf)
Define properties for global variables.
Definition newgrf.cpp:2755
AllowedSubtags _tags_root[]
Action14 root tags.
Definition newgrf.cpp:8543
static ChangeInfoResult CargoChangeInfo(uint cid, int numinfo, int prop, ByteReader &buf)
Define properties for cargoes.
Definition newgrf.cpp:3050
static bool ChangeGRFParamDefault(size_t len, ByteReader &buf)
Callback function for 'INFO'->'PARAM'->param_num->'DFLT' to set the default value.
Definition newgrf.cpp:8351
static ChangeInfoResult BridgeChangeInfo(uint brid, int numinfo, int prop, ByteReader &buf)
Define properties for bridges.
Definition newgrf.cpp:2251
static void TranslateGRFStrings(ByteReader &buf)
Action 0x13.
Definition newgrf.cpp:8108
static void GRFUnsafe(ByteReader &)
Set the current NewGRF as unsafe for static use.
Definition newgrf.cpp:8658
static void DefineGotoLabel(ByteReader &buf)
Action 0x10 - Define goto label.
Definition newgrf.cpp:7881
static void ActivateOldShore()
Relocates the old shore sprites at new positions.
Definition newgrf.cpp:9826
static void EnsureEarlyHouse(HouseZones bitmask)
Make sure there is at least one house available in the year 0 for the given climate / housezone combi...
Definition newgrf.cpp:9400
static const uint NUM_STATIONS_PER_GRF
The maximum amount of stations a single GRF is allowed to add.
Definition newgrf.cpp:312
static void ParamSet(ByteReader &buf)
Action 0x0D: Set parameter.
Definition newgrf.cpp:7453
static bool ChangeGRFParamValueNames(ByteReader &buf)
Callback function for 'INFO'->'PARA'->param_num->'VALU' to set the names of some parameter values (ty...
Definition newgrf.cpp:8455
static GRFFile * GetCurrentGRFOverride()
Get overridden GRF for current GRF if present.
Definition newgrf.cpp:609
static void LoadNewGRFFileFromFile(GRFConfig *config, GrfLoadingStage stage, SpriteFile &file)
Load a particular NewGRF from a SpriteFile.
Definition newgrf.cpp:9701
static void FinaliseEngineArray()
Check for invalid engines.
Definition newgrf.cpp:9257
static const SpriteGroup * CreateGroupFromGroupID(uint8_t feature, uint8_t setid, uint8_t type, uint16_t spriteid)
Helper function to either create a callback or a result sprite group.
Definition newgrf.cpp:5201
static ChangeInfoResult LoadTranslationTable(uint gvid, int numinfo, ByteReader &buf, TGetTableFunc gettable, std::string_view name)
Load a cargo- or railtype-translation table.
Definition newgrf.cpp:2709
static ChangeInfoResult IndustrytilesChangeInfo(uint indtid, int numinfo, int prop, ByteReader &buf)
Define properties for industry tiles.
Definition newgrf.cpp:3303
static bool HandleParameterInfo(ByteReader &buf)
Callback function for 'INFO'->'PARA' to set extra information about the parameters.
Definition newgrf.cpp:8502
static void ReadSpriteLayoutRegisters(ByteReader &buf, TileLayoutFlags flags, bool is_parent, NewGRFSpriteLayout *dts, uint index)
Preprocess the TileLayoutFlags and read register modifiers from the GRF.
Definition newgrf.cpp:817
static GRFParameterInfo * _cur_parameter
The parameter which info is currently changed by the newgrf.
Definition newgrf.cpp:8274
static ChangeInfoResult AircraftVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader &buf)
Define properties for aircraft.
Definition newgrf.cpp:1764
static uint32_t _grm_engines[256]
Contains the GRF ID of the owner of a vehicle if it has been reserved.
Definition newgrf.cpp:354
static bool HandleNode(uint8_t type, uint32_t id, ByteReader &buf, AllowedSubtags subtags[])
Handle the nodes of an Action14.
Definition newgrf.cpp:8595
static void ResetNewGRFErrors()
Clear all NewGRF errors.
Definition newgrf.cpp:8817
uint8_t _misc_grf_features
Miscellaneous GRF features, set by Action 0x0D, parameter 0x9E.
Definition newgrf.cpp:78
AllowedSubtags _tags_info[]
Action14 tags for the INFO node.
Definition newgrf.cpp:8529
static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader &buf)
Define properties for ships.
Definition newgrf.cpp:1573
static void SetNewGRFOverride(uint32_t source_grfid, uint32_t target_grfid)
Set the override for a NewGRF.
Definition newgrf.cpp:594
static bool ChangeGRFName(uint8_t langid, std::string_view str)
Callback function for 'INFO'->'NAME' to add a translation to the newgrf name.
Definition newgrf.cpp:8161
static std::vector< StringIDMapping > _string_to_grf_mapping
Strings to be mapped during load.
Definition newgrf.cpp:466
static ChangeInfoResult RoadTypeChangeInfo(uint id, int numinfo, int prop, ByteReader &buf, RoadTramType rtt)
Define properties for roadtypes.
Definition newgrf.cpp:4483
static void LoadGRFSound(size_t offs, SoundEntry *sound)
Load a sound from a file.
Definition newgrf.cpp:7930
static StringID TTDPStringIDToOTTDStringIDMapping(StringID str)
Perform a mapping from TTDPatch's string IDs to OpenTTD's string IDs, but only for the ones we are aw...
Definition newgrf.cpp:496
bool(* TextHandler)(uint8_t, std::string_view str)
Type of callback function for text nodes.
Definition newgrf.cpp:8364
GRFLoadedFeatures _loaded_newgrf_features
Indicates which are the newgrf features currently loaded ingame.
Definition newgrf.cpp:84
static const uint MAX_SPRITEGROUP
Maximum GRF-local ID for a spritegroup.
Definition newgrf.cpp:86
void LoadNewGRF(SpriteID load_index, uint num_baseset)
Load all the NewGRFs.
Definition newgrf.cpp:10117
static void InitializeGRFSpecial()
Initialize the TTDPatch flags.
Definition newgrf.cpp:8668
static std::string ReadDWordAsString(ByteReader &reader)
Helper to read a DWord worth of bytes from the reader and to return it as a valid string.
Definition newgrf.cpp:2740
static void ClearTemporaryNewGRFData(GRFFile *gf)
Reset all NewGRFData that was used only while processing data.
Definition newgrf.cpp:422
static void FinaliseCanals()
Set to use the correct action0 properties for each canal feature.
Definition newgrf.cpp:9246
AllowedSubtags _tags_parameters[]
Action14 parameter tags.
Definition newgrf.cpp:8485
static bool IsValidNewGRFImageIndex(uint8_t image_index)
Helper to check whether an image index is valid for a particular NewGRF vehicle.
Definition newgrf.cpp:208
static ChangeInfoResult RailTypeChangeInfo(uint id, int numinfo, int prop, ByteReader &buf)
Define properties for railtypes.
Definition newgrf.cpp:4265
void LoadNewGRFFile(GRFConfig *config, GrfLoadingStage stage, Subdirectory subdir, bool temporary)
Load a particular NewGRF.
Definition newgrf.cpp:9790
static ChangeInfoResult IgnoreObjectProperty(uint prop, ByteReader &buf)
Ignore properties for objects.
Definition newgrf.cpp:4088
void ResetNewGRFData()
Reset all NewGRF loaded data.
Definition newgrf.cpp:8827
static bool IsGRMReservedSprite(SpriteID first_sprite, uint16_t num_sprites)
Check if a sprite ID range is within the GRM reversed range for the currently loading NewGRF.
Definition newgrf.cpp:7115
static void CalculateRefitMasks()
Precalculate refit masks from cargo classes for all vehicles.
Definition newgrf.cpp:9050
void FinaliseCargoArray()
Check for invalid cargoes.
Definition newgrf.cpp:9324
static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader &buf)
Define properties for rail vehicles.
Definition newgrf.cpp:1060
static CargoTypes TranslateRefitMask(uint32_t refit_mask)
Translate the refit mask.
Definition newgrf.cpp:963
static void StaticGRFInfo(ByteReader &buf)
Handle Action 0x14.
Definition newgrf.cpp:8648
static GRFFile * GetFileByGRFID(uint32_t grfid)
Obtain a NewGRF file by its grfID.
Definition newgrf.cpp:400
static ChangeInfoResult IgnoreRoadStopProperty(uint prop, ByteReader &buf)
Ignore properties for roadstops.
Definition newgrf.cpp:4792
static ChangeInfoResult IgnoreIndustryProperty(int prop, ByteReader &buf)
Ignore an industry property.
Definition newgrf.cpp:3438
static void BuildCargoTranslationMap()
Construct the Cargo Mapping.
Definition newgrf.cpp:8941
static bool ChangeGRFParamMask(size_t len, ByteReader &buf)
Callback function for 'INFO'->'PARAM'->param_num->'MASK' to set the parameter and bits to use.
Definition newgrf.cpp:8330
static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, ByteReader &buf)
Define properties for industries.
Definition newgrf.cpp:3561
static void ImportGRFSound(SoundEntry *sound)
Process a sound import from another GRF file.
Definition newgrf.cpp:7899
static bool SkipUnknownInfo(ByteReader &buf, uint8_t type)
Try to skip the current node and all subnodes (if it's a branch node).
Definition newgrf.cpp:8555
static ChangeInfoResult IgnoreTownHouseProperty(int prop, ByteReader &buf)
Ignore a house property.
Definition newgrf.cpp:2362
static bool ReadSpriteLayout(ByteReader &buf, uint num_building_sprites, bool use_cur_spritesets, uint8_t feature, bool allow_var10, bool no_z_position, NewGRFSpriteLayout *dts)
Read a spritelayout from the GRF.
Definition newgrf.cpp:870
void GrfMsgI(int severity, const std::string &msg)
Debug() function dedicated to newGRF debugging messages Function is essentially the same as Debug(grf...
Definition newgrf.cpp:390
static void ResetCustomHouses()
Reset and clear all NewGRF houses.
Definition newgrf.cpp:8765
EngineID GetNewEngineID(const GRFFile *file, VehicleType type, uint16_t internal_id)
Return the ID of a new engine.
Definition newgrf.cpp:711
static bool ChangeGRFDescription(uint8_t langid, std::string_view str)
Callback function for 'INFO'->'DESC' to add a translation to the newgrf description.
Definition newgrf.cpp:8168
static void LoadFontGlyph(ByteReader &buf)
Action 0x12.
Definition newgrf.cpp:8051
static void ResetCustomIndustries()
Reset and clear all NewGRF industries.
Definition newgrf.cpp:8782
static std::vector< GRFFile * > _grf_files
List of all loaded GRF files.
Definition newgrf.cpp:70
static void ResetCustomObjects()
Reset and clear all NewObjects.
Definition newgrf.cpp:8791
static void ConvertTTDBasePrice(uint32_t base_pointer, const char *error_location, Price *index)
Converts TTD(P) Base Price pointers into the enum used by OTTD See http://wiki.ttdpatch....
Definition newgrf.cpp:980
static void FinaliseHouseArray()
Add all new houses to the house array.
Definition newgrf.cpp:9425
static bool ChangeGRFPalette(size_t len, ByteReader &buf)
Callback function for 'INFO'->'PALS' to set the number of valid parameters.
Definition newgrf.cpp:8194
static constexpr auto _action5_types
The information about action 5 types.
Definition newgrf.cpp:6433
static bool ChangeGRFVersion(size_t len, ByteReader &buf)
Callback function for 'INFO'->'VRSN' to the version of the NewGRF.
Definition newgrf.cpp:8242
ChangeInfoResult
Possible return values for the FeatureChangeInfo functions.
Definition newgrf.cpp:1000
@ CIR_INVALID_ID
Attempt to modify an invalid ID.
Definition newgrf.cpp:1005
@ CIR_DISABLED
GRF was disabled due to error.
Definition newgrf.cpp:1002
@ CIR_UNKNOWN
Variable is unknown.
Definition newgrf.cpp:1004
@ CIR_UNHANDLED
Variable was parsed but unread.
Definition newgrf.cpp:1003
@ CIR_SUCCESS
Variable was parsed and read.
Definition newgrf.cpp:1001
static bool ValidateIndustryLayout(const IndustryTileLayout &layout)
Validate the industry layout; e.g.
Definition newgrf.cpp:3528
static TileLayoutFlags ReadSpriteLayoutSprite(ByteReader &buf, bool read_flags, bool invert_action1_flag, bool use_cur_spritesets, int feature, PalSpriteID *grf_sprite, uint16_t *max_sprite_offset=nullptr, uint16_t *max_palette_offset=nullptr)
Read a sprite and a palette from the GRF and convert them into a format suitable to OpenTTD.
Definition newgrf.cpp:759
static void DisableStaticNewGRFInfluencingNonStaticNewGRFs(GRFConfig *c)
Disable a static NewGRF when it is influencing another (non-static) NewGRF as this could cause desync...
Definition newgrf.cpp:6862
static void ActivateOldTramDepot()
Replocate the old tram depot sprites to the new position, if no new ones were loaded.
Definition newgrf.cpp:9863
static uint32_t _ttdpatch_flags[8]
32 * 8 = 256 flags.
Definition newgrf.cpp:81
static ChangeInfoResult IgnoreIndustryTileProperty(int prop, ByteReader &buf)
Ignore an industry tile property.
Definition newgrf.cpp:3263
static Engine * GetNewEngine(const GRFFile *file, VehicleType type, uint16_t internal_id, bool static_access=false)
Returns the engine associated to a certain internal_id, resp.
Definition newgrf.cpp:627
static void MapSpriteMappingRecolour(PalSpriteID *grf_sprite)
Map the colour modifiers of TTDPatch to those that Open is using.
Definition newgrf.cpp:728
static void AfterLoadGRFs()
Finish loading NewGRFs and execute needed post-processing.
Definition newgrf.cpp:9994
static bool ChangeGRFParamName(uint8_t langid, std::string_view str)
Callback function for 'INFO'->'PARAM'->param_num->'NAME' to set the name of a parameter.
Definition newgrf.cpp:8277
static void ResetNewGRF()
Reset and clear all NewGRFs.
Definition newgrf.cpp:8806
void InitGRFTownGeneratorNames()
Allocate memory for the NewGRF town names.
static ChangeInfoResult SoundEffectChangeInfo(uint sid, int numinfo, int prop, ByteReader &buf)
Define properties for sound effects.
Definition newgrf.cpp:3208
static bool ChangeGRFBlitter(size_t len, ByteReader &buf)
Callback function for 'INFO'->'BLTR' to set the blitter info.
Definition newgrf.cpp:8220
static GRFError * DisableGrf(StringID message=STR_NULL, GRFConfig *config=nullptr)
Disable a GRF.
Definition newgrf.cpp:433
static void FeatureTownName(ByteReader &buf)
Action 0x0F - Define Town names.
Definition newgrf.cpp:7803
static void ResetCustomAirports()
Reset and clear all NewGRF airports.
Definition newgrf.cpp:8773
static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, ByteReader &buf)
Define properties for objects.
Definition newgrf.cpp:4135
static std::vector< CachedCallback > _cached_callback_groups
Sorted list of cached callback result spritegroups.
Definition newgrf.cpp:5156
static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, ByteReader &buf)
Define properties for houses.
Definition newgrf.cpp:2429
@ GMB_TRAIN_WIDTH_32_PIXELS
Use 32 pixels per train vehicle in depot gui and vehicle details. Never set in the global variable;.
Definition newgrf.h:61
@ TRAMWAY_REPLACE_DEPOT_WITH_TRACK
Electrified depot graphics with tram track were loaded.
Definition newgrf.h:171
@ TRAMWAY_REPLACE_DEPOT_NO_TRACK
Electrified depot graphics without tram track were loaded.
Definition newgrf.h:172
@ TRAMWAY_REPLACE_DEPOT_NONE
No tram depot graphics were loaded.
Definition newgrf.h:170
@ SHORE_REPLACE_ACTION_A
Shore sprites were replaced by ActionA (using grass tiles for the corner-shores).
Definition newgrf.h:165
@ SHORE_REPLACE_NONE
No shore sprites were replaced.
Definition newgrf.h:163
@ SHORE_REPLACE_ONLY_NEW
Only corner-shores were loaded by Action5 (openttd(w/d).grf only).
Definition newgrf.h:166
@ SHORE_REPLACE_ACTION_5
Shore sprites were replaced by Action5.
Definition newgrf.h:164
Information about NewGRF Action 5.
@ A5BLOCK_ALLOW_OFFSET
Allow replacing any subset by specifiing an offset.
Definition newgrf_act5.h:16
@ A5BLOCK_INVALID
unknown/not-implemented type
Definition newgrf_act5.h:17
@ A5BLOCK_FIXED
Only allow replacing a whole block of sprites. (TTDP compatible)
Definition newgrf_act5.h:15
void BindAirportSpecs()
Tie all airportspecs to their class.
NewGRF handling of airports.
TTDPAirportType
Allow incrementing of AirportClassID variables.
NewGRF handling of airport tiles.
static const uint8_t ANIM_STATUS_NO_ANIMATION
There is no animation.
@ CBID_VEHICLE_CUSTOM_REFIT
Called to get custom engine refit mask.
@ CBM_VEHICLE_CUSTOM_REFIT
Custom refit mask.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
WaterFeature _water_feature[CF_END]
Table of canal 'feature' sprite groups.
Handling of NewGRF canals.
CargoID GetCargoTranslation(uint8_t cargo, const GRFFile *grffile, bool usebit)
Translate a GRF-local cargo slot/bitnum into a CargoID.
Cargo support for NewGRFs.
void ErrorUnknownCallbackResult(uint32_t grfid, uint16_t cbid, uint16_t cb_res)
Record that a NewGRF returned an unknown/invalid callback result.
static const uint TLR_MAX_VAR10
Maximum value for var 10.
TileLayoutFlags
Flags to enable register usage in sprite layouts.
@ TLF_BB_Z_OFFSET
Add signed offset to bounding box Z positions from register TileLayoutRegisters::delta....
@ TLF_CUSTOM_PALETTE
Palette is from Action 1 (moved to SPRITE_MODIFIER_CUSTOM_SPRITE in palette during loading).
@ TLF_SPRITE
Add signed offset to sprite from register TileLayoutRegisters::sprite.
@ TLF_CHILD_X_OFFSET
Add signed offset to child sprite X positions from register TileLayoutRegisters::delta....
@ TLF_DRAWING_FLAGS
Flags which are still required after loading the GRF.
@ TLF_DODRAW
Only draw sprite if value of register TileLayoutRegisters::dodraw is non-zero.
@ TLF_PALETTE_REG_FLAGS
Flags which require resolving the action-1-2-3 chain for the palette, even if it is no action-1 palet...
@ TLF_NON_GROUND_FLAGS
Flags which do not work for the (first) ground sprite.
@ TLF_BB_XY_OFFSET
Add signed offset to bounding box X and Y positions from register TileLayoutRegisters::delta....
@ TLF_SPRITE_REG_FLAGS
Flags which require resolving the action-1-2-3 chain for the sprite, even if it is no action-1 sprite...
@ TLF_PALETTE_VAR10
Resolve palette with a specific value in variable 10.
@ TLF_SPRITE_VAR10
Resolve sprite with a specific value in variable 10.
@ TLF_KNOWN_FLAGS
Known flags. Any unknown set flag will disable the GRF.
@ TLF_PALETTE
Add signed offset to palette from register TileLayoutRegisters::palette.
@ TLF_CHILD_Y_OFFSET
Add signed offset to child sprite Y positions from register TileLayoutRegisters::delta....
GRFConfig * _grfconfig
First item in list of current GRF set up.
GRFConfig * GetGRFConfig(uint32_t grfid, uint32_t mask)
Retrieve a NewGRF from the current config by its grfid.
GRFPalette
Information that can/has to be stored about a GRF's palette.
@ GRFP_GRF_UNSET
The NewGRF provided no information.
@ GRFP_BLT_UNSET
The NewGRF provided no information or doesn't care about a 32 bpp blitter.
@ GRFP_GRF_WINDOWS
The NewGRF says the Windows palette can be used.
@ GRFP_GRF_DOS
The NewGRF says the DOS palette can be used.
@ GRFP_GRF_ANY
The NewGRF says any palette can be used.
@ GRFP_BLT_32BPP
The NewGRF prefers a 32 bpp blitter.
@ GRFP_USE_MASK
Bitmask to get only the use palette use states.
@ GCF_INIT_ONLY
GRF file is processed up to GLS_INIT.
@ GCF_INVALID
GRF is unusable with this version of OpenTTD.
@ GCF_STATIC
GRF file is used statically (can be used in any MP game)
@ GCF_UNSAFE
GRF file is unsafe for static usage.
@ GCF_RESERVED
GRF file passed GLS_RESERVE stage.
@ GCF_SYSTEM
GRF file is an openttd-internal system grf.
@ GCS_INITIALISED
GRF file has been initialised.
@ GCS_DISABLED
GRF file is disabled.
@ GCS_NOT_FOUND
GRF file was not found in the local cache.
@ GCS_UNKNOWN
The status of this grf file is unknown.
@ GCS_ACTIVATED
GRF file has been activated.
GRFParameterType
The possible types of a newgrf parameter.
@ PTYPE_UINT_ENUM
The parameter allows a range of numbers, each of which can have a special name.
@ PTYPE_END
Invalid parameter type.
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.
uint16_t GetVehicleCallback(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v)
Evaluate a newgrf callback for vehicles.
void CommitVehicleListOrderChanges()
Deternine default engine sorting and execute recorded ListOrderChanges from AlterVehicleListOrder.
void AlterVehicleListOrder(EngineID engine, uint16_t target)
Record a vehicle ListOrderChange.
Functions for NewGRF engines.
void AddGenericCallback(uint8_t feature, const GRFFile *file, const SpriteGroup *group)
Add a generic feature callback sprite group to the appropriate feature list.
void ResetGenericCallbacks()
Reset all generic feature callback sprite groups.
Functions related to NewGRF houses.
IndustryType MapNewGRFIndustryType(IndustryType grf_type, uint32_t grf_id)
Map the GRF local type to an industry type.
Functions for NewGRF industries.
void ResetObjects()
This function initialize the spec arrays of objects.
Functions related to NewGRF objects.
static const uint8_t OBJECT_SIZE_1X1
The value of a NewGRF's size property when the object is 1x1 tiles: low nibble for X,...
ObjectFlags
Various object behaviours.
@ OBJECT_FLAG_2CC_COLOUR
Object wants 2CC colour mapping.
@ PROP_AIRCRAFT_PASSENGER_CAPACITY
Passenger Capacity.
@ PROP_ROADVEH_CARGO_AGE_PERIOD
Number of ticks before carried cargo is aged.
@ PROP_TRAIN_SHORTEN_FACTOR
Shorter vehicles.
@ PROP_TRAIN_CURVE_SPEED_MOD
Modifier to maximum speed in curves.
@ PROP_ROADVEH_WEIGHT
Weight in 1/4 t.
@ PROP_TRAIN_COST_FACTOR
Purchase cost (if dualheaded: sum of both vehicles)
@ PROP_TRAIN_USER_DATA
User defined data for vehicle variable 0x42.
@ PROP_TRAIN_WEIGHT
Weight in t (if dualheaded: for each single vehicle)
@ PROP_AIRCRAFT_RANGE
Aircraft range.
@ PROP_TRAIN_CARGO_CAPACITY
Capacity (if dualheaded: for each single vehicle)
@ PROP_AIRCRAFT_RUNNING_COST_FACTOR
Yearly runningcost.
@ PROP_VEHICLE_LOAD_AMOUNT
Loading speed.
@ PROP_ROADVEH_RUNNING_COST_FACTOR
Yearly runningcost.
@ PROP_TRAIN_TRACTIVE_EFFORT
Tractive effort coefficient in 1/256.
@ PROP_SHIP_CARGO_CAPACITY
Capacity.
@ PROP_ROADVEH_TRACTIVE_EFFORT
Tractive effort coefficient in 1/256.
@ PROP_SHIP_COST_FACTOR
Purchase cost.
@ PROP_ROADVEH_CARGO_CAPACITY
Capacity.
@ PROP_AIRCRAFT_SPEED
Max. speed: 1 unit = 8 mph = 12.8 km-ish/h.
@ PROP_AIRCRAFT_MAIL_CAPACITY
Mail Capacity.
@ PROP_SHIP_SPEED
Max. speed: 1 unit = 1/3.2 mph = 0.5 km-ish/h.
@ PROP_SHIP_RUNNING_COST_FACTOR
Yearly runningcost.
@ PROP_TRAIN_CARGO_AGE_PERIOD
Number of ticks before carried cargo is aged.
@ PROP_ROADVEH_COST_FACTOR
Purchase cost.
@ PROP_ROADVEH_SHORTEN_FACTOR
Shorter vehicles.
@ PROP_ROADVEH_POWER
Power in 10 HP.
@ PROP_SHIP_CARGO_AGE_PERIOD
Number of ticks before carried cargo is aged.
@ PROP_AIRCRAFT_COST_FACTOR
Purchase cost.
@ PROP_TRAIN_RUNNING_COST_FACTOR
Yearly runningcost (if dualheaded: sum of both vehicles)
@ PROP_AIRCRAFT_CARGO_AGE_PERIOD
Number of ticks before carried cargo is aged.
@ PROP_TRAIN_POWER
Power in hp (if dualheaded: sum of both vehicles)
@ PROP_TRAIN_SPEED
Max. speed: 1 unit = 1/1.6 mph = 1 km-ish/h.
@ PROP_ROADVEH_SPEED
Max. speed: 1 unit = 1/0.8 mph = 2 km-ish/h.
NewGRF definitions and structures for road stops.
RoadStopDrawMode
Different draw modes to disallow rendering of some parts of the stop or road.
RoadStopAvailabilityType
Various different options for availability, restricting the roadstop to be only for busses or for tru...
static const int NUM_ROADSTOPS_PER_GRF
The maximum amount of roadstops a single GRF is allowed to add.
SoundEntry * AllocateSound(uint num)
Allocate sound slots.
SoundID GetNewGRFSoundID(const GRFFile *file, SoundID sound_id)
Resolve NewGRF sound ID.
Functions related to NewGRF provided sounds.
DeterministicSpriteGroupAdjustOperation
@ DSGA_OP_ADD
a + b
@ VSG_SCOPE_SELF
Resolved object itself.
@ VSG_SCOPE_PARENT
Related object of the resolved one.
@ VSG_SCOPE_RELATIVE
Relative position (vehicles only)
Header file for NewGRF stations.
uint16_t GetStationLayoutKey(uint8_t platforms, uint8_t length)
Get the station layout key for a given station layout size.
StationClassID
void CleanUpStrings()
House cleaning.
static void AddGRFTextToList(GRFTextList &list, uint8_t langid, std::string_view text_to_add)
Add a new text to a GRFText list.
std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool allow_newlines, std::string_view str, StringControlCode byte80)
Translate TTDPatch string codes into something OpenTTD can handle (better).
StringID AddGRFString(uint32_t grfid, uint16_t stringid, uint8_t langid_to_add, bool new_scheme, bool allow_newlines, std::string_view text_to_add, StringID def_string)
Add the new read string into our structure.
StringID GetGRFStringID(uint32_t grfid, StringID stringid)
Returns the index for this stringid associated with its grfID.
Header of Action 04 "universal holder" structure and functions.
std::vector< GRFText > GRFTextList
A GRF text with a list of translations.
static const char32_t NFO_UTF8_IDENTIFIER
This character (thorn) indicates a unicode string to NFO.
Header of Action 0F "universal holder" structure and functions.
static const ObjectType NUM_OBJECTS_PER_GRF
Number of supported objects per NewGRF.
Definition object_type.h:24
RailType GetRailTypeByLabel(RailTypeLabel label, bool allow_alternate_labels)
Get the rail type for a given label.
Definition rail.cpp:311
RailType AllocateRailType(RailTypeLabel label)
Allocate a new rail type label.
Definition rail_cmd.cpp:150
void InitRailTypes()
Resolve sprites of custom rail types.
Definition rail_cmd.cpp:130
void ResetRailTypes()
Reset all rail type information to its default values.
Definition rail_cmd.cpp:65
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition rail.h:307
RailTypeFlags
Railtype flags.
Definition rail.h:35
RailType
Enumeration for all possible railtypes.
Definition rail_type.h:27
@ RAILTYPE_END
Used for iterations.
Definition rail_type.h:33
@ RAILTYPE_MONO
Monorail.
Definition rail_type.h:31
@ INVALID_RAILTYPE
Flag for invalid railtype.
Definition rail_type.h:34
@ RAILTYPE_ELECTRIC
Electric rails.
Definition rail_type.h:30
@ RAILTYPE_RAIL
Standard non-electric rails.
Definition rail_type.h:29
@ RAILTYPE_MAGLEV
Maglev.
Definition rail_type.h:32
declaration of OTTD revision dependent variables
RoadType GetRoadTypeByLabel(RoadTypeLabel label, bool allow_alternate_labels)
Get the road type for a given label.
Definition road.cpp:254
Road specific functions.
void ResetRoadTypes()
Reset all road type information to its default values.
Definition road_cmd.cpp:67
void InitRoadTypes()
Resolve sprites of custom road types.
Definition road_cmd.cpp:114
RoadTypeFlags
Roadtype flags.
Definition road.h:46
RoadType AllocateRoadType(RoadTypeLabel label, RoadTramType rtt)
Allocate a new road type label.
Definition road_cmd.cpp:134
RoadType
The different roadtypes we support.
Definition road_type.h:25
@ INVALID_ROADTYPE
flag for invalid roadtype
Definition road_type.h:30
@ ROADTYPE_TRAM
Trams.
Definition road_type.h:28
@ ROADTYPE_ROAD
Basic road type.
Definition road_type.h:27
@ ROADTYPE_END
Used for iterations.
Definition road_type.h:29
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:57
@ SP_CUSTOM
No profile, special "custom" highscore.
Slope
Enumeration for the slope-type.
Definition slope_type.h:48
void BuildLinkStatsLegend()
Populate legend table for the link stat view.
void BuildIndustriesLegend()
Fills an array for the industries legends.
Smallmap GUI functions.
static const uint ORIGINAL_SAMPLE_COUNT
The number of sounds in the original sample.cat.
Definition sound_type.h:124
SpriteFile & OpenCachedSpriteFile(const std::string &filename, Subdirectory subdir, bool palette_remap)
Open/get the SpriteFile that is cached for use in the sprite cache.
bool LoadNextSprite(SpriteID load_index, SpriteFile &file, uint file_sprite_id)
Load a real or recolour sprite.
size_t GetGRFSpriteOffset(uint32_t id)
Get the file offset for a specific sprite in the sprite section of a GRF.
bool SkipSpriteData(SpriteFile &file, uint8_t type, uint16_t num)
Skip the given amount of sprite graphics data.
void ReadGRFSpriteOffsets(SpriteFile &file)
Parse the sprite section of GRFs.
static constexpr uint8_t SPRITE_MODIFIER_OPAQUE
Set when a sprite must not ever be displayed transparently.
Definition sprites.h:1546
static const SpriteID SPR_AQUEDUCT_BASE
Sprites for the Aqueduct.
Definition sprites.h:186
static const SpriteID SPR_OPENTTD_BASE
Extra graphic spritenumbers.
Definition sprites.h:56
static const SpriteID SPR_TRACKS_FOR_SLOPES_BASE
Sprites for 'highlighting' tracks on sloped land.
Definition sprites.h:198
static const SpriteID SPR_ROAD_WAYPOINTS_BASE
Road waypoint sprites.
Definition sprites.h:311
static constexpr uint8_t PALETTE_MODIFIER_TRANSPARENT
when a sprite is to be displayed transparently, this bit needs to be set.
Definition sprites.h:1547
static const SpriteID SPR_RAILTYPE_TUNNEL_BASE
Tunnel sprites with grass only for custom railtype tunnel.
Definition sprites.h:299
static const SpriteID SPR_TRAMWAY_BASE
Tramway sprites.
Definition sprites.h:272
static constexpr uint8_t SPRITE_MODIFIER_CUSTOM_SPRITE
these masks change the colours of the palette for a sprite.
Definition sprites.h:1545
static constexpr uint8_t SPRITE_WIDTH
number of bits for the sprite number
Definition sprites.h:1535
static const SpriteID SPR_AIRPORT_PREVIEW_BASE
Airport preview sprites.
Definition sprites.h:248
static constexpr uint8_t PALETTE_MODIFIER_COLOUR
this bit is set when a recolouring process is in action
Definition sprites.h:1548
static const SpriteID SPR_ONEWAY_BASE
One way road sprites.
Definition sprites.h:293
static const SpriteID SPR_SHORE_BASE
shore tiles - action 05-0D
Definition sprites.h:224
static constexpr uint MAX_CATCHMENT
Maximum catchment for airports with "modified catchment" enabled.
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:280
static void StrMakeValid(T &dst, const char *str, const char *last, StringValidationSettings settings)
Copies the valid (UTF-8) characters from str up to last to the dst.
Definition string.cpp:107
size_t Utf8Decode(char32_t *c, const char *s)
Decode and consume the next UTF-8 encoded character.
Definition string.cpp:419
Functions related to low-level strings.
size_t ttd_strnlen(const char *str, size_t maxlen)
Get the length of a string, within a limited buffer.
Definition string_func.h:69
std::string GetString(StringID string)
Resolve the given StringID into a std::string with all the associated DParam lookups and formatting.
Definition strings.cpp:333
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
static const uint MAX_LANG
Maximum number of languages supported by the game, and the NewGRF specs.
Information about a single action 5 type.
Definition newgrf_act5.h:21
Action5BlockType block_type
How is this Action5 type processed?
Definition newgrf_act5.h:22
uint16_t max_sprites
If the Action5 contains more sprites, only the first max_sprites sprites will be used.
Definition newgrf_act5.h:25
uint16_t min_sprites
If the Action5 contains less sprites, the whole block will be ignored.
Definition newgrf_act5.h:24
SpriteID sprite_base
Load the sprites starting from this sprite.
Definition newgrf_act5.h:23
const std::string_view name
Name for error messages.
Definition newgrf_act5.h:26
Information about a aircraft vehicle.
uint16_t max_speed
Maximum speed (1 unit = 8 mph = 12.8 km-ish/h)
uint8_t mail_capacity
Mail capacity (bags).
uint8_t subtype
Type of aircraft.
uint16_t passenger_capacity
Passenger capacity (persons).
uint16_t max_range
Maximum range of this aircraft.
Defines the data structure for an airport.
static void ResetAirports()
This function initializes the airportspec array.
struct GRFFileProps grf_prop
Properties related to the grf file.
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.
Defines the data structure of each individual tile of an airport.
static const AirportTileSpec * Get(StationGfx gfx)
Retrieve airport tile spec for the given airport tile.
GRFFileProps grf_prop
properties related the the grf file
static void ResetAirportTiles()
This function initializes the tile array of AirportTileSpec.
Data structure to store the allowed id/type combinations for action 14.
Definition newgrf.cpp:8374
AllowedSubtags * subtags
Pointer to a list of subtags, only valid if type == 'C' && !call_handler.
Definition newgrf.cpp:8439
uint32_t id
The identifier for this node.
Definition newgrf.cpp:8431
AllowedSubtags(uint32_t id, BranchHandler handler)
Create a branch node with a callback handler.
Definition newgrf.cpp:8410
uint8_t type
The type of the node, must be one of 'C', 'B' or 'T'.
Definition newgrf.cpp:8432
AllowedSubtags(uint32_t id, DataHandler handler)
Create a binary leaf node.
Definition newgrf.cpp:8386
TextHandler text
Callback function for a text node, only valid if type == 'T'.
Definition newgrf.cpp:8435
AllowedSubtags()
Create empty subtags object used to identify the end of a list.
Definition newgrf.cpp:8376
AllowedSubtags(uint32_t id, AllowedSubtags *subtags)
Create a branch node with a list of sub-nodes.
Definition newgrf.cpp:8423
bool call_handler
True if there is a callback function for this node, false if there is a list of subnodes.
Definition newgrf.cpp:8441
DataHandler data
Callback function for a binary node, only valid if type == 'B'.
Definition newgrf.cpp:8434
AllowedSubtags(uint32_t id, TextHandler handler)
Create a text leaf node.
Definition newgrf.cpp:8398
BranchHandler branch
Callback function for a branch node, only valid if type == 'C' && call_handler.
Definition newgrf.cpp:8438
uint8_t frames
The number of frames.
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
Struct containing information about a single bridge type.
Definition bridge.h:43
uint16_t price
the price multiplier
Definition bridge.h:47
uint8_t min_length
the minimum length (not counting start and end tile)
Definition bridge.h:45
StringID material
the string that contains the bridge description
Definition bridge.h:51
TimerGameCalendar::Year avail_year
the year where it becomes available
Definition bridge.h:44
PalSpriteID ** sprite_table
table of sprites for drawing the bridge
Definition bridge.h:53
StringID transport_name[2]
description of the bridge, when built for road or rail
Definition bridge.h:52
uint8_t flags
bit 0 set: disable drawing of far pillars.
Definition bridge.h:54
uint16_t speed
maximum travel speed (1 unit = 1/1.6 mph = 1 km-ish/h)
Definition bridge.h:48
uint16_t max_length
the maximum length (not counting start and end tile)
Definition bridge.h:46
Canal properties local to the NewGRF.
Definition newgrf.h:40
uint8_t callback_mask
Bitmask of canal callbacks that have to be called.
Definition newgrf.h:41
uint8_t flags
Flags controlling display.
Definition newgrf.h:42
Specification of a cargo type.
Definition cargotype.h:76
int32_t initial_payment
Initial payment rate before inflation is applied.
Definition cargotype.h:84
CargoClasses classes
Classes of this cargo type.
Definition cargotype.h:83
uint16_t multiplier
Capacity multiplier for vehicles. (8 fractional bits)
Definition cargotype.h:82
StringID units_volume
Name of a single unit of cargo of this type.
Definition cargotype.h:95
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo ID.
Definition cargotype.h:139
StringID abbrev
Two letter abbreviation for this cargo type.
Definition cargotype.h:97
uint8_t bitnum
Cargo bit number, is INVALID_CARGO_BITNUM for a non-used spec.
Definition cargotype.h:78
StringID quantifier
Text for multiple units of cargo of this type.
Definition cargotype.h:96
SpriteID sprite
Icon to display this cargo type, may be 0xFFF (which means to resolve an action123 chain).
Definition cargotype.h:99
bool is_freight
Cargo type is considered to be freight (affects train freight multiplier).
Definition cargotype.h:87
uint8_t weight
Weight of a single unit of this cargo type in 1/16 ton (62.5 kg).
Definition cargotype.h:81
CargoLabel label
Unique label of the cargo type.
Definition cargotype.h:77
const struct GRFFile * grffile
NewGRF where group belongs to.
Definition cargotype.h:101
static IterateWrapper Iterate(size_t from=0)
Returns an iterable ensemble of all valid CargoSpec.
Definition cargotype.h:195
static CargoSpec array[NUM_CARGO]
Array holding all CargoSpecs.
Definition cargotype.h:201
uint8_t callback_mask
Bitmask of cargo callbacks that have to be called.
Definition cargotype.h:91
StringID name
Name of this type of cargo.
Definition cargotype.h:93
TownProductionEffect town_production_effect
The effect on town cargo production.
Definition cargotype.h:89
TownAcceptanceEffect town_acceptance_effect
The effect that delivering this cargo type has on towns. Also affects destination of subsidies.
Definition cargotype.h:88
uint16_t town_production_multiplier
Town production multipler, if commanded by TownProductionEffect.
Definition cargotype.h:90
bool IsValid() const
Tests for validity of this cargospec.
Definition cargotype.h:120
StringID name_single
Name of a single entity of this type of cargo.
Definition cargotype.h:94
bool build_on_slopes
allow building on slopes
uint16_t max_bridge_length
maximum length of bridges
uint8_t map_height_limit
the maximum allowed heightlevel
uint8_t train_signal_side
show signals on left / driving / right side
uint8_t parameter
Used for variables between 0x60 and 0x7F inclusive.
A tile child sprite and palette to draw for stations etc, with 3D bounding box.
Definition sprite.h:25
int8_t delta_z
0x80 identifies child sprites
Definition sprite.h:28
bool IsParentSprite() const
Check whether this is a parent sprite with a boundingbox.
Definition sprite.h:47
bool IsTerminator() const
Check whether this is a sequence terminator.
Definition sprite.h:41
int8_t delta_x
0x80 is sequence terminator
Definition sprite.h:26
Ground palette sprite of a tile, together with its sprite layout.
Definition sprite.h:58
const DrawTileSeqStruct * seq
Array of child sprites. Terminated with a terminator entry.
Definition sprite.h:60
PalSpriteID ground
Palette and sprite for the ground.
Definition sprite.h:59
bool inflation
disable inflation
bool allow_town_roads
towns are allowed to build roads (always allowed when generating world / in SE)
bool station_noise_level
build new airports when the town noise level is still within accepted limits
Information about a vehicle.
uint16_t cargo_age_period
Number of ticks before carried cargo is aged.
TimerGameCalendar::Year base_life
Basic duration of engine availability (without random parts). 0xFF means infinite life.
EngineID variant_id
Engine variant ID. If set, will be treated specially in purchase lists.
uint8_t misc_flags
Miscellaneous flags.
StringID string_id
Default name of engine.
uint8_t climates
Climates supported by the engine.
TimerGameCalendar::Date base_intro
Basic date of engine introduction (without random parts).
uint16_t callback_mask
Bitmask of vehicle callbacks that have to be called.
int8_t retire_early
Number of years early to retire vehicle.
TimerGameCalendar::Year lifelength
Lifetime of a single vehicle.
void ResetToDefaultMapping()
Initializes the EngineOverrideManager with the default engines.
Definition engine.cpp:509
EngineID UseUnreservedID(VehicleType type, uint16_t grf_local_id, uint32_t grfid, bool static_access)
Look for an unreserved EngineID matching the local id, and reserve it if found.
Definition engine.cpp:549
EngineID GetID(VehicleType type, uint16_t grf_local_id, uint32_t grfid)
Looks up an EngineID in the EngineOverrideManager.
Definition engine.cpp:530
GRFFilePropsBase< NUM_CARGO+2 > grf_prop
Properties related the the grf file.
Definition engine_base.h:82
const GRFFile * GetGRF() const
Retrieve the NewGRF the engine is tied to.
static Pool::IterateWrapperFiltered< Engine, EngineTypeFilter > IterateType(VehicleType vt, size_t from=0)
Returns an iterable ensemble of all valid engines of the given type.
VehicleType type
Vehicle type, ie VEH_ROAD, VEH_TRAIN, etc.
Definition engine_base.h:60
Information about GRF, used in the game and (part of it) in savegames.
GRFTextWrapper url
NOSAVE: URL belonging to this GRF.
uint8_t palette
GRFPalette, bitset.
uint8_t flags
NOSAVE: GCF_Flags, bitset.
GRFTextWrapper info
NOSAVE: GRF info (author, copyright, ...) (Action 0x08)
std::vector< std::optional< GRFParameterInfo > > param_info
NOSAVE: extra information about the parameters.
uint32_t version
NOSAVE: Version a NewGRF can set so only the newest NewGRF is shown.
std::vector< uint32_t > param
GRF parameters.
bool has_param_defaults
NOSAVE: did this newgrf specify any defaults for it's parameters.
GRFTextWrapper name
NOSAVE: GRF name (Action 0x08)
struct GRFConfig * next
NOSAVE: Next item in the linked list.
GRFStatus status
NOSAVE: GRFStatus, enum.
std::optional< GRFError > error
NOSAVE: Error/Warning during GRF loading (Action 0x0B)
uint8_t num_valid_params
NOSAVE: Number of valid parameters (action 0x14)
std::string filename
Filename - either with or without full path.
GRFIdentifier ident
grfid and md5sum to uniquely identify newgrfs
const char * GetName() const
Get the name of this grf.
uint32_t min_loadable_version
NOSAVE: Minimum compatible version a NewGRF can define.
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.
StringID message
Default message.
std::string custom_message
Custom message (if present)
std::string data
Additional data for message and custom_message.
bool HasGrfFile() const
Test if this entity was introduced by NewGRF.
uint16_t local_id
id defined by the grf file for this entity
uint32_t grfid
grfid that introduced this entity.
const struct GRFFile * grffile
grf file that introduced this entity
std::array< const struct SpriteGroup *, Tcnt > spritegroup
pointers to the different sprites of the entity
Dynamic data of a loaded NewGRF.
Definition newgrf.h:108
std::array< uint8_t, NUM_CARGO > cargo_map
Inverse cargo translation table (CargoID -> local ID)
Definition newgrf.h:130
std::vector< RailTypeLabel > railtype_list
Railtype translation table.
Definition newgrf.h:132
uint32_t GetParam(uint number) const
Get GRF Parameter with range checking.
Definition newgrf.h:154
CanalProperties canal_local_properties[CF_END]
Canal properties as set by this NewGRF.
Definition newgrf.h:141
std::vector< RoadTypeLabel > roadtype_list
Roadtype translation table (road)
Definition newgrf.h:135
uint32_t grf_features
Bitset of GrfSpecFeature the grf uses.
Definition newgrf.h:148
GRFFile(const struct GRFConfig *config)
Constructor for GRFFile.
Definition newgrf.cpp:8977
std::vector< RoadTypeLabel > tramtype_list
Roadtype translation table (tram)
Definition newgrf.h:138
std::vector< CargoLabel > cargo_list
Cargo translation table (local ID -> label)
Definition newgrf.h:129
uint traininfo_vehicle_width
Width (in pixels) of a 8/8 train vehicle in depot GUI and vehicle details.
Definition newgrf.h:146
int traininfo_vehicle_pitch
Vertical offset for drawing train images in depot GUI and vehicle details.
Definition newgrf.h:145
std::unordered_map< uint8_t, LanguageMap > language_map
Mappings related to the languages.
Definition newgrf.h:143
std::vector< GRFLabel > labels
List of labels.
Definition newgrf.h:127
PriceMultipliers price_base_multipliers
Price base multipliers as set by the grf.
Definition newgrf.h:149
uint32_t grfid
GRF ID (defined by Action 0x08)
bool has_2CC
Set if any vehicle is loaded which uses 2cc (two company colours).
Definition newgrf.h:176
ShoreReplacement shore
In which way shore sprites were replaced.
Definition newgrf.h:178
uint64_t used_liveries
Bitmask of LiveryScheme used by the defined engines.
Definition newgrf.h:177
TramReplacement tram
In which way tram depots were replaced.
Definition newgrf.h:179
Information about one grf parameter.
std::map< uint32_t, GRFTextList > value_names
Names for each value.
uint8_t param_nr
GRF parameter to store content in.
uint32_t min_value
The minimal value this parameter can have.
uint8_t num_bit
Number of bits to use for this parameter.
uint8_t first_bit
First bit to use in the GRF parameter.
uint32_t max_value
The maximal value of this parameter.
GRFParameterType type
The type of this parameter.
uint32_t def_value
Default value of this parameter.
GRFTextList name
The name of this parameter.
GRFTextList desc
The description of this parameter.
Temporary engine data used when loading only.
Definition newgrf.cpp:315
CargoTypes ctt_exclude_mask
Cargo types always excluded from the refit mask.
Definition newgrf.cpp:332
Refittability refittability
Did the newgrf set any refittability property? If not, default refittability will be applied.
Definition newgrf.cpp:329
CargoClasses cargo_disallowed
Bitmask of cargo classes that are disallowed as a refit.
Definition newgrf.cpp:325
CargoTypes ctt_include_mask
Cargo types always included in the refit mask.
Definition newgrf.cpp:331
Refittability
Summary state of refittability properties.
Definition newgrf.cpp:317
@ UNSET
No properties assigned. Default refit masks shall be activated.
Definition newgrf.cpp:318
@ EMPTY
GRF defined vehicle as not-refittable. The vehicle shall only carry the default cargo.
Definition newgrf.cpp:319
@ NONEMPTY
GRF defined the vehicle as refittable. If the refitmask is empty after translation (cargotypes not av...
Definition newgrf.cpp:320
uint8_t rv_max_speed
Temporary storage of RV prop 15, maximum speed in mph/0.8.
Definition newgrf.cpp:330
CargoClasses cargo_allowed
Bitmask of cargo classes that are allowed as a refit.
Definition newgrf.cpp:323
void UpdateRefittability(bool non_empty)
Update the summary refittability on setting a refittability property.
Definition newgrf.cpp:338
CargoClasses cargo_allowed_required
Bitmask of cargo classes that are required to be all present to allow a cargo as a refit.
Definition newgrf.cpp:324
const GRFFile * defaultcargo_grf
GRF defining the cargo translation table to use if the default cargo is the 'first refittable'.
Definition newgrf.cpp:328
std::vector< NamePartList > partlists[MAX_LISTS]
Lists of town name parts.
static const uint MAX_LISTS
Maximum number of town name lists that can be defined per GRF.
std::vector< TownNameStyle > styles
Style names defined by the Town Name NewGRF.
uint8_t landscape
the landscape we're currently in
TimerGameCalendar::Year starting_year
starting date
uint32_t generation_seed
noise seed for world generation
EconomySettings economy
settings to change the economy
ConstructionSettings construction
construction of things in-game
GameCreationSettings game_creation
settings used during the creation of a game (map)
StationSettings station
settings related to station management
VehicleSettings vehicle
options for vehicles
OrderSettings order
settings related to orders
Definition of a single Action1 spriteset.
Definition newgrf.cpp:92
uint num_sprites
Number of sprites in the set.
Definition newgrf.cpp:94
SpriteID sprite
SpriteID of the first sprite of the set.
Definition newgrf.cpp:93
Temporary data during loading of GRFs.
Definition newgrf.cpp:89
SpriteFile * file
File of currently processed GRF file.
Definition newgrf.cpp:106
GRFFile * grffile
Currently processed GRF file.
Definition newgrf.cpp:107
void AddSpriteSets(uint8_t feature, SpriteID first_sprite, uint first_set, uint numsets, uint numents)
Records new spritesets.
Definition newgrf.cpp:138
uint32_t nfo_line
Currently processed pseudo sprite number in the GRF.
Definition newgrf.cpp:109
SpriteID spriteid
First available SpriteID for loading realsprites.
Definition newgrf.cpp:103
GRFConfig * grfconfig
Config of the currently processed GRF file.
Definition newgrf.cpp:108
SpriteID GetSprite(uint8_t feature, uint set) const
Returns the first sprite of a spriteset.
Definition newgrf.cpp:179
bool IsValidSpriteSet(uint8_t feature, uint set) const
Check whether a specific set is defined.
Definition newgrf.cpp:167
uint GetNumEnts(uint8_t feature, uint set) const
Returns the number of sprites in a spriteset.
Definition newgrf.cpp:191
bool HasValidSpriteSets(uint8_t feature) const
Check whether there are any valid spritesets for a feature.
Definition newgrf.cpp:154
std::map< uint, SpriteSet > spritesets[GSF_END]
Currently referenceable spritesets.
Definition newgrf.cpp:98
void ClearDataForNextFile()
Clear temporary data before processing the next file in the current loading stage.
Definition newgrf.cpp:118
GrfLoadingStage stage
Current loading stage.
Definition newgrf.cpp:102
int skip_sprites
Number of pseudo sprites to skip before processing the next one. (-1 to skip to end of file)
Definition newgrf.cpp:112
CargoID accepts_cargo[HOUSE_NUM_ACCEPTS]
input cargo slots
Definition house.h:103
bool enabled
the house is available to build (true by default, but can be disabled by newgrf)
Definition house.h:106
CargoLabel accepts_cargo_label[HOUSE_ORIGINAL_NUM_ACCEPTS]
input landscape cargo slots
Definition house.h:120
static HouseSpec * Get(size_t house_id)
Get the spec for a house ID.
BuildingFlags building_flags
some flags that describe the house (size, stadium etc...)
Definition house.h:104
uint8_t population
population (Zero on other tiles in multi tile house.)
Definition house.h:97
uint8_t cargo_acceptance[HOUSE_NUM_ACCEPTS]
acceptance level for the cargo slots
Definition house.h:102
TimerGameCalendar::Year min_year
introduction year of the house
Definition house.h:95
GRFFileProps grf_prop
Properties related the the grf file.
Definition house.h:109
HouseZones building_availability
where can it be built (climates, zones)
Definition house.h:105
static std::vector< HouseSpec > & Specs()
Get a reference to all HouseSpecs.
uint16_t add_output[INDUSTRY_NUM_OUTPUTS]
Add this much output cargo when successful (unsigned, is indirect in cb version 1+)
CargoID cargo_input[INDUSTRY_NUM_INPUTS]
Which input cargoes to take from (only cb version 2)
uint8_t num_input
How many subtract_input values are valid.
int16_t subtract_input[INDUSTRY_NUM_INPUTS]
Take this much of the input cargo (can be negative, is indirect in cb version 1+)
uint8_t version
Production callback version used, or 0xFF if marked invalid.
uint8_t num_output
How many add_output values are valid.
CargoID cargo_output[INDUSTRY_NUM_OUTPUTS]
Which output cargoes to add to (only cb version 2)
Defines the data structure for constructing industry.
std::array< CargoID, INDUSTRY_NUM_INPUTS > accepts_cargo
16 accepted cargoes.
StringID production_up_text
Message appearing when the industry's production is increasing.
StringID name
Displayed name of the industry.
std::array< std::variant< CargoLabel, MixedCargoType >, INDUSTRY_ORIGINAL_NUM_INPUTS > accepts_cargo_label
Cargo labels of accepted cargo for default industries.
IndustryType conflicting[3]
Industries this industry cannot be close to.
GRFFileProps grf_prop
properties related to the grf file
StringID production_down_text
Message appearing when the industry's production is decreasing.
StringID station_name
Default name for nearby station.
StringID closure_text
Message appearing when the industry closes.
StringID new_industry_text
Message appearing when the industry is built.
bool enabled
entity still available (by default true).newgrf can disable it, though
std::array< std::variant< CargoLabel, MixedCargoType >, INDUSTRY_ORIGINAL_NUM_OUTPUTS > produced_cargo_label
Cargo labels of produced cargo for default industries.
Definition of one tile in an industry tile layout.
Defines the data structure of each individual tile of an industry.
std::array< CargoID, INDUSTRY_NUM_INPUTS > accepts_cargo
Cargo accepted by this tile.
GRFFileProps grf_prop
properties related to the grf file
std::array< std::variant< CargoLabel, MixedCargoType >, INDUSTRY_ORIGINAL_NUM_INPUTS > accepts_cargo_label
Cargo labels of accepted cargo for default industry tiles.
Mapping between NewGRF and OpenTTD IDs.
uint8_t newgrf_id
NewGRF's internal ID for a case/gender.
uint8_t openttd_id
OpenTTD's internal ID for a case/gender.
Mapping of language data between a NewGRF and OpenTTD.
static const LanguageMap * GetLanguageMap(uint32_t grfid, uint8_t language_id)
Get the language map associated with a given NewGRF and language.
Definition newgrf.cpp:2687
Make sure the size is right.
Definition language.h:93
uint8_t GetGenderIndex(const char *gender_str) const
Get the index for the given gender.
Definition language.h:68
uint8_t GetCaseIndex(const char *case_str) const
Get the index for the given case.
Definition language.h:81
static debug_inline uint LogX()
Logarithm of the map size along the X side.
Definition map_func.h:251
static uint LogY()
Logarithm of the map size along the y side.
Definition map_func.h:261
uint8_t bitcount
Number of bits of random seed to use.
uint16_t maxprob
Total probability of all parts.
std::vector< NamePart > parts
List of parts to choose from.
uint8_t bitstart
Start of random seed bits to use.
uint8_t prob
The relative probability of the following name to appear in the bottom 7 bits.
uint8_t id
If probability bit 7 is set.
std::string text
If probability bit 7 is clear.
NewGRF supplied spritelayout.
void Allocate(uint num_sprites)
Allocate a spritelayout for num_sprites building sprites.
uint consistent_max_offset
Number of sprites in all referenced spritesets.
void Clone(const DrawTileSeqStruct *source)
Clone the building sprites of a spritelayout.
void AllocateRegisters()
Allocate memory for register modifiers.
Allow incrementing of ObjectClassID variables.
GRFFilePropsBase< 2 > grf_prop
Properties related the the grf file.
static void BindToClasses()
Tie all ObjectSpecs to their class.
bool improved_load
improved loading algorithm
bool gradual_loading
load vehicles gradually
Combination of a palette sprite and a 'real' sprite.
Definition gfx_type.h:23
SpriteID sprite
The 'real' sprite.
Definition gfx_type.h:24
PaletteID pal
The palette (use PAL_NONE) if not needed)
Definition gfx_type.h:25
static size_t GetPoolSize()
Returns first unused index.
Tindex index
Index of this pool item.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
static Titem * Get(size_t index)
Returns Titem with given index.
void CleanPool() override
Virtual method that deletes all items in the pool.
Describes properties of price bases.
Price fallback_price
Fallback price multiplier for new prices but old grfs.
uint grf_feature
GRF Feature that decides whether price multipliers apply locally or globally, GSF_END if none.
Information about a rail vehicle.
Definition engine_type.h:42
uint16_t power
Power of engine (hp); For multiheaded engines the sum of both engine powers.
Definition engine_type.h:50
uint8_t user_def_data
Property 0x25: "User-defined bit mask" Used only for (very few) NewGRF vehicles.
Definition engine_type.h:62
uint8_t running_cost
Running cost of engine; For multiheaded engines the sum of both running costs.
Definition engine_type.h:52
uint8_t cost_factor
Purchase cost factor; For multiheaded engines the sum of both engine prices.
Definition engine_type.h:45
uint8_t shorten_factor
length on main map for this type is 8 - shorten_factor
Definition engine_type.h:59
RailType intended_railtype
Intended railtype, regardless of elrail being enabled or disabled.
Definition engine_type.h:47
uint16_t pow_wag_power
Extra power applied to consist if wagon should be powered.
Definition engine_type.h:56
uint16_t max_speed
Maximum speed (1 unit = 1/1.6 mph = 1 km-ish/h)
Definition engine_type.h:49
int16_t curve_speed_mod
Modifier to maximum speed in curves (fixed-point binary with 8 fractional bits)
Definition engine_type.h:63
uint16_t weight
Weight of vehicle (tons); For multiheaded engines the weight of each single engine.
Definition engine_type.h:51
uint8_t capacity
Cargo capacity of vehicle; For multiheaded engines the capacity of each single engine.
Definition engine_type.h:55
uint8_t visual_effect
Bitstuffed NewGRF visual effect data.
Definition engine_type.h:58
uint8_t air_drag
Coefficient of air drag.
Definition engine_type.h:61
EngineClass engclass
Class of engine for this vehicle.
Definition engine_type.h:54
uint8_t ai_passenger_only
Bit value to tell AI that this engine is for passenger use only.
Definition engine_type.h:48
RailType railtype
Railtype, mangled if elrail is disabled.
Definition engine_type.h:46
uint8_t tractive_effort
Tractive effort coefficient.
Definition engine_type.h:60
uint8_t pow_wag_weight
Extra weight applied to consist if wagon should be powered.
Definition engine_type.h:57
uint8_t lowest_randbit
Look for this in the per-object randomized bitmask:
VarSpriteGroupScope var_scope
Take this object:
std::vector< const SpriteGroup * > groups
Take the group with appropriate index:
RandomizedSpriteGroupCompareMode cmp_mode
Check for these triggers:
std::vector< const SpriteGroup * > loaded
List of loaded groups (can be SpriteIDs or Callback results)
std::vector< const SpriteGroup * > loading
List of loading groups (can be SpriteIDs or Callback results)
Road stop specification.
GRFFilePropsBase< NUM_CARGO+3 > grf_prop
Properties related the the grf file.
Information about a road vehicle.
uint8_t tractive_effort
Coefficient of tractive effort.
uint16_t max_speed
Maximum speed (1 unit = 1/3.2 mph = 0.5 km-ish/h)
uint8_t air_drag
Coefficient of air drag.
uint8_t power
Power in 10hp units.
RoadType roadtype
Road type.
uint8_t weight
Weight in 1/4t units.
uint8_t shorten_factor
length on main map for this type is 8 - shorten_factor
uint8_t visual_effect
Bitstuffed NewGRF visual effect data.
Iterable ensemble of each set bit in a value.
Information about a ship vehicle.
Definition engine_type.h:67
bool old_refittable
Is ship refittable; only used during initialisation. Later use EngineInfo::refit_mask.
Definition engine_type.h:75
uint8_t ocean_speed_frac
Fraction of maximum speed for ocean tiles.
Definition engine_type.h:77
uint8_t visual_effect
Bitstuffed NewGRF visual effect data.
Definition engine_type.h:76
uint16_t max_speed
Maximum speed (1 unit = 1/3.2 mph = 0.5 km-ish/h)
Definition engine_type.h:72
uint8_t acceleration
Acceleration (1 unit = 1/3.2 mph per tick = 0.5 km-ish/h per tick)
Definition engine_type.h:71
uint8_t canal_speed_frac
Fraction of maximum speed for canal/river tiles.
Definition engine_type.h:78
uint8_t grf_container_ver
NewGRF container version if the sound is from a NewGRF.
Definition sound_type.h:30
bool never_expire_airports
never expire airports
Station specification.
std::unordered_map< uint16_t, std::vector< uint8_t > > layouts
Custom platform layouts, keyed by platform and length combined.
@ NoWires
Tile should NOT contain catenary wires.
@ Pylons
Tile should contain catenary pylons.
@ Blocked
Tile is blocked to vehicles.
GRFFilePropsBase< NUM_CARGO+3 > grf_prop
Properties related the the grf file.
CargoTypes cargo_triggers
Bitmask of cargo types which cause trigger re-randomizing.
std::vector< NewGRFSpriteLayout > renderdata
Number of tile layouts.
Information for mapping static StringIDs.
Definition newgrf.cpp:457
uint32_t grfid
Source NewGRF.
Definition newgrf.cpp:458
StringID source
Source StringID (GRF local).
Definition newgrf.cpp:459
std::function< void(StringID)> func
Function for mapping result.
Definition newgrf.cpp:460
Templated helper to make a type-safe 'typedef' representing a single POD value.
int16_t x
The x value of the coordinate.
Definition map_type.h:32
int16_t y
The y value of the coordinate.
Definition map_type.h:33
Additional modifiers for items in sprite layouts.
uint8_t parent[3]
Registers for signed offsets for the bounding box position of parent sprites.
TileLayoutFlags flags
Flags defining which members are valid and to be used.
uint8_t dodraw
Register deciding whether the sprite shall be drawn at all. Non-zero means drawing.
uint16_t max_sprite_offset
Maximum offset to add to the sprite. (limited by size of the spriteset)
uint8_t palette
Register specifying a signed offset for the palette.
uint8_t sprite_var10
Value for variable 10 when resolving the sprite.
uint16_t max_palette_offset
Maximum offset to add to the palette. (limited by size of the spriteset)
uint8_t palette_var10
Value for variable 10 when resolving the palette.
uint8_t child[2]
Registers for signed offsets for the position of child sprites.
uint8_t sprite
Register specifying a signed offset for the sprite.
Action 2 sprite layout for houses, industry tiles, objects and airport tiles.
uint8_t road_side
the side of the road vehicles drive on
bool wagon_speed_limits
enable wagon speed limits
bool dynamic_engines
enable dynamic allocation of engine data
uint8_t freight_trains
value to multiply the weight of cargo by
uint8_t plane_speed
divisor for speed of aircraft
bool never_expire_vehicles
never expire vehicles
bool disable_elrails
when true, the elrails are disabled
uint8_t callback_mask
Bitmask of canal callbacks that have to be called.
const SpriteGroup * group
Sprite group to start resolving.
const GRFFile * grffile
NewGRF where 'group' belongs to.
uint8_t flags
Flags controlling display.
static const uint TILE_HEIGHT
Height of a height level in world coordinate AND in pixels in ZOOM_BASE.
Definition tile_type.h:18
Definition of the game-calendar-timer.
Definition of the tick-based game-timer.
Base of the town class.
uint8_t _display_opt
What do we want to draw/do?
LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
Determines the LiveryScheme for a vehicle.
Definition vehicle.cpp:1970
Base class for all vehicles.
@ VE_TYPE_COUNT
Number of bits used for the effect type.
@ VE_TYPE_START
First bit used for the type of effect.
@ VE_DISABLE_EFFECT
Flag to disable visual effect.
@ VE_DEFAULT
Default value to indicate that visual effect should be based on engine class.
Functions related to vehicles.
VehicleType
Available vehicle types.
@ VEH_ROAD
Road vehicle type.
@ VEH_AIRCRAFT
Aircraft vehicle type.
@ VEH_SHIP
Ship vehicle type.
@ VEH_TRAIN
Train vehicle type.